{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "dependencies": [],
  "description": "Grouped toggle buttons (APG toolbar-like focus). type=single (one pressed, radio-like) or type=multiple (independent aria-pressed). Roving tabindex + Arrow/Home/End. Requires label. Composition via renderHeidiElement.",
  "files": [
    {
      "content": "\"use client\";\n\n/**\n * heidi-ui ToggleGroup — grouped toggle buttons\n * (docs/HEIDI-UI-HEADLESS.md § P4 / Slice G). role=group with required label.\n * type=single (one pressed; second click clears) or type=multiple (set of\n * pressed values). Roving tabindex + Arrow/Home/End (toolbar-like).\n * Items use aria-pressed (APG toggle button), not radiogroup.\n * Root/Item `disabled` → native disabled + data-disabled; nav skips disabled.\n *\n * RSC rule: named exports from Server Components; ToggleGroup.X is client sugar.\n */\n\nimport {\n  Children,\n  type ComponentPropsWithoutRef,\n  createContext,\n  Fragment,\n  isValidElement,\n  useCallback,\n  useContext,\n  useEffect,\n  useRef,\n  useState,\n  type FocusEvent,\n  type KeyboardEvent,\n  type MouseEvent,\n  type ReactNode,\n  type Ref\n} from \"react\";\nimport {\n  collectRovingItems,\n  NAVIGATION_KEYS,\n  resolveRovingIndex\n} from \"../_internal/roving-focus\";\nimport { dataDisabledAttrs, isDisabledElement, nativeDisabledAttrs } from \"../_internal/disabled\";\nimport {\n  composeHeidiEventHandlers,\n  mergeHeidiRefs,\n  renderHeidiElement,\n  type HeidiIntrinsicHostProps\n} from \"../_internal/render-element\";\nimport { useHeidiLayoutEffect } from \"../_internal/use-layout-effect\";\nimport {\n  type ToggleGroupOrientation,\n  type ToggleGroupType\n} from \"./toggle-group.anatomy.generated\";\nimport { TOGGLE_GROUP_CLASSES } from \"./toggle-group.classes.generated\";\n\nexport type { ToggleGroupOrientation, ToggleGroupType };\n\ntype ToggleGroupContextValue = {\n  claimInitialTabStop: (value: string, disabled: boolean) => boolean;\n  disabled: boolean;\n  orientation: ToggleGroupOrientation;\n  registerValue: (value: string, disabled: boolean) => void;\n  selected: readonly string[];\n  setTabbableValue: (value: string) => void;\n  tabbableValue: string | null;\n  toggle: (value: string) => void;\n  type: ToggleGroupType;\n  unregisterValue: (value: string) => void;\n};\n\nconst ToggleGroupContext = createContext<ToggleGroupContextValue | null>(null);\n\nfunction useToggleGroupContext(part: string): ToggleGroupContextValue {\n  const context = useContext(ToggleGroupContext);\n  if (!context) {\n    throw new Error(`ToggleGroup.${part} must be rendered inside ToggleGroup.Root.`);\n  }\n  return context;\n}\n\nfunction normalizeValue(\n  type: ToggleGroupType,\n  value: string | string[] | null | undefined\n): string[] {\n  if (value == null) {\n    return [];\n  }\n  if (type === \"single\") {\n    return typeof value === \"string\" ? [value] : value.slice(0, 1);\n  }\n  return Array.isArray(value) ? value : [value];\n}\n\nfunction emitValue(type: ToggleGroupType, selected: string[]): string | string[] | null {\n  if (type === \"single\") {\n    return selected[0] ?? null;\n  }\n  return selected;\n}\n\nfunction groupItems(container: HTMLElement): HTMLButtonElement[] {\n  return collectRovingItems<HTMLButtonElement>(\n    container,\n    '[data-hui-part=\"toggle-group-item\"]',\n    '[data-hui-part=\"toggle-group-root\"]',\n    isDisabledElement\n  );\n}\n\ntype ToggleGroupItemCandidateProps = {\n  children?: ReactNode;\n  disabled?: boolean;\n  value?: string;\n};\n\nfunction initialTabStopValueForChildren(\n  children: ReactNode,\n  groupDisabled: boolean,\n  selected: readonly string[]\n): string | null {\n  let firstEnabled: string | null = null;\n  let firstSelectedEnabled: string | null = null;\n\n  const visit = (nodes: ReactNode) => {\n    Children.forEach(nodes, (child) => {\n      if (!isValidElement<ToggleGroupItemCandidateProps>(child)) {\n        return;\n      }\n      if (\n        child.type === ToggleGroupItem &&\n        child.props.value !== undefined &&\n        !groupDisabled &&\n        child.props.disabled !== true\n      ) {\n        firstEnabled ??= child.props.value;\n        if (\n          firstSelectedEnabled === null &&\n          selected.includes(child.props.value)\n        ) {\n          firstSelectedEnabled = child.props.value;\n        }\n        return;\n      }\n      if (child.type === Fragment || typeof child.type === \"string\") {\n        visit(child.props.children);\n      }\n    });\n  };\n\n  visit(children);\n  return firstSelectedEnabled ?? firstEnabled;\n}\n\nexport type ToggleGroupRootState = {\n  disabled: boolean;\n  orientation: ToggleGroupOrientation;\n  type: ToggleGroupType;\n  value: string | string[] | null;\n};\n\ntype ToggleGroupRootNativeProps = Omit<\n  ComponentPropsWithoutRef<\"div\">,\n  | \"aria-label\"\n  | \"aria-orientation\"\n  | \"children\"\n  | \"className\"\n  | \"defaultValue\"\n  | \"onKeyDown\"\n  | \"ref\"\n  | \"role\"\n  | \"style\"\n  | \"value\"\n>;\n\nexport type ToggleGroupRootProps = HeidiIntrinsicHostProps<ToggleGroupRootState, \"div\"> &\n  ToggleGroupRootNativeProps & {\n    children?: ReactNode;\n    defaultValue?: string | string[] | null;\n    disabled?: boolean;\n    /** Accessible name for the group (aria-label). Required. */\n    label: string;\n    onKeyDown?: ComponentPropsWithoutRef<\"div\">[\"onKeyDown\"];\n    onValueChange?: (value: string | string[] | null) => void;\n    orientation?: ToggleGroupOrientation;\n    ref?: Ref<HTMLDivElement>;\n    type?: ToggleGroupType;\n    value?: string | string[] | null;\n  };\n\nexport function ToggleGroupRoot({\n  children,\n  className,\n  defaultValue = null,\n  disabled = false,\n  label,\n  onKeyDown,\n  onValueChange,\n  orientation = \"horizontal\",\n  ref,\n  render,\n  style,\n  type = \"single\",\n  value: valueProp,\n  ...nativeProps\n}: ToggleGroupRootProps) {\n  const [internal, setInternal] = useState<string[]>(() =>\n    normalizeValue(type, defaultValue)\n  );\n  const [order, setOrder] = useState<Array<{ disabled: boolean; value: string }>>([]);\n  const [rovingValue, setRovingValue] = useState<string | null>(null);\n  const rootRef = useRef<HTMLDivElement | null>(null);\n  const controlled = valueProp !== undefined;\n  const selected = controlled ? normalizeValue(type, valueProp) : internal;\n\n  const setSelected = useCallback(\n    (next: string[]) => {\n      if (!controlled) {\n        setInternal(next);\n      }\n      onValueChange?.(emitValue(type, next));\n    },\n    [controlled, onValueChange, type]\n  );\n\n  const toggle = useCallback(\n    (itemValue: string) => {\n      if (disabled) {\n        return;\n      }\n      if (type === \"single\") {\n        setSelected(selected.includes(itemValue) ? [] : [itemValue]);\n        return;\n      }\n      setSelected(\n        selected.includes(itemValue)\n          ? selected.filter((entry) => entry !== itemValue)\n          : [...selected, itemValue]\n      );\n    },\n    [disabled, selected, setSelected, type]\n  );\n\n  const registerValue = useCallback((itemValue: string, itemDisabled: boolean) => {\n    setOrder((prev) => {\n      const existing = prev.find((entry) => entry.value === itemValue);\n      if (existing) {\n        if (existing.disabled === itemDisabled) {\n          return prev;\n        }\n        return prev.map((entry) =>\n          entry.value === itemValue ? { disabled: itemDisabled, value: itemValue } : entry\n        );\n      }\n      return [...prev, { disabled: itemDisabled, value: itemValue }];\n    });\n  }, []);\n\n  const unregisterValue = useCallback((itemValue: string) => {\n    setOrder((prev) => prev.filter((entry) => entry.value !== itemValue));\n  }, []);\n\n  const enabledOrder = order.filter((entry) => !entry.disabled).map((entry) => entry.value);\n  const tabbableValue =\n    (rovingValue !== null && enabledOrder.includes(rovingValue)\n      ? rovingValue\n      : undefined) ??\n    selected.find((entry) => enabledOrder.includes(entry)) ??\n    enabledOrder[0] ??\n    null;\n  const setTabbableValue = useCallback((itemValue: string) => {\n    setRovingValue(itemValue);\n  }, []);\n\n  // Keyed children can reorder without a prop change, so reconcile DOM order\n  // after every commit while preserving the previous state when it is equal.\n  // eslint-disable-next-line react-hooks/exhaustive-deps\n  useHeidiLayoutEffect(() => {\n    const root = rootRef.current;\n    if (!root) {\n      return;\n    }\n    const next = Array.from(\n      root.querySelectorAll<HTMLButtonElement>(\n        \"[data-hui-toggle-group-value]\"\n      )\n    )\n      .filter(\n        (element) =>\n          element.closest('[data-hui-part=\"toggle-group-root\"]') === root\n      )\n      .flatMap((element) => {\n        const itemValue = element.dataset.huiToggleGroupValue;\n        return itemValue === undefined\n          ? []\n          : [{ disabled: isDisabledElement(element), value: itemValue }];\n      });\n    setOrder((previous) =>\n      previous.length === next.length &&\n      previous.every(\n        (entry, index) =>\n          entry.disabled === next[index]?.disabled &&\n          entry.value === next[index]?.value\n      )\n        ? previous\n        : next\n    );\n  });\n\n  const handleKeyDown = composeHeidiEventHandlers(\n    onKeyDown,\n    (event: KeyboardEvent<HTMLDivElement>) => {\n      if (!NAVIGATION_KEYS.includes(event.key)) {\n        return;\n      }\n      const items = groupItems(event.currentTarget);\n      if (items.length === 0) {\n        return;\n      }\n      const next = resolveRovingIndex(\n        items,\n        document.activeElement,\n        event.key,\n        event.currentTarget,\n        { crossAxis: true, orientation }\n      );\n      if (next === null) {\n        return;\n      }\n      event.preventDefault();\n      const nextItem = items[next];\n      if (nextItem) {\n        const nextValue = nextItem.dataset.huiToggleGroupValue;\n        if (nextValue !== undefined) {\n          setTabbableValue(nextValue);\n        }\n        nextItem.focus();\n      }\n    }\n  );\n\n  const preparedInitialTabStopValue = initialTabStopValueForChildren(\n    children,\n    disabled,\n    selected\n  );\n  let fallbackInitialTabStopValue: string | null = null;\n\n  const context: ToggleGroupContextValue = {\n    claimInitialTabStop: (itemValue, itemDisabled) => {\n      if (preparedInitialTabStopValue !== null) {\n        return !itemDisabled && itemValue === preparedInitialTabStopValue;\n      }\n      if (\n        itemDisabled ||\n        (fallbackInitialTabStopValue !== null &&\n          fallbackInitialTabStopValue !== itemValue)\n      ) {\n        return false;\n      }\n      fallbackInitialTabStopValue = itemValue;\n      return true;\n    },\n    disabled,\n    orientation,\n    registerValue,\n    selected,\n    setTabbableValue,\n    tabbableValue,\n    toggle,\n    type,\n    unregisterValue\n  };\n\n  const emittedValue = emitValue(type, selected);\n\n  return (\n    <ToggleGroupContext value={context}>\n      {renderHeidiElement({\n        className: TOGGLE_GROUP_CLASSES.root,\n        dataPart: \"toggle-group-root\",\n        element: \"div\",\n        props: {\n          ...nativeProps,\n          \"aria-label\": label,\n          // ponytail: NO `aria-orientation` here. ARIA 1.2 supports it only on\n          // scrollbar/select/separator/slider/tablist/toolbar and the composite\n          // container roles (listbox, menu, menubar, radiogroup, tree,\n          // treegrid, toolbar) — `group` is on none of those lists, so setting\n          // it was an axe `aria-allowed-attr` violation on every ToggleGroup.\n          // `data-orientation` below is the styling and testing hook, and the\n          // roving-focus handler reads the `orientation` prop directly.\n          // Rejected switching the root to `role=\"toolbar\"` for type=\"multiple\"\n          // (Radix's escape hatch): toolbar changes the announced semantics and\n          // the Tab-stop contract of a control that is not a toolbar, purely to\n          // legalise an attribute nothing consumes. Base UI's ToggleGroup keeps\n          // role=group and omits the attribute, which is what this now does.\n          children,\n          \"data-orientation\": orientation,\n          \"data-type\": type,\n          onKeyDown: handleKeyDown,\n          ref: mergeHeidiRefs(rootRef, ref),\n          role: \"group\",\n          ...dataDisabledAttrs(disabled)\n        },\n        renderProps: { className, render, style },\n        state: { disabled, orientation, type, value: emittedValue }\n      })}\n    </ToggleGroupContext>\n  );\n}\n\nexport type ToggleGroupItemState = { disabled: boolean; pressed: boolean };\n\ntype ToggleGroupItemNativeProps = Omit<\n  ComponentPropsWithoutRef<\"button\">,\n  | \"aria-pressed\"\n  | \"children\"\n  | \"className\"\n  | \"disabled\"\n  | \"onClick\"\n  | \"onFocus\"\n  | \"ref\"\n  | \"style\"\n  | \"tabIndex\"\n  | \"type\"\n  | \"value\"\n>;\n\nexport type ToggleGroupItemProps = HeidiIntrinsicHostProps<\n  ToggleGroupItemState,\n  \"button\"\n> &\n  ToggleGroupItemNativeProps & {\n    children?: ReactNode;\n    disabled?: boolean;\n    onClick?: ComponentPropsWithoutRef<\"button\">[\"onClick\"];\n    onFocus?: ComponentPropsWithoutRef<\"button\">[\"onFocus\"];\n    ref?: Ref<HTMLButtonElement>;\n    value: string;\n  };\n\nexport function ToggleGroupItem({\n  children,\n  className,\n  disabled: disabledProp = false,\n  onClick,\n  onFocus,\n  ref,\n  render,\n  style,\n  value,\n  ...nativeProps\n}: ToggleGroupItemProps) {\n  const {\n    claimInitialTabStop,\n    disabled: groupDisabled,\n    registerValue,\n    selected,\n    setTabbableValue,\n    tabbableValue,\n    toggle,\n    unregisterValue\n  } =\n    useToggleGroupContext(\"Item\");\n  const disabled = groupDisabled || disabledProp;\n  const pressed = selected.includes(value);\n\n  useEffect(() => {\n    registerValue(value, disabled);\n    return () => unregisterValue(value);\n  }, [disabled, registerValue, unregisterValue, value]);\n  const initialTabStop =\n    tabbableValue === null && claimInitialTabStop(value, disabled);\n  const handleClick = composeHeidiEventHandlers(\n    onClick,\n    (event: MouseEvent<HTMLButtonElement>) => {\n      if (disabled) {\n        event.preventDefault();\n        return;\n      }\n      toggle(value);\n    }\n  );\n  const handleFocus = composeHeidiEventHandlers(\n    onFocus,\n    (_event: FocusEvent<HTMLButtonElement>) => {\n      if (!disabled) {\n        setTabbableValue(value);\n      }\n    }\n  );\n\n  return renderHeidiElement({\n    className: TOGGLE_GROUP_CLASSES.item,\n    dataPart: \"toggle-group-item\",\n    element: \"button\",\n    props: {\n      ...nativeProps,\n      \"aria-pressed\": pressed,\n      children,\n      \"data-hui-toggle-group-value\": value,\n      \"data-state\": pressed ? \"on\" : \"off\",\n      onClick: handleClick,\n      onFocus: handleFocus,\n      ref,\n      tabIndex:\n        !disabled &&\n        (tabbableValue === value || initialTabStop)\n          ? 0\n          : -1,\n      type: \"button\",\n      ...nativeDisabledAttrs(disabled)\n    },\n    renderProps: { className, render, style },\n    state: { disabled, pressed }\n  });\n}\n\nexport const ToggleGroup = {\n  Item: ToggleGroupItem,\n  Root: ToggleGroupRoot\n} as const;\n",
      "path": "packages/heidi-ui/src/toggle-group/toggle-group.tsx",
      "target": "components/ui/heidi/toggle-group/toggle-group.tsx",
      "type": "registry:ui"
    },
    {
      "content": "/*\n * heidi-ui toggle-group — STRUCTURAL CSS only. No --hui-*.\n */\n\n@layer heidi-ui-base {\n  .hui-toggle-group-root {\n    box-sizing: border-box;\n    display: inline-flex;\n    gap: 0;\n    max-inline-size: 100%;\n    min-inline-size: 0;\n  }\n\n  .hui-toggle-group-root[data-orientation=\"horizontal\"] {\n    flex-direction: row;\n    overflow-x: auto;\n    overscroll-behavior-x: contain;\n  }\n\n  .hui-toggle-group-root[data-orientation=\"vertical\"] {\n    flex-direction: column;\n  }\n\n  .hui-toggle-group-root[data-type=\"single\"],\n  .hui-toggle-group-root[data-type=\"multiple\"] {\n    /* Type is behavioral; keep a structural hook for consumers/agents. */\n    display: inline-flex;\n  }\n\n  .hui-toggle-group-item {\n    flex: 0 0 auto;\n  }\n}\n",
      "path": "packages/heidi-ui/src/toggle-group/toggle-group.base.css",
      "target": "components/ui/heidi/toggle-group/toggle-group.base.css",
      "type": "registry:ui"
    },
    {
      "content": "/*\n * heidi-ui toggle-group — VISUAL theme (opt-in). Consumes --hui-*.\n */\n\n@layer heidi-ui {\n  .hui-toggle-group-root {\n    background: var(--hui-color-bg-elevated);\n    border: var(--hui-border-width) var(--hui-border-style) var(--hui-color-border-default);\n    border-radius: var(--hui-radius-md);\n    gap: 0;\n    /* Keep the segmented edge clipped without making a long horizontal group\n       unreachable at a narrow width. The base layer supplies overflow-x:auto;\n       this block-axis clip is the visual half of that structural policy. */\n    overflow: hidden;\n    overflow-x: auto;\n  }\n\n  .hui-toggle-group-item {\n    align-items: center;\n    background: var(--hui-color-bg-elevated);\n    border: 0;\n    border-radius: 0;\n    color: var(--hui-color-fg-default);\n    cursor: pointer;\n    font: inherit;\n    justify-content: center;\n    padding: var(--hui-space-1-5) var(--hui-space-3);\n  }\n\n  .hui-toggle-group-root[data-orientation=\"horizontal\"]\n    .hui-toggle-group-item\n    + .hui-toggle-group-item {\n    border-inline-start: var(--hui-border-width) var(--hui-border-style)\n      var(--hui-color-border-default);\n  }\n\n  .hui-toggle-group-root[data-orientation=\"vertical\"]\n    .hui-toggle-group-item\n    + .hui-toggle-group-item {\n    border-block-start: var(--hui-border-width) var(--hui-border-style)\n      var(--hui-color-border-default);\n  }\n\n  .hui-toggle-group-item:focus-visible {\n    outline: var(--hui-focus-ring-width) solid var(--hui-color-focus-ring);\n    /* The segmented root is a scroll/clipping boundary. Keep the ring inside\n       the focused segment so the first and last controls retain all four sides. */\n    outline-offset: calc(-1 * var(--hui-focus-ring-offset));\n  }\n\n  .hui-toggle-group-item[data-state=\"off\"] {\n    background: var(--hui-color-bg-elevated);\n  }\n\n  /* Selected reads as a LIT control, matching filled buttons: gradient fill,\n     a ring in the fill's dark stop, inset top highlight, soft drop. */\n  .hui-toggle-group-item[data-state=\"on\"] {\n    background-color: var(--hui-color-brand-primary);\n    background-image: linear-gradient(\n      var(--hui-color-brand-primary-active, var(--hui-color-brand-primary)),\n      var(--hui-color-brand-primary)\n    );\n    border-color: var(\n      --hui-color-brand-primary-active,\n      var(--hui-color-brand-primary)\n    );\n    box-shadow: var(--hui-shadow-pill-raised);\n    color: var(--hui-color-on-brand, #fff);\n  }\n\n  .hui-toggle-group-item:hover {\n    background: var(--hui-color-interactive-ghost-bg-hover);\n  }\n\n  .hui-toggle-group-item[data-state=\"on\"]:hover {\n    background-color: var(--hui-color-brand-primary);\n    background-image: linear-gradient(\n      var(--hui-color-brand-primary),\n      var(--hui-color-brand-primary)\n    );\n  }\n\n  .hui-toggle-group-root[data-disabled=\"true\"] {\n    cursor: not-allowed;\n  }\n\n  .hui-toggle-group-item:disabled,\n  .hui-toggle-group-item[data-disabled=\"true\"] {\n    cursor: not-allowed;\n    opacity: 0.5;\n  }\n\n  /* ponytail: scoped off the selected state — this rule reset the ground\n     without resetting the foreground, so a disabled+selected item hovered in\n     the light scheme painted `--hui-color-on-brand` white on\n     `--hui-color-bg-elevated` white and the label vanished. Same fix and same\n     rejected alternative as toggle.theme.css: a disabled control must not\n     change appearance on hover, so the selected pair stays intact rather than\n     gaining a foreground reset here. */\n  .hui-toggle-group-item:disabled:hover:not([data-state=\"on\"]),\n  .hui-toggle-group-item[data-disabled=\"true\"]:hover:not([data-state=\"on\"]) {\n    background: var(--hui-color-bg-elevated);\n  }\n\n  @media (forced-colors: active) {\n    .hui-toggle-group-root {\n      border-color: CanvasText;\n    }\n\n    .hui-toggle-group-item {\n      background: Canvas;\n      border-color: CanvasText;\n      color: CanvasText;\n      forced-color-adjust: none;\n    }\n\n    .hui-toggle-group-item[data-state=\"on\"],\n    .hui-toggle-group-item[data-state=\"on\"]:hover {\n      background: Highlight;\n      background-image: none;\n      border-color: Highlight;\n      box-shadow: none;\n      color: HighlightText;\n    }\n\n    .hui-toggle-group-item:focus-visible {\n      outline-color: Highlight;\n    }\n\n    .hui-toggle-group-item:disabled,\n    .hui-toggle-group-item[data-disabled=\"true\"] {\n      border-color: GrayText;\n      color: GrayText;\n      opacity: 1;\n    }\n  }\n}\n",
      "path": "packages/heidi-ui/src/toggle-group/toggle-group.theme.css",
      "target": "components/ui/heidi/toggle-group/toggle-group.theme.css",
      "type": "registry:ui"
    },
    {
      "content": "/*\n * heidi-ui toggle-group — aggregator.\n */\n\n@import \"./toggle-group.base.css\";\n@import \"../../../../styles/heidi-ui-adapter.css\";\n@import \"./toggle-group.theme.css\";\n",
      "path": "packages/heidi-ui/src/toggle-group/toggle-group.css",
      "target": "components/ui/heidi/toggle-group/toggle-group.css",
      "type": "registry:ui"
    },
    {
      "content": "/** GENERATED from packages/heidi-ui/src/toggle-group/toggle-group.base.css + packages/heidi-ui/src/toggle-group/toggle-group.theme.css — do not edit by hand.\n * Rebuild: `bun run hui:build`. Freshness: `bun run contracts:check`. */\nexport const TOGGLE_GROUP_CLASSES = {\n  item: \"hui-toggle-group-item\",\n  root: \"hui-toggle-group-root\",\n} as const;\n",
      "path": "packages/heidi-ui/src/toggle-group/toggle-group.classes.generated.ts",
      "target": "components/ui/heidi/toggle-group/toggle-group.classes.generated.ts",
      "type": "registry:ui"
    },
    {
      "content": "/** GENERATED from toggle-group.anatomy.json + toggle-group.base.css + toggle-group.theme.css — do not edit by hand.\n * Rebuild: `bun run hui:build`. Freshness: `bun run contracts:check`. */\n\nexport type ToggleGroupDisabled = \"true\";\nexport type ToggleGroupOrientation = \"horizontal\" | \"vertical\";\nexport type ToggleGroupState = \"off\" | \"on\";\nexport type ToggleGroupType = \"multiple\" | \"single\";\n\nexport const TOGGLE_GROUP_ANATOMY = {\n  \"component\": \"toggle-group\",\n  \"description\": \"Grouped toggle buttons (APG toolbar-like focus). type=single (one pressed, radio-like) or type=multiple (independent aria-pressed). Roving tabindex + Arrow/Home/End. Requires label. Composition via renderHeidiElement.\",\n  \"schemaVersion\": 2,\n  \"parts\": {\n    \"item\": {\n      \"aria\": {\n        \"owns\": [\n          \"aria-pressed\"\n        ],\n        \"role\": null\n      },\n      \"class\": \"hui-toggle-group-item\",\n      \"css\": {\n        \"structural\": []\n      },\n      \"dataPart\": \"toggle-group-item\",\n      \"description\": \"Toggle button inside the group; value identifies selection. aria-pressed + data-state on|off.\",\n      \"element\": \"button\",\n      \"nativeProps\": true,\n      \"props\": [\n        \"className\",\n        \"disabled\",\n        \"onClick\",\n        \"onFocus\",\n        \"ref\",\n        \"render\",\n        \"style\",\n        \"value\"\n      ],\n      \"pseudoStates\": [\n        \":disabled\",\n        \":focus-visible\",\n        \":hover\"\n      ],\n      \"states\": {\n        \"data-disabled\": [\n          \"true\"\n        ],\n        \"data-state\": [\n          \"off\",\n          \"on\"\n        ]\n      }\n    },\n    \"root\": {\n      \"aria\": {\n        \"owns\": [\n          \"aria-label\"\n        ],\n        \"role\": \"group\"\n      },\n      \"class\": \"hui-toggle-group-root\",\n      \"css\": {\n        \"structural\": [\n          \"display\",\n          \"flex-direction\",\n          \"gap\"\n        ]\n      },\n      \"dataPart\": \"toggle-group-root\",\n      \"description\": \"Group container; role=group with required label. Owns arrow-key focus among items. Orientation is exposed as data-orientation only — ARIA does not allow aria-orientation on role=group.\",\n      \"element\": \"div\",\n      \"nativeProps\": true,\n      \"props\": [\n        \"className\",\n        \"defaultValue\",\n        \"disabled\",\n        \"label\",\n        \"onKeyDown\",\n        \"onValueChange\",\n        \"orientation\",\n        \"ref\",\n        \"render\",\n        \"style\",\n        \"type\",\n        \"value\"\n      ],\n      \"pseudoStates\": [],\n      \"states\": {\n        \"data-disabled\": [\n          \"true\"\n        ],\n        \"data-orientation\": [\n          \"horizontal\",\n          \"vertical\"\n        ],\n        \"data-type\": [\n          \"multiple\",\n          \"single\"\n        ]\n      }\n    }\n  },\n  \"rootProps\": [\n    \"defaultValue\",\n    \"disabled\",\n    \"label\",\n    \"onValueChange\",\n    \"orientation\",\n    \"type\",\n    \"value\"\n  ],\n  \"tokens\": [\n    \"--hui-border-style\",\n    \"--hui-border-width\",\n    \"--hui-color-bg-elevated\",\n    \"--hui-color-border-default\",\n    \"--hui-color-brand-primary\",\n    \"--hui-color-brand-primary-active\",\n    \"--hui-color-fg-default\",\n    \"--hui-color-focus-ring\",\n    \"--hui-color-interactive-ghost-bg-hover\",\n    \"--hui-color-on-brand\",\n    \"--hui-focus-ring-offset\",\n    \"--hui-focus-ring-width\",\n    \"--hui-radius-md\",\n    \"--hui-shadow-pill-raised\",\n    \"--hui-space-1-5\",\n    \"--hui-space-3\"\n  ]\n} as const;\n",
      "path": "packages/heidi-ui/src/toggle-group/toggle-group.anatomy.generated.ts",
      "target": "components/ui/heidi/toggle-group/toggle-group.anatomy.generated.ts",
      "type": "registry:ui"
    },
    {
      "content": "{\n  \"component\": \"toggle-group\",\n  \"description\": \"Grouped toggle buttons (APG toolbar-like focus). type=single (one pressed, radio-like) or type=multiple (independent aria-pressed). Roving tabindex + Arrow/Home/End. Requires label. Composition via renderHeidiElement.\",\n  \"schemaVersion\": 2,\n  \"parts\": {\n    \"item\": {\n      \"aria\": {\n        \"owns\": [\n          \"aria-pressed\"\n        ],\n        \"role\": null\n      },\n      \"class\": \"hui-toggle-group-item\",\n      \"css\": {\n        \"structural\": []\n      },\n      \"dataPart\": \"toggle-group-item\",\n      \"description\": \"Toggle button inside the group; value identifies selection. aria-pressed + data-state on|off.\",\n      \"element\": \"button\",\n      \"nativeProps\": true,\n      \"props\": [\n        \"className\",\n        \"disabled\",\n        \"onClick\",\n        \"onFocus\",\n        \"ref\",\n        \"render\",\n        \"style\",\n        \"value\"\n      ],\n      \"pseudoStates\": [\n        \":disabled\",\n        \":focus-visible\",\n        \":hover\"\n      ],\n      \"states\": {\n        \"data-disabled\": [\n          \"true\"\n        ],\n        \"data-state\": [\n          \"off\",\n          \"on\"\n        ]\n      }\n    },\n    \"root\": {\n      \"aria\": {\n        \"owns\": [\n          \"aria-label\"\n        ],\n        \"role\": \"group\"\n      },\n      \"class\": \"hui-toggle-group-root\",\n      \"css\": {\n        \"structural\": [\n          \"display\",\n          \"flex-direction\",\n          \"gap\"\n        ]\n      },\n      \"dataPart\": \"toggle-group-root\",\n      \"description\": \"Group container; role=group with required label. Owns arrow-key focus among items. Orientation is exposed as data-orientation only — ARIA does not allow aria-orientation on role=group.\",\n      \"element\": \"div\",\n      \"nativeProps\": true,\n      \"props\": [\n        \"className\",\n        \"defaultValue\",\n        \"disabled\",\n        \"label\",\n        \"onKeyDown\",\n        \"onValueChange\",\n        \"orientation\",\n        \"ref\",\n        \"render\",\n        \"style\",\n        \"type\",\n        \"value\"\n      ],\n      \"pseudoStates\": [],\n      \"states\": {\n        \"data-disabled\": [\n          \"true\"\n        ],\n        \"data-orientation\": [\n          \"horizontal\",\n          \"vertical\"\n        ],\n        \"data-type\": [\n          \"multiple\",\n          \"single\"\n        ]\n      }\n    }\n  },\n  \"rootProps\": [\n    \"defaultValue\",\n    \"disabled\",\n    \"label\",\n    \"onValueChange\",\n    \"orientation\",\n    \"type\",\n    \"value\"\n  ]\n}\n",
      "path": "packages/heidi-ui/src/toggle-group/toggle-group.anatomy.json",
      "target": "components/ui/heidi/toggle-group/toggle-group.anatomy.json",
      "type": "registry:ui"
    },
    {
      "content": "/**\n * Cross-cutting disabled attrs for heidi-ui interactive hosts.\n *\n * House convention (Phase 23):\n * - Button widgets → native `disabled` + `data-disabled=\"true\"` (CSS + a11y).\n * - Non-button options (Select.Item) → `aria-disabled` + `data-disabled=\"true\"`\n *   (native disabled is invalid on role=option divs).\n * - Group roots may cascade `disabled` to children and mirror `data-disabled`.\n * - Keyboard nav / activation always skip disabled hosts.\n */\n\nexport type NativeDisabledAttrs = {\n  \"data-disabled\"?: true;\n  disabled?: true;\n};\n\nexport type AriaDisabledAttrs = {\n  \"aria-disabled\"?: true;\n  \"data-disabled\"?: true;\n};\n\nexport type DataDisabledAttrs = {\n  \"data-disabled\"?: true;\n};\n\n/** Native button/input disabled + styling hook. */\nexport function nativeDisabledAttrs(disabled: boolean | undefined): NativeDisabledAttrs {\n  if (!disabled) {\n    return {};\n  }\n  return {\n    \"data-disabled\": true,\n    disabled: true\n  };\n}\n\n/** ARIA-disabled for non-native hosts (e.g. role=option). */\nexport function ariaDisabledAttrs(disabled: boolean | undefined): AriaDisabledAttrs {\n  if (!disabled) {\n    return {};\n  }\n  return {\n    \"aria-disabled\": true,\n    \"data-disabled\": true\n  };\n}\n\n/** Styling hook only (group roots that cascade disabled). */\nexport function dataDisabledAttrs(disabled: boolean | undefined): DataDisabledAttrs {\n  if (!disabled) {\n    return {};\n  }\n  return {\n    \"data-disabled\": true\n  };\n}\n\nexport function isDisabledElement(el: Element | null | undefined): boolean {\n  if (!el || !(el instanceof HTMLElement)) {\n    return false;\n  }\n  if (el.matches(\":disabled\")) {\n    return true;\n  }\n  return el.getAttribute(\"aria-disabled\") === \"true\" || el.getAttribute(\"data-disabled\") === \"true\";\n}\n",
      "path": "packages/heidi-ui/src/_internal/disabled.ts",
      "target": "components/ui/heidi/_internal/disabled.ts",
      "type": "registry:ui"
    },
    {
      "content": "/**\n * Shared host rendering for heidi-ui parts — Base-UI-shaped composition\n * (docs/HEIDI-UI-HEADLESS.md § 4 / HEIDI-UI.md § 4.5):\n *   - className / style as value or (state) => value\n *   - render as ReactElement or (props, state) => ReactElement\n *   - ref forwarding\n *   - data-hui-part always set (stable unstyled hook)\n *\n * Structural inline styles (e.g. anchorName) are merged last so a consumer\n * style override cannot drop platform wiring.\n */\n\nimport {\n  cloneElement,\n  createElement,\n  isValidElement,\n  type CSSProperties,\n  type ComponentPropsWithRef,\n  type HTMLAttributes,\n  type ReactElement,\n  type ReactNode,\n  type Ref,\n  type RefCallback\n} from \"react\";\n\nexport type HeidiClassName<State> = string | ((state: State) => string | undefined) | undefined;\n\nexport type HeidiStyle<State> =\n  | CSSProperties\n  | ((state: State) => CSSProperties | undefined)\n  | undefined;\n\nexport type HeidiRenderFn<State, Props> = (\n  props: Props,\n  state: State\n) => ReactElement;\n\nexport type HeidiRender<State, Props> =\n  | ReactElement\n  | HeidiRenderFn<State, Props>\n  | undefined;\n\ntype DefaultRenderProps = HTMLAttributes<HTMLElement> & { ref?: Ref<HTMLElement> };\n\nexport type HeidiHostProps<\n  State,\n  RenderProps extends object = DefaultRenderProps\n> = {\n  className?: HeidiClassName<State>;\n  render?: HeidiRender<State, RenderProps>;\n  style?: HeidiStyle<State>;\n};\n\nexport type HeidiIntrinsicHostProps<\n  State,\n  Tag extends keyof HTMLElementTagNameMap\n> = HeidiHostProps<State, ComponentPropsWithRef<Tag>>;\n\nfunction resolveClassName<State>(\n  className: HeidiClassName<State>,\n  state: State\n): string | undefined {\n  return typeof className === \"function\" ? className(state) : className;\n}\n\nfunction resolveStyle<State>(style: HeidiStyle<State>, state: State): CSSProperties | undefined {\n  return typeof style === \"function\" ? style(state) : style;\n}\n\nfunction mergeClassNames(...parts: Array<string | undefined>): string | undefined {\n  const merged = parts.filter(Boolean).join(\" \");\n  return merged.length > 0 ? merged : undefined;\n}\n\n/**\n * Compose a consumer event with library behavior. Consumers run first and may\n * cancel the component behavior with `event.preventDefault()`. Heidi keeps\n * this native-event convention intentionally: it avoids a second branded event\n * API while still making async/controlled actions vetoable.\n */\nexport function composeHeidiEventHandlers<Event extends { defaultPrevented: boolean }>(\n  consumer: ((event: Event) => void) | undefined,\n  library: (event: Event) => void\n): (event: Event) => void {\n  return (event) => {\n    consumer?.(event);\n    if (!event.defaultPrevented) {\n      library(event);\n    }\n  };\n}\n\n/** React 19-safe ref fan-out, including callback-ref cleanup functions. */\nexport function mergeHeidiRefs<Element>(\n  ...inputRefs: Array<Ref<Element> | undefined>\n): Ref<Element> | undefined {\n  const refs = Array.from(\n    new Set(\n      inputRefs.filter(\n        (ref): ref is Exclude<Ref<Element>, null> => ref != null\n      )\n    )\n  );\n  if (refs.length === 0) {\n    return undefined;\n  }\n  if (refs.length === 1) {\n    return refs[0];\n  }\n\n  let cache = mergedRefCache;\n  for (const ref of refs) {\n    const key = ref as object;\n    let child = cache.children.get(key);\n    if (!child) {\n      child = { children: new WeakMap() };\n      cache.children.set(key, child);\n    }\n    cache = child;\n  }\n  if (cache.callback) {\n    return cache.callback as RefCallback<Element>;\n  }\n\n  const callback: RefCallback<Element> = (node) => {\n    const cleanups: Array<() => void> = [];\n    for (const ref of refs) {\n      if (typeof ref === \"function\") {\n        const cleanup = ref(node);\n        if (node !== null) {\n          cleanups.push(typeof cleanup === \"function\" ? cleanup : () => ref(null));\n        }\n      } else if (ref) {\n        ref.current = node;\n        if (node !== null) {\n          cleanups.push(() => {\n            ref.current = null;\n          });\n        }\n      }\n    }\n    return cleanups.length > 0\n      ? () => {\n          for (const cleanup of cleanups) {\n            cleanup();\n          }\n        }\n      : undefined;\n  };\n  cache.callback = callback as RefCallback<unknown>;\n  return callback;\n}\n\ntype MergedRefCache = {\n  callback?: RefCallback<unknown>;\n  children: WeakMap<object, MergedRefCache>;\n};\n\nconst mergedRefCache: MergedRefCache = { children: new WeakMap() };\n\ntype UnknownHandler = (...args: never[]) => unknown;\n\nfunction isEventHandler(key: string, value: unknown): value is UnknownHandler {\n  return /^on[A-Z]/.test(key) && typeof value === \"function\";\n}\n\nfunction defaultPrevented(args: unknown[]): boolean {\n  const event = args[0];\n  return (\n    typeof event === \"object\" &&\n    event !== null &&\n    \"defaultPrevented\" in event &&\n    event.defaultPrevented === true\n  );\n}\n\nfunction composeUnknownHandlers(\n  consumer: UnknownHandler,\n  library: UnknownHandler\n): UnknownHandler {\n  if (consumer === library) {\n    return library;\n  }\n  return ((...args: unknown[]) => {\n    (consumer as (...handlerArgs: unknown[]) => unknown)(...args);\n    if (!defaultPrevented(args)) {\n      (library as (...handlerArgs: unknown[]) => unknown)(...args);\n    }\n  }) as UnknownHandler;\n}\n\n/** Library-owned host props — permissive so button `type`, `data-*`, `popover`, etc. type-check. */\nexport type HeidiElementProps<Tag extends keyof HTMLElementTagNameMap> = Record<\n  string,\n  unknown\n> & {\n  children?: ReactNode;\n  className?: string;\n  ref?: Ref<HTMLElementTagNameMap[Tag]>;\n  style?: CSSProperties;\n};\n\ntype RenderElementParams<\n  State,\n  Tag extends keyof HTMLElementTagNameMap,\n  RenderProps extends object = DefaultRenderProps\n> = {\n  /** Default class from the generated hui-* map (theme/base target). */\n  className?: string;\n  /** Stable machine hook — always emitted. */\n  dataPart: string;\n  /** Intrinsic tag when `render` is omitted. */\n  element: Tag;\n  /** Props the library owns (aria, ids, handlers, popover, …). */\n  props: HeidiElementProps<Tag>;\n  /** Optional consumer composition props. */\n  renderProps?: HeidiHostProps<State, RenderProps>;\n  /** Typed state passed to functional className/style/render. */\n  state: State;\n  /** Structural inline styles that must survive consumer style merges. */\n  structuralStyle?: CSSProperties;\n  /**\n   * Render-element handlers to remove instead of composing. This is reserved\n   * for states such as a focusable disabled composite item where the public\n   * contract requires press handlers to be completely inert.\n   */\n  suppressRenderedHandlers?: readonly string[];\n};\n\n/**\n * Render a heidi-ui host element with optional Base-shaped composition.\n */\nexport function renderHeidiElement<\n  State,\n  Tag extends keyof HTMLElementTagNameMap,\n  RenderProps extends object = DefaultRenderProps\n>(\n  params: RenderElementParams<State, Tag, RenderProps>\n): ReactElement {\n  const {\n    className,\n    dataPart,\n    element,\n    props,\n    renderProps,\n    state,\n    structuralStyle,\n    suppressRenderedHandlers\n  } = params;\n  const consumerClass = resolveClassName(renderProps?.className, state);\n  const consumerStyle = resolveStyle(renderProps?.style, state);\n  const mergedStyle: CSSProperties | undefined =\n    props.style || consumerStyle || structuralStyle\n      ? { ...props.style, ...consumerStyle, ...structuralStyle }\n      : undefined;\n\n  const outProps: HTMLAttributes<HTMLElement> & {\n    \"data-hui-part\": string;\n    ref?: Ref<HTMLElement>;\n  } = {\n    ...(props as HTMLAttributes<HTMLElement> & { ref?: Ref<HTMLElement> }),\n    className: mergeClassNames(consumerClass, className),\n    \"data-hui-part\": dataPart,\n    style: mergedStyle\n  };\n\n  const render = renderProps?.render;\n  if (typeof render === \"function\") {\n    // Post-merge the returned element as well. This deliberately makes the\n    // stable data hook, owned semantics, refs, and internal handlers survive\n    // even when a render function forgets to spread one of the supplied props.\n    return mergeRenderedElement(\n      render(outProps as unknown as RenderProps, state),\n      outProps,\n      dataPart,\n      structuralStyle,\n      suppressRenderedHandlers\n    );\n  }\n  if (isValidElement(render)) {\n    return mergeRenderedElement(\n      render,\n      outProps,\n      dataPart,\n      structuralStyle,\n      suppressRenderedHandlers\n    );\n  }\n\n  return createElement(element, outProps as never, props.children);\n}\n\ntype RenderedProps = Record<string, unknown> & {\n  children?: ReactNode;\n  className?: string;\n  ref?: Ref<HTMLElement>;\n  style?: CSSProperties;\n};\n\nfunction mergeRenderedElement(\n  element: ReactElement,\n  libraryProps: HTMLAttributes<HTMLElement> & {\n    \"data-hui-part\": string;\n    ref?: Ref<HTMLElement>;\n  },\n  dataPart: string,\n  structuralStyle: CSSProperties | undefined,\n  suppressRenderedHandlers: readonly string[] | undefined\n): ReactElement {\n  const rendered = element as ReactElement<RenderedProps>;\n  const renderedProps = rendered.props;\n  const renderedClass =\n    renderedProps.className === libraryProps.className\n      ? undefined\n      : renderedProps.className;\n  const merged: RenderedProps = {\n    ...renderedProps,\n    ...libraryProps,\n    className: mergeClassNames(renderedClass, libraryProps.className),\n    \"data-hui-part\": dataPart,\n    ref: mergeHeidiRefs(libraryProps.ref, renderedProps.ref),\n    style: {\n      ...libraryProps.style,\n      ...renderedProps.style,\n      ...structuralStyle\n    }\n  };\n\n  if (Object.prototype.hasOwnProperty.call(renderedProps, \"children\")) {\n    merged.children = renderedProps.children;\n  }\n\n  const suppressedHandlers = suppressRenderedHandlers\n    ? new Set(suppressRenderedHandlers)\n    : null;\n  for (const key of new Set([...Object.keys(renderedProps), ...Object.keys(libraryProps)])) {\n    const consumer = renderedProps[key];\n    const library = (libraryProps as unknown as Record<string, unknown>)[key];\n    if (suppressedHandlers?.has(key)) {\n      merged[key] = library;\n      continue;\n    }\n    if (isEventHandler(key, consumer) && isEventHandler(key, library)) {\n      merged[key] = composeUnknownHandlers(consumer, library);\n    }\n  }\n\n  return cloneElement(rendered, merged as never);\n}\n",
      "path": "packages/heidi-ui/src/_internal/render-element.ts",
      "target": "components/ui/heidi/_internal/render-element.ts",
      "type": "registry:ui"
    },
    {
      "content": "/**\n * Shared roving-tabindex arrow navigation (P7).\n *\n * Radio, Tabs, Toolbar and ToggleGroup each declared `NAVIGATION_KEYS`\n * byte-identically, each wrote the same enabled-descendants query with two\n * different selector strings, and each resolved arrow keys to a target index.\n *\n * ponytail: the audit listed the resolvers as four divergent implementations —\n * \"radio treats ArrowDown as forward regardless of orientation; toggle-group\n * accepts both axes when horizontal; tabs restricts to its axis\". Normalising\n * the spellings shows THREE of the four agree exactly. Radio's\n * `ArrowDown || (rtl ? ArrowLeft : ArrowRight)` and Toolbar's\n * `(horizontal ? horizontalForward : \"ArrowDown\") || (horizontal && \"ArrowDown\")\n * || (!horizontal && \"ArrowRight\")` accept the identical key set in both\n * orientations and both directions; they only look different. The single real\n * divergence is Tabs, which returns early on a cross-axis key. So the option\n * that matters is `crossAxis`, and it is false in exactly one place.\n *\n * That distinction is deliberate and worth keeping: a Toolbar is a\n * two-dimensional cluster where reaching for either axis is reasonable, while\n * a tablist has one axis and a cross-axis arrow should stay available to the\n * page (scrolling, or an outer roving container).\n *\n * `rtl` is read per event rather than per render because `direction` can change\n * without a React update, and it is gated on horizontal orientation: on a\n * vertical list the inline direction says nothing about which way is \"next\".\n */\n\nexport const NAVIGATION_KEYS = [\n  \"ArrowDown\",\n  \"ArrowLeft\",\n  \"ArrowRight\",\n  \"ArrowUp\",\n  \"End\",\n  \"Home\"\n];\n\n/**\n * Enabled items owned by THIS container — `closest()` re-anchors the match so\n * a nested roving container's items never join its ancestor's ring.\n */\nexport function collectRovingItems<TItem extends HTMLElement>(\n  container: HTMLElement,\n  itemSelector: string,\n  rootSelector: string,\n  isDisabled: (element: HTMLElement) => boolean\n): TItem[] {\n  return [...container.querySelectorAll<TItem>(itemSelector)].filter(\n    (element) =>\n      !isDisabled(element) && element.closest(rootSelector) === container\n  );\n}\n\nexport type RovingResolveOptions = {\n  /** Accept the perpendicular axis too. False only for Tabs. */\n  crossAxis: boolean;\n  orientation: \"horizontal\" | \"vertical\";\n};\n\n/**\n * The index this key should move focus to, or `null` when the key does not\n * apply — the caller must then return WITHOUT calling `preventDefault`, so an\n * unhandled arrow stays available to the page.\n */\nexport function resolveRovingIndex(\n  items: readonly HTMLElement[],\n  activeElement: Element | null,\n  key: string,\n  container: HTMLElement,\n  { crossAxis, orientation }: RovingResolveOptions\n): number | null {\n  if (items.length === 0) {\n    return null;\n  }\n  if (key === \"Home\") {\n    return 0;\n  }\n  if (key === \"End\") {\n    return items.length - 1;\n  }\n  const horizontal = orientation === \"horizontal\";\n  const rtl =\n    horizontal && getComputedStyle(container).direction === \"rtl\";\n  const inlineForward = rtl ? \"ArrowLeft\" : \"ArrowRight\";\n  const inlineBackward = rtl ? \"ArrowRight\" : \"ArrowLeft\";\n  const forwardKey = horizontal ? inlineForward : \"ArrowDown\";\n  const backwardKey = horizontal ? inlineBackward : \"ArrowUp\";\n  const crossForward = horizontal ? \"ArrowDown\" : inlineForward;\n  const crossBackward = horizontal ? \"ArrowUp\" : inlineBackward;\n\n  const current = items.indexOf(activeElement as HTMLElement);\n  if (key === forwardKey || (crossAxis && key === crossForward)) {\n    return current === -1 ? 0 : (current + 1) % items.length;\n  }\n  if (key === backwardKey || (crossAxis && key === crossBackward)) {\n    return (current <= 0 ? items.length : current) - 1;\n  }\n  return null;\n}\n",
      "path": "packages/heidi-ui/src/_internal/roving-focus.ts",
      "target": "components/ui/heidi/_internal/roving-focus.ts",
      "type": "registry:ui"
    },
    {
      "content": "import { useEffect, useLayoutEffect } from \"react\";\n\n/**\n * `useLayoutEffect` that does not warn on the server.\n *\n * ponytail: fifteen primitives imported `useLayoutEffect` straight from React.\n * Every one of them carries `\"use client\"`, which is easy to misread as\n * \"client-only\" — in the App Router it means \"hydrated on the client\", and the\n * component is still rendered to HTML on the server first. React logs\n * \"useLayoutEffect does nothing on the server\" for each one, so a consumer\n * doing SSR saw a wall of warnings the app that ships this library never saw,\n * because it renders these routes on the client path.\n *\n * The branch is evaluated ONCE at module scope, not per render, and it is\n * therefore stable across a component's lifetime — swapping which hook is\n * called between renders would violate the rules of hooks. `typeof document`\n * rather than `typeof window`: both work, but `document` is the thing the\n * effect actually needs, and it keeps the check honest in exotic runtimes that\n * define a partial `window`.\n *\n * Rejected: `useInsertionEffect`, which runs earlier but is specified for\n * style injection and is not a general layout hook; and per-file guards, which\n * is what the 15 copies would have become.\n */\nexport const useHeidiLayoutEffect =\n  typeof document === \"undefined\" ? useEffect : useLayoutEffect;\n",
      "path": "packages/heidi-ui/src/_internal/use-layout-effect.ts",
      "target": "components/ui/heidi/_internal/use-layout-effect.ts",
      "type": "registry:ui"
    }
  ],
  "name": "toggle-group",
  "registryDependencies": [
    "@heidi-ui/heidi-tokens"
  ],
  "title": "Toggle-group",
  "type": "registry:ui"
}
