{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "dependencies": [],
  "description": "Visual/semantic divider. role=separator when not decorative; aria-orientation horizontal|vertical. Zero JS — server-safe. Decorative separators are aria-hidden and omit role.",
  "files": [
    {
      "content": "/**\n * heidi-ui Separator — ZERO JavaScript. Visual/semantic divider.\n * decorative=true → aria-hidden (pure chrome). Otherwise role=separator\n * + aria-orientation. Server-Component safe.\n */\n\nimport {\n  type ComponentPropsWithoutRef,\n  type ReactNode,\n  type Ref\n} from \"react\";\nimport {\n  renderHeidiElement,\n  type HeidiIntrinsicHostProps\n} from \"../_internal/render-element\";\nimport { type SeparatorOrientation } from \"./separator.anatomy.generated\";\nimport { SEPARATOR_CLASSES } from \"./separator.classes.generated\";\n\nexport type { SeparatorOrientation };\n\nexport type SeparatorRootState = {\n  decorative: boolean;\n  orientation: SeparatorOrientation;\n};\n\ntype SeparatorRootNativeProps = Omit<\n  ComponentPropsWithoutRef<\"div\">,\n  | \"aria-hidden\"\n  | \"aria-orientation\"\n  | \"children\"\n  | \"className\"\n  | \"ref\"\n  | \"role\"\n  | \"style\"\n>;\n\nexport type SeparatorRootProps = HeidiIntrinsicHostProps<\n  SeparatorRootState,\n  \"div\"\n> &\n  SeparatorRootNativeProps & {\n    children?: ReactNode;\n    /** When true, purely visual — aria-hidden, no role. Default false. */\n    decorative?: boolean;\n    orientation?: SeparatorOrientation;\n    ref?: Ref<HTMLDivElement>;\n  };\n\nexport function SeparatorRoot({\n  children,\n  className,\n  decorative = false,\n  orientation = \"horizontal\",\n  ref,\n  render,\n  style,\n  ...nativeProps\n}: SeparatorRootProps) {\n  return renderHeidiElement({\n    className: SEPARATOR_CLASSES.root,\n    dataPart: \"separator-root\",\n    element: \"div\",\n    props: {\n      ...nativeProps,\n      \"aria-hidden\": decorative ? true : undefined,\n      \"aria-orientation\": decorative ? undefined : orientation,\n      children,\n      \"data-orientation\": orientation,\n      ref,\n      role: decorative ? undefined : \"separator\"\n    },\n    renderProps: { className, render, style },\n    state: { decorative, orientation }\n  });\n}\n\nexport const Separator = {\n  Root: SeparatorRoot\n} as const;\n",
      "path": "packages/heidi-ui/src/separator/separator.tsx",
      "target": "components/ui/heidi/separator/separator.tsx",
      "type": "registry:ui"
    },
    {
      "content": "/*\n * heidi-ui separator — STRUCTURAL CSS only. No --hui-*.\n */\n\n@layer heidi-ui-base {\n  .hui-separator-root[data-orientation=\"horizontal\"] {\n    block-size: 0;\n    border: none;\n    border-block-start-width: 1px;\n    border-block-start-style: solid;\n    inline-size: 100%;\n    margin: 0;\n  }\n\n  .hui-separator-root[data-orientation=\"vertical\"] {\n    align-self: stretch;\n    block-size: auto;\n    border: none;\n    border-inline-start-width: 1px;\n    border-inline-start-style: solid;\n    inline-size: 0;\n    margin: 0;\n    min-block-size: 1em;\n  }\n}\n",
      "path": "packages/heidi-ui/src/separator/separator.base.css",
      "target": "components/ui/heidi/separator/separator.base.css",
      "type": "registry:ui"
    },
    {
      "content": "/*\n * heidi-ui separator — VISUAL theme (opt-in). Consumes --hui-*.\n */\n\n@layer heidi-ui {\n  .hui-separator-root {\n    border-color: var(--hui-color-border-default);\n  }\n\n  @media (forced-colors: active) {\n    .hui-separator-root {\n      border-color: CanvasText;\n    }\n  }\n}\n",
      "path": "packages/heidi-ui/src/separator/separator.theme.css",
      "target": "components/ui/heidi/separator/separator.theme.css",
      "type": "registry:ui"
    },
    {
      "content": "/*\n * heidi-ui separator — aggregator.\n */\n\n@import \"./separator.base.css\";\n@import \"../../../../styles/heidi-ui-adapter.css\";\n@import \"./separator.theme.css\";\n",
      "path": "packages/heidi-ui/src/separator/separator.css",
      "target": "components/ui/heidi/separator/separator.css",
      "type": "registry:ui"
    },
    {
      "content": "/** GENERATED from packages/heidi-ui/src/separator/separator.base.css + packages/heidi-ui/src/separator/separator.theme.css — do not edit by hand.\n * Rebuild: `bun run hui:build`. Freshness: `bun run contracts:check`. */\nexport const SEPARATOR_CLASSES = {\n  root: \"hui-separator-root\",\n} as const;\n",
      "path": "packages/heidi-ui/src/separator/separator.classes.generated.ts",
      "target": "components/ui/heidi/separator/separator.classes.generated.ts",
      "type": "registry:ui"
    },
    {
      "content": "/** GENERATED from separator.anatomy.json + separator.base.css + separator.theme.css — do not edit by hand.\n * Rebuild: `bun run hui:build`. Freshness: `bun run contracts:check`. */\n\nexport type SeparatorOrientation = \"horizontal\" | \"vertical\";\n\nexport const SEPARATOR_ANATOMY = {\n  \"component\": \"separator\",\n  \"description\": \"Visual/semantic divider. role=separator when not decorative; aria-orientation horizontal|vertical. Zero JS — server-safe. Decorative separators are aria-hidden and omit role.\",\n  \"schemaVersion\": 2,\n  \"parts\": {\n    \"root\": {\n      \"aria\": {\n        \"owns\": [\n          \"aria-orientation\"\n        ],\n        \"role\": \"separator\"\n      },\n      \"class\": \"hui-separator-root\",\n      \"css\": {\n        \"structural\": [\n          \"block-size\",\n          \"border\",\n          \"inline-size\",\n          \"margin\"\n        ]\n      },\n      \"dataPart\": \"separator-root\",\n      \"description\": \"The divider element (div). Decorative → aria-hidden; otherwise role=separator.\",\n      \"element\": \"div\",\n      \"nativeProps\": true,\n      \"props\": [\n        \"className\",\n        \"decorative\",\n        \"orientation\",\n        \"ref\",\n        \"render\",\n        \"style\"\n      ],\n      \"pseudoStates\": [],\n      \"states\": {\n        \"data-orientation\": [\n          \"horizontal\",\n          \"vertical\"\n        ]\n      }\n    }\n  },\n  \"rootProps\": [\n    \"decorative\",\n    \"orientation\"\n  ],\n  \"tokens\": [\n    \"--hui-color-border-default\"\n  ]\n} as const;\n",
      "path": "packages/heidi-ui/src/separator/separator.anatomy.generated.ts",
      "target": "components/ui/heidi/separator/separator.anatomy.generated.ts",
      "type": "registry:ui"
    },
    {
      "content": "{\n  \"component\": \"separator\",\n  \"description\": \"Visual/semantic divider. role=separator when not decorative; aria-orientation horizontal|vertical. Zero JS — server-safe. Decorative separators are aria-hidden and omit role.\",\n  \"schemaVersion\": 2,\n  \"parts\": {\n    \"root\": {\n      \"aria\": {\n        \"owns\": [\"aria-orientation\"],\n        \"role\": \"separator\"\n      },\n      \"class\": \"hui-separator-root\",\n      \"css\": {\n        \"structural\": [\"block-size\", \"border\", \"inline-size\", \"margin\"]\n      },\n      \"dataPart\": \"separator-root\",\n      \"description\": \"The divider element (div). Decorative → aria-hidden; otherwise role=separator.\",\n      \"element\": \"div\",\n      \"nativeProps\": true,\n      \"props\": [\"className\", \"decorative\", \"orientation\", \"ref\", \"render\", \"style\"],\n      \"pseudoStates\": [],\n      \"states\": {\n        \"data-orientation\": [\"horizontal\", \"vertical\"]\n      }\n    }\n  },\n  \"rootProps\": [\"decorative\", \"orientation\"]\n}\n",
      "path": "packages/heidi-ui/src/separator/separator.anatomy.json",
      "target": "components/ui/heidi/separator/separator.anatomy.json",
      "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"
    }
  ],
  "name": "separator",
  "registryDependencies": [
    "@heidi-ui/heidi-tokens"
  ],
  "title": "Separator",
  "type": "registry:ui"
}
