@godxjp/ui-mcp 0.19.1 → 0.21.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 +2 -2
- package/dist/index.js +411 -33
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
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",
|
|
@@ -729,10 +735,21 @@ function MyShell({ children }: { content: React.ReactNode }) {
|
|
|
729
735
|
description: "Render as Radix Slot \u2014 merge props onto the child (<a>/<Link>)."
|
|
730
736
|
},
|
|
731
737
|
{ name: "disabled", type: "boolean", description: "Disable the button." },
|
|
738
|
+
{
|
|
739
|
+
name: "loading",
|
|
740
|
+
type: "boolean",
|
|
741
|
+
defaultValue: "false",
|
|
742
|
+
description: 'In-flight state \u2014 shows a leading `Loader2` spinner (replaces a leading icon if present), sets `aria-busy="true"`, and blocks activation (non-interactive, pointer-events disabled) while keeping the label visible so the width doesn\'t jump. Prefer this over a hand-rolled `<Loader2 className="animate-spin">` inside the button. Ignored when `asChild` (Slot requires a single child).'
|
|
743
|
+
},
|
|
744
|
+
{
|
|
745
|
+
name: "loadingText",
|
|
746
|
+
type: "string",
|
|
747
|
+
description: "Optional label to swap in while `loading` (pass the `t()`-translated string, e.g. `loadingText={t('saving')}`). When omitted the original children stay beside the spinner."
|
|
748
|
+
},
|
|
732
749
|
{
|
|
733
750
|
name: "onClick",
|
|
734
751
|
type: "React.MouseEventHandler<HTMLButtonElement>",
|
|
735
|
-
description: "Click handler."
|
|
752
|
+
description: "Click handler. Does not fire while `loading` or `disabled`."
|
|
736
753
|
}
|
|
737
754
|
],
|
|
738
755
|
usage: [
|
|
@@ -741,7 +758,8 @@ function MyShell({ children }: { content: React.ReactNode }) {
|
|
|
741
758
|
"DO use `asChild` to render the button as a React Router/Inertia `<Link>` or native `<a>` while keeping all button styling and a11y: `<Button asChild variant=\"outline\"><Link href={route('invoices.show', id)}>\u8A73\u7D30</Link></Button>`. Never wrap a `<button>` around an `<a>` \u2014 that is invalid HTML.",
|
|
742
759
|
"DON'T use raw `<button>` elements anywhere in the UI \u2014 always use this `Button`. The only exception is an `aria-hidden` native control used as an e2e/a11y hook paired with a visible godx-ui control.",
|
|
743
760
|
'DO set `type="submit"` explicitly on form submit buttons (the default HTML button type inside `<form>` is already `submit`, but being explicit prevents accidental double-submissions when a `type="button"` sibling exists). For cancel/reset actions set `type="button"` to avoid accidental form submission.',
|
|
744
|
-
"DON'T apply raw padding, height, or `rounded-*` overrides to `Button` via `className` \u2014 the size variants encode the full box model. If a custom size is truly needed, use `buttonVariants` from `@godxjp/ui/general` to compose a new cva class rather than fighting the existing ones."
|
|
761
|
+
"DON'T apply raw padding, height, or `rounded-*` overrides to `Button` via `className` \u2014 the size variants encode the full box model. If a custom size is truly needed, use `buttonVariants` from `@godxjp/ui/general` to compose a new cva class rather than fighting the existing ones.",
|
|
762
|
+
"DO use the `loading` prop for async/pending actions instead of hand-rolling `<Loader2 className=\"animate-spin\">` inside the button \u2014 `loading` renders the spinner, sets `aria-busy`, and blocks activation for you; pair with `loadingText={t('saving')}` to swap the label. For a TanStack Query refetch use `ButtonRefetch` (it owns its own loading lifecycle) rather than wiring `loading` manually."
|
|
745
763
|
],
|
|
746
764
|
useCases: [
|
|
747
765
|
'Primary form submission in a Dialog or Sheet (e.g. `<Button type="submit" disabled={form.processing}>\u4FDD\u5B58</Button>`) \u2014 the `disabled` prop greys it out and blocks pointer events, preventing double-submit during async operations.',
|
|
@@ -768,6 +786,98 @@ import { Trash2 } from "lucide-react";
|
|
|
768
786
|
storyPath: "general/Button.stories.tsx",
|
|
769
787
|
rules: [23]
|
|
770
788
|
},
|
|
789
|
+
{
|
|
790
|
+
name: "Text",
|
|
791
|
+
group: "general",
|
|
792
|
+
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.',
|
|
793
|
+
props: [
|
|
794
|
+
{
|
|
795
|
+
name: "size",
|
|
796
|
+
type: '"2xs" | "xs" | "sm" | "md" | "lg" | "xl" | "2xl"',
|
|
797
|
+
defaultValue: '"sm"',
|
|
798
|
+
description: "Golden-ratio type-scale step (2xs\u20262xl). NEVER an arbitrary px (`text-[13px]` is banned) \u2014 pick the nearest step."
|
|
799
|
+
},
|
|
800
|
+
{
|
|
801
|
+
name: "tone",
|
|
802
|
+
type: '"default" | "muted" | "primary" | "success" | "warning" | "destructive" | "info"',
|
|
803
|
+
defaultValue: '"default"',
|
|
804
|
+
description: "Semantic foreground colour. Replaces `text-muted-foreground` etc. on a raw span."
|
|
805
|
+
},
|
|
806
|
+
{
|
|
807
|
+
name: "weight",
|
|
808
|
+
type: '"regular" | "medium" | "bold"',
|
|
809
|
+
defaultValue: '"regular"',
|
|
810
|
+
description: "Font weight \u2014 the 3-weight canon: regular 400 (body), medium 500 (label), bold 700 (emphasis). 600/semibold is forbidden."
|
|
811
|
+
},
|
|
812
|
+
{ name: "align", type: '"start" | "center" | "end"', description: "Logical text alignment." },
|
|
813
|
+
{ name: "truncate", type: "boolean", description: "Single-line ellipsis." },
|
|
814
|
+
{ name: "tabular", type: "boolean", description: "Tabular figures for aligned numbers." },
|
|
815
|
+
{ name: "mono", type: "boolean", description: "Monospace family for codes / ids." },
|
|
816
|
+
{
|
|
817
|
+
name: "as",
|
|
818
|
+
type: '"span" | "p" | "div" | "label" | "strong" | "em" | "small" | "code" | "kbd" | "dt" | "dd" | "caption" | "abbr"',
|
|
819
|
+
defaultValue: '"span"',
|
|
820
|
+
description: "Rendered element. `code`/`kbd` are monospace by default."
|
|
821
|
+
}
|
|
822
|
+
],
|
|
823
|
+
usage: [
|
|
824
|
+
"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.",
|
|
825
|
+
'DO use `tone` for colour (`muted`/`primary`/semantic), `tabular` for numbers, `mono` for codes \u2014 not `className="text-muted-foreground font-mono tabular-nums"`.',
|
|
826
|
+
"For a heading, use `<Heading level>` instead of a large-size `<Text>`."
|
|
827
|
+
],
|
|
828
|
+
useCases: [
|
|
829
|
+
'A muted caption under a value: `<Text size="xs" tone="muted">2026\u5E745\u6708\u5EA6</Text>`.',
|
|
830
|
+
'A monospace id in a list row: `<Text size="xs" mono tone="muted">RC-204881</Text>`.',
|
|
831
|
+
'An emphasized inline figure: `<Text weight="medium" tabular>\xA51,240,000</Text>`.'
|
|
832
|
+
],
|
|
833
|
+
storyPath: "general/typography.tsx",
|
|
834
|
+
rules: [2, 23],
|
|
835
|
+
example: `import { Text } from "@godxjp/ui/general";
|
|
836
|
+
|
|
837
|
+
<Text size="xs" tone="muted">\u88DC\u52A9\u30C6\u30AD\u30B9\u30C8</Text>
|
|
838
|
+
<Text weight="medium" tabular>\xA51,240,000</Text>
|
|
839
|
+
<Text size="xs" mono tone="muted">RC-204881</Text>`
|
|
840
|
+
},
|
|
841
|
+
{
|
|
842
|
+
name: "Heading",
|
|
843
|
+
group: "general",
|
|
844
|
+
tagline: "Section heading sized from the --heading-h* tokens. `level` sets the size AND the semantic <h1..h4>.",
|
|
845
|
+
props: [
|
|
846
|
+
{
|
|
847
|
+
name: "level",
|
|
848
|
+
type: "1 | 2 | 3 | 4",
|
|
849
|
+
defaultValue: "2",
|
|
850
|
+
description: "Heading level \u2014 sizes from --heading-h{1..4} and renders the matching <h*>."
|
|
851
|
+
},
|
|
852
|
+
{
|
|
853
|
+
name: "as",
|
|
854
|
+
type: '"h1" | "h2" | "h3" | "h4" | "div"',
|
|
855
|
+
description: "Override the rendered element (e.g. a visual h2 that is a real <h1>)."
|
|
856
|
+
},
|
|
857
|
+
{
|
|
858
|
+
name: "tone",
|
|
859
|
+
type: '"default" | "muted" | "primary" | "success" | "warning" | "destructive" | "info"',
|
|
860
|
+
defaultValue: '"default"',
|
|
861
|
+
description: "Semantic foreground colour."
|
|
862
|
+
},
|
|
863
|
+
{ name: "align", type: '"start" | "center" | "end"', description: "Logical text alignment." },
|
|
864
|
+
{ name: "truncate", type: "boolean", description: "Single-line ellipsis." }
|
|
865
|
+
],
|
|
866
|
+
usage: [
|
|
867
|
+
'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.',
|
|
868
|
+
"Inside a Card use `<CardTitle>`; use `<Heading>` for free-standing page/section headings not covered by a component slot."
|
|
869
|
+
],
|
|
870
|
+
useCases: [
|
|
871
|
+
"A section heading on a dashboard: `<Heading level={3}>\u4ECA\u6708\u306EKPI</Heading>`.",
|
|
872
|
+
'A visually-smaller heading that must stay an <h1> for a11y: `<Heading level={1} as="h1">\u2026</Heading>`.'
|
|
873
|
+
],
|
|
874
|
+
storyPath: "general/typography.tsx",
|
|
875
|
+
rules: [6, 23],
|
|
876
|
+
example: `import { Heading } from "@godxjp/ui/general";
|
|
877
|
+
|
|
878
|
+
<Heading level={2}>\u8ACB\u6C42\u66F8\u4E00\u89A7</Heading>
|
|
879
|
+
<Heading level={3} tone="muted">\u88DC\u8DB3\u30BB\u30AF\u30B7\u30E7\u30F3</Heading>`
|
|
880
|
+
},
|
|
771
881
|
// ─── data-display ───────────────────────────────────────────────────────
|
|
772
882
|
{
|
|
773
883
|
name: "DataTable",
|
|
@@ -1015,6 +1125,13 @@ export default function InvoiceList({
|
|
|
1015
1125
|
"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
1126
|
"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
1127
|
],
|
|
1128
|
+
useCases: [
|
|
1129
|
+
"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.)",
|
|
1130
|
+
"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.",
|
|
1131
|
+
"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.",
|
|
1132
|
+
"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.",
|
|
1133
|
+
"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."
|
|
1134
|
+
],
|
|
1018
1135
|
related: ["DataTable", "Table", "DataState", "Select", "DropdownMenu"],
|
|
1019
1136
|
example: `import { DataGrid, type ColumnDef } from "@godxjp/ui/data-grid";
|
|
1020
1137
|
import { Flex } from "@godxjp/ui/layout";
|
|
@@ -1225,14 +1342,25 @@ import { ResponsiveGrid } from "@godxjp/ui/layout";
|
|
|
1225
1342
|
props: [
|
|
1226
1343
|
{
|
|
1227
1344
|
name: "variant",
|
|
1228
|
-
type: '"default" | "secondary" | "outline" | "
|
|
1345
|
+
type: '"default" | "secondary" | "outline" | "dashed"',
|
|
1229
1346
|
defaultValue: '"default"',
|
|
1230
|
-
description: "
|
|
1347
|
+
description: "STRUCTURAL emphasis only (fill/border style) \u2014 NOT colour. Use `tone` for semantic colour. `dashed` = dashed border."
|
|
1348
|
+
},
|
|
1349
|
+
{
|
|
1350
|
+
name: "tone",
|
|
1351
|
+
type: '"default" | "success" | "warning" | "destructive" | "info" | "muted" | "neutral"',
|
|
1352
|
+
description: "SEMANTIC colour intent (ToneProp). This is the colour knob \u2014 success/warning/destructive/info/etc. Keep variant for structure, tone for meaning."
|
|
1353
|
+
},
|
|
1354
|
+
{
|
|
1355
|
+
name: "shape",
|
|
1356
|
+
type: '"default" | "pill" | "sharp"',
|
|
1357
|
+
defaultValue: '"default"',
|
|
1358
|
+
description: "Corner radius from the tokens \u2014 `default` (badge radius), `pill` (fully rounded), `sharp` (square). Use the prop instead of a `rounded-*` className."
|
|
1231
1359
|
},
|
|
1232
1360
|
{
|
|
1233
1361
|
name: "status",
|
|
1234
1362
|
type: "string",
|
|
1235
|
-
description: "Lifecycle key. Known keys auto-map to
|
|
1363
|
+
description: "Lifecycle key. Known keys auto-map to tone + icon + i18n label; unknown keys fall back to neutral."
|
|
1236
1364
|
},
|
|
1237
1365
|
{
|
|
1238
1366
|
name: "icon",
|
|
@@ -1801,6 +1929,119 @@ import { ResponsiveGrid } from "@godxjp/ui/layout";
|
|
|
1801
1929
|
storyPath: "data-entry/Input.stories.tsx",
|
|
1802
1930
|
rules: []
|
|
1803
1931
|
},
|
|
1932
|
+
{
|
|
1933
|
+
name: "NumberInput",
|
|
1934
|
+
group: "data-entry",
|
|
1935
|
+
tagline: "WAI-ARIA spinbutton for localized numeric entry \u2014 composes the real Input (role=spinbutton, inputMode=decimal) with stacked increment/decrement step Buttons. Type freely, Arrow/Shift-Arrow step, value commits clamped to min/max + rounded to precision.",
|
|
1936
|
+
props: [
|
|
1937
|
+
{
|
|
1938
|
+
name: "value",
|
|
1939
|
+
type: "number | null",
|
|
1940
|
+
description: "Controlled value. `null` = empty field. Pair with `onValueChange`."
|
|
1941
|
+
},
|
|
1942
|
+
{
|
|
1943
|
+
name: "defaultValue",
|
|
1944
|
+
type: "number | null",
|
|
1945
|
+
defaultValue: "null",
|
|
1946
|
+
description: "Uncontrolled initial value."
|
|
1947
|
+
},
|
|
1948
|
+
{
|
|
1949
|
+
name: "onValueChange",
|
|
1950
|
+
type: "(value: number | null) => void",
|
|
1951
|
+
description: "Value change callback (vocabulary triad \u2014 NOT onChange). Receives `null` when the field is empty."
|
|
1952
|
+
},
|
|
1953
|
+
{
|
|
1954
|
+
name: "min",
|
|
1955
|
+
type: "number",
|
|
1956
|
+
description: "Lower bound \u2014 clamps on commit and disables the decrement stepper at the floor."
|
|
1957
|
+
},
|
|
1958
|
+
{
|
|
1959
|
+
name: "max",
|
|
1960
|
+
type: "number",
|
|
1961
|
+
description: "Upper bound \u2014 clamps on commit and disables the increment stepper at the ceiling."
|
|
1962
|
+
},
|
|
1963
|
+
{
|
|
1964
|
+
name: "step",
|
|
1965
|
+
type: "number",
|
|
1966
|
+
defaultValue: "1",
|
|
1967
|
+
description: "Increment for the steppers + ArrowUp/ArrowDown (Shift = \xD710)."
|
|
1968
|
+
},
|
|
1969
|
+
{
|
|
1970
|
+
name: "precision",
|
|
1971
|
+
type: "number",
|
|
1972
|
+
description: "Committed decimal places. Inferred from `step` when omitted."
|
|
1973
|
+
},
|
|
1974
|
+
{ name: "disabled", type: "boolean", description: "Disables typing and stepping." },
|
|
1975
|
+
{
|
|
1976
|
+
name: "readOnly",
|
|
1977
|
+
type: "boolean",
|
|
1978
|
+
description: "Value is shown and selectable but not typeable or steppable."
|
|
1979
|
+
},
|
|
1980
|
+
{
|
|
1981
|
+
name: "size",
|
|
1982
|
+
type: '"xs" | "sm" | "md" | "lg"',
|
|
1983
|
+
defaultValue: '"md"',
|
|
1984
|
+
description: "Control height tier (--control-height). Aligns with sibling controls on a row."
|
|
1985
|
+
},
|
|
1986
|
+
{ name: "placeholder", type: "string", description: "Placeholder shown when empty." },
|
|
1987
|
+
{
|
|
1988
|
+
name: "prefix",
|
|
1989
|
+
type: "React.ReactNode",
|
|
1990
|
+
description: "Leading decorative affix inside the field (e.g. `\xA5`). aria-hidden."
|
|
1991
|
+
},
|
|
1992
|
+
{
|
|
1993
|
+
name: "suffix",
|
|
1994
|
+
type: "React.ReactNode",
|
|
1995
|
+
description: "Trailing decorative affix inside the field (e.g. `%`). aria-hidden."
|
|
1996
|
+
},
|
|
1997
|
+
{
|
|
1998
|
+
name: "name",
|
|
1999
|
+
type: "string",
|
|
2000
|
+
description: "Form field name \u2014 submits its value natively."
|
|
2001
|
+
},
|
|
2002
|
+
{ name: "id", type: "string", description: "Associates with a <label htmlFor> / FormField." },
|
|
2003
|
+
{
|
|
2004
|
+
name: "aria-label",
|
|
2005
|
+
type: "string",
|
|
2006
|
+
description: "Accessible name for the spinbutton when no visible FormField label is present."
|
|
2007
|
+
}
|
|
2008
|
+
],
|
|
2009
|
+
usage: [
|
|
2010
|
+
"DO use NumberInput (not `<Input type='number'>`) whenever numeric entry wants steppers, min/max clamping, precision rounding, or a \xA5/% affix \u2014 it is the canonical numeric primitive. Plain Input has no stepper and no clamp.",
|
|
2011
|
+
"DO drive it controlled with `value` + `onValueChange` carrying `number | null` (the vocabulary triad \u2014 NOT `onChange`). `null` means the field is empty; never substitute 0 for empty.",
|
|
2012
|
+
"DON'T pass `value` without `onValueChange` \u2014 like every controlled @godxjp/ui input it would freeze. Omit both for uncontrolled (use `defaultValue`).",
|
|
2013
|
+
"DO set `step` to your increment and let `precision` (or the decimals of `step`) round the committed value: `step={0.25} precision={2}` gives quarter-step entry rounded to 2 places on blur/Enter.",
|
|
2014
|
+
"DO set `min`/`max` for bounded quantities \u2014 the value clamps on commit and the matching stepper Button auto-disables at the bound. The steppers are tabIndex=-1 so they never pollute the keyboard tab order (Arrow keys cover keyboard stepping).",
|
|
2015
|
+
"DON'T wrap it in a hand-rolled label/error markup \u2014 compose it inside FormField (matching `id`) for the aria wiring, exactly like Input.",
|
|
2016
|
+
"DON'T format the value yourself for display \u2014 NumberInput formats at rest via Intl.NumberFormat in the active locale while keeping the raw value typeable on focus."
|
|
2017
|
+
],
|
|
2018
|
+
useCases: [
|
|
2019
|
+
"Quantity / line-item steppers in order, invoice, or cart forms (min={1}, step={1}) where \xB1 buttons and a floor are expected.",
|
|
2020
|
+
"Price / amount fields with a currency affix (prefix='\xA5', step={10}) \u2014 the affix is decorative and the committed value stays a plain number.",
|
|
2021
|
+
"Percentage / rate inputs bounded 0\u2013100 (suffix='%', min={0} max={100}).",
|
|
2022
|
+
"Decimal measurements \u2014 weight, dimensions, exchange rates (step={0.25}, precision={2}) needing rounded commit.",
|
|
2023
|
+
"Any bounded numeric setting (timeouts, retry counts, page sizes) where a slider is too coarse and a free Input lacks clamping."
|
|
2024
|
+
],
|
|
2025
|
+
related: [
|
|
2026
|
+
"Input \u2014 the plain single-line field NumberInput composes; use Input directly only for free numeric text with no stepper/clamp need.",
|
|
2027
|
+
"Slider \u2014 use instead when the user picks an approximate value within a range by dragging; NumberInput is for exact keyed entry.",
|
|
2028
|
+
"FormField \u2014 compose NumberInput inside FormField (matching id) for label/helper/error a11y wiring.",
|
|
2029
|
+
"TimeInput \u2014 the HH:mm sibling spinbutton; NumberInput is for plain numbers, TimeInput for clock times."
|
|
2030
|
+
],
|
|
2031
|
+
storyPath: "data-entry/NumberInput.stories.tsx",
|
|
2032
|
+
rules: [3, 6],
|
|
2033
|
+
example: `import { NumberInput } from "@godxjp/ui/data-entry";
|
|
2034
|
+
|
|
2035
|
+
<NumberInput
|
|
2036
|
+
value={qty}
|
|
2037
|
+
onValueChange={setQty}
|
|
2038
|
+
min={1}
|
|
2039
|
+
max={99}
|
|
2040
|
+
step={1}
|
|
2041
|
+
prefix="\xA5"
|
|
2042
|
+
aria-label="\u6570\u91CF"
|
|
2043
|
+
/>`
|
|
2044
|
+
},
|
|
1804
2045
|
{
|
|
1805
2046
|
name: "SearchInput",
|
|
1806
2047
|
group: "data-entry",
|
|
@@ -3316,7 +3557,7 @@ export function InvoicePeriodFilter() {
|
|
|
3316
3557
|
description: "Initial value for uncontrolled mode. Same shape as value."
|
|
3317
3558
|
},
|
|
3318
3559
|
{
|
|
3319
|
-
name: "
|
|
3560
|
+
name: "onValueChange",
|
|
3320
3561
|
type: "(value: string[] | string[][], selectedOptions?: TreeOptionProp[] | TreeOptionProp[][]) => void",
|
|
3321
3562
|
description: "Fires when selection changes. First arg is the selected path(s); second is the matching node objects. On clear, called with []."
|
|
3322
3563
|
},
|
|
@@ -3500,7 +3741,7 @@ function MultiRegionPicker() {
|
|
|
3500
3741
|
description: "Initial value for uncontrolled usage. Ignored once `value` is provided."
|
|
3501
3742
|
},
|
|
3502
3743
|
{
|
|
3503
|
-
name: "
|
|
3744
|
+
name: "onValueChange",
|
|
3504
3745
|
type: "(value: string | string[] | undefined) => void",
|
|
3505
3746
|
description: "Called on selection change. Returns `string` in single mode, `string[]` in multi/checkable mode, or `undefined` when cleared."
|
|
3506
3747
|
},
|
|
@@ -6024,18 +6265,35 @@ export default function PasswordBlock() {
|
|
|
6024
6265
|
group: "navigation",
|
|
6025
6266
|
tagline: "Context menu primitives with keyboard support and compound parts for command-style action surfaces.",
|
|
6026
6267
|
props: [
|
|
6027
|
-
{ name: "open", type: "boolean", description: "Controlled open state." },
|
|
6028
6268
|
{
|
|
6029
6269
|
name: "onOpenChange",
|
|
6030
6270
|
type: "(open: boolean) => void",
|
|
6031
6271
|
description: "Open-state callback."
|
|
6032
6272
|
},
|
|
6033
|
-
{
|
|
6273
|
+
{
|
|
6274
|
+
name: "modal",
|
|
6275
|
+
type: "boolean",
|
|
6276
|
+
defaultValue: "true",
|
|
6277
|
+
description: "Modal mode \u2014 locks scroll + outside interaction while open. Set false to keep the rest of the page interactive."
|
|
6278
|
+
},
|
|
6279
|
+
{
|
|
6280
|
+
name: "dir",
|
|
6281
|
+
type: '"ltr" | "rtl"',
|
|
6282
|
+
description: "Reading direction for arrow-key navigation (inherits from the document if omitted)."
|
|
6283
|
+
}
|
|
6284
|
+
],
|
|
6285
|
+
usage: [
|
|
6286
|
+
"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.",
|
|
6287
|
+
"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.",
|
|
6288
|
+
"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.",
|
|
6289
|
+
'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.',
|
|
6290
|
+
"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
6291
|
],
|
|
6035
6292
|
useCases: [
|
|
6036
|
-
"Right-click action
|
|
6037
|
-
"Contextual
|
|
6038
|
-
"Nested action
|
|
6293
|
+
"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.",
|
|
6294
|
+
"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).",
|
|
6295
|
+
"Nested action menu with submenus and shortcuts (e.g. '\u30A8\u30AF\u30B9\u30DD\u30FC\u30C8 \u25B8 CSV / PDF') on a report card.",
|
|
6296
|
+
"Stateful toggles on a board/kanban card via ContextMenuCheckboxItem (e.g. \u30D4\u30F3\u7559\u3081, \u5B8C\u4E86\u3068\u3057\u3066\u30DE\u30FC\u30AF)."
|
|
6039
6297
|
],
|
|
6040
6298
|
storyPath: "navigation/ContextMenu.stories.tsx",
|
|
6041
6299
|
rules: [3, 6],
|
|
@@ -6059,21 +6317,34 @@ export default function PasswordBlock() {
|
|
|
6059
6317
|
group: "navigation",
|
|
6060
6318
|
tagline: "Application menubar primitives (menus, sub-menus, and check/radio items).",
|
|
6061
6319
|
props: [
|
|
6320
|
+
{
|
|
6321
|
+
name: "value",
|
|
6322
|
+
type: "string",
|
|
6323
|
+
description: "Controlled value of the currently-open menu (pair with onValueChange)."
|
|
6324
|
+
},
|
|
6062
6325
|
{
|
|
6063
6326
|
name: "defaultValue",
|
|
6064
6327
|
type: "string",
|
|
6065
|
-
description: "Uncontrolled initial
|
|
6328
|
+
description: "Uncontrolled initial open menu."
|
|
6066
6329
|
},
|
|
6067
6330
|
{
|
|
6068
6331
|
name: "onValueChange",
|
|
6069
6332
|
type: "(value: string) => void",
|
|
6070
|
-
description: "
|
|
6333
|
+
description: "Fires with the id of the menu that opened (or '' when all close)."
|
|
6071
6334
|
}
|
|
6072
6335
|
],
|
|
6336
|
+
usage: [
|
|
6337
|
+
"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.",
|
|
6338
|
+
"DON'T use Menubar for primary site/page navigation (links between pages) \u2014 that is `NavigationMenu`. Menubar items run *commands*; NavigationMenu items *navigate*.",
|
|
6339
|
+
"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.",
|
|
6340
|
+
"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.",
|
|
6341
|
+
'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.'
|
|
6342
|
+
],
|
|
6073
6343
|
useCases: [
|
|
6074
|
-
"Top-bar
|
|
6075
|
-
"Workspace menus
|
|
6076
|
-
"Desktop-like
|
|
6344
|
+
"Top-bar command menu for a back-office editor (\u30D5\u30A1\u30A4\u30EB / \u7DE8\u96C6 / \u8868\u793A / \u30D8\u30EB\u30D7) with shortcuts and submenus.",
|
|
6345
|
+
"Workspace tool menus in an admin console where each menu groups a category of actions (\u30C7\u30FC\u30BF / \u30EC\u30DD\u30FC\u30C8 / \u8A2D\u5B9A).",
|
|
6346
|
+
"Desktop-like application shell (e.g. an internal POS or accounting workstation) that mirrors native menubar conventions.",
|
|
6347
|
+
"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
6348
|
],
|
|
6078
6349
|
storyPath: "navigation/Menubar.stories.tsx",
|
|
6079
6350
|
rules: [3, 6],
|
|
@@ -6099,18 +6370,41 @@ export default function PasswordBlock() {
|
|
|
6099
6370
|
defaultValue: '"horizontal"',
|
|
6100
6371
|
description: "Main-axis arrangement for the nav menu."
|
|
6101
6372
|
},
|
|
6373
|
+
{
|
|
6374
|
+
name: "value",
|
|
6375
|
+
type: "string",
|
|
6376
|
+
description: "Controlled value of the currently-open item (pair with onValueChange)."
|
|
6377
|
+
},
|
|
6102
6378
|
{
|
|
6103
6379
|
name: "defaultValue",
|
|
6104
6380
|
type: "string",
|
|
6105
|
-
description: "Uncontrolled initial
|
|
6381
|
+
description: "Uncontrolled initial open item."
|
|
6106
6382
|
},
|
|
6107
6383
|
{
|
|
6108
6384
|
name: "onValueChange",
|
|
6109
6385
|
type: "(value: string) => void",
|
|
6110
|
-
description: "
|
|
6386
|
+
description: "Fires with the id of the item whose dropdown opened (or '' when all close)."
|
|
6387
|
+
},
|
|
6388
|
+
{
|
|
6389
|
+
name: "delayDuration",
|
|
6390
|
+
type: "number",
|
|
6391
|
+
defaultValue: "200",
|
|
6392
|
+
description: "Hover delay (ms) before a trigger's content opens."
|
|
6111
6393
|
}
|
|
6112
6394
|
],
|
|
6113
|
-
|
|
6395
|
+
usage: [
|
|
6396
|
+
"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`.",
|
|
6397
|
+
"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.",
|
|
6398
|
+
"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.",
|
|
6399
|
+
"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.",
|
|
6400
|
+
"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."
|
|
6401
|
+
],
|
|
6402
|
+
useCases: [
|
|
6403
|
+
"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).",
|
|
6404
|
+
"Sectioned marketing or docs navigation with featured link cards inside NavigationMenuContent.",
|
|
6405
|
+
"Nested link groups where one trigger reveals a multi-column panel of related destinations.",
|
|
6406
|
+
"Vertical in-content navigation (orientation='vertical') for a settings or documentation area \u2014 distinct from the global Sidebar shell."
|
|
6407
|
+
],
|
|
6114
6408
|
storyPath: "navigation/NavigationMenu.stories.tsx",
|
|
6115
6409
|
rules: [3, 6],
|
|
6116
6410
|
example: `import { NavigationMenu, NavigationMenuList, NavigationMenuItem, NavigationMenuTrigger } from "@godxjp/ui/navigation";
|
|
@@ -6128,12 +6422,53 @@ export default function PasswordBlock() {
|
|
|
6128
6422
|
group: "layout",
|
|
6129
6423
|
tagline: "Resizable panel group/child/handle primitives from react-resizable-panels.",
|
|
6130
6424
|
props: [
|
|
6131
|
-
{
|
|
6132
|
-
|
|
6133
|
-
|
|
6134
|
-
|
|
6425
|
+
{
|
|
6426
|
+
name: "orientation",
|
|
6427
|
+
type: '"horizontal" | "vertical"',
|
|
6428
|
+
defaultValue: '"horizontal"',
|
|
6429
|
+
description: "ResizablePanelGroup prop \u2014 axis the panels are laid out / resized along (horizontal = side-by-side)."
|
|
6430
|
+
},
|
|
6431
|
+
{
|
|
6432
|
+
name: "id",
|
|
6433
|
+
type: "string",
|
|
6434
|
+
description: "ResizablePanel identifier \u2014 required for collapse/expand control and for layout persistence."
|
|
6435
|
+
},
|
|
6436
|
+
{
|
|
6437
|
+
name: "defaultSize",
|
|
6438
|
+
type: "number",
|
|
6439
|
+
description: "ResizablePanel initial size as a percentage (0\u2013100) of the group."
|
|
6440
|
+
},
|
|
6441
|
+
{
|
|
6442
|
+
name: "minSize",
|
|
6443
|
+
type: "number",
|
|
6444
|
+
description: "ResizablePanel minimum size (%) \u2014 drag can't shrink below this."
|
|
6445
|
+
},
|
|
6446
|
+
{ name: "maxSize", type: "number", description: "ResizablePanel maximum size (%)." },
|
|
6447
|
+
{
|
|
6448
|
+
name: "collapsible",
|
|
6449
|
+
type: "boolean",
|
|
6450
|
+
defaultValue: "false",
|
|
6451
|
+
description: "ResizablePanel \u2014 allow the panel to collapse to collapsedSize when dragged below minSize. Pair with onResize to react to collapse."
|
|
6452
|
+
},
|
|
6453
|
+
{
|
|
6454
|
+
name: "onResize",
|
|
6455
|
+
type: "(size: PanelSize, id, prevSize) => void",
|
|
6456
|
+
description: "ResizablePanel \u2014 fires while/after the panel is resized (e.g. to persist layout)."
|
|
6457
|
+
}
|
|
6458
|
+
],
|
|
6459
|
+
usage: [
|
|
6460
|
+
'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.',
|
|
6461
|
+
"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.",
|
|
6462
|
+
"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.",
|
|
6463
|
+
"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`.",
|
|
6464
|
+
"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>`."
|
|
6465
|
+
],
|
|
6466
|
+
useCases: [
|
|
6467
|
+
"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).",
|
|
6468
|
+
"Collapsible filters or navigation rail beside a data table that operators can widen for long labels or tuck away to maximize the table.",
|
|
6469
|
+
"Stacked vertical split (orientation='vertical') such as a results table over a live JSON/log preview in a data-import tool.",
|
|
6470
|
+
"Three-pane workbench (nav | content | inspector) where each boundary is independently draggable and layout is persisted via id + onResize."
|
|
6135
6471
|
],
|
|
6136
|
-
useCases: ["Split-pane layouts", "Resizable sidebars", "Code editors with adjustable zones"],
|
|
6137
6472
|
storyPath: "layout/ResizablePanel.stories.tsx",
|
|
6138
6473
|
rules: [3, 6],
|
|
6139
6474
|
example: `import { ResizablePanelGroup, ResizablePanel, ResizableHandle } from "@godxjp/ui/layout";
|
|
@@ -6162,10 +6497,23 @@ export default function PasswordBlock() {
|
|
|
6162
6497
|
{
|
|
6163
6498
|
name: "setApi",
|
|
6164
6499
|
type: "(api: CarouselApi) => void",
|
|
6165
|
-
description: "Receive
|
|
6500
|
+
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
6501
|
}
|
|
6167
6502
|
],
|
|
6168
|
-
|
|
6503
|
+
usage: [
|
|
6504
|
+
"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.",
|
|
6505
|
+
"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.",
|
|
6506
|
+
"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`.",
|
|
6507
|
+
"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.",
|
|
6508
|
+
"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.",
|
|
6509
|
+
"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)."
|
|
6510
|
+
],
|
|
6511
|
+
useCases: [
|
|
6512
|
+
"Feature / onboarding highlight cards on a dashboard or landing surface, with CarouselDots showing position.",
|
|
6513
|
+
"Image or document thumbnail gallery (e.g. uploaded receipts / \u7269\u4EF6\u5199\u771F) with looping and prev/next arrows.",
|
|
6514
|
+
"Horizontal stepping list of compact KPI or announcement cards that overflow the viewport width.",
|
|
6515
|
+
"Product/plan comparison cards on a marketing page where swiping between a few options is acceptable (not the primary action)."
|
|
6516
|
+
],
|
|
6169
6517
|
storyPath: "data-display/Carousel.stories.tsx",
|
|
6170
6518
|
rules: [3, 6],
|
|
6171
6519
|
example: `import { Carousel, CarouselContent, CarouselItem, CarouselPrevious, CarouselNext, CarouselDots } from "@godxjp/ui/data-display";
|
|
@@ -6197,10 +6545,28 @@ export default function PasswordBlock() {
|
|
|
6197
6545
|
type: "(value: string) => void",
|
|
6198
6546
|
description: "Validated value callback."
|
|
6199
6547
|
},
|
|
6200
|
-
{
|
|
6548
|
+
{
|
|
6549
|
+
name: "step",
|
|
6550
|
+
type: "number",
|
|
6551
|
+
defaultValue: "1",
|
|
6552
|
+
description: "Minute step (clamped 1\u201359). Snaps the committed minute to the nearest lower multiple and sets the ArrowUp/ArrowDown increment."
|
|
6553
|
+
},
|
|
6201
6554
|
{ name: "name", type: "string", description: "Form field name." }
|
|
6202
6555
|
],
|
|
6203
|
-
|
|
6556
|
+
usage: [
|
|
6557
|
+
"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`.",
|
|
6558
|
+
"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.",
|
|
6559
|
+
"DON'T pass `value` without `onValueChange` \u2014 like every controlled @godxjp/ui input that freezes the field. Omit both for uncontrolled (use `defaultValue`).",
|
|
6560
|
+
"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).",
|
|
6561
|
+
"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.",
|
|
6562
|
+
"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."
|
|
6563
|
+
],
|
|
6564
|
+
useCases: [
|
|
6565
|
+
"\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.",
|
|
6566
|
+
"Business-hours / reservation slot editor where times snap to a 15- or 30-minute grid (step={15}).",
|
|
6567
|
+
"A from\u2013to time range filter on a report or log screen (two TimeInputs) with no date component.",
|
|
6568
|
+
"Any calendar-free HH:mm-only form field (e.g. a recurring daily batch time, a \u7DE0\u3081\u6642\u523B)."
|
|
6569
|
+
],
|
|
6204
6570
|
storyPath: "data-entry/TimeInput.stories.tsx",
|
|
6205
6571
|
rules: [3, 6],
|
|
6206
6572
|
example: `import { TimeInput } from "@godxjp/ui/data-entry";
|
|
@@ -6671,6 +7037,11 @@ var CARDINAL_RULES = [
|
|
|
6671
7037
|
number: 41,
|
|
6672
7038
|
title: "Drawer & dialog footer layout",
|
|
6673
7039
|
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.'
|
|
7040
|
+
},
|
|
7041
|
+
{
|
|
7042
|
+
number: 42,
|
|
7043
|
+
title: "Props & Tokens Before Customization",
|
|
7044
|
+
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
7045
|
}
|
|
6675
7046
|
];
|
|
6676
7047
|
function findRule(num) {
|
|
@@ -9633,7 +10004,10 @@ function lintJsx(jsx) {
|
|
|
9633
10004
|
check(/<input[\s>]/, "Use `<Input>` instead of raw `<input>` (rule 29).");
|
|
9634
10005
|
check(/<select[\s>]/, "Use `<Select>` instead of raw `<select>` (rule 29).");
|
|
9635
10006
|
check(/<textarea[\s>]/, "Use `<Textarea>` instead of raw `<textarea>` (rule 29).");
|
|
9636
|
-
check(
|
|
10007
|
+
check(
|
|
10008
|
+
/<(table|thead|tbody)[\s>]/,
|
|
10009
|
+
"Use `<DataTable>` instead of a hand-rolled `<table>` (rule 29)."
|
|
10010
|
+
);
|
|
9637
10011
|
check(
|
|
9638
10012
|
/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
10013
|
"Use semantic token utilities (`bg-primary`/`bg-destructive`) not raw color scales (rule 2)."
|
|
@@ -9646,6 +10020,10 @@ function lintJsx(jsx) {
|
|
|
9646
10020
|
/size=["']default["']/,
|
|
9647
10021
|
'`size="default"` is not in the controlled vocabulary \u2014 use `size` \u2208 xs|sm|md|lg.'
|
|
9648
10022
|
);
|
|
10023
|
+
check(
|
|
10024
|
+
/\btext-\[[0-9.]+px\]/,
|
|
10025
|
+
"Arbitrary text size `text-[Npx]` bypasses the golden type scale \u2014 use `<Text size>` / `<Heading level>` (rule 42)."
|
|
10026
|
+
);
|
|
9649
10027
|
check(
|
|
9650
10028
|
/<Tag[\s\S]*?color=["']error["']/i,
|
|
9651
10029
|
'Tag `color="error"` \u2192 `"destructive"` (v5.0, PR #60).'
|
|
@@ -9844,7 +10222,7 @@ ${c.example}
|
|
|
9844
10222
|
// package.json
|
|
9845
10223
|
var package_default = {
|
|
9846
10224
|
name: "@godxjp/ui-mcp",
|
|
9847
|
-
version: "0.
|
|
10225
|
+
version: "0.21.0",
|
|
9848
10226
|
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
10227
|
type: "module",
|
|
9850
10228
|
main: "./dist/index.js",
|