@godxjp/ui-mcp 0.19.1 → 0.20.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/README.md CHANGED
@@ -7,7 +7,7 @@ MCP-aware agent live access to:
7
7
  - 80+ component catalog (props, types, defaults, examples)
8
8
  - 14 shared prop-vocabulary types (`SizeProp`, `ColorProp`, `LoadingProp`, …)
9
9
  - 48 design tokens across the primitive / semantic / component tiers
10
- - 41 cardinal rules from `CLAUDE.md`
10
+ - 42 cardinal rules from `CLAUDE.md`
11
11
  - 9 canonical copy-paste-ready patterns (sign-up, settings, data-table, …)
12
12
  - 15 design skills, each tagged by **audience** — 12 taste-family (taste / soft / minimalist /
13
13
  brutalist / gpt-tasteskill / redesign / output / brandkit / stitch / imagegen-mobile /
@@ -270,7 +270,7 @@ consumer/core guides are framework-native.
270
270
  | `godx-ui://prop-vocabulary` | JSON | Shared vocab |
271
271
  | `godx-ui://tokens` | JSON | All tokens |
272
272
  | `godx-ui://tokens/{category}` | JSON | Tokens by category |
273
- | `godx-ui://rules` | Markdown | All 41 rules |
273
+ | `godx-ui://rules` | Markdown | All 42 rules |
274
274
  | `godx-ui://rules/{number}` | Markdown | One rule |
275
275
  | `godx-ui://patterns` | JSON | Pattern index |
276
276
  | `godx-ui://patterns/{name}` | Markdown | One pattern |
package/dist/index.js CHANGED
@@ -712,9 +712,9 @@ function MyShell({ children }: { content: React.ReactNode }) {
712
712
  props: [
713
713
  {
714
714
  name: "variant",
715
- type: '"default" | "destructive" | "outline" | "secondary" | "ghost" | "link"',
715
+ type: '"default" | "destructive" | "outline" | "dashed" | "secondary" | "ghost" | "link"',
716
716
  defaultValue: '"default"',
717
- description: "Visual style."
717
+ description: "Visual style. `dashed` = outline with a dashed border (Ant-style add-row / placeholder action)."
718
718
  },
719
719
  {
720
720
  name: "size",
@@ -722,6 +722,12 @@ function MyShell({ children }: { content: React.ReactNode }) {
722
722
  defaultValue: '"default"',
723
723
  description: "Size preset (height, padding, icon dims)."
724
724
  },
725
+ {
726
+ name: "shape",
727
+ type: '"default" | "pill" | "sharp"',
728
+ defaultValue: '"default"',
729
+ description: "Corner radius from the tokens \u2014 `default` (control radius), `pill` (fully rounded, --radius-pill), `sharp` (square, --radius-sharp). Use the prop instead of a `rounded-*` className."
730
+ },
725
731
  {
726
732
  name: "asChild",
727
733
  type: "boolean",
@@ -768,6 +774,98 @@ import { Trash2 } from "lucide-react";
768
774
  storyPath: "general/Button.stories.tsx",
769
775
  rules: [23]
770
776
  },
777
+ {
778
+ name: "Text",
779
+ group: "general",
780
+ tagline: 'Typographic primitive \u2014 use INSTEAD of a hand-rolled `<span className="text-[13px] font-medium text-muted-foreground">`. Size is a type-scale step (never px); tone/weight are tokens.',
781
+ props: [
782
+ {
783
+ name: "size",
784
+ type: '"2xs" | "xs" | "sm" | "md" | "lg" | "xl"',
785
+ defaultValue: '"sm"',
786
+ description: "Golden-ratio type-scale step. NEVER an arbitrary px (`text-[13px]` is banned) \u2014 pick the nearest step."
787
+ },
788
+ {
789
+ name: "tone",
790
+ type: '"default" | "muted" | "primary" | "success" | "warning" | "destructive" | "info"',
791
+ defaultValue: '"default"',
792
+ description: "Semantic foreground colour. Replaces `text-muted-foreground` etc. on a raw span."
793
+ },
794
+ {
795
+ name: "weight",
796
+ type: '"regular" | "medium" | "semibold"',
797
+ defaultValue: '"regular"',
798
+ description: "Font weight (system 2-weight 400/500; semibold resolves to the 500 token)."
799
+ },
800
+ { name: "align", type: '"start" | "center" | "end"', description: "Logical text alignment." },
801
+ { name: "truncate", type: "boolean", description: "Single-line ellipsis." },
802
+ { name: "tabular", type: "boolean", description: "Tabular figures for aligned numbers." },
803
+ { name: "mono", type: "boolean", description: "Monospace family for codes / ids." },
804
+ {
805
+ name: "as",
806
+ type: '"span" | "p" | "div" | "label" | "strong" | "em" | "small"',
807
+ defaultValue: '"span"',
808
+ description: "Rendered element."
809
+ }
810
+ ],
811
+ usage: [
812
+ "DO use `<Text>` for ALL body / inline / caption text instead of a styled `<span>`/`<p>`. Pick `size` from the scale; never write `text-[13px]`/`text-[11px]` or `font-semibold` by hand.",
813
+ 'DO use `tone` for colour (`muted`/`primary`/semantic), `tabular` for numbers, `mono` for codes \u2014 not `className="text-muted-foreground font-mono tabular-nums"`.',
814
+ "For a heading, use `<Heading level>` instead of a large-size `<Text>`."
815
+ ],
816
+ useCases: [
817
+ 'A muted caption under a value: `<Text size="xs" tone="muted">2026\u5E745\u6708\u5EA6</Text>`.',
818
+ 'A monospace id in a list row: `<Text size="xs" mono tone="muted">RC-204881</Text>`.',
819
+ 'An emphasized inline figure: `<Text weight="medium" tabular>\xA51,240,000</Text>`.'
820
+ ],
821
+ storyPath: "general/typography.tsx",
822
+ rules: [2, 23],
823
+ example: `import { Text } from "@godxjp/ui/general";
824
+
825
+ <Text size="xs" tone="muted">\u88DC\u52A9\u30C6\u30AD\u30B9\u30C8</Text>
826
+ <Text weight="medium" tabular>\xA51,240,000</Text>
827
+ <Text size="xs" mono tone="muted">RC-204881</Text>`
828
+ },
829
+ {
830
+ name: "Heading",
831
+ group: "general",
832
+ tagline: "Section heading sized from the --heading-h* tokens. `level` sets the size AND the semantic <h1..h4>.",
833
+ props: [
834
+ {
835
+ name: "level",
836
+ type: "1 | 2 | 3 | 4",
837
+ defaultValue: "2",
838
+ description: "Heading level \u2014 sizes from --heading-h{1..4} and renders the matching <h*>."
839
+ },
840
+ {
841
+ name: "as",
842
+ type: '"h1" | "h2" | "h3" | "h4" | "div"',
843
+ description: "Override the rendered element (e.g. a visual h2 that is a real <h1>)."
844
+ },
845
+ {
846
+ name: "tone",
847
+ type: '"default" | "muted" | "primary" | "success" | "warning" | "destructive" | "info"',
848
+ defaultValue: '"default"',
849
+ description: "Semantic foreground colour."
850
+ },
851
+ { name: "align", type: '"start" | "center" | "end"', description: "Logical text alignment." },
852
+ { name: "truncate", type: "boolean", description: "Single-line ellipsis." }
853
+ ],
854
+ usage: [
855
+ 'DO use `<Heading level>` for section titles instead of a raw `<h2 className="text-lg font-semibold">`. The level drives both the token size and the semantic element.',
856
+ "Inside a Card use `<CardTitle>`; use `<Heading>` for free-standing page/section headings not covered by a component slot."
857
+ ],
858
+ useCases: [
859
+ "A section heading on a dashboard: `<Heading level={3}>\u4ECA\u6708\u306EKPI</Heading>`.",
860
+ 'A visually-smaller heading that must stay an <h1> for a11y: `<Heading level={1} as="h1">\u2026</Heading>`.'
861
+ ],
862
+ storyPath: "general/typography.tsx",
863
+ rules: [6, 23],
864
+ example: `import { Heading } from "@godxjp/ui/general";
865
+
866
+ <Heading level={2}>\u8ACB\u6C42\u66F8\u4E00\u89A7</Heading>
867
+ <Heading level={3} tone="muted">\u88DC\u8DB3\u30BB\u30AF\u30B7\u30E7\u30F3</Heading>`
868
+ },
771
869
  // ─── data-display ───────────────────────────────────────────────────────
772
870
  {
773
871
  name: "DataTable",
@@ -1015,6 +1113,13 @@ export default function InvoiceList({
1015
1113
  "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=[...]>.",
1016
1114
  "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."
1017
1115
  ],
1116
+ useCases: [
1117
+ "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.)",
1118
+ "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.",
1119
+ "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.",
1120
+ "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.",
1121
+ "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."
1122
+ ],
1018
1123
  related: ["DataTable", "Table", "DataState", "Select", "DropdownMenu"],
1019
1124
  example: `import { DataGrid, type ColumnDef } from "@godxjp/ui/data-grid";
1020
1125
  import { Flex } from "@godxjp/ui/layout";
@@ -1225,14 +1330,25 @@ import { ResponsiveGrid } from "@godxjp/ui/layout";
1225
1330
  props: [
1226
1331
  {
1227
1332
  name: "variant",
1228
- type: '"default" | "secondary" | "outline" | "success" | "warning" | "destructive" | "info" | "neutral"',
1333
+ type: '"default" | "secondary" | "outline" | "dashed"',
1229
1334
  defaultValue: '"default"',
1230
- description: "Visual variant. Overrides the auto-mapped status tone when status is provided."
1335
+ description: "STRUCTURAL emphasis only (fill/border style) \u2014 NOT colour. Use `tone` for semantic colour. `dashed` = dashed border."
1336
+ },
1337
+ {
1338
+ name: "tone",
1339
+ type: '"default" | "success" | "warning" | "destructive" | "info" | "muted" | "neutral"',
1340
+ description: "SEMANTIC colour intent (ToneProp). This is the colour knob \u2014 success/warning/destructive/info/etc. Keep variant for structure, tone for meaning."
1341
+ },
1342
+ {
1343
+ name: "shape",
1344
+ type: '"default" | "pill" | "sharp"',
1345
+ defaultValue: '"default"',
1346
+ description: "Corner radius from the tokens \u2014 `default` (badge radius), `pill` (fully rounded), `sharp` (square). Use the prop instead of a `rounded-*` className."
1231
1347
  },
1232
1348
  {
1233
1349
  name: "status",
1234
1350
  type: "string",
1235
- description: "Lifecycle key. Known keys auto-map to variant + icon + i18n label; unknown keys fall back to neutral."
1351
+ description: "Lifecycle key. Known keys auto-map to tone + icon + i18n label; unknown keys fall back to neutral."
1236
1352
  },
1237
1353
  {
1238
1354
  name: "icon",
@@ -3316,7 +3432,7 @@ export function InvoicePeriodFilter() {
3316
3432
  description: "Initial value for uncontrolled mode. Same shape as value."
3317
3433
  },
3318
3434
  {
3319
- name: "onChange",
3435
+ name: "onValueChange",
3320
3436
  type: "(value: string[] | string[][], selectedOptions?: TreeOptionProp[] | TreeOptionProp[][]) => void",
3321
3437
  description: "Fires when selection changes. First arg is the selected path(s); second is the matching node objects. On clear, called with []."
3322
3438
  },
@@ -3500,7 +3616,7 @@ function MultiRegionPicker() {
3500
3616
  description: "Initial value for uncontrolled usage. Ignored once `value` is provided."
3501
3617
  },
3502
3618
  {
3503
- name: "onChange",
3619
+ name: "onValueChange",
3504
3620
  type: "(value: string | string[] | undefined) => void",
3505
3621
  description: "Called on selection change. Returns `string` in single mode, `string[]` in multi/checkable mode, or `undefined` when cleared."
3506
3622
  },
@@ -6024,18 +6140,35 @@ export default function PasswordBlock() {
6024
6140
  group: "navigation",
6025
6141
  tagline: "Context menu primitives with keyboard support and compound parts for command-style action surfaces.",
6026
6142
  props: [
6027
- { name: "open", type: "boolean", description: "Controlled open state." },
6028
6143
  {
6029
6144
  name: "onOpenChange",
6030
6145
  type: "(open: boolean) => void",
6031
6146
  description: "Open-state callback."
6032
6147
  },
6033
- { name: "value", type: "string", description: "Selected value (for controlled patterns)." }
6148
+ {
6149
+ name: "modal",
6150
+ type: "boolean",
6151
+ defaultValue: "true",
6152
+ description: "Modal mode \u2014 locks scroll + outside interaction while open. Set false to keep the rest of the page interactive."
6153
+ },
6154
+ {
6155
+ name: "dir",
6156
+ type: '"ltr" | "rtl"',
6157
+ description: "Reading direction for arrow-key navigation (inherits from the document if omitted)."
6158
+ }
6159
+ ],
6160
+ usage: [
6161
+ "DO trigger this on `onContextMenu` (right-click / long-press), NOT on left-click \u2014 for a button that opens a list of actions on left-click use `DropdownMenu` instead. The two are not interchangeable.",
6162
+ "DO wrap exactly the right-clickable surface in `<ContextMenuTrigger>` (a table row, a card, a file tile) \u2014 the menu anchors to the pointer position, so the trigger should be the whole interactive region the menu acts on.",
6163
+ "DON'T put primary, always-visible actions only behind a context menu \u2014 right-click is a discoverability dead-end on touch and for new users. Mirror critical actions in a visible `Button`/`DropdownMenu` and use ContextMenu as an accelerator.",
6164
+ 'DO mark irreversible items with `variant="destructive"` (\u524A\u9664 / \u53D6\u308A\u6D88\u3057) and group them under a `<ContextMenuSeparator>`; use `<ContextMenuShortcut>` to show the keyboard accelerator, `<ContextMenuSub>`/`<ContextMenuSubTrigger>` for nested submenus, and `<ContextMenuCheckboxItem>`/`<ContextMenuRadioItem>` for stateful toggles.',
6165
+ "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."
6034
6166
  ],
6035
6167
  useCases: [
6036
- "Right-click action menu",
6037
- "Contextual menus for rows and cards",
6038
- "Nested action rows with shortcuts"
6168
+ "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.",
6169
+ "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).",
6170
+ "Nested action menu with submenus and shortcuts (e.g. '\u30A8\u30AF\u30B9\u30DD\u30FC\u30C8 \u25B8 CSV / PDF') on a report card.",
6171
+ "Stateful toggles on a board/kanban card via ContextMenuCheckboxItem (e.g. \u30D4\u30F3\u7559\u3081, \u5B8C\u4E86\u3068\u3057\u3066\u30DE\u30FC\u30AF)."
6039
6172
  ],
6040
6173
  storyPath: "navigation/ContextMenu.stories.tsx",
6041
6174
  rules: [3, 6],
@@ -6059,21 +6192,34 @@ export default function PasswordBlock() {
6059
6192
  group: "navigation",
6060
6193
  tagline: "Application menubar primitives (menus, sub-menus, and check/radio items).",
6061
6194
  props: [
6195
+ {
6196
+ name: "value",
6197
+ type: "string",
6198
+ description: "Controlled value of the currently-open menu (pair with onValueChange)."
6199
+ },
6062
6200
  {
6063
6201
  name: "defaultValue",
6064
6202
  type: "string",
6065
- description: "Uncontrolled initial selected value."
6203
+ description: "Uncontrolled initial open menu."
6066
6204
  },
6067
6205
  {
6068
6206
  name: "onValueChange",
6069
6207
  type: "(value: string) => void",
6070
- description: "Selection callback."
6208
+ description: "Fires with the id of the menu that opened (or '' when all close)."
6071
6209
  }
6072
6210
  ],
6211
+ usage: [
6212
+ "DO reserve Menubar for a persistent, desktop-app-style command bar (\u30D5\u30A1\u30A4\u30EB / \u7DE8\u96C6 / \u8868\u793A \u2026) where multiple top-level menus sit side by side \u2014 moving the pointer across triggers opens the adjacent menu without an extra click.",
6213
+ "DON'T use Menubar for primary site/page navigation (links between pages) \u2014 that is `NavigationMenu`. Menubar items run *commands*; NavigationMenu items *navigate*.",
6214
+ "DON'T use Menubar when there is only one menu button \u2014 a single trigger that drops a list of actions is a `DropdownMenu`. Menubar earns its weight only with several coordinated menus.",
6215
+ "DO compose the full structure: `<Menubar>` \u203A `<MenubarMenu>` \u203A `<MenubarTrigger>` + `<MenubarContent>` with `<MenubarItem>`; use `<MenubarSeparator>` to group, `<MenubarShortcut>` for accelerators, `<MenubarSub>` for nested menus, and `<MenubarCheckboxItem>`/`<MenubarRadioItem>` for view toggles.",
6216
+ 'DO mark destructive commands with `variant="destructive"` and give every item an `onSelect` handler \u2014 items are commands, so they should *do* something, not just close.'
6217
+ ],
6073
6218
  useCases: [
6074
- "Top-bar application command menus",
6075
- "Workspace menus with nested items",
6076
- "Desktop-like navigation shells"
6219
+ "Top-bar command menu for a back-office editor (\u30D5\u30A1\u30A4\u30EB / \u7DE8\u96C6 / \u8868\u793A / \u30D8\u30EB\u30D7) with shortcuts and submenus.",
6220
+ "Workspace tool menus in an admin console where each menu groups a category of actions (\u30C7\u30FC\u30BF / \u30EC\u30DD\u30FC\u30C8 / \u8A2D\u5B9A).",
6221
+ "Desktop-like application shell (e.g. an internal POS or accounting workstation) that mirrors native menubar conventions.",
6222
+ "View-state toggles via MenubarCheckboxItem/MenubarRadioItem (e.g. \u8868\u793A \u203A \u30B0\u30EA\u30C3\u30C9\u7DDA\u3092\u8868\u793A, \u901A\u8CA8\u8868\u793A \u25B8 \xA5 / $)."
6077
6223
  ],
6078
6224
  storyPath: "navigation/Menubar.stories.tsx",
6079
6225
  rules: [3, 6],
@@ -6099,18 +6245,41 @@ export default function PasswordBlock() {
6099
6245
  defaultValue: '"horizontal"',
6100
6246
  description: "Main-axis arrangement for the nav menu."
6101
6247
  },
6248
+ {
6249
+ name: "value",
6250
+ type: "string",
6251
+ description: "Controlled value of the currently-open item (pair with onValueChange)."
6252
+ },
6102
6253
  {
6103
6254
  name: "defaultValue",
6104
6255
  type: "string",
6105
- description: "Uncontrolled initial selected value."
6256
+ description: "Uncontrolled initial open item."
6106
6257
  },
6107
6258
  {
6108
6259
  name: "onValueChange",
6109
6260
  type: "(value: string) => void",
6110
- description: "Selection callback."
6261
+ description: "Fires with the id of the item whose dropdown opened (or '' when all close)."
6262
+ },
6263
+ {
6264
+ name: "delayDuration",
6265
+ type: "number",
6266
+ defaultValue: "200",
6267
+ description: "Hover delay (ms) before a trigger's content opens."
6111
6268
  }
6112
6269
  ],
6113
- useCases: ["Primary app navigation", "Sectioned marketing navigation", "Nested link groups"],
6270
+ usage: [
6271
+ "DO use NavigationMenu for primary *navigation* between pages/sections \u2014 items wrap `<NavigationMenuLink>` (an `<a>`), not command buttons. For command bars (\u30D5\u30A1\u30A4\u30EB/\u7DE8\u96C6 \u2026) use `Menubar`; for a single action drop-down use `DropdownMenu`.",
6272
+ "DO render real links inside `<NavigationMenuLink asChild>` so SPA routers work: `<NavigationMenuLink asChild><Link href={route('reports.index')}>\u30EC\u30DD\u30FC\u30C8</Link></NavigationMenuLink>` \u2014 never nest a raw `<a>` directly with its own onClick navigation.",
6273
+ "DO use `<NavigationMenuTrigger>` + `<NavigationMenuContent>` only when an item needs a rich dropdown panel (link groups, featured cards). Top-level items that go straight to a page should be a bare `<NavigationMenuLink>` with NO trigger.",
6274
+ "DON'T use it as the app's left sidebar \u2014 for a persistent vertical app sidebar use `Sidebar`/`AppShell`. Set `orientation=\"vertical\"` only for an in-content vertical link menu, not the global shell.",
6275
+ "DON'T hand-roll the hover/focus dropdown timing \u2014 the primitive manages open-on-hover with `delayDuration`, keyboard navigation, and the animated viewport for you."
6276
+ ],
6277
+ useCases: [
6278
+ "Primary top navigation for an admin/portal app with dropdown panels grouping related pages (e.g. \u30EC\u30DD\u30FC\u30C8 \u25BE \u2192 \u58F2\u4E0A / \u7D4C\u8CBB / \u5165\u91D1).",
6279
+ "Sectioned marketing or docs navigation with featured link cards inside NavigationMenuContent.",
6280
+ "Nested link groups where one trigger reveals a multi-column panel of related destinations.",
6281
+ "Vertical in-content navigation (orientation='vertical') for a settings or documentation area \u2014 distinct from the global Sidebar shell."
6282
+ ],
6114
6283
  storyPath: "navigation/NavigationMenu.stories.tsx",
6115
6284
  rules: [3, 6],
6116
6285
  example: `import { NavigationMenu, NavigationMenuList, NavigationMenuItem, NavigationMenuTrigger } from "@godxjp/ui/navigation";
@@ -6128,12 +6297,53 @@ export default function PasswordBlock() {
6128
6297
  group: "layout",
6129
6298
  tagline: "Resizable panel group/child/handle primitives from react-resizable-panels.",
6130
6299
  props: [
6131
- { name: "id", type: "string", description: "Panel identifier for persistence." },
6132
- { name: "defaultSize", type: "number", description: "Initial panel size (percent/units)." },
6133
- { name: "minSize", type: "number", description: "Minimum size constraint." },
6134
- { name: "maxSize", type: "number", description: "Maximum size constraint." }
6300
+ {
6301
+ name: "orientation",
6302
+ type: '"horizontal" | "vertical"',
6303
+ defaultValue: '"horizontal"',
6304
+ description: "ResizablePanelGroup prop \u2014 axis the panels are laid out / resized along (horizontal = side-by-side)."
6305
+ },
6306
+ {
6307
+ name: "id",
6308
+ type: "string",
6309
+ description: "ResizablePanel identifier \u2014 required for collapse/expand control and for layout persistence."
6310
+ },
6311
+ {
6312
+ name: "defaultSize",
6313
+ type: "number",
6314
+ description: "ResizablePanel initial size as a percentage (0\u2013100) of the group."
6315
+ },
6316
+ {
6317
+ name: "minSize",
6318
+ type: "number",
6319
+ description: "ResizablePanel minimum size (%) \u2014 drag can't shrink below this."
6320
+ },
6321
+ { name: "maxSize", type: "number", description: "ResizablePanel maximum size (%)." },
6322
+ {
6323
+ name: "collapsible",
6324
+ type: "boolean",
6325
+ defaultValue: "false",
6326
+ description: "ResizablePanel \u2014 allow the panel to collapse to collapsedSize when dragged below minSize. Pair with onResize to react to collapse."
6327
+ },
6328
+ {
6329
+ name: "onResize",
6330
+ type: "(size: PanelSize, id, prevSize) => void",
6331
+ description: "ResizablePanel \u2014 fires while/after the panel is resized (e.g. to persist layout)."
6332
+ }
6333
+ ],
6334
+ usage: [
6335
+ '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.',
6336
+ "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.",
6337
+ "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.",
6338
+ "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`.",
6339
+ "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>`."
6340
+ ],
6341
+ useCases: [
6342
+ "Master\u2013detail admin layout: a draggable list pane on the left and a detail/preview pane on the right (e.g. \u4ED5\u8A33\u4E00\u89A7 | \u4ED5\u8A33\u8A73\u7D30).",
6343
+ "Collapsible filters or navigation rail beside a data table that operators can widen for long labels or tuck away to maximize the table.",
6344
+ "Stacked vertical split (orientation='vertical') such as a results table over a live JSON/log preview in a data-import tool.",
6345
+ "Three-pane workbench (nav | content | inspector) where each boundary is independently draggable and layout is persisted via id + onResize."
6135
6346
  ],
6136
- useCases: ["Split-pane layouts", "Resizable sidebars", "Code editors with adjustable zones"],
6137
6347
  storyPath: "layout/ResizablePanel.stories.tsx",
6138
6348
  rules: [3, 6],
6139
6349
  example: `import { ResizablePanelGroup, ResizablePanel, ResizableHandle } from "@godxjp/ui/layout";
@@ -6162,10 +6372,23 @@ export default function PasswordBlock() {
6162
6372
  {
6163
6373
  name: "setApi",
6164
6374
  type: "(api: CarouselApi) => void",
6165
- description: "Receive carousel API for custom logic."
6375
+ description: "Receive the Embla api for custom logic (autoplay, external prev/next). NOT needed for dots \u2014 CarouselDots reads the api from context itself."
6166
6376
  }
6167
6377
  ],
6168
- useCases: ["Feature cards", "Image galleries", "Horizontal stepping lists"],
6378
+ usage: [
6379
+ "DO compose the full set: `<Carousel>` \u203A `<CarouselContent>` \u203A many `<CarouselItem>`, with `<CarouselPrevious>`/`<CarouselNext>` for arrows and `<CarouselDots>` for the indicator row. Don't render items outside `<CarouselContent>` \u2014 the track is the scroll container.",
6380
+ "DO use `<CarouselDots>` for the active-slide indicator instead of wiring `setApi` by hand \u2014 it reads `selectedIndex`/`scrollSnaps` from the Carousel context, renders one `aria-current` dot per snap, and auto-hides when there is \u22641 slide.",
6381
+ "DON'T use a Carousel where ALL items must be seen/compared at once or be keyboard-reachable in reading order (e.g. a list of selectable options, a data table, primary navigation) \u2014 hiding content behind a swipe is an anti-pattern there; use a Grid/`ResponsiveGrid`, `ScrollArea`, or `Tabs`.",
6382
+ "DON'T autoplay without a pause-on-hover/focus control and reduced-motion respect \u2014 pass the Embla autoplay plugin via `plugins` only for non-essential decorative content, never for content the user must read.",
6383
+ "DO set `opts={{ loop: true }}` for galleries that wrap, and rely on the built-in disabling: `CarouselPrevious`/`CarouselNext` auto-disable at the ends (via `canScrollPrev`/`canScrollNext`) \u2014 don't hide them, let them grey out.",
6384
+ "DO give each `<CarouselItem>` real, meaningful content; the component already injects an 'N of M' slide label for screen readers, so don't add a redundant one (a consumer `aria-label` on the item overrides the default)."
6385
+ ],
6386
+ useCases: [
6387
+ "Feature / onboarding highlight cards on a dashboard or landing surface, with CarouselDots showing position.",
6388
+ "Image or document thumbnail gallery (e.g. uploaded receipts / \u7269\u4EF6\u5199\u771F) with looping and prev/next arrows.",
6389
+ "Horizontal stepping list of compact KPI or announcement cards that overflow the viewport width.",
6390
+ "Product/plan comparison cards on a marketing page where swiping between a few options is acceptable (not the primary action)."
6391
+ ],
6169
6392
  storyPath: "data-display/Carousel.stories.tsx",
6170
6393
  rules: [3, 6],
6171
6394
  example: `import { Carousel, CarouselContent, CarouselItem, CarouselPrevious, CarouselNext, CarouselDots } from "@godxjp/ui/data-display";
@@ -6197,10 +6420,28 @@ export default function PasswordBlock() {
6197
6420
  type: "(value: string) => void",
6198
6421
  description: "Validated value callback."
6199
6422
  },
6200
- { name: "step", type: "number", defaultValue: "1", description: "Minute step." },
6423
+ {
6424
+ name: "step",
6425
+ type: "number",
6426
+ defaultValue: "1",
6427
+ description: "Minute step (clamped 1\u201359). Snaps the committed minute to the nearest lower multiple and sets the ArrowUp/ArrowDown increment."
6428
+ },
6201
6429
  { name: "name", type: "string", description: "Form field name." }
6202
6430
  ],
6203
- useCases: ["Time filters", "Schedule pickers (calendar-free)", "HH:mm-only forms"],
6431
+ usage: [
6432
+ "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`.",
6433
+ "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.",
6434
+ "DON'T pass `value` without `onValueChange` \u2014 like every controlled @godxjp/ui input that freezes the field. Omit both for uncontrolled (use `defaultValue`).",
6435
+ "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).",
6436
+ "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.",
6437
+ "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."
6438
+ ],
6439
+ useCases: [
6440
+ "\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.",
6441
+ "Business-hours / reservation slot editor where times snap to a 15- or 30-minute grid (step={15}).",
6442
+ "A from\u2013to time range filter on a report or log screen (two TimeInputs) with no date component.",
6443
+ "Any calendar-free HH:mm-only form field (e.g. a recurring daily batch time, a \u7DE0\u3081\u6642\u523B)."
6444
+ ],
6204
6445
  storyPath: "data-entry/TimeInput.stories.tsx",
6205
6446
  rules: [3, 6],
6206
6447
  example: `import { TimeInput } from "@godxjp/ui/data-entry";
@@ -6671,6 +6912,11 @@ var CARDINAL_RULES = [
6671
6912
  number: 41,
6672
6913
  title: "Drawer & dialog footer layout",
6673
6914
  body: 'Sheet/Dialog/AlertDialog footers are a pinned action bar (Ant Design Drawer footer): the footer sticks to the bottom, SheetFooter draws a full-bleed top border, and actions are RIGHT-aligned with the PRIMARY button rightmost (Cancel/secondary to its left). A destructive / clear / reset action goes far-LEFT \u2014 give that button `className="mr-auto"`. NEVER stack footer buttons full-width or center them.'
6915
+ },
6916
+ {
6917
+ number: 42,
6918
+ title: "Props & Tokens Before Customization",
6919
+ body: "Before reaching for a Tailwind class, inline `style`, or extra CSS, you MUST first check whether the component already supports the need via a PROP, a design TOKEN, or a layout/typography PRIMITIVE. godx-ui is meant to be enough on its own (Ant-Design-style): `className` is for genuine one-offs only \u2014 never to redo what an API already does. Specifically: (1) NEVER hand-roll typography \u2014 no `text-[13px]`/`text-[11px]` arbitrary px (bypasses the golden type scale), no `font-medium`/`font-semibold`/`text-muted-foreground` on a raw `<span>`; use `<Text size tone weight tabular mono>` / `<Heading level>`. (2) NEVER hand-roll a trivial flex/grid wrapper; use `<Flex>` / `<ResponsiveGrid>` / `<PageContainer>`. (3) NEVER set a control's radius/height/colour with a utility when a `shape`/`size`/`tone`/token exists. If a real need has NO prop/token/primitive, that is a library GAP \u2014 file it (draft_bug_report), don't paper over it with ad-hoc Tailwind."
6674
6920
  }
6675
6921
  ];
6676
6922
  function findRule(num) {
@@ -9633,7 +9879,10 @@ function lintJsx(jsx) {
9633
9879
  check(/<input[\s>]/, "Use `<Input>` instead of raw `<input>` (rule 29).");
9634
9880
  check(/<select[\s>]/, "Use `<Select>` instead of raw `<select>` (rule 29).");
9635
9881
  check(/<textarea[\s>]/, "Use `<Textarea>` instead of raw `<textarea>` (rule 29).");
9636
- check(/<(table|thead|tbody)[\s>]/, "Use `<DataTable>` instead of a hand-rolled `<table>` (rule 29).");
9882
+ check(
9883
+ /<(table|thead|tbody)[\s>]/,
9884
+ "Use `<DataTable>` instead of a hand-rolled `<table>` (rule 29)."
9885
+ );
9637
9886
  check(
9638
9887
  /bg-(red|blue|green|yellow|gray|slate|zinc|neutral|stone|orange|amber|lime|emerald|teal|cyan|sky|indigo|violet|purple|fuchsia|pink|rose)-\d{2,3}\b/,
9639
9888
  "Use semantic token utilities (`bg-primary`/`bg-destructive`) not raw color scales (rule 2)."
@@ -9646,6 +9895,10 @@ function lintJsx(jsx) {
9646
9895
  /size=["']default["']/,
9647
9896
  '`size="default"` is not in the controlled vocabulary \u2014 use `size` \u2208 xs|sm|md|lg.'
9648
9897
  );
9898
+ check(
9899
+ /\btext-\[[0-9.]+px\]/,
9900
+ "Arbitrary text size `text-[Npx]` bypasses the golden type scale \u2014 use `<Text size>` / `<Heading level>` (rule 42)."
9901
+ );
9649
9902
  check(
9650
9903
  /<Tag[\s\S]*?color=["']error["']/i,
9651
9904
  'Tag `color="error"` \u2192 `"destructive"` (v5.0, PR #60).'
@@ -9844,7 +10097,7 @@ ${c.example}
9844
10097
  // package.json
9845
10098
  var package_default = {
9846
10099
  name: "@godxjp/ui-mcp",
9847
- version: "0.19.1",
10100
+ version: "0.20.0",
9848
10101
  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, 34 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).",
9849
10102
  type: "module",
9850
10103
  main: "./dist/index.js",