{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "data-key-value",
  "type": "registry:component",
  "title": "Key-value displays",
  "description": "A two-column list of labels and values",
  "author": "sudo-kw <https://github.com/sudo-kw>",
  "dependencies": [
    "@gpuix/native@0.11.0",
    "@gpuix/react@0.11.0",
    "effect@4.1.2",
    "react@^19.2.4"
  ],
  "registryDependencies": [
    "https://gpuixui.sudokw.com/gpuix-primitives.json",
    "https://gpuixui.sudokw.com/gpuix-tokens.json",
    "https://gpuixui.sudokw.com/gpuix-tw.json"
  ],
  "files": [
    {
      "path": "packages/data/src/internal/list.ts",
      "target": "@ui/gpuixui/data/internal/list.ts",
      "type": "registry:lib",
      "content": "import * as Arr from \"effect/Array\";\nimport * as P from \"effect/Predicate\";\nimport * as Str from \"effect/String\";\n\nexport const listOf = <A>(\n  value: ReadonlyArray<A> | null | undefined,\n): ReadonlyArray<A> => (Arr.isArray(value) ? value : []);\n\nexport const recordsOf = <A extends { readonly key: string }>(\n  value: ReadonlyArray<A> | undefined,\n): ReadonlyArray<A> =>\n  Arr.filter(\n    listOf(value),\n    (entry) => P.isObject(entry) && P.isString(entry.key),\n  );\n\nexport const textsOf = (\n  value: ReadonlyArray<string> | undefined,\n): ReadonlyArray<string> =>\n  Arr.map(listOf(value), (entry) => (P.isString(entry) ? entry : \"\"));\n\nconst namesRow = (value: unknown): boolean =>\n  P.isString(value) && Str.isNonEmpty(Str.trim(value));\n\nexport const rowsOf = <A>(\n  value: ReadonlyArray<A> | null | undefined,\n  keyOf: (row: A) => string,\n): ReadonlyArray<A> =>\n  Arr.filter(listOf(value), (row) => P.isObject(row) && namesRow(keyOf(row)));\n"
    },
    {
      "path": "packages/data/src/internal/readable.tsx",
      "target": "@ui/gpuixui/data/internal/readable.tsx",
      "type": "registry:component",
      "content": "/** @jsxImportSource @gpuix/react */\nimport type { StyleDesc } from \"@gpuix/react\";\nimport * as P from \"effect/Predicate\";\nimport type { ReactNode } from \"react\";\n\nexport interface ReadableProps {\n  readonly testId?: string;\n  readonly style?: StyleDesc;\n}\n\nexport const readable = (\n  value: ReactNode,\n  { testId, style }: ReadableProps = {},\n) =>\n  P.isString(value) || P.isNumber(value) ? (\n    <text testId={testId} style={style}>\n      {value}\n    </text>\n  ) : (\n    <div testId={testId} style={style}>\n      {value}\n    </div>\n  );\n"
    },
    {
      "path": "packages/data/src/recipe.ts",
      "target": "@ui/gpuixui/data/recipe.ts",
      "type": "registry:lib",
      "content": "import type { StyleDesc } from \"@gpuix/react\";\nimport { createRecipeCache } from \"../tw/index.js\";\nimport type { Theme } from \"./theme.js\";\n\nexport const recipeStyle: (recipe: string, theme: Theme) => StyleDesc =\n  createRecipeCache(256);\n"
    },
    {
      "path": "packages/data/src/surfaces/key-value.tsx",
      "target": "@ui/gpuixui/data/surfaces/key-value.tsx",
      "type": "registry:component",
      "content": "/** @jsxImportSource @gpuix/react */\nimport type { Props } from \"@gpuix/react\";\nimport { mergeStyles } from \"@gpuix/react/floating\";\nimport { spaceValue } from \"../../primitives/core/index.js\";\nimport { cn } from \"../../tw/index.js\";\nimport * as Arr from \"effect/Array\";\nimport type { ReactNode } from \"react\";\nimport { recordsOf } from \"../internal/list.js\";\nimport { readable } from \"../internal/readable.js\";\nimport { recipeStyle } from \"../recipe.js\";\nimport { useTheme } from \"../theme.js\";\nimport { propertyName } from \"./logic.js\";\nimport { KEY_VALUE_LABEL, KEY_VALUE_ROW, KEY_VALUE_VALUE } from \"./recipe.js\";\n\nexport interface KeyValueEntry {\n  readonly key: string;\n\n  readonly label: string;\n\n  readonly value: ReactNode;\n}\n\nexport interface KeyValueProps extends Omit<Props, \"children\"> {\n  readonly entries: ReadonlyArray<KeyValueEntry>;\n\n  readonly labelWidth?: number;\n\n  readonly valueWidth?: number;\n  readonly className?: string;\n\n  readonly testId?: string;\n}\n\nexport const DEFAULT_LABEL_WIDTH = 120;\n\nexport const KeyValue = ({\n  entries,\n  labelWidth = DEFAULT_LABEL_WIDTH,\n  valueWidth,\n  className,\n  style,\n  testId,\n  ...rest\n}: KeyValueProps) => {\n  const theme = useTheme();\n  const labelTrack =\n    Number.isFinite(labelWidth) && labelWidth > 0\n      ? labelWidth\n      : DEFAULT_LABEL_WIDTH;\n  const valueTrack =\n    valueWidth !== undefined && Number.isFinite(valueWidth) && valueWidth > 0\n      ? valueWidth\n      : undefined;\n  return (\n    <div\n      {...rest}\n      role=\"list\"\n      style={mergeStyles(recipeStyle(cn(\"\", className), theme), style)}\n    >\n      {Arr.map(recordsOf(entries), (entry) => (\n        <div\n          key={entry.key}\n          role=\"listitem\"\n          style={{\n            display: \"flex\",\n            flexDirection: \"row\",\n            alignItems: \"center\",\n            gap: spaceValue(theme, \"sm\"),\n            ...recipeStyle(KEY_VALUE_ROW, theme),\n          }}\n        >\n          <text\n            testId={\n              testId === undefined ? undefined : `${testId}-label-${entry.key}`\n            }\n            style={{\n              ...recipeStyle(KEY_VALUE_LABEL, theme),\n              width: labelTrack,\n              flexGrow: 0,\n              flexShrink: 0,\n              flexBasis: labelTrack,\n            }}\n          >\n            {propertyName(entry.label, entry.key)}\n          </text>\n          {readable(entry.value, {\n            testId:\n              testId === undefined ? undefined : `${testId}-value-${entry.key}`,\n            style: {\n              ...recipeStyle(KEY_VALUE_VALUE, theme),\n              ...(valueTrack === undefined\n                ? { flexGrow: 1, flexShrink: 1, flexBasis: 0, minWidth: 0 }\n                : {\n                    width: valueTrack,\n                    flexGrow: 0,\n                    flexShrink: 0,\n                    flexBasis: valueTrack,\n                  }),\n            },\n          })}\n        </div>\n      ))}\n    </div>\n  );\n};\n"
    },
    {
      "path": "packages/data/src/surfaces/logic.ts",
      "target": "@ui/gpuixui/data/surfaces/logic.ts",
      "type": "registry:lib",
      "content": "import { spokenText } from \"../../primitives/core/index.js\";\nimport { Match } from \"effect\";\nimport * as Arr from \"effect/Array\";\nimport * as Number from \"effect/Number\";\nimport * as Option from \"effect/Option\";\nimport * as Schema from \"effect/Schema\";\nimport * as Str from \"effect/String\";\n\nexport const propertyName = (label: string, key: string): string =>\n  spokenText(Option.fromNullishOr(label), key);\n\nexport const UNNAMED_CLAUSE_FIELD = \"Field\";\n\nexport const clauseFieldName = (field: string): string =>\n  spokenText(Option.fromNullishOr(field), UNNAMED_CLAUSE_FIELD);\n\nexport const comparisons = [\n  \"equals\",\n  \"notEquals\",\n  \"contains\",\n  \"greaterThan\",\n  \"lessThan\",\n] as const;\n\nexport const Comparison = Schema.Literals(comparisons);\n\nexport type Comparison = typeof Comparison.Type;\n\nexport type GroupKind = \"all\" | \"any\" | \"not\";\n\nexport interface FieldPredicate {\n  readonly kind: \"predicate\";\n\n  readonly field: string;\n  readonly comparison: Comparison;\n\n  readonly value: string;\n}\n\nexport interface AllClause {\n  readonly kind: \"all\";\n  readonly children: ReadonlyArray<FilterTree>;\n}\n\nexport interface AnyClause {\n  readonly kind: \"any\";\n  readonly children: ReadonlyArray<FilterTree>;\n}\n\nexport interface NotClause {\n  readonly kind: \"not\";\n  readonly child: FilterTree;\n}\n\nexport type FilterTree = FieldPredicate | AllClause | AnyClause | NotClause;\n\nexport const FilterTree: Schema.Schema<FilterTree> = Schema.Union([\n  Schema.Struct({\n    kind: Schema.tag(\"predicate\"),\n    field: Schema.String,\n    comparison: Comparison,\n    value: Schema.String,\n  }),\n  Schema.Struct({\n    kind: Schema.tag(\"all\"),\n    children: Schema.Array(Schema.suspend(() => FilterTree)),\n  }),\n  Schema.Struct({\n    kind: Schema.tag(\"any\"),\n    children: Schema.Array(Schema.suspend(() => FilterTree)),\n  }),\n  Schema.Struct({\n    kind: Schema.tag(\"not\"),\n    child: Schema.suspend(() => FilterTree),\n  }),\n]);\n\nexport const UNREADABLE_TREE = \"a filter this release cannot read\";\n\nexport const isFilterTree = (value: unknown): value is FilterTree =>\n  Schema.is(FilterTree)(value);\n\nexport const isComparison = (value: unknown): value is Comparison =>\n  Schema.is(Comparison)(value);\n\nexport const readFilterTree = (value: unknown): Option.Option<FilterTree> =>\n  isFilterTree(value) ? Option.some(value) : Option.none();\n\nexport const isPredicate = (tree: FilterTree): tree is FieldPredicate =>\n  tree.kind === \"predicate\";\n\nexport const isAll = (tree: FilterTree): tree is AllClause =>\n  tree.kind === \"all\";\n\nexport const isAny = (tree: FilterTree): tree is AnyClause =>\n  tree.kind === \"any\";\n\nexport const isNot = (tree: FilterTree): tree is NotClause =>\n  tree.kind === \"not\";\n\nconst numeric = (value: string | number): Option.Option<number> =>\n  typeof value === \"number\" ? Option.some(value) : Number.parse(value);\n\nconst ordered = (\n  left: string | number,\n  right: string,\n  compare: (one: number, other: number) => boolean,\n): boolean =>\n  Option.match(Option.all([numeric(left), numeric(right)]), {\n    onNone: () => false,\n    onSome: ([one, other]) => compare(one, other),\n  });\n\nexport const matchesComparison = (\n  comparison: Comparison,\n  left: string | number,\n  right: string,\n): boolean =>\n  Arr.contains(comparisons, comparison) &&\n  Match.value(comparison).pipe(\n    Match.when(\"equals\", () => `${left}` === right),\n    Match.when(\"notEquals\", () => `${left}` !== right),\n    Match.when(\"contains\", () =>\n      Str.includes(Str.toLowerCase(right), 0)(Str.toLowerCase(`${left}`)),\n    ),\n    Match.when(\"greaterThan\", () =>\n      ordered(left, right, (one, other) => one > other),\n    ),\n    Match.when(\"lessThan\", () =>\n      ordered(left, right, (one, other) => one < other),\n    ),\n    Match.exhaustive,\n  );\n\nconst matchesReadable = <Row>(\n  tree: FilterTree,\n  row: Row,\n  valueOf: (row: Row, field: string) => string | number,\n): boolean =>\n  Match.value(tree).pipe(\n    Match.when(isPredicate, (clause) =>\n      matchesComparison(\n        clause.comparison,\n        valueOf(row, clause.field),\n        clause.value,\n      ),\n    ),\n    Match.when(isAll, (group) =>\n      Arr.every(group.children, (child) =>\n        matchesReadable(child, row, valueOf),\n      ),\n    ),\n    Match.when(isAny, (group) =>\n      Arr.some(group.children, (child) => matchesReadable(child, row, valueOf)),\n    ),\n    Match.when(isNot, (group) => !matchesReadable(group.child, row, valueOf)),\n    Match.exhaustive,\n  );\n\nexport const matchesTree = <Row>(\n  tree: FilterTree,\n  row: Row,\n  valueOf: (row: Row, field: string) => string | number,\n): boolean => isFilterTree(tree) && matchesReadable(tree, row, valueOf);\n\nexport const filterByTree = <Row>(\n  rows: ReadonlyArray<Row>,\n  tree: FilterTree,\n  valueOf: (row: Row, field: string) => string | number,\n): ReadonlyArray<Row> =>\n  isFilterTree(tree)\n    ? Arr.filter(rows, (row) => matchesReadable(tree, row, valueOf))\n    : [];\n\nconst clauseCountReadable = (tree: FilterTree): number =>\n  Match.value(tree).pipe(\n    Match.when(isPredicate, () => 1),\n    Match.when(isAll, (group) =>\n      Arr.reduce(\n        group.children,\n        0,\n        (total, child) => total + clauseCountReadable(child),\n      ),\n    ),\n    Match.when(isAny, (group) =>\n      Arr.reduce(\n        group.children,\n        0,\n        (total, child) => total + clauseCountReadable(child),\n      ),\n    ),\n    Match.when(isNot, (group) => clauseCountReadable(group.child)),\n    Match.exhaustive,\n  );\n\nexport const clauseCount = (tree: FilterTree): number =>\n  isFilterTree(tree) ? clauseCountReadable(tree) : 0;\n\nconst describeReadable = (tree: FilterTree): string =>\n  Match.value(tree).pipe(\n    Match.when(isPredicate, (clause) =>\n      Str.trim(\n        `${clauseFieldName(clause.field)} ${clause.comparison} ${clause.value}`,\n      ),\n    ),\n    Match.when(isAll, (group) =>\n      group.children.length === 0\n        ? \"everything\"\n        : `all of (${Arr.map(group.children, describeReadable).join(\", \")})`,\n    ),\n    Match.when(isAny, (group) =>\n      group.children.length === 0\n        ? \"nothing\"\n        : `any of (${Arr.map(group.children, describeReadable).join(\", \")})`,\n    ),\n    Match.when(isNot, (group) => `not (${describeReadable(group.child)})`),\n    Match.exhaustive,\n  );\n\nexport const describeTree = (tree: FilterTree): string =>\n  isFilterTree(tree) ? describeReadable(tree) : UNREADABLE_TREE;\n\nconst updatePredicateReadable = (\n  tree: FilterTree,\n  change: {\n    readonly field?: string;\n    readonly comparison?: Comparison;\n    readonly value?: string;\n  },\n): FilterTree =>\n  Match.value(tree).pipe(\n    Match.when(isPredicate, (clause) => ({\n      ...clause,\n      ...(change.field === undefined ? {} : { field: change.field }),\n      ...(change.comparison === undefined\n        ? {}\n        : { comparison: change.comparison }),\n      ...(change.value === undefined ? {} : { value: change.value }),\n    })),\n    Match.when(isAll, (group) => ({\n      ...group,\n      children: Arr.map(group.children, (child) =>\n        updatePredicateReadable(child, change),\n      ),\n    })),\n    Match.when(isAny, (group) => ({\n      ...group,\n      children: Arr.map(group.children, (child) =>\n        updatePredicateReadable(child, change),\n      ),\n    })),\n    Match.when(isNot, (group) => ({\n      ...group,\n      child: updatePredicateReadable(group.child, change),\n    })),\n    Match.exhaustive,\n  );\n\nexport const updatePredicate = (\n  tree: FilterTree,\n  change: {\n    readonly field?: string;\n    readonly comparison?: Comparison;\n    readonly value?: string;\n  },\n): FilterTree =>\n  isFilterTree(tree) ? updatePredicateReadable(tree, change) : tree;\n\nexport type FilterPath = ReadonlyArray<number>;\n\nexport const emptyTree: FilterTree = { kind: \"all\", children: [] };\n\nconst nodeAt = (\n  tree: FilterTree,\n  path: FilterPath,\n): Option.Option<FilterTree> => {\n  if (path.length === 0) return Option.some(tree);\n  const [head, ...rest] = path;\n  return Option.flatMap(Option.fromNullishOr(head), (at) =>\n    Match.value(tree).pipe(\n      Match.when(isPredicate, () => Option.none()),\n      Match.when(isAll, (group) => childAt(group.children, at, rest)),\n      Match.when(isAny, (group) => childAt(group.children, at, rest)),\n      Match.when(isNot, (group) =>\n        at === 0 ? nodeAt(group.child, rest) : Option.none(),\n      ),\n      Match.exhaustive,\n    ),\n  );\n};\n\nconst childAt = (\n  children: ReadonlyArray<FilterTree>,\n  at: number,\n  rest: FilterPath,\n): Option.Option<FilterTree> =>\n  Arr.get(children, at).pipe(Option.flatMap((child) => nodeAt(child, rest)));\n\nexport const clauseAt = (\n  tree: FilterTree,\n  path: FilterPath,\n): Option.Option<FieldPredicate> =>\n  isFilterTree(tree)\n    ? Option.flatMap(nodeAt(tree, path), (node) =>\n        isPredicate(node) ? Option.some(node) : Option.none(),\n      )\n    : Option.none();\n\nconst asGroup = (node: FilterTree, kind: \"all\" | \"any\"): FilterTree =>\n  Match.value(node).pipe(\n    Match.when(isPredicate, (clause) => ({ kind, children: [clause] })),\n    Match.when(isAll, (group) => ({ kind, children: group.children })),\n    Match.when(isAny, (group) => ({ kind, children: group.children })),\n    Match.when(isNot, (group) => asGroup(group.child, kind)),\n    Match.exhaustive,\n  );\n\nexport const withClauseField = (\n  clause: FieldPredicate,\n  field: string,\n): FieldPredicate => ({ ...clause, field, value: \"\" });\n\nexport const updateAt = (\n  tree: FilterTree,\n  path: FilterPath,\n  next: FilterTree,\n): FilterTree => {\n  if (!isFilterTree(tree) || !isFilterTree(next)) return tree;\n  if (path.length === 0) return next;\n  const [head, ...rest] = path;\n  const replaceChild = (children: ReadonlyArray<FilterTree>) =>\n    Arr.map(children, (child, at) =>\n      at === head ? updateAt(child, rest, next) : child,\n    );\n  return Match.value(tree).pipe(\n    Match.when(isPredicate, () => tree),\n    Match.when(isAll, (group) => ({\n      ...group,\n      children: replaceChild(group.children),\n    })),\n    Match.when(isAny, (group) => ({\n      ...group,\n      children: replaceChild(group.children),\n    })),\n    Match.when(isNot, (group) =>\n      head === 0\n        ? { ...group, child: updateAt(group.child, rest, next) }\n        : group,\n    ),\n    Match.exhaustive,\n  );\n};\n\nexport const setGroupKind = (\n  tree: FilterTree,\n  path: FilterPath,\n  kind: \"all\" | \"any\",\n): FilterTree => {\n  if (!isFilterTree(tree)) return tree;\n  return Option.match(nodeAt(tree, path), {\n    onNone: () => tree,\n    onSome: (node) => updateAt(tree, path, asGroup(node, kind)),\n  });\n};\n\nexport const negateAt = (tree: FilterTree, path: FilterPath): FilterTree => {\n  if (!isFilterTree(tree)) return tree;\n  return Option.match(nodeAt(tree, path), {\n    onNone: () => tree,\n    onSome: (node) =>\n      updateAt(\n        tree,\n        path,\n        isNot(node) ? node.child : { kind: \"not\", child: node },\n      ),\n  });\n};\n\nexport const removeAt = (tree: FilterTree, path: FilterPath): FilterTree => {\n  if (!isFilterTree(tree)) return tree;\n  if (path.length === 0) return tree;\n  const [head, ...rest] = path;\n  const dropChild = (children: ReadonlyArray<FilterTree>) =>\n    Arr.filter(children, (_, at) => at !== head);\n  return Match.value(tree).pipe(\n    Match.when(isPredicate, () => tree),\n    Match.when(isAll, (group) => ({\n      ...group,\n      children:\n        rest.length === 0\n          ? dropChild(group.children)\n          : Arr.map(group.children, (child, at) =>\n              at === head ? removeAt(child, rest) : child,\n            ),\n    })),\n    Match.when(isAny, (group) => ({\n      ...group,\n      children:\n        rest.length === 0\n          ? dropChild(group.children)\n          : Arr.map(group.children, (child, at) =>\n              at === head ? removeAt(child, rest) : child,\n            ),\n    })),\n    Match.when(isNot, (group) =>\n      head === 0 && rest.length > 0\n        ? { ...group, child: removeAt(group.child, rest) }\n        : tree,\n    ),\n    Match.exhaustive,\n  );\n};\n\nconst appendNode = (tree: FilterTree, node: FilterTree): FilterTree =>\n  Match.value(tree).pipe(\n    Match.when(isPredicate, () => ({\n      kind: \"all\" as const,\n      children: [tree, node],\n    })),\n    Match.when(isAll, (group) => ({\n      ...group,\n      children: [...group.children, node],\n    })),\n    Match.when(isAny, (group) => ({\n      ...group,\n      children: [...group.children, node],\n    })),\n    Match.when(isNot, (group) => ({\n      ...group,\n      child: appendNode(group.child, node),\n    })),\n    Match.exhaustive,\n  );\n\nexport const appendClause = (\n  tree: FilterTree,\n  clause: FieldPredicate,\n): FilterTree =>\n  isFilterTree(tree) && isFilterTree(clause) ? appendNode(tree, clause) : tree;\n\nexport const appendAt = (\n  tree: FilterTree,\n  path: FilterPath,\n  added: FilterTree,\n): FilterTree => {\n  if (!isFilterTree(tree) || !isFilterTree(added)) return tree;\n\n  if (path.length === 0) return appendNode(tree, added);\n  const appendInto = (current: FilterTree, rest: FilterPath): FilterTree => {\n    if (rest.length === 0) {\n      return isAll(current) || isAny(current)\n        ? appendNode(current, added)\n        : current;\n    }\n    const [head, ...tail] = rest;\n    const intoChildren = (\n      children: ReadonlyArray<FilterTree>,\n    ): ReadonlyArray<FilterTree> =>\n      Arr.map(children, (child, at) =>\n        at === head ? appendInto(child, tail) : child,\n      );\n    return Match.value(current).pipe(\n      Match.when(isPredicate, () => current),\n      Match.when(isNot, (group) =>\n        head === 0\n          ? { ...group, child: appendInto(group.child, tail) }\n          : current,\n      ),\n      Match.when(isAll, (group) => ({\n        ...group,\n        children: intoChildren(group.children),\n      })),\n      Match.when(isAny, (group) => ({\n        ...group,\n        children: intoChildren(group.children),\n      })),\n      Match.exhaustive,\n    );\n  };\n  return appendInto(tree, path);\n};\n"
    },
    {
      "path": "packages/data/src/surfaces/recipe.ts",
      "target": "@ui/gpuixui/data/surfaces/recipe.ts",
      "type": "registry:lib",
      "content": "export const SURFACE_PANEL =\n  \"flex flex-col rounded-lg border border-input bg-card text-foreground\";\n\nexport const SURFACE_HEADER =\n  \"flex flex-row items-center justify-between gap-2 border-b border-input px-3 py-2\";\n\nexport const KEY_VALUE_ROW = \"flex flex-row items-center gap-2 py-1\";\n\nexport const KEY_VALUE_LABEL = \"text-xs text-muted-foreground\";\n\nexport const KEY_VALUE_VALUE = \"text-xs text-foreground\";\n\nexport const STAT_CARD =\n  \"flex flex-col gap-1 rounded-lg border border-input bg-card px-3 py-2\";\n\nexport const STAT_VALUE = \"text-2xl font-semibold text-foreground\";\n\nexport const STAT_LABEL = \"text-xs text-muted-foreground\";\n\nexport const STAT_HINT = \"text-xs text-muted-foreground\";\n\nexport const DATA_TOOLBAR =\n  \"flex flex-row items-center gap-2 rounded-md border border-input bg-muted px-2 py-1\";\n\nexport const FILTER_CLAUSE = \"flex flex-row items-center gap-2 py-1\";\n\nexport const FILTER_GROUP = \"flex flex-col gap-1 border-l border-input pl-2\";\n\nexport const ADVANCED_FILTER =\n  \"flex flex-col gap-2 rounded-lg border border-input bg-card px-3 py-2\";\n\nexport const FILTER_SENTENCE = \"text-xs text-foreground\";\n"
    },
    {
      "path": "packages/data/src/theme.ts",
      "target": "@ui/gpuixui/data/theme.ts",
      "type": "registry:lib",
      "content": "import type { Theme } from \"../tokens/index.js\";\nimport { useTheme as useTokenTheme } from \"../tokens/react.js\";\n\nexport {\n  controlFocusRing,\n  dividerOn,\n  pointerWash,\n  textStyle,\n  themeColors,\n} from \"../tokens/index.js\";\nexport type { Theme };\n\nexport const useTheme = (): Theme => useTokenTheme();\n"
    }
  ],
  "docs": "[Key-value displays](https://gpuixui.sudokw.com/data-display/key-value) — These are GPUix native components: the files render through GPUix's reconciler against `@gpuix/react`, not the DOM, and need the per-platform `@gpuix/native` binding. The CLI installs the `@gpuixui/*` runtime the components import as registry items, so the copied tree resolves on its own; wrap it in `ThemeProvider` before it renders.",
  "meta": {
    "url": "/data-display/key-value",
    "kind": "component",
    "runtime": "gpuix",
    "registry": "gpuixui"
  }
}