{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "button-group",
  "title": "Button group",
  "description": "A set of actions, drawn three ways: one pair of parentheses with hairlines between, a narrow column with a dash hung in the margin, or a list written into the sentence around it.",
  "registryDependencies": [
    "https://thedirectors.agency/ui/r/0nlytype.json",
    "https://thedirectors.agency/ui/r/button.json"
  ],
  "files": [
    {
      "path": "registry/0nlytype/ui/button-group.tsx",
      "content": "import * as React from \"react\"\n\nimport { cn } from \"@/lib/utils\"\n\ntype ButtonGroupProps = React.ComponentProps<\"div\"> & {\n  /** Names the set for a screen reader: \"Share Halden\". */\n  \"aria-label\": string\n  /**\n   * parentheses: one pair holds the set, hairlines between. column: the actions stacked as a narrow\n   * ragged column, a dash hung in the margin beside the one you point at. sentence: the actions\n   * written as a list in running text, with commas and a conjunction between them.\n   */\n  variant?: \"parentheses\" | \"column\" | \"sentence\"\n  /** The word before the last action in a sentence: \"or\", \"and\", or the page's own language. */\n  conjunction?: string\n}\n\n/** One pair of parentheses holds a set of Buttons; hairlines stand between them. Its Buttons drop their own brackets. */\nfunction ButtonGroup({ className, variant = \"parentheses\", conjunction = \"or\", children, ...props }: ButtonGroupProps) {\n  if (variant === \"sentence\") {\n    // ponytail: the separators are English list punctuation; `conjunction` covers the word, not the commas.\n    const items = React.Children.toArray(children)\n    const last = items.length - 1\n    return (\n      <span role=\"group\" data-slot=\"button-group\" data-variant={variant} className={cn(\"ot-btn-group\", className)} {...(props as React.ComponentProps<\"span\">)}>\n        {items.map((item, i) => (\n          <React.Fragment key={i}>\n            {i > 0 ? (\n              <span className=\"ot-btn-group-sep\" aria-hidden=\"true\">\n                {i < last ? \", \" : `${last > 1 ? \",\" : \"\"} ${conjunction} `}\n              </span>\n            ) : null}\n            {item}\n          </React.Fragment>\n        ))}\n      </span>\n    )\n  }\n  return (\n    <div role=\"group\" data-slot=\"button-group\" data-variant={variant} className={cn(\"ot-btn-group\", className)} {...props}>\n      {children}\n    </div>\n  )\n}\n\nexport { ButtonGroup, type ButtonGroupProps }\n",
      "type": "registry:ui"
    },
    {
      "path": "registry/0nlytype/styles/button-group.css",
      "content": "@layer components {\n  /* ── ot-btn-group ── one pair of parentheses holds the set */\n  .ot-btn-group { display: inline-flex; align-items: baseline; flex-wrap: wrap; color: var(--ot-ink); }\n  .ot-btn-group::before, .ot-btn-group::after { font-weight: 200; font-size: 1.2em; line-height: 0; }\n  .ot-btn-group::before { content: \"(\" / \"\"; margin-inline-end: 0.1em; }\n  .ot-btn-group::after { content: \")\" / \"\"; margin-inline-start: 0.1em; }\n  /* The set has its own brackets, so its Buttons drop theirs (and any redraw) whatever variant they carry. */\n  .ot-btn-group > .ot-btn[data-slot=\"button\"] {\n    padding: 0 0.6em 0.16em; animation: none;\n    background: linear-gradient(currentColor, currentColor) no-repeat 100% 100% / 0% var(--ot-hairline);\n    background-origin: content-box; background-clip: content-box;\n    transition: background-size var(--ot-moderato) var(--ot-exhale), background-position 0s;\n  }\n  .ot-btn-group > .ot-btn[data-slot=\"button\"]::before,\n  .ot-btn-group > .ot-btn[data-slot=\"button\"]::after { content: none; }\n  .ot-btn-group > .ot-btn[data-slot=\"button\"] + .ot-btn { border-inline-start: var(--ot-hairline) solid var(--ot-rule-strong); }\n  .ot-btn-group > .ot-btn[data-slot=\"button\"]:is(:hover, [data-force~=\"hover\"]):not(:disabled) { background-position: 0 100%; background-size: 100% var(--ot-hairline); animation: none; }\n  /* Right to left, the line enters from the other side. */\n  .ot-btn-group:is([dir=\"rtl\"], [dir=\"rtl\"] *) > .ot-btn[data-slot=\"button\"] { background-position: 0 100%; }\n  .ot-btn-group:is([dir=\"rtl\"], [dir=\"rtl\"] *) > .ot-btn[data-slot=\"button\"]:is(:hover, [data-force~=\"hover\"]):not(:disabled) { background-position: 100% 100%; }\n\n  /* column: after \"Less is more.\" and Healthy habits, the actions stacked as a narrow ragged column at tight leading, no rules between.\n     Pointing hangs the poster's short heavy dash in the margin beside the action; it grows out from the word and goes back into it. */\n  .ot-btn-group[data-variant=\"column\"] { display: inline-flex; flex-direction: column; align-items: flex-start; flex-wrap: nowrap; }\n  .ot-btn-group:is([data-variant=\"column\"], [data-variant=\"sentence\"])::before, .ot-btn-group:is([data-variant=\"column\"], [data-variant=\"sentence\"])::after { content: none; }\n  .ot-btn-group[data-variant=\"column\"] > .ot-btn[data-slot=\"button\"] { padding: 0.2em 0; line-height: 1.25; background: none; }\n  .ot-btn-group[data-variant=\"column\"] > .ot-btn[data-slot=\"button\"] + .ot-btn { border: 0; }\n  .ot-btn-group[data-variant=\"column\"] > .ot-btn[data-slot=\"button\"]::before {\n    content: \"\"; position: absolute; inset-inline: auto calc(100% + 0.5em); inset-block: calc(50% - 0.05em) auto; font-size: 1em; inline-size: 0.9em; block-size: max(var(--ot-stroke), 0.15em);\n    background: currentColor; scale: 0 1; transform-origin: 100% 50%; transition: scale var(--ot-moderato) var(--ot-exhale);\n  }\n  .ot-btn-group[data-variant=\"column\"]:is([dir=\"rtl\"], [dir=\"rtl\"] *) > .ot-btn[data-slot=\"button\"]::before { transform-origin: 0 50%; }\n  .ot-btn-group[data-variant=\"column\"] > .ot-btn[data-slot=\"button\"]:is(:hover, :focus-visible, [data-force~=\"hover\"]):not(:disabled)::before { scale: 1 1; }\n  .ot-btn-group[data-variant=\"column\"] > .ot-btn[data-slot=\"button\"]:active:not(:disabled)::before { scale: 1.4 1; transition-duration: var(--ot-allegro); }\n\n  /* sentence: the actions written as a list in running text (copy the link, email it, or export a PDF), the way prose names choices.\n     Each action stands on a pencil hairline; pointing passes an ink line through it, the group's own motion. The group takes the text's size. */\n  .ot-btn-group[data-variant=\"sentence\"] { display: inline; color: inherit; }\n  .ot-btn-group[data-variant=\"sentence\"] > .ot-btn[data-slot=\"button\"] {\n    vertical-align: baseline; padding: 0 0 0.12em; font-size: inherit; line-height: inherit; letter-spacing: inherit; color: var(--ot-ink);\n    background:\n      linear-gradient(currentColor, currentColor) no-repeat 100% 100% / 0% var(--ot-hairline),\n      linear-gradient(var(--ot-rule-strong), var(--ot-rule-strong)) no-repeat 0 100% / 100% var(--ot-hairline);\n    background-origin: border-box; background-clip: border-box;\n  }\n  .ot-btn-group[data-variant=\"sentence\"] > .ot-btn[data-slot=\"button\"]:is(:hover, [data-force~=\"hover\"]):not(:disabled) { background-position: 0 100%, 0 100%; background-size: 100% var(--ot-hairline), 100% var(--ot-hairline); }\n  .ot-btn-group[data-variant=\"sentence\"]:is([dir=\"rtl\"], [dir=\"rtl\"] *) > .ot-btn[data-slot=\"button\"] { background-position: 0 100%, 0 100%; }\n  .ot-btn-group[data-variant=\"sentence\"]:is([dir=\"rtl\"], [dir=\"rtl\"] *) > .ot-btn[data-slot=\"button\"]:is(:hover, [data-force~=\"hover\"]):not(:disabled) { background-position: 100% 100%, 0 100%; }\n  .ot-btn-group[data-variant=\"sentence\"] > .ot-btn[data-slot=\"button\"]:disabled { background-image: none; }\n  .ot-btn-group-sep { white-space: pre-wrap; }\n\n  @media (forced-colors: active) {\n    .ot-btn-group[data-variant=\"column\"] > .ot-btn[data-slot=\"button\"]::before { forced-color-adjust: none; background: ButtonText; }\n    .ot-btn-group[data-variant=\"sentence\"] > .ot-btn[data-slot=\"button\"] { text-decoration: underline; text-decoration-thickness: 1px; }\n  }\n}\n",
      "type": "registry:file",
      "target": "styles/0nlytype/button-group.css"
    }
  ],
  "css": {
    "@import \"../styles/0nlytype/button-group.css\"": {}
  },
  "meta": {
    "movement": "VI",
    "underneath": "native",
    "contract": "ot-btn-group"
  },
  "type": "registry:ui"
}
