@godxjp/ui-mcp 14.0.1 → 16.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -275,7 +275,7 @@ import { StatCard } from "@godxjp/ui/data-display";
275
275
  {
276
276
  name: "logo",
277
277
  type: "ReactNode",
278
- description: "Logo at the far-left of the auto-built topbar rail."
278
+ description: "Brand mark at the far-left of the auto-built topbar rail (e.g. an Avatar)."
279
279
  },
280
280
  {
281
281
  name: "sidebarCollapsed",
@@ -488,7 +488,7 @@ export default function Shell() {
488
488
  name: "start",
489
489
  type: "ReactNode",
490
490
  defaultValue: "undefined",
491
- description: "Inline-start cluster \u2014 typically the sidebar toggle (a `Button` with a `PanelLeftClose` icon), the brand `Logo`, and primary nav."
491
+ description: "Inline-start cluster \u2014 typically the sidebar toggle (a `Button` with a `PanelLeftClose` icon), the brand mark (an `Avatar`), and primary nav."
492
492
  },
493
493
  {
494
494
  name: "center",
@@ -515,25 +515,26 @@ export default function Shell() {
515
515
  }
516
516
  ],
517
517
  usage: [
518
- "DO compose the bar yourself: brand `Logo` + sidebar toggle in `start`, a search trigger in `center`, settings pickers + notifications + user menu in `end`. The shell only positions; it never decides WHICH controls exist.",
518
+ "DO compose the bar yourself: a brand mark (an `Avatar`) + sidebar toggle in `start`, a search trigger in `center`, settings pickers + notifications + user menu in `end`. The shell only positions; it never decides WHICH controls exist.",
519
519
  'DO build the sidebar toggle as a `Button variant="ghost" size="icon-sm"` with a `PanelLeftClose`/`PanelLeftOpen` icon and your own `t()` aria-label, wired to AppShell\'s `sidebarCollapsed`. There is no baked toggle.',
520
520
  "DO put a locale/theme switcher in `end` using `AppSettingPicker` (or your own control) \u2014 icon-only vs labelled, bordered vs not, is THAT component's prop, not Topbar's. Topbar does not ship or force a language picker.",
521
521
  "DON'T look for `product`/`project`/`onSearchOpen`/`onNotificationsOpen`/`collapsed` props \u2014 they were removed. A chrome control only exists if YOU put it in a slot, so there is never a dead dropdown / empty search with nothing behind it.",
522
522
  "DO render Topbar inside `AppShell`'s `topbar` slot (or any `<header>`). For a non-three-cluster layout, pass `children` and lay it out yourself."
523
523
  ],
524
524
  useCases: [
525
- "Admin shell: `start` = sidebar toggle + Logo + an entity switcher (`DropdownMenu` around a `Button`); `center` = a `Button` search trigger; `end` = `AppSettingPicker` (locale) + a notifications `Button` + a user `DropdownMenu`.",
526
- "Minimal shell (no search, no notifications): pass only `start` (Logo) and `end` (user menu). Nothing else renders \u2014 no empty chrome.",
525
+ "Admin shell: `start` = sidebar toggle + brand mark (`Avatar`) + an entity switcher (`DropdownMenu` around a `Button`); `center` = a `Button` search trigger; `end` = `AppSettingPicker` (locale) + a notifications `Button` + a user `DropdownMenu`.",
526
+ "Minimal shell (no search, no notifications): pass only `start` (brand mark) and `end` (user menu). Nothing else renders \u2014 no empty chrome.",
527
527
  "Marketing / docs header: pass `children` with a fully custom flex layout when the three-cluster model doesn't fit."
528
528
  ],
529
529
  related: [
530
530
  "AppShell \u2014 place Topbar in its `topbar` slot. AppShell also exposes its own `logo`/`topbarLeft`/`topbarRight` slots if you don't want a separate Topbar at all.",
531
- "Logo \u2014 the brand mark for the `start` slot.",
531
+ 'Avatar \u2014 the brand mark for the `start` slot (use `className="rounded-md"` for a square-ish product glyph).',
532
532
  "AppSettingPicker \u2014 locale/theme/timezone/currency picker; the consumer drops it into `end`. Its appearance (icon-only, labelled, bordered) is configured on IT, not on Topbar.",
533
533
  "DropdownMenu \u2014 wrap a `Button` to build an entity switcher or user menu yourself, then place it in a slot."
534
534
  ],
535
535
  example: `import { Topbar, AppShell } from "@godxjp/ui/layout";
536
- import { Logo, Button } from "@godxjp/ui/general";
536
+ import { Button } from "@godxjp/ui/general";
537
+ import { Avatar, AvatarFallback } from "@godxjp/ui/data-display";
537
538
  import { AppSettingPicker } from "@godxjp/ui/navigation";
538
539
  import { PanelLeftClose, Search } from "lucide-react";
539
540
 
@@ -547,7 +548,9 @@ import { PanelLeftClose, Search } from "lucide-react";
547
548
  <Button variant="ghost" size="icon-sm" aria-label={t("toggleSidebar")} onClick={toggle}>
548
549
  <PanelLeftClose />
549
550
  </Button>
550
- <Logo label="CoreBooks" />
551
+ <Avatar className="rounded-md">
552
+ <AvatarFallback className="bg-primary text-primary-foreground font-bold">C</AvatarFallback>
553
+ </Avatar>
551
554
  </>
552
555
  }
553
556
  center={
@@ -864,68 +867,11 @@ import { Trash2 } from "lucide-react";
864
867
  <Heading level={2}>\u8ACB\u6C42\u66F8\u4E00\u89A7</Heading>
865
868
  <Heading level={3} tone="muted">\u88DC\u8DB3\u30BB\u30AF\u30B7\u30E7\u30F3</Heading>`
866
869
  },
867
- {
868
- name: "Logo",
869
- group: "general",
870
- tagline: 'Product brand-mark \u2014 the lettermark (or custom SVG) in a tokenized box. Use instead of a hand-rolled `<span className="flex size-8 rounded-md bg-primary font-bold">g</span>` (typography-on-span, literal size/radius).',
871
- props: [
872
- {
873
- name: "glyph",
874
- type: "ReactNode",
875
- defaultValue: '"G"',
876
- description: "The mark \u2014 a short lettermark string or a custom SVG/image node."
877
- },
878
- {
879
- name: "label",
880
- type: "string",
881
- description: 'Accessible product name. When set the mark exposes `role="img"` + `aria-label` (use when the Logo IS the accessible name, e.g. a home link). Omitted \u2192 the mark is `aria-hidden` (decorative; an adjacent wordmark names it).'
882
- },
883
- {
884
- name: "size",
885
- type: '"xs" | "sm" | "md" | "lg"',
886
- defaultValue: '"md"',
887
- description: "Square box size (24 / 28 / 32 / 40). Size comes from the prop, never a literal."
888
- },
889
- {
890
- name: "shape",
891
- type: '"default" | "pill" | "sharp"',
892
- defaultValue: '"default"',
893
- description: "Corner shape \u2014 `default` (--logo-radius, a service knob), `pill` (fully rounded), `sharp` (square)."
894
- }
895
- ],
896
- usage: [
897
- "DO use Logo for the product glyph in a topbar, sidebar header, or auth shell instead of hand-rolling a styled `<span>`/`<div>` with a literal size + radius + bg (cardinal rules #42/#46).",
898
- "DO pass `label` when the mark is the only branding AND acts as the accessible name (e.g. wrapped in a home link); omit it when a wordmark sits beside it (then the mark is decorative `aria-hidden`).",
899
- "DO retheme via tokens \u2014 brand fill follows `--primary`; a service squares/rounds the corner globally via `--logo-radius`. DON'T override size/radius with a raw className.",
900
- "DON'T put body copy in Logo \u2014 it is a brand mark (bold lettermark / SVG), not a Text/Heading substitute."
901
- ],
902
- useCases: [
903
- 'Topbar / sidebar header brand mark next to a wordmark: `<Logo /> <Text weight="bold">GoDX</Text>`.',
904
- 'Auth shell (sign-in card) centered product mark with an accessible name: `<Logo size="lg" label="GoDX" />`.',
905
- 'A home link in an app shell where the logo IS the link label: `<a href="/"><Logo label="GoDX \u30DB\u30FC\u30E0" /></a>`.'
906
- ],
907
- related: [
908
- "Avatar \u2014 for a USER/person image or initials; Logo is for the PRODUCT/brand mark.",
909
- "Text / Heading \u2014 for the wordmark or any real copy beside the mark; Logo never holds prose."
910
- ],
911
- example: `import { Logo, Text } from "@godxjp/ui/general";
912
-
913
- // Topbar lettermark + wordmark
914
- <span className="inline-flex items-center gap-2">
915
- <Logo />
916
- <Text weight="bold">GoDX</Text>
917
- </span>
918
-
919
- // Auth shell, the mark is the accessible name
920
- <Logo size="lg" label="GoDX" />`,
921
- storyPath: "general/Logo.stories.tsx",
922
- rules: [42, 46]
923
- },
924
870
  // ─── data-display ───────────────────────────────────────────────────────
925
871
  {
926
872
  name: "DataTable",
927
873
  group: "data-display",
928
- tagline: "Compound admin list component with sticky header, sorting, bulk selection, cursor pagination, and built-in empty/loading states \u2014 never hand-roll a data.length===0 guard around it.",
874
+ tagline: "The one TanStack-powered compound admin list \u2014 sticky header, sorting, global search, column visibility ('set view'), bulk selection, BOTH cursor and numbered pagination, density, and built-in empty/loading states. Keep the SIMPLE `data` + lean `columns` (ColumnDef) API for the common case; opt into the full grid chrome via the compound parts. Internally driven by @tanstack/react-table (a real dependency). Lives on @godxjp/ui/data-display only (it is NOT on the runtime-neutral root/admin barrel because it pulls TanStack). This is the single table component \u2014 the former DataGrid has been merged in and removed. Never hand-roll a data.length===0 guard around it.",
929
875
  props: [
930
876
  {
931
877
  name: "data",
@@ -937,7 +883,7 @@ import { Trash2 } from "lucide-react";
937
883
  name: "columns",
938
884
  type: "ColumnDef<T>[]",
939
885
  required: true,
940
- description: "Column definitions. Each column: { key: string; header: ReactNode; render?: (row: T) => ReactNode; sortable?: boolean; width?: string; align?: 'left'|'center'|'right'; hiddenOnMobile?: boolean; pin?: 'end' }. If render is omitted, the raw value at row[key] is rendered as a string. pin:'end' sticks the column (typically row actions) to the inline-end edge on horizontal scroll with a separating shadow \u2014 pin at most one column."
886
+ description: "Lean column definitions (adapted to TanStack internally). Each column: { key: string; header: ReactNode; render?: (row: T) => ReactNode; sortable?: boolean; width?: string; align?: 'left'|'center'|'right'; hiddenOnMobile?: boolean; enableHiding?: boolean; pin?: 'end' }. If render is omitted, the raw value at row[key] is rendered as a string. sortable opts the column into the sort cycle (client-side by default, or server-side via sort+onSortChange). enableHiding (default true) lists the column in DataTable.ViewOptions; set false to keep a key/actions column always visible. pin:'end' sticks the column (typically row actions) to the inline-end edge on horizontal scroll with a separating shadow \u2014 pin at most one column."
941
887
  },
942
888
  {
943
889
  name: "getRowId",
@@ -997,13 +943,34 @@ import { Trash2 } from "lucide-react";
997
943
  },
998
944
  {
999
945
  name: "sort",
1000
- type: "{ value: string; direction: 'asc' | 'desc' }",
1001
- description: "Active sort state. When provided alongside onSortChange, sortable columns show directional arrow icons and are clickable. Clicking the active column twice clears sort (calls onSortChange(undefined))."
946
+ type: "{ key: string; direction: 'asc' | 'desc' }",
947
+ description: "Active sort state (controlled/server surface). When provided alongside onSortChange, sortable columns show directional arrow icons and clicking the active column twice clears sort (calls onSortChange(undefined)). Omit both sort and onSortChange to sort client-side via TanStack."
1002
948
  },
1003
949
  {
1004
950
  name: "onSortChange",
1005
- type: "(sort: { value: string; direction: 'asc' | 'desc' } | undefined) => void",
1006
- description: "Called when a sortable column header is clicked. Receives undefined when sort is cleared (third click on same column)."
951
+ type: "(sort: { key: string; direction: 'asc' | 'desc' } | undefined) => void",
952
+ description: "Called when a sortable column header is clicked. Receives undefined when sort is cleared (third click on same column). Providing sort or onSortChange opts into the controlled (server) sort surface; omit both and the table sorts client-side via TanStack."
953
+ },
954
+ {
955
+ name: "globalFilter / onGlobalFilterChange",
956
+ type: "string / (next: string) => void",
957
+ description: "Global search term surfaced by DataTable.Search. Omit both for client-side filtering; pass them to drive a server query (with manualFiltering)."
958
+ },
959
+ {
960
+ name: "pagination / onPaginationChange / rowCount",
961
+ type: "{ pageIndex: number; pageSize: number } / OnChangeFn / number",
962
+ description: "Numbered-pagination state surfaced by DataTable.Pagination (page-size form). For server pagination pass all three (rowCount = total) with manualPagination; omit for client pagination."
963
+ },
964
+ {
965
+ name: "columnVisibility / onColumnVisibilityChange",
966
+ type: "VisibilityState / OnChangeFn<VisibilityState>",
967
+ description: "Column show/hide state surfaced by DataTable.ViewOptions ('set view'). Internal if omitted."
968
+ },
969
+ {
970
+ name: "manualSorting / manualFiltering / manualPagination",
971
+ type: "boolean",
972
+ defaultValue: "false",
973
+ description: "Default false so the simple data+columns case sorts/filters/paginates in-browser. Set the relevant flag true and drive the matching state from your query for server-side behaviour."
1007
974
  },
1008
975
  {
1009
976
  name: "loading",
@@ -1024,14 +991,15 @@ import { Trash2 } from "lucide-react";
1024
991
  {
1025
992
  name: "children",
1026
993
  type: "ReactNode",
1027
- description: "Compound sub-parts: DataTable.Toolbar, DataTable.BulkActions, DataTable.DensityToggle, DataTable.Pagination, DataTable.Content. If no DataTable.Content is present in children, one is auto-rendered."
994
+ description: "Compound sub-parts: DataTable.Toolbar, DataTable.Search (global filter), DataTable.ViewOptions (column show/hide), DataTable.SelectAll, DataTable.BulkActions (ReactNode children OR a (count)=>node render-prop), DataTable.DensityToggle, DataTable.Pagination (cursor first/next when given cursor+hasMore+onChange, else numbered page-size form), DataTable.RowActions (kebab trigger), DataTable.Content. If no DataTable.Content is present in children, one is auto-rendered."
1028
995
  }
1029
996
  ],
1030
997
  usage: [
1031
998
  "DO pass loading={isFetching} during data fetches \u2014 it renders a loading row in the table body and suppresses the empty state. Never show a spinner outside DataTable while the table is visible.",
1032
999
  "DO NOT add a data.length===0 conditional around DataTable. When data is empty and loading is false, the built-in EmptyState renders automatically. Pass empty={<EmptyState title='...'/>} only when you need a custom message.",
1033
1000
  "DO provide getRowId when selectable is true or when rows do not have a string/number 'id' field \u2014 the default falls back to row.id and silently returns '' for missing IDs, which breaks selection.",
1034
- "DO use DataTable.Toolbar as the immediate child that wraps search/filter controls on the left and DataTable.DensityToggle/action buttons on the right. DataTable.BulkActions inside the toolbar auto-hides when selection count is 0.",
1001
+ "DO use DataTable.Toolbar as the immediate child that wraps search/filter controls on the left and DataTable.DensityToggle/action buttons on the right. DataTable.BulkActions inside the toolbar auto-hides when selection count is 0; it accepts either plain ReactNode children (built-in 'N selected' status bar) or a (count)=>node render-prop (you own the whole bar).",
1002
+ "DO reach for the grid chrome (DataTable.Search, DataTable.ViewOptions, DataTable.Pagination pageSizeOptions) when you need global search, a column 'set view' picker, or numbered pagination \u2014 these are the merged former-DataGrid features, now on the one DataTable. Drive them client-side by default; pass the matching state + manual* flag for a server query.",
1035
1003
  "DO use ColumnDef.render for custom cell content (Badge, Link, RowActions). For plain string/number fields render can be omitted \u2014 DataTable falls back to String(row[key]).",
1036
1004
  "DO NOT nest DataTable.Content in a conditional \u2014 it is already guarded internally. If you need to override the table body slot, drop exactly one <DataTable.Content /> in children; DataTable auto-detects it by displayName and skips the default."
1037
1005
  ],
@@ -1039,7 +1007,8 @@ import { Trash2 } from "lucide-react";
1039
1007
  "Admin list pages (invoices, customers, orders, accounts) where rows are clickable for detail navigation via onRowClick.",
1040
1008
  "Bulk-action workflows (e.g. mark invoices paid, export selected rows) \u2014 use selectable + DataTable.BulkActions to show contextual action buttons only when something is selected.",
1041
1009
  "Server-side sorted tables: pass sort + onSortChange and update the data prop after the API call; DataTable renders asc/desc/neutral icons on the header automatically.",
1042
- "Cursor-paginated lists: add DataTable.Pagination with cursor + hasMore + onChange inside children to get First/Next navigation without offset arithmetic.",
1010
+ "Cursor-paginated lists: add DataTable.Pagination with cursor + hasMore + onChange inside children to get First/Next navigation without offset arithmetic. For page-size + numbered prev/next instead, use DataTable.Pagination with pageSizeOptions (no cursor/onChange) driven by the internal TanStack pagination.",
1011
+ "Full grid screens (global search + column 'set view' + numbered pagination): compose DataTable.Search, DataTable.ViewOptions, DataTable.DensityToggle in the toolbar and DataTable.Pagination pageSizeOptions={[\u2026]} \u2014 client-side by default, or server-side by passing globalFilter/pagination/sort state with the matching manual* flag.",
1043
1012
  "Responsive admin tables where lower-priority columns (e.g. internal IDs, dates) should collapse below mobile breakpoints \u2014 set hiddenOnMobile: true on those ColumnDef entries.",
1044
1013
  "Loading skeletons during initial page load or filter change: set loading={true} alongside an empty data={[]} to show the loading row without flashing an empty state."
1045
1014
  ],
@@ -1062,10 +1031,10 @@ type Invoice = {
1062
1031
  };
1063
1032
 
1064
1033
  const columns: ColumnDef<Invoice>[] = [
1065
- { value: "id", header: "Invoice #", width: "w-32" },
1066
- { value: "customer", header: "Customer" },
1034
+ { key: "id", header: "Invoice #", width: "w-32" },
1035
+ { key: "customer", header: "Customer" },
1067
1036
  {
1068
- value: "status",
1037
+ key: "status",
1069
1038
  header: "Status",
1070
1039
  render: (row) => (
1071
1040
  <Badge
@@ -1077,7 +1046,7 @@ const columns: ColumnDef<Invoice>[] = [
1077
1046
  </Badge>
1078
1047
  ),
1079
1048
  },
1080
- { value: "amount", header: "Amount", align: "right", sortable: true },
1049
+ { key: "amount", header: "Amount", align: "right", sortable: true },
1081
1050
  ];
1082
1051
 
1083
1052
  export default function InvoiceList({
@@ -1088,7 +1057,7 @@ export default function InvoiceList({
1088
1057
  loading: boolean;
1089
1058
  }) {
1090
1059
  const [selected, setSelected] = useState<Set<string>>(new Set());
1091
- const [sort, setSort] = useState<{ value: string; direction: "asc" | "desc" } | undefined>();
1060
+ const [sort, setSort] = useState<{ key: string; direction: "asc" | "desc" } | undefined>();
1092
1061
 
1093
1062
  return (
1094
1063
  <DataTable
@@ -1122,106 +1091,6 @@ export default function InvoiceList({
1122
1091
  storyPath: "data-display/DataTable.stories.tsx",
1123
1092
  rules: [24, 31, 35, 37]
1124
1093
  },
1125
- {
1126
- name: "DataGrid",
1127
- group: "data-display",
1128
- tagline: "Full-feature data grid \u2014 the TanStack Table adapter on `@godxjp/ui/data-grid` (NOT the data-display barrel). Adds column sort, global search, column visibility ('set view'), per-page + numbered pagination, row selection + bulk actions, and density over the styled Table* primitives. Defaults to SERVER/manual mode: wire sorting/columnFilters/globalFilter/pagination to your AJAX query (pass rowCount). Use DataTable instead for a lean server-driven list that must NOT pull TanStack. Requires the `@tanstack/react-table` peer dependency.",
1129
- props: [
1130
- {
1131
- name: "columns",
1132
- type: "ColumnDef<T, unknown>[]",
1133
- required: true,
1134
- description: "TanStack column definitions ({ accessorKey, header, cell, enableSorting, enableHiding, meta:{label} }). Set enableHiding:false to keep a column out of the ViewOptions menu; meta.label gives a human label there when header is JSX."
1135
- },
1136
- {
1137
- name: "data",
1138
- type: "T[]",
1139
- required: true,
1140
- description: "Row data. Empty + loading=false renders a built-in EmptyState in the body."
1141
- },
1142
- {
1143
- name: "getRowId",
1144
- type: "(row: T) => string",
1145
- description: "Stable row id (defaults to row[rowIdKey], rowIdKey defaults to 'id')."
1146
- },
1147
- {
1148
- name: "enableRowSelection",
1149
- type: "boolean",
1150
- defaultValue: "false",
1151
- description: "Adds a checkbox column + header select-all; pair with DataGrid.BulkActions."
1152
- },
1153
- {
1154
- name: "sorting / onSortingChange",
1155
- type: "SortingState / OnChangeFn<SortingState>",
1156
- description: "Server sort: pass both and sort in your query (manualSorting defaults true). Omit both for client sort."
1157
- },
1158
- {
1159
- name: "globalFilter / onGlobalFilterChange",
1160
- type: "string / OnChangeFn<string>",
1161
- description: "Global search term, surfaced by DataGrid.Search. Server or client like sorting."
1162
- },
1163
- {
1164
- name: "pagination / onPaginationChange / rowCount",
1165
- type: "PaginationState / OnChangeFn / number",
1166
- description: "Server pagination: pass pagination + onPaginationChange + rowCount (total). Omit for client pagination."
1167
- },
1168
- {
1169
- name: "columnVisibility / onColumnVisibilityChange",
1170
- type: "VisibilityState / OnChangeFn<VisibilityState>",
1171
- description: "Column show/hide state surfaced by DataGrid.ViewOptions ('set view'). Internal if omitted."
1172
- },
1173
- {
1174
- name: "manualSorting / manualFiltering / manualPagination",
1175
- type: "boolean",
1176
- defaultValue: "true",
1177
- description: "Default true (server/AJAX). Set false to let TanStack sort/filter/paginate in-browser."
1178
- },
1179
- {
1180
- name: "loading / density / onRowClick / empty",
1181
- type: "boolean / 'compact'|'comfortable' / (row:T)=>void / ReactNode",
1182
- description: "Loading row, controlled density, clickable rows, custom empty content."
1183
- }
1184
- ],
1185
- usage: [
1186
- "Import from `@godxjp/ui/data-grid` \u2014 it lives on its own subpath because it pulls @tanstack/react-table; it is NOT in the runtime-neutral root or the data-display barrel.",
1187
- "Compose the compound parts as children: <DataGrid.Toolbar> (holds <DataGrid.BulkActions>, <DataGrid.Search>, <DataGrid.ViewOptions>, <DataGrid.DensityToggle>), then <DataGrid.Content> (auto-included if omitted) and <DataGrid.Pagination pageSizeOptions=[...]>.",
1188
- "Server mode (default): drive sorting/globalFilter/pagination from useQuery and pass rowCount. Client mode: set manualSorting/manualFiltering/manualPagination={false} and the grid handles it on the data array."
1189
- ],
1190
- useCases: [
1191
- "Server-paginated \u4ED5\u8A33 (journal entry) or \u8ACB\u6C42 (invoice) admin list backed by an AJAX/useQuery endpoint: drive sorting + globalFilter + pagination from the query and pass rowCount \u2014 the grid never loads the whole table into the browser. (Prefer DataTable here if the screen must NOT pull @tanstack/react-table.)",
1192
- "Member / employee directory with a user-toggled 'set view' column picker (DataGrid.ViewOptions) \u2014 let admins hide columns like \u5165\u793E\u65E5 or \u90E8\u7F72 they don't need, persisting the columnVisibility state per user.",
1193
- "Bulk-operation worklist (e.g. approve/export selected \u7D4C\u8CBB\u7CBE\u7B97 rows): enableRowSelection + DataGrid.BulkActions to show a 'N\u4EF6\u9078\u629E\u4E2D' action bar with \u4E00\u62EC\u627F\u8A8D / CSV\u51FA\u529B buttons only when rows are checked.",
1194
- "Dense reconciliation or ledger table where operators flip between compact and comfortable row height via DataGrid.DensityToggle to fit more rows on screen during data-entry-heavy sessions.",
1195
- "Client-side grid for a fully-loaded small dataset (e.g. a fixed master list of \u52D8\u5B9A\u79D1\u76EE): set manualSorting/manualFiltering/manualPagination={false} so TanStack sorts, searches, and paginates in-browser without any server round-trip."
1196
- ],
1197
- related: ["DataTable", "Table", "DataState", "Select", "DropdownMenu"],
1198
- example: `import { DataGrid, type ColumnDef } from "@godxjp/ui/data-grid";
1199
- import { Flex } from "@godxjp/ui/layout";
1200
-
1201
- type Row = { id: string; name: string; amount: number };
1202
- const columns: ColumnDef<Row, unknown>[] = [
1203
- { accessorKey: "name", header: "Name", meta: { label: "Name" } },
1204
- { accessorKey: "amount", header: "Amount", meta: { label: "Amount" } },
1205
- ];
1206
-
1207
- export function Grid({ rows }: { rows: Row[] }) {
1208
- return (
1209
- <DataGrid columns={columns} data={rows} getRowId={(r) => r.id} enableRowSelection manualSorting={false} manualFiltering={false} manualPagination={false}>
1210
- <DataGrid.Toolbar>
1211
- <Flex direction="row" align="center" gap="sm" className="ms-auto">
1212
- <DataGrid.Search />
1213
- <DataGrid.ViewOptions />
1214
- <DataGrid.DensityToggle />
1215
- </Flex>
1216
- </DataGrid.Toolbar>
1217
- <DataGrid.Content />
1218
- <DataGrid.Pagination pageSizeOptions={[10, 20, 50]} />
1219
- </DataGrid>
1220
- );
1221
- }`,
1222
- storyPath: "data-display/DataGrid.stories.tsx",
1223
- rules: [24, 31, 35, 37]
1224
- },
1225
1094
  {
1226
1095
  name: "Card",
1227
1096
  group: "data-display",
@@ -1256,7 +1125,8 @@ export function Grid({ rows }: { rows: Row[] }) {
1256
1125
  "DO use <CardContent flush> for edge-to-edge children such as DataTable, Table, or a Tabs list \u2014 this removes horizontal padding. Combine with <CardContent tight> when there is no visual gap needed after the header, and <CardContent solo> when there is no CardHeader above (top padding matches the card shell).",
1257
1126
  "DO use <CardFooter separated> to render a top-bordered action band (Save/Cancel buttons, table summary row). Use <CardFooter flush> for a full-bleed footer bar.",
1258
1127
  "DO use <CardCover> as the first child for full-bleed cover media \u2014 the header below it uses card-section top spacing, not the card shell.",
1259
- "DON'T hand-roll a stat/KPI tile with <Card> + raw divs \u2014 use <StatCard> (label, value, hint, delta, layout, inverse props) which is already a Card internally with correct token-driven layout."
1128
+ "DON'T hand-roll a stat/KPI tile with <Card> + raw divs \u2014 use <StatCard> (label, value, hint, delta, layout, inverse props) which is already a Card internally with correct token-driven layout.",
1129
+ "SPACING IS BORDER-AWARE & token-driven (theme via src/tokens/components/card.css, never hard-code padding on slots): `--card-space-inset` is the shared horizontal column every slot (header/content/footer) aligns to. A DIVIDED section \u2014 a `banded` header or a `separated` footer, i.e. one carrying a divider border \u2014 pads SYMMETRICALLY top+bottom from `--card-space-divided-y` (a band reads as its own region). A PLAIN header flows into the body instead: top `--card-space-inset`, no bottom, and the body supplies the gap via `--card-space-body-y`. Special case: a header above `<CardContent flush>` with a <Table> gets its own `--card-space-body-y` bottom gap (the flush table zeroes its top), so the title never butts the table. `--card-space-gap` is the in-slot stack gap (title\u2195description). Tune the band rhythm once at `--card-space-divided-y`; tune the accent stripe width at `--card-accent-rail-width` (default 6px)."
1260
1130
  ],
1261
1131
  useCases: [
1262
1132
  'Dashboard KPI summary row: wrap each metric in <StatCard> (or a plain <Card size="compact"> with <CardContent>) to render a uniform grid of labeled value tiles with optional trend deltas.',
@@ -1347,6 +1217,11 @@ export function Grid({ rows }: { rows: Row[] }) {
1347
1217
  description: "Metric value (string/number/ReactNode)."
1348
1218
  },
1349
1219
  { name: "hint", type: "ReactNode", description: "Secondary context below the value." },
1220
+ {
1221
+ name: "icon",
1222
+ type: "LucideIcon",
1223
+ description: "Optional leading icon rendered as a tinted medallion above the metric. Decorative (aria-hidden) \u2014 the label carries the meaning. Tint via the --stat-card-icon-{background,foreground} tokens (default a soft brand-primary wash)."
1224
+ },
1350
1225
  {
1351
1226
  name: "delta",
1352
1227
  type: "ReactNode",
@@ -1565,6 +1440,12 @@ import { Smartphone } from "lucide-react";
1565
1440
  defaultValue: "2",
1566
1441
  description: "Column count; collapses to 1 on mobile."
1567
1442
  },
1443
+ {
1444
+ name: "layout",
1445
+ type: '"vertical" | "horizontal"',
1446
+ defaultValue: '"vertical"',
1447
+ description: "Label placement within each item \u2014 `vertical` stacks the label over the value (default); `horizontal` puts the label BESIDE the value in a token-aligned column (mirrors `<Form layout>`). Tune the horizontal label-column width via `--descriptions-label-width`."
1448
+ },
1568
1449
  {
1569
1450
  name: "children",
1570
1451
  type: "ReactNode",
@@ -2092,6 +1973,11 @@ import { Smartphone } from "lucide-react";
2092
1973
  name: "onClear",
2093
1974
  type: "() => void",
2094
1975
  description: "Called after the field is cleared via the inline \u2715 (requires `allowClear`)."
1976
+ },
1977
+ {
1978
+ name: "trailingIcon",
1979
+ type: "React.ReactNode",
1980
+ description: "A trailing affordance pinned inside the field (e.g. a calendar / clock popover trigger). ONE trailing icon shows at a time: when `allowClear` and the field holds a value the clear \u2715 REPLACES this icon; otherwise this icon shows. Never both \u2014 this is how DatePicker/TimePicker render their open trigger."
2095
1981
  }
2096
1982
  ],
2097
1983
  usage: [
@@ -2218,7 +2104,7 @@ import { Smartphone } from "lucide-react";
2218
2104
  "Input \u2014 the plain single-line field NumberInput composes; use Input directly only for free numeric text with no stepper/clamp need.",
2219
2105
  "Slider \u2014 use instead when the user picks an approximate value within a range by dragging; NumberInput is for exact keyed entry.",
2220
2106
  "FormField \u2014 compose NumberInput inside FormField (matching id) for label/helper/error a11y wiring.",
2221
- "TimeInput \u2014 the HH:mm sibling spinbutton; NumberInput is for plain numbers, TimeInput for clock times."
2107
+ "TimePicker \u2014 the HH:mm time sibling; NumberInput is for plain numbers, TimePicker for clock times."
2222
2108
  ],
2223
2109
  storyPath: "data-entry/NumberInput.stories.tsx",
2224
2110
  rules: [3, 6],
@@ -6857,7 +6743,7 @@ export default function PasswordBlock() {
6857
6743
  "DON'T hand-roll a positioned `<div>` + `onContextMenu={e => e.preventDefault()}` \u2014 the primitive already gives you keyboard navigation, focus trapping, typeahead, and WAI-ARIA menu semantics for free."
6858
6744
  ],
6859
6745
  useCases: [
6860
- "Right-click actions on a DataTable/DataGrid row (\u8A73\u7D30 / \u8907\u88FD / \u524A\u9664) as a power-user accelerator alongside the visible row action button.",
6746
+ "Right-click actions on a DataTable row (\u8A73\u7D30 / \u8907\u88FD / \u524A\u9664) as a power-user accelerator alongside the visible row action button.",
6861
6747
  "Contextual menu on a file or document tile in an upload/asset manager (\u30C0\u30A6\u30F3\u30ED\u30FC\u30C9 / \u540D\u524D\u5909\u66F4 / \u524A\u9664).",
6862
6748
  "Nested action menu with submenus and shortcuts (e.g. '\u30A8\u30AF\u30B9\u30DD\u30FC\u30C8 \u25B8 CSV / PDF') on a report card.",
6863
6749
  "Stateful toggles on a board/kanban card via ContextMenuCheckboxItem (e.g. \u30D4\u30F3\u7559\u3081, \u5B8C\u4E86\u3068\u3057\u3066\u30DE\u30FC\u30AF)."
@@ -7002,15 +6888,19 @@ export default function PasswordBlock() {
7002
6888
  },
7003
6889
  {
7004
6890
  name: "defaultSize",
7005
- type: "number",
7006
- description: "ResizablePanel initial size as a percentage (0\u2013100) of the group."
6891
+ type: "string | number",
6892
+ description: 'ResizablePanel initial size. react-resizable-panels v4: a STRING is a unit ("35%", "20rem", "240px"); a bare NUMBER is PIXELS. For a percentage of the group pass a string like "35%" \u2014 `defaultSize={35}` means 35px (a sliver), not 35%.'
7007
6893
  },
7008
6894
  {
7009
6895
  name: "minSize",
7010
- type: "number",
7011
- description: "ResizablePanel minimum size (%) \u2014 drag can't shrink below this."
6896
+ type: "string | number",
6897
+ description: `ResizablePanel minimum size \u2014 drag can't shrink below this. Same unit rule: "20%" for percent, bare number = px.`
6898
+ },
6899
+ {
6900
+ name: "maxSize",
6901
+ type: "string | number",
6902
+ description: 'ResizablePanel maximum size. "60%" for percent, bare number = px.'
7012
6903
  },
7013
- { name: "maxSize", type: "number", description: "ResizablePanel maximum size (%)." },
7014
6904
  {
7015
6905
  name: "collapsible",
7016
6906
  type: "boolean",
@@ -7025,7 +6915,7 @@ export default function PasswordBlock() {
7025
6915
  ],
7026
6916
  usage: [
7027
6917
  'DO put the layout on `<ResizablePanelGroup orientation="horizontal|vertical">`, the resizable regions in `<ResizablePanel>`, and a `<ResizableHandle>` BETWEEN every adjacent pair \u2014 a group of N panels needs N-1 handles or there is nothing to drag.',
7028
- "DO size panels with `defaultSize`/`minSize`/`maxSize` as PERCENTAGES (the group totals 100), not pixels \u2014 don't fight this with a fixed `w-[280px]` className on the panel.",
6918
+ 'DO express `defaultSize`/`minSize`/`maxSize` as PERCENTAGE STRINGS like `defaultSize="35%"` (react-resizable-panels v4: a bare number is PIXELS, so `defaultSize={35}` renders a 35px sliver, NOT 35% \u2014 pass the string). Don\'t fight sizing with a fixed `w-[280px]` className on the panel.',
7029
6919
  "DON'T reach for ResizablePanel when the split is fixed and never user-adjustable \u2014 use a plain `Flex`/`ResponsiveGrid`, or `SplitPane` for a simple two-pane layout. Resizable is for *user-draggable* boundaries only.",
7030
6920
  "DO give each panel a stable `id` and use `collapsible` + `collapsedSize` for a side panel the user can fully tuck away (e.g. a filters rail), reacting via `onResize`.",
7031
6921
  "DON'T hand-roll a draggable divider with mouse-move listeners \u2014 the primitive handles pointer + keyboard resizing, ARIA separator semantics, and min/max clamping. Always render `<ResizableHandle>`, never a bare styled `<div>`."
@@ -7040,10 +6930,10 @@ export default function PasswordBlock() {
7040
6930
  rules: [3, 6],
7041
6931
  example: `import { ResizablePanelGroup, ResizablePanel, ResizableHandle } from "@godxjp/ui/layout";
7042
6932
 
7043
- <ResizablePanelGroup>
7044
- <ResizablePanel>Panel A</ResizablePanel>
6933
+ <ResizablePanelGroup orientation="horizontal">
6934
+ <ResizablePanel id="list" defaultSize="35%" minSize="20%">Panel A</ResizablePanel>
7045
6935
  <ResizableHandle />
7046
- <ResizablePanel>Panel B</ResizablePanel>
6936
+ <ResizablePanel id="detail" defaultSize="65%" minSize="40%">Panel B</ResizablePanel>
7047
6937
  </ResizablePanelGroup>`
7048
6938
  },
7049
6939
  {
@@ -7095,50 +6985,6 @@ export default function PasswordBlock() {
7095
6985
  <CarouselNext />
7096
6986
  <CarouselDots />
7097
6987
  </Carousel>`
7098
- },
7099
- {
7100
- name: "TimeInput",
7101
- group: "data-entry",
7102
- tagline: "Masking HH:mm input with validation and optional minute step quantization.",
7103
- props: [
7104
- { name: "value", type: "string", description: "Controlled HH:mm value." },
7105
- {
7106
- name: "defaultValue",
7107
- type: "string",
7108
- description: "Uncontrolled initial HH:mm value."
7109
- },
7110
- {
7111
- name: "onValueChange",
7112
- type: "(value: string) => void",
7113
- description: "Validated value callback."
7114
- },
7115
- {
7116
- name: "step",
7117
- type: "number",
7118
- defaultValue: "1",
7119
- description: "Minute step (clamped 1\u201359). Snaps the committed minute to the nearest lower multiple and sets the ArrowUp/ArrowDown increment."
7120
- },
7121
- { name: "name", type: "string", description: "Form field name." }
7122
- ],
7123
- usage: [
7124
- "DO treat the value as a plain `HH:mm` string (24-hour, zero-padded) \u2014 TimeInput is calendar-free. For a date, or a date+time, use `DatePicker`/`Calendar`; for a richer dropdown time selector use `TimePicker`.",
7125
- "DO drive it controlled with `value` + `onValueChange` (it follows the vocabulary \u2014 NOT `onChange`/`defaultValue` pairing for control). `onValueChange` fires only with a VALID, step-snapped `HH:mm`, so your state never holds a half-typed value.",
7126
- "DON'T pass `value` without `onValueChange` \u2014 like every controlled @godxjp/ui input that freezes the field. Omit both for uncontrolled (use `defaultValue`).",
7127
- "DO set `step` to your scheduling granularity (e.g. `15` or `30`) \u2014 the user can still type freely, but blur/Enter snaps the minute down to the nearest multiple, and ArrowUp/ArrowDown step by that amount (wrapping across midnight).",
7128
- "DO let the built-in masking + validation work: digits auto-format to `HH:mm`, invalid input sets `aria-invalid` and is reverted on blur. Don't add your own regex/onChange masking on top.",
7129
- "DON'T use it for a duration/elapsed time that can exceed 23:59 \u2014 it's a clock time-of-day input (00:00\u201323:59). Use a numeric Input for durations."
7130
- ],
7131
- useCases: [
7132
- "\u52E4\u6020 (attendance) start/end time fields \u2014 \u51FA\u52E4 / \u9000\u52E4 HH:mm entry with step={1} or a rounding step for shift schedules.",
7133
- "Business-hours / reservation slot editor where times snap to a 15- or 30-minute grid (step={15}).",
7134
- "A from\u2013to time range filter on a report or log screen (two TimeInputs) with no date component.",
7135
- "Any calendar-free HH:mm-only form field (e.g. a recurring daily batch time, a \u7DE0\u3081\u6642\u523B)."
7136
- ],
7137
- storyPath: "data-entry/TimeInput.stories.tsx",
7138
- rules: [3, 6],
7139
- example: `import { TimeInput } from "@godxjp/ui/data-entry";
7140
-
7141
- <TimeInput value="09:00" step={15} onValueChange={(time) => console.log(time)} />`
7142
6988
  },
7143
6989
  {
7144
6990
  name: "AppSettingPicker",
@@ -7795,6 +7641,36 @@ var TOKENS = [
7795
7641
  tier: "primitive",
7796
7642
  role: "Distance (10px) a revealed element travels on enter (translateY/-X). Read instead of a literal `translateY(10px)` for staggered reveals."
7797
7643
  },
7644
+ {
7645
+ name: "--shadow-color",
7646
+ category: "primitive",
7647
+ tier: "primitive",
7648
+ role: "RGB channels (space-separated, e.g. `12 26 49`) that tint the WHOLE elevation ramp (--shadow-xs..2xl) at once. Default `0 0 0`. Single-brand :root only \u2014 a scoped override does not re-resolve the ramp (the steps compute at :root); for a scoped/multi-tenant card lift set --card-shadow to a literal value."
7649
+ },
7650
+ {
7651
+ name: "--shadow-glow",
7652
+ category: "primitive",
7653
+ tier: "primitive",
7654
+ role: "Opt-in brand GLOW halo layered on the primary CTA's resting shadow. Default invisible (`0 0 0 0 transparent`, valid inside a comma shadow list). A service sets the whole value, e.g. `--shadow-glow: 0 8px 20px hsl(var(--primary) / .32)` \u2014 works scoped under [data-tenant] because the service declares it inside the scope."
7655
+ },
7656
+ {
7657
+ name: "--focus-ring-color",
7658
+ category: "primitive",
7659
+ tier: "primitive",
7660
+ role: "Themeable hue of EVERY keyboard-focus ring (HSL components, default var(--ring)). A leaf token, so it re-resolves at the element that paints the ring \u2014 override it once, even scoped under [data-tenant], to retint all focus rings. Pair with --focus-ring-width."
7661
+ },
7662
+ {
7663
+ name: "--focus-ring-width",
7664
+ category: "primitive",
7665
+ tier: "primitive",
7666
+ role: "Thickness (2px) of the solid keyboard-focus ring. Leaf token \u2014 :focus-visible rules read it directly as `0 0 0 var(--focus-ring-width) hsl(var(--focus-ring-color))`, never via an intermediate composite (which would freeze at :root). Propagates scoped."
7667
+ },
7668
+ {
7669
+ name: "--gradient-{brand,hero,glow}",
7670
+ category: "primitive",
7671
+ tier: "primitive",
7672
+ role: "Opt-in decorative gradient fills, default `none`. --gradient-hero paints the PageContainer header (hero banner); --gradient-glow paints the AppShell .app-main (ambient brand wash); --gradient-brand is a spare. A service sets the full gradient, e.g. `--gradient-glow: radial-gradient(60% 80% at 50% 0%, hsl(var(--primary) / .25), transparent)`."
7673
+ },
7798
7674
  { name: "--primary", category: "semantic", tier: "semantic", role: "Brand/action color role." },
7799
7675
  { name: "--success", category: "semantic", tier: "semantic", role: "Success status role." },
7800
7676
  { name: "--warning", category: "semantic", tier: "semantic", role: "Warning status role." },
@@ -7812,6 +7688,12 @@ var TOKENS = [
7812
7688
  tier: "semantic",
7813
7689
  role: "PageContainer header bottom divider. Default none; a service theme opts in with `1px solid hsl(var(--border))`."
7814
7690
  },
7691
+ {
7692
+ name: "--overlay-background",
7693
+ category: "semantic",
7694
+ tier: "semantic",
7695
+ role: "Modal scrim \u2014 the single backdrop colour shared by every overlay (Dialog, AlertDialog, Sheet, Drawer). Default `rgb(0 0 0 / 0.5)`. A service tints it once, e.g. a navy `rgb(12 26 49 / .55)`. NOTE: portaled overlays render outside a [data-tenant] subtree, so for multi-tenant scoping put the tenant attribute on the portal container too."
7696
+ },
7815
7697
  {
7816
7698
  name: "--page-header-pad-bottom",
7817
7699
  category: "semantic",
@@ -7880,72 +7762,77 @@ var COMPONENT_TOKENS = [
7880
7762
  {
7881
7763
  "name": "--card-space-inset",
7882
7764
  "value": "var(--space-section-active)",
7883
- "description": "Card component tokens: card chrome derives from semantic layout tokens."
7765
+ "description": "Horizontal inset of every slot (header / content / footer) + the resting top/bottom * shell padding. This is the column the title, body and footer all align to."
7884
7766
  },
7885
7767
  {
7886
7768
  "name": "--card-space-header-y",
7887
7769
  "value": "var(--space-stack-sm)",
7888
- "description": "Card component tokens: card chrome derives from semantic layout tokens."
7770
+ "description": "Vertical padding of a BANDED header band (top = bottom). Drives --card-space-divided-y."
7889
7771
  },
7890
7772
  {
7891
7773
  "name": "--card-space-body-y",
7892
7774
  "value": "var(--space-section-active)",
7893
- "description": "Card component tokens: card chrome derives from semantic layout tokens."
7775
+ "description": "Gap between the header and the body, and the body's own top padding \u2014 the breathing * room under a title before content begins."
7894
7776
  },
7895
7777
  {
7896
7778
  "name": "--card-space-footer-y",
7897
7779
  "value": "var(--space-stack-sm)",
7898
- "description": "Card component tokens: card chrome derives from semantic layout tokens."
7780
+ "description": "Vertical padding of a SEPARATED footer band (top = bottom). Drives --card-space-divided-y."
7781
+ },
7782
+ {
7783
+ "name": "--card-space-divided-y",
7784
+ "value": "var(--card-space-header-y)",
7785
+ "description": "DIVIDED-section vertical padding (rule #44/#45). A header/footer that carries a divider * border (banded header, separated footer) reads as its own band, so it pads SYMMETRICALLY * top+bottom \u2014 distinct from a plain header that flows into the body (top inset, no bottom). * One themeable knob keeps the header- and footer-band rhythm in sync; a service theme tunes * the band density here instead of forking per-slot CSS."
7899
7786
  },
7900
7787
  {
7901
7788
  "name": "--card-space-gap",
7902
7789
  "value": "var(--space-stack-xs)",
7903
- "description": "Card component tokens: card chrome derives from semantic layout tokens."
7790
+ "description": "Vertical gap between stacked items WITHIN a slot (e.g. title \u2195 description in the header)."
7904
7791
  },
7905
7792
  {
7906
7793
  "name": "--card-title-font-size",
7907
7794
  "value": "var(--font-size-base)",
7908
- "description": "Card component tokens: card chrome derives from semantic layout tokens."
7795
+ "description": "Vertical gap between stacked items WITHIN a slot (e.g. title \u2195 description in the header)."
7909
7796
  },
7910
7797
  {
7911
7798
  "name": "--card-title-line-height",
7912
7799
  "value": "var(--line-height-tight)",
7913
- "description": "Card component tokens: card chrome derives from semantic layout tokens."
7800
+ "description": "Vertical gap between stacked items WITHIN a slot (e.g. title \u2195 description in the header)."
7914
7801
  },
7915
7802
  {
7916
7803
  "name": "--card-title-font-weight",
7917
7804
  "value": "var(--font-weight-semibold)",
7918
- "description": "Card component tokens: card chrome derives from semantic layout tokens."
7805
+ "description": "Vertical gap between stacked items WITHIN a slot (e.g. title \u2195 description in the header)."
7919
7806
  },
7920
7807
  {
7921
7808
  "name": "--card-description-font-size",
7922
7809
  "value": "var(--font-size-sm)",
7923
- "description": "Card component tokens: card chrome derives from semantic layout tokens."
7810
+ "description": "Vertical gap between stacked items WITHIN a slot (e.g. title \u2195 description in the header)."
7924
7811
  },
7925
7812
  {
7926
7813
  "name": "--card-description-line-height",
7927
7814
  "value": "var(--line-height-normal)",
7928
- "description": "Card component tokens: card chrome derives from semantic layout tokens."
7815
+ "description": "Vertical gap between stacked items WITHIN a slot (e.g. title \u2195 description in the header)."
7929
7816
  },
7930
7817
  {
7931
7818
  "name": "--card-background",
7932
7819
  "value": "var(--card)",
7933
- "description": "Card component tokens: card chrome derives from semantic layout tokens."
7820
+ "description": "Vertical gap between stacked items WITHIN a slot (e.g. title \u2195 description in the header)."
7934
7821
  },
7935
7822
  {
7936
7823
  "name": "--card-border",
7937
7824
  "value": "var(--border)",
7938
- "description": "Card component tokens: card chrome derives from semantic layout tokens."
7825
+ "description": "Vertical gap between stacked items WITHIN a slot (e.g. title \u2195 description in the header)."
7939
7826
  },
7940
7827
  {
7941
7828
  "name": "--card-header-background",
7942
7829
  "value": "var(--muted)",
7943
- "description": "Card component tokens: card chrome derives from semantic layout tokens."
7830
+ "description": "Banded-header fill \u2014 already role-tintable (rule #45): a service points this at any role, * e.g. --card-header-background: var(--primary), and tunes --card-header-background-alpha for * the wash strength. No separate tint token needed."
7944
7831
  },
7945
7832
  {
7946
7833
  "name": "--card-header-background-alpha",
7947
7834
  "value": "0.55",
7948
- "description": "Card component tokens: card chrome derives from semantic layout tokens."
7835
+ "description": "Banded-header fill \u2014 already role-tintable (rule #45): a service points this at any role, * e.g. --card-header-background: var(--primary), and tunes --card-header-background-alpha for * the wash strength. No separate tint token needed."
7949
7836
  },
7950
7837
  {
7951
7838
  "name": "--card-header-border-bottom",
@@ -7957,6 +7844,21 @@ var COMPONENT_TOKENS = [
7957
7844
  "value": "var(--radius)",
7958
7845
  "description": "Banded-header divider \u2014 tokenised (rule #44) so a service theme can make it * dashed / heavier / none without forking CSS. Pair with * --card-header-background-alpha: 0 for a quiet borderless-band header."
7959
7846
  },
7847
+ {
7848
+ "name": "--card-shadow",
7849
+ "value": "0 0 0 0 transparent",
7850
+ "description": "Resting elevation \u2014 quiet by default (rule #44): cards are flat (1px border, no shadow) in the * dxs-kintai baseline. A service that wants lifted cards sets this to an elevation token once, * e.g. --card-shadow: var(--shadow-sm), and every Card picks up the shadow with no markup change."
7851
+ },
7852
+ {
7853
+ "name": "--card-glow",
7854
+ "value": "0 0 0 0 transparent",
7855
+ "description": "Brand glow layer \u2014 invisible no-op at rest (rule #44). Paired AFTER --card-shadow in the * surface box-shadow so a service can wash every card with the global glow, e.g. * --card-glow: var(--shadow-glow), with no markup change."
7856
+ },
7857
+ {
7858
+ "name": "--card-tint",
7859
+ "value": "transparent",
7860
+ "description": "Fill tint \u2014 subtle role wash over the card background (default transparent = invisible). * Painted as an overlay so a service sets --card-tint: hsl(var(--primary) / 0.04) once."
7861
+ },
7960
7862
  {
7961
7863
  "name": "--card-accent-rail-width",
7962
7864
  "value": "6px",
@@ -8007,10 +7909,30 @@ var COMPONENT_TOKENS = [
8007
7909
  "value": "2.25rem",
8008
7910
  "description": "Accent edge \u2014 width of the semantic leading-edge stripe (data-accent). * Tokenised (rule #44) so a service theme can re-tune it without forking CSS. * The slot padding compensation in card-layout.css subtracts the same token, * so content stays aligned on the shell whatever the rail width."
8009
7911
  },
7912
+ {
7913
+ "name": "--stat-card-icon-glyph-size",
7914
+ "value": "1.25rem",
7915
+ "description": "Accent edge \u2014 width of the semantic leading-edge stripe (data-accent). * Tokenised (rule #44) so a service theme can re-tune it without forking CSS. * The slot padding compensation in card-layout.css subtracts the same token, * so content stays aligned on the shell whatever the rail width."
7916
+ },
7917
+ {
7918
+ "name": "--stat-card-icon-radius",
7919
+ "value": "var(--radius-md)",
7920
+ "description": "Accent edge \u2014 width of the semantic leading-edge stripe (data-accent). * Tokenised (rule #44) so a service theme can re-tune it without forking CSS. * The slot padding compensation in card-layout.css subtracts the same token, * so content stays aligned on the shell whatever the rail width."
7921
+ },
7922
+ {
7923
+ "name": "--stat-card-icon-background",
7924
+ "value": "hsl(var(--primary) / 0.1)",
7925
+ "description": "Medallion tint \u2014 soft brand wash + brand glyph by default; a service retints by overriding * --primary or these tokens directly (rule #44/#45)."
7926
+ },
7927
+ {
7928
+ "name": "--stat-card-icon-foreground",
7929
+ "value": "hsl(var(--primary))",
7930
+ "description": "Medallion tint \u2014 soft brand wash + brand glyph by default; a service retints by overriding * --primary or these tokens directly (rule #44/#45)."
7931
+ },
8010
7932
  {
8011
7933
  "name": "--stat-card-delta-font-size",
8012
7934
  "value": "var(--font-size-xs)",
8013
- "description": "Accent edge \u2014 width of the semantic leading-edge stripe (data-accent). * Tokenised (rule #44) so a service theme can re-tune it without forking CSS. * The slot padding compensation in card-layout.css subtracts the same token, * so content stays aligned on the shell whatever the rail width."
7935
+ "description": "Medallion tint \u2014 soft brand wash + brand glyph by default; a service retints by overriding * --primary or these tokens directly (rule #44/#45)."
8014
7936
  },
8015
7937
  {
8016
7938
  "name": "--control-height-compact",
@@ -8094,7 +8016,7 @@ var COMPONENT_TOKENS = [
8094
8016
  },
8095
8017
  {
8096
8018
  "name": "--control-focus-ring-width",
8097
- "value": "2px",
8019
+ "value": "var(--focus-ring-width)",
8098
8020
  "description": "Adjacent control sizes, derived from the active --control-height. The \xB1step * is scaled too so the whole control ladder stays proportional under --scaling."
8099
8021
  },
8100
8022
  {
@@ -8207,85 +8129,110 @@ var COMPONENT_TOKENS = [
8207
8129
  "value": "1rem",
8208
8130
  "description": "Adjacent control sizes, derived from the active --control-height. The \xB1step * is scaled too so the whole control ladder stays proportional under --scaling."
8209
8131
  },
8132
+ {
8133
+ "name": "--checkbox-checked-background",
8134
+ "value": "hsl(var(--primary))",
8135
+ "description": 'Checked/on/active fills \u2014 themeable role expression, defaults equal the current literal * (quiet: no visual change). A service retints the "selected" state by overriding these.'
8136
+ },
8137
+ {
8138
+ "name": "--switch-checked-background",
8139
+ "value": "hsl(var(--primary))",
8140
+ "description": 'Checked/on/active fills \u2014 themeable role expression, defaults equal the current literal * (quiet: no visual change). A service retints the "selected" state by overriding these.'
8141
+ },
8142
+ {
8143
+ "name": "--toggle-on-background",
8144
+ "value": "hsl(var(--primary))",
8145
+ "description": 'Checked/on/active fills \u2014 themeable role expression, defaults equal the current literal * (quiet: no visual change). A service retints the "selected" state by overriding these.'
8146
+ },
8147
+ {
8148
+ "name": "--slider-track-background",
8149
+ "value": "hsl(var(--primary) / 0.2)",
8150
+ "description": 'Checked/on/active fills \u2014 themeable role expression, defaults equal the current literal * (quiet: no visual change). A service retints the "selected" state by overriding these.'
8151
+ },
8152
+ {
8153
+ "name": "--slider-range-background",
8154
+ "value": "hsl(var(--primary))",
8155
+ "description": 'Checked/on/active fills \u2014 themeable role expression, defaults equal the current literal * (quiet: no visual change). A service retints the "selected" state by overriding these.'
8156
+ },
8210
8157
  {
8211
8158
  "name": "--color-picker-input-width",
8212
8159
  "value": "6.5rem",
8213
- "description": "Adjacent control sizes, derived from the active --control-height. The \xB1step * is scaled too so the whole control ladder stays proportional under --scaling."
8160
+ "description": 'Checked/on/active fills \u2014 themeable role expression, defaults equal the current literal * (quiet: no visual change). A service retints the "selected" state by overriding these.'
8214
8161
  },
8215
8162
  {
8216
8163
  "name": "--command-list-max-height",
8217
8164
  "value": "min(300px, 50vh)",
8218
- "description": "Adjacent control sizes, derived from the active --control-height. The \xB1step * is scaled too so the whole control ladder stays proportional under --scaling."
8165
+ "description": 'Checked/on/active fills \u2014 themeable role expression, defaults equal the current literal * (quiet: no visual change). A service retints the "selected" state by overriding these.'
8219
8166
  },
8220
8167
  {
8221
8168
  "name": "--command-input-padding-x",
8222
8169
  "value": "var(--space-3)",
8223
- "description": "Adjacent control sizes, derived from the active --control-height. The \xB1step * is scaled too so the whole control ladder stays proportional under --scaling."
8170
+ "description": 'Checked/on/active fills \u2014 themeable role expression, defaults equal the current literal * (quiet: no visual change). A service retints the "selected" state by overriding these.'
8224
8171
  },
8225
8172
  {
8226
8173
  "name": "--command-group-padding",
8227
8174
  "value": "var(--space-1)",
8228
- "description": "Adjacent control sizes, derived from the active --control-height. The \xB1step * is scaled too so the whole control ladder stays proportional under --scaling."
8175
+ "description": 'Checked/on/active fills \u2014 themeable role expression, defaults equal the current literal * (quiet: no visual change). A service retints the "selected" state by overriding these.'
8229
8176
  },
8230
8177
  {
8231
8178
  "name": "--command-item-padding-y",
8232
8179
  "value": "var(--space-2)",
8233
- "description": "Adjacent control sizes, derived from the active --control-height. The \xB1step * is scaled too so the whole control ladder stays proportional under --scaling."
8180
+ "description": 'Checked/on/active fills \u2014 themeable role expression, defaults equal the current literal * (quiet: no visual change). A service retints the "selected" state by overriding these.'
8234
8181
  },
8235
8182
  {
8236
8183
  "name": "--command-item-padding-x",
8237
8184
  "value": "var(--space-2)",
8238
- "description": "Adjacent control sizes, derived from the active --control-height. The \xB1step * is scaled too so the whole control ladder stays proportional under --scaling."
8185
+ "description": 'Checked/on/active fills \u2014 themeable role expression, defaults equal the current literal * (quiet: no visual change). A service retints the "selected" state by overriding these.'
8239
8186
  },
8240
8187
  {
8241
8188
  "name": "--search-input-edge-inset",
8242
8189
  "value": "var(--space-3)",
8243
- "description": "Adjacent control sizes, derived from the active --control-height. The \xB1step * is scaled too so the whole control ladder stays proportional under --scaling."
8190
+ "description": 'Checked/on/active fills \u2014 themeable role expression, defaults equal the current literal * (quiet: no visual change). A service retints the "selected" state by overriding these.'
8244
8191
  },
8245
8192
  {
8246
8193
  "name": "--search-input-start-padding",
8247
8194
  "value": "calc( var(--search-input-edge-inset) + var(--control-icon-size) + var(--control-gap) )",
8248
- "description": "Adjacent control sizes, derived from the active --control-height. The \xB1step * is scaled too so the whole control ladder stays proportional under --scaling."
8195
+ "description": 'Checked/on/active fills \u2014 themeable role expression, defaults equal the current literal * (quiet: no visual change). A service retints the "selected" state by overriding these.'
8249
8196
  },
8250
8197
  {
8251
8198
  "name": "--search-input-end-padding",
8252
8199
  "value": "calc( var(--search-input-edge-inset) + var(--control-icon-size) + var(--control-gap) )",
8253
- "description": "Adjacent control sizes, derived from the active --control-height. The \xB1step * is scaled too so the whole control ladder stays proportional under --scaling."
8200
+ "description": 'Checked/on/active fills \u2014 themeable role expression, defaults equal the current literal * (quiet: no visual change). A service retints the "selected" state by overriding these.'
8254
8201
  },
8255
8202
  {
8256
8203
  "name": "--choice-description-font-size",
8257
8204
  "value": "var(--font-size-xs)",
8258
- "description": "Adjacent control sizes, derived from the active --control-height. The \xB1step * is scaled too so the whole control ladder stays proportional under --scaling."
8205
+ "description": 'Checked/on/active fills \u2014 themeable role expression, defaults equal the current literal * (quiet: no visual change). A service retints the "selected" state by overriding these.'
8259
8206
  },
8260
8207
  {
8261
8208
  "name": "--color-picker-hex-font-size",
8262
8209
  "value": "var(--font-size-xs)",
8263
- "description": "Adjacent control sizes, derived from the active --control-height. The \xB1step * is scaled too so the whole control ladder stays proportional under --scaling."
8210
+ "description": 'Checked/on/active fills \u2014 themeable role expression, defaults equal the current literal * (quiet: no visual change). A service retints the "selected" state by overriding these.'
8264
8211
  },
8265
8212
  {
8266
8213
  "name": "--command-group-heading-font-size",
8267
8214
  "value": "var(--font-size-xs)",
8268
- "description": "Adjacent control sizes, derived from the active --control-height. The \xB1step * is scaled too so the whole control ladder stays proportional under --scaling."
8215
+ "description": 'Checked/on/active fills \u2014 themeable role expression, defaults equal the current literal * (quiet: no visual change). A service retints the "selected" state by overriding these.'
8269
8216
  },
8270
8217
  {
8271
8218
  "name": "--search-input-label-font-size",
8272
8219
  "value": "var(--font-size-xs)",
8273
- "description": "Adjacent control sizes, derived from the active --control-height. The \xB1step * is scaled too so the whole control ladder stays proportional under --scaling."
8220
+ "description": 'Checked/on/active fills \u2014 themeable role expression, defaults equal the current literal * (quiet: no visual change). A service retints the "selected" state by overriding these.'
8274
8221
  },
8275
8222
  {
8276
8223
  "name": "--tag-input-chip-font-size",
8277
8224
  "value": "var(--font-size-xs)",
8278
- "description": "Adjacent control sizes, derived from the active --control-height. The \xB1step * is scaled too so the whole control ladder stays proportional under --scaling."
8225
+ "description": 'Checked/on/active fills \u2014 themeable role expression, defaults equal the current literal * (quiet: no visual change). A service retints the "selected" state by overriding these.'
8279
8226
  },
8280
8227
  {
8281
8228
  "name": "--toggle-sm-font-size",
8282
8229
  "value": "var(--font-size-xs)",
8283
- "description": "Adjacent control sizes, derived from the active --control-height. The \xB1step * is scaled too so the whole control ladder stays proportional under --scaling."
8230
+ "description": 'Checked/on/active fills \u2014 themeable role expression, defaults equal the current literal * (quiet: no visual change). A service retints the "selected" state by overriding these.'
8284
8231
  },
8285
8232
  {
8286
8233
  "name": "--button-sm-font-size",
8287
8234
  "value": "var(--font-size-xs)",
8288
- "description": "Adjacent control sizes, derived from the active --control-height. The \xB1step * is scaled too so the whole control ladder stays proportional under --scaling."
8235
+ "description": 'Checked/on/active fills \u2014 themeable role expression, defaults equal the current literal * (quiet: no visual change). A service retints the "selected" state by overriding these.'
8289
8236
  },
8290
8237
  {
8291
8238
  "name": "--control-height-compact",
@@ -8317,6 +8264,51 @@ var COMPONENT_TOKENS = [
8317
8264
  "value": "var(--font-size-xs)",
8318
8265
  "description": "Data-display component tokens \u2014 small-by-design text knobs (rule #45/#46)."
8319
8266
  },
8267
+ {
8268
+ "name": "--avatar-background",
8269
+ "value": "hsl(var(--muted))",
8270
+ "description": "Avatar surface \u2014 reads the muted role by default. A service can re-tint the placeholder fill once (e.g. --avatar-background: hsl(var(--accent)))."
8271
+ },
8272
+ {
8273
+ "name": "--avatar-tint",
8274
+ "value": "transparent",
8275
+ "description": "Optional role wash over the avatar (default transparent = invisible, rule #44). Painted as an overlay so a service sets --avatar-tint: hsl(var(--primary) / 0.08)."
8276
+ },
8277
+ {
8278
+ "name": "--progress-track-background",
8279
+ "value": "hsl(var(--secondary))",
8280
+ "description": "Progress track + fill \u2014 quiet defaults equal the current literals (rule #44). Track reads secondary, fill reads success; a service re-tones once."
8281
+ },
8282
+ {
8283
+ "name": "--progress-fill-background",
8284
+ "value": "hsl(var(--success))",
8285
+ "description": "Progress track + fill \u2014 quiet defaults equal the current literals (rule #44). Track reads secondary, fill reads success; a service re-tones once."
8286
+ },
8287
+ {
8288
+ "name": "--timeline-dot-done-background",
8289
+ "value": "hsl(var(--success))",
8290
+ "description": "Timeline accents \u2014 dot/line roles, defaults unchanged (rule #44)."
8291
+ },
8292
+ {
8293
+ "name": "--timeline-dot-current-background",
8294
+ "value": "hsl(var(--primary))",
8295
+ "description": "Timeline accents \u2014 dot/line roles, defaults unchanged (rule #44)."
8296
+ },
8297
+ {
8298
+ "name": "--timeline-line-completed-background",
8299
+ "value": "hsl(var(--primary))",
8300
+ "description": "Timeline accents \u2014 dot/line roles, defaults unchanged (rule #44)."
8301
+ },
8302
+ {
8303
+ "name": "--tree-item-active-border",
8304
+ "value": "hsl(var(--primary) / 0.3)",
8305
+ "description": "Tree active item \u2014 border + soft bg tint over the primary role. Defaults equal the current literals (rule #44)."
8306
+ },
8307
+ {
8308
+ "name": "--tree-item-active-background",
8309
+ "value": "hsl(var(--primary) / 0.05)",
8310
+ "description": "Tree active item \u2014 border + soft bg tint over the primary role. Defaults equal the current literals (rule #44)."
8311
+ },
8320
8312
  {
8321
8313
  "name": "--password-strength-score-font-size",
8322
8314
  "value": "var(--font-size-xs)",
@@ -8327,6 +8319,11 @@ var COMPONENT_TOKENS = [
8327
8319
  "value": "var(--font-size-xs)",
8328
8320
  "description": "Data-entry component tokens \u2014 small-by-design text knobs (rule #45/#46)."
8329
8321
  },
8322
+ {
8323
+ "name": "--descriptions-label-width",
8324
+ "value": "8rem",
8325
+ "description": 'Width of the label column when <Descriptions layout="horizontal">. Labels align to this * shared column so the values line up (the horizontal-detail look, mirroring <Form layout>). * A rem value gives a fixed aligned column; set `max-content` to size each label to its text. * (rule #44/#45 \u2014 a service theme tunes it here instead of forking CSS.)'
8326
+ },
8330
8327
  {
8331
8328
  "name": "--dialog-space-x",
8332
8329
  "value": "var(--space-chrome-x)",
@@ -8382,35 +8379,55 @@ var COMPONENT_TOKENS = [
8382
8379
  "value": "0.3",
8383
8380
  "description": "Soft (subtle) semantic tint ratios \u2014 themeable so a service can hit its exact spec * (a brand's success-bg/-border are often more present than the faint 5%/30% default)."
8384
8381
  },
8382
+ {
8383
+ "name": "--dialog-content-glow",
8384
+ "value": "0 0 0 0 transparent",
8385
+ "description": "Brand glow layer for the raised dialog/sheet panel \u2014 invisible no-op at rest (rule #44). * Paired AFTER --shadow-lg in the surface box-shadow so a service can wash the overlay with the * global glow, e.g. --dialog-content-glow: var(--shadow-glow), with no markup change."
8386
+ },
8385
8387
  {
8386
8388
  "name": "--empty-state-space-y",
8387
8389
  "value": "var(--space-10)",
8388
- "description": "Soft (subtle) semantic tint ratios \u2014 themeable so a service can hit its exact spec * (a brand's success-bg/-border are often more present than the faint 5%/30% default)."
8390
+ "description": "Brand glow layer for the raised dialog/sheet panel \u2014 invisible no-op at rest (rule #44). * Paired AFTER --shadow-lg in the surface box-shadow so a service can wash the overlay with the * global glow, e.g. --dialog-content-glow: var(--shadow-glow), with no markup change."
8389
8391
  },
8390
8392
  {
8391
8393
  "name": "--empty-state-space-x",
8392
8394
  "value": "var(--space-6)",
8393
- "description": "Soft (subtle) semantic tint ratios \u2014 themeable so a service can hit its exact spec * (a brand's success-bg/-border are often more present than the faint 5%/30% default)."
8395
+ "description": "Brand glow layer for the raised dialog/sheet panel \u2014 invisible no-op at rest (rule #44). * Paired AFTER --shadow-lg in the surface box-shadow so a service can wash the overlay with the * global glow, e.g. --dialog-content-glow: var(--shadow-glow), with no markup change."
8396
+ },
8397
+ {
8398
+ "name": "--empty-state-icon-foreground",
8399
+ "value": "hsl(var(--muted-foreground))",
8400
+ "description": "EmptyState icon medallion colour \u2014 defaults to the current literal (rule #44), so a service can * recolour the glyph (--icon-foreground) or wash the medallion fill (--icon-tint) without forking."
8401
+ },
8402
+ {
8403
+ "name": "--empty-state-icon-tint",
8404
+ "value": "hsl(var(--muted))",
8405
+ "description": "EmptyState icon medallion colour \u2014 defaults to the current literal (rule #44), so a service can * recolour the glyph (--icon-foreground) or wash the medallion fill (--icon-tint) without forking."
8394
8406
  },
8395
8407
  {
8396
8408
  "name": "--skeleton-row-gap",
8397
8409
  "value": "var(--space-stack-sm)",
8398
- "description": "Soft (subtle) semantic tint ratios \u2014 themeable so a service can hit its exact spec * (a brand's success-bg/-border are often more present than the faint 5%/30% default)."
8410
+ "description": "EmptyState icon medallion colour \u2014 defaults to the current literal (rule #44), so a service can * recolour the glyph (--icon-foreground) or wash the medallion fill (--icon-tint) without forking."
8399
8411
  },
8400
8412
  {
8401
8413
  "name": "--skeleton-cell-gap",
8402
8414
  "value": "var(--space-inline-lg)",
8403
- "description": "Soft (subtle) semantic tint ratios \u2014 themeable so a service can hit its exact spec * (a brand's success-bg/-border are often more present than the faint 5%/30% default)."
8415
+ "description": "EmptyState icon medallion colour \u2014 defaults to the current literal (rule #44), so a service can * recolour the glyph (--icon-foreground) or wash the medallion fill (--icon-tint) without forking."
8404
8416
  },
8405
8417
  {
8406
8418
  "name": "--skeleton-card-inset",
8407
8419
  "value": "var(--space-section-active)",
8408
- "description": "Soft (subtle) semantic tint ratios \u2014 themeable so a service can hit its exact spec * (a brand's success-bg/-border are often more present than the faint 5%/30% default)."
8420
+ "description": "EmptyState icon medallion colour \u2014 defaults to the current literal (rule #44), so a service can * recolour the glyph (--icon-foreground) or wash the medallion fill (--icon-tint) without forking."
8409
8421
  },
8410
8422
  {
8411
8423
  "name": "--skeleton-radius",
8412
8424
  "value": "var(--radius)",
8413
- "description": "Soft (subtle) semantic tint ratios \u2014 themeable so a service can hit its exact spec * (a brand's success-bg/-border are often more present than the faint 5%/30% default)."
8425
+ "description": "EmptyState icon medallion colour \u2014 defaults to the current literal (rule #44), so a service can * recolour the glyph (--icon-foreground) or wash the medallion fill (--icon-tint) without forking."
8426
+ },
8427
+ {
8428
+ "name": "--skeleton-background",
8429
+ "value": "hsl(var(--muted))",
8430
+ "description": "Skeleton placeholder fill \u2014 defaults to the current literal hsl(var(--muted)); themeable so a * service can tint the shimmer to its surface (rule #44) without forking the keyframes."
8414
8431
  },
8415
8432
  {
8416
8433
  "name": "--form-label-width",
@@ -8442,31 +8459,6 @@ var COMPONENT_TOKENS = [
8442
8459
  "value": "1px solid hsl(var(--border))",
8443
8460
  "description": "ListRow component tokens \u2014 a single-line entity row for short lists inside a Card * (sessions / API tokens / linked accounts / passkeys \u2026). Sits in a flush CardContent; * rows separate with a quiet divider (#44 \u2014 chrome defaults to the calm semantic border)."
8444
8461
  },
8445
- {
8446
- "name": "--logo-size",
8447
- "value": "2rem",
8448
- "description": "Logo (brand mark) component tokens. Box size and corner radius are knobs (#45) so a service can * match its own grid without forking the mark; brand fill follows --primary. The `size` prop picks * the step; a service retunes the steps globally here. (Not a --control-height tier \u2014 the mark is * decorative, not a density-aware interactive control.)"
8449
- },
8450
- {
8451
- "name": "--logo-size-xs",
8452
- "value": "1.5rem",
8453
- "description": "md"
8454
- },
8455
- {
8456
- "name": "--logo-size-sm",
8457
- "value": "1.75rem",
8458
- "description": "md"
8459
- },
8460
- {
8461
- "name": "--logo-size-lg",
8462
- "value": "2.5rem",
8463
- "description": "md"
8464
- },
8465
- {
8466
- "name": "--logo-radius",
8467
- "value": "var(--radius)",
8468
- "description": "md"
8469
- },
8470
8462
  {
8471
8463
  "name": "--pagination-gap",
8472
8464
  "value": "var(--space-inline-sm)",
@@ -8522,6 +8514,16 @@ var COMPONENT_TOKENS = [
8522
8514
  "value": "var(--font-size-xs)",
8523
8515
  "description": "Navigation primitive tokens: pagination, filters, compact pickers."
8524
8516
  },
8517
+ {
8518
+ "name": "--menubar-item-hover-background",
8519
+ "value": "hsl(var(--accent))",
8520
+ "description": "Menu item hover/highlight tint \u2014 reads the accent role; default unchanged."
8521
+ },
8522
+ {
8523
+ "name": "--menubar-item-hover-foreground",
8524
+ "value": "hsl(var(--accent-foreground))",
8525
+ "description": "Menu item hover/highlight tint \u2014 reads the accent role; default unchanged."
8526
+ },
8525
8527
  {
8526
8528
  "name": "--sidebar-section-label-font-size",
8527
8529
  "value": "var(--font-size-2xs)",
@@ -8577,6 +8579,36 @@ var COMPONENT_TOKENS = [
8577
8579
  "value": "var(--font-size-xs)",
8578
8580
  "description": "Shell (sidebar / topbar / kbd) component tokens \u2014 small-by-design text * knobs (rule #45/#46). A service re-tunes chrome text without moving the * global scale."
8579
8581
  },
8582
+ {
8583
+ "name": "--sidebar-gradient",
8584
+ "value": "none",
8585
+ "description": "Brand-chrome gradient hooks \u2014 opt-in, invisible by default. A service paints * the sidebar/topbar surface by setting these to a gradient (no-op = none)."
8586
+ },
8587
+ {
8588
+ "name": "--topbar-gradient",
8589
+ "value": "none",
8590
+ "description": "Brand-chrome gradient hooks \u2014 opt-in, invisible by default. A service paints * the sidebar/topbar surface by setting these to a gradient (no-op = none)."
8591
+ },
8592
+ {
8593
+ "name": "--sidebar-item-active-color",
8594
+ "value": "hsl(var(--primary))",
8595
+ "description": "Sidebar active-item tint/marker \u2014 tokenised from the literal hsl(var(--primary)) * usages; defaults are byte-identical to the prior hard-coded values. A service * can re-tune the active sub-item accent without forking CSS."
8596
+ },
8597
+ {
8598
+ "name": "--sidebar-item-active-tint",
8599
+ "value": "hsl(var(--primary))",
8600
+ "description": "Sidebar active-item tint/marker \u2014 tokenised from the literal hsl(var(--primary)) * usages; defaults are byte-identical to the prior hard-coded values. A service * can re-tune the active sub-item accent without forking CSS."
8601
+ },
8602
+ {
8603
+ "name": "--sidebar-item-active-background",
8604
+ "value": "hsl(var(--accent))",
8605
+ "description": "Main nav-item active row \u2014 defaults are byte-identical to the hover state (accent bg, * foreground text). A service overrides these to brand the selected row (e.g. a gold tint + * gold text on a navy sidebar)."
8606
+ },
8607
+ {
8608
+ "name": "--sidebar-item-active-foreground",
8609
+ "value": "hsl(var(--foreground))",
8610
+ "description": "Main nav-item active row \u2014 defaults are byte-identical to the hover state (accent bg, * foreground text). A service overrides these to brand the selected row (e.g. a gold tint + * gold text on a navy sidebar)."
8611
+ },
8580
8612
  {
8581
8613
  "name": "--table-row-height-compact",
8582
8614
  "value": "1.75rem",
@@ -8612,10 +8644,35 @@ var COMPONENT_TOKENS = [
8612
8644
  "value": "var(--font-size-xs)",
8613
8645
  "description": "Table component tokens: row height, cell padding."
8614
8646
  },
8647
+ {
8648
+ "name": "--table-header-background",
8649
+ "value": "hsl(var(--muted))",
8650
+ "description": "Header band \u2014 its OWN bg + fg tokens (decoupled from --secondary, which == --muted by default so * this is byte-identical). A brand whose --secondary is dark (navy buttons) no longer bleeds a * dark band under the dark header text; it sets both header tokens together to keep contrast."
8651
+ },
8652
+ {
8653
+ "name": "--table-header-foreground",
8654
+ "value": "hsl(var(--muted-foreground))",
8655
+ "description": "Header band \u2014 its OWN bg + fg tokens (decoupled from --secondary, which == --muted by default so * this is byte-identical). A brand whose --secondary is dark (navy buttons) no longer bleeds a * dark band under the dark header text; it sets both header tokens together to keep contrast."
8656
+ },
8615
8657
  {
8616
8658
  "name": "--table-pin-shadow",
8617
8659
  "value": "-6px 0 6px -5px hsl(var(--foreground) / 0.12)",
8618
8660
  "description": "Inline-end shadow that lifts a pinned (sticky) action column off the body it scrolls over."
8661
+ },
8662
+ {
8663
+ "name": "--table-row-striped-background",
8664
+ "value": "hsl(var(--muted) / 0.4)",
8665
+ "description": "Row-state tint washes \u2014 translucent muted over the opaque base. Defaults equal * the prior literals; a service retints by reading another role (e.g. --primary)."
8666
+ },
8667
+ {
8668
+ "name": "--table-row-hover-background",
8669
+ "value": "hsl(var(--muted) / 0.5)",
8670
+ "description": "Row-state tint washes \u2014 translucent muted over the opaque base. Defaults equal * the prior literals; a service retints by reading another role (e.g. --primary)."
8671
+ },
8672
+ {
8673
+ "name": "--table-row-selected-background",
8674
+ "value": "hsl(var(--muted) / 0.3)",
8675
+ "description": "Row-state tint washes \u2014 translucent muted over the opaque base. Defaults equal * the prior literals; a service retints by reading another role (e.g. --primary)."
8619
8676
  }
8620
8677
  ];
8621
8678
 
@@ -12674,7 +12731,7 @@ ${c.example}
12674
12731
  // package.json
12675
12732
  var package_default = {
12676
12733
  name: "@godxjp/ui-mcp",
12677
- version: "14.0.1",
12734
+ version: "16.5.0",
12678
12735
  description: "Model Context Protocol server for @godxjp/ui \u2014 gives Claude Code / Codex CLI / Cursor / any MCP-aware agent live access to the component catalog, prop vocabulary, design tokens, 45 cardinal rules, copy-paste-ready patterns, 12 design / taste skills synthesised from Leonxlnx/taste-skill, 20+ anti-AI-tell patterns, and a 50-check redesign audit \u2014 token-efficient (list \u2192 drill-down).",
12679
12736
  type: "module",
12680
12737
  main: "./dist/index.js",