@godxjp/ui-mcp 33.18.0 → 33.19.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.
Files changed (2) hide show
  1. package/dist/index.js +5 -5
  2. package/package.json +2 -2
package/dist/index.js CHANGED
@@ -47,7 +47,7 @@ import { Button } from "@godxjp/ui/general";
47
47
  }
48
48
  >
49
49
  {body}
50
- </PageContainer>`,docPath:"docs/layout/page-cover.tsx",storyPath:"layout/page-cover.tsx",rules:[]},{name:"Flex",absorbed:["SpaceCompact"],group:"layout",tagline:"Token-spaced flex primitive with explicit direction, alignment, justification, and wrapping controls \u2014 and, with `attached`, a row of controls welded into ONE visual unit (antd Space.Compact).",props:[{name:"attached",type:"boolean",defaultValue:"false",description:'Weld the children into one control \u2014 antd Space.Compact (v32 folded `SpaceCompact` in here). Each child gets its own flex-item wrapper, inner corner radii are zeroed and the shared border collapses to one hairline; each child keeps its own focus ring, name and `size`. `direction` picks the axis ("row" default, "col"); `gap`/`wrap`/`pad` and the other layout knobs do not apply (a seam has no gap). Named (aria-label/-labelledby, e.g. by a wrapping FormField) it becomes role="group".'},{name:"fullWidth",type:"boolean",defaultValue:"false",description:"`attached` only. The joined row fills its parent's inline size (antd `block`, renamed to match Button.fullWidth). Field children grow to fill it; a Button keeps its content width (gh#1062)."},{name:"density",type:'"compact" | "default" | "comfortable"',description:"`attached` only. Scoped control density for the whole joined row (antd Space.Compact `size`). Each child still carries its OWN `size` prop."},{name:"reveal",type:'"hover"',description:"Floating child actions shown on parent hover/focus-within; always visible on touch."},{name:"bleed",type:"GapProp",description:"Negative inline inset on the token scale."},{name:"surface",type:'"muted" | "popover" | "warning"',description:"Lightweight surface, without Card structure."},{name:"shrink",type:"boolean",description:"false prevents shrinking."},{name:"grow",type:"boolean",description:"Grow into remaining flex space."},{name:"as",type:'"div" | "span" | "ul" | "ol" | "li"',description:'Semantic element. A list keeps its marker and indentation unless marker="none" says otherwise.'},{name:"marker",type:'"disc" | "decimal" | "none"',defaultValue:'as="ul" \u2192 "disc", as="ol" \u2192 "decimal"',description:'Marker for a LIST element; ignored by every other tag. marker="none" emits NO data-list, so the list keeps its <ul>/<ol>, its <li> semantics and its gap token, and loses the bullet AND the --space-5 indent \u2014 that is the container a short entity list needs: <Flex as="ul" marker="none" direction="col" gap="none"> with <ListRow as="li"> rows. Before it, the bullet was unconditional and .ui-flex[data-list] > li { display: list-item } outranked [data-slot="list-row"] { display: flex }, so rows fell out of flex layout (94.58px tall instead of 69.98px) and the only move left was a raw <ul>, which carries no gap token (gh#714). disc/decimal stay available so an <ol> can be bulleted, or a <ul> numbered, without a list-style-type in a className.'},{name:"direction",type:'"row" | "col" | {base?: "row" | "col"; sm?: "row" | "col"; md?: "row" | "col"; lg?: "row" | "col"; xl?: "row" | "col"}',description:"Responsive axis; omitted steps inherit."},{name:"gap",type:'"none" | "xs" | "sm" | "md" | "lg" | "xl"',defaultValue:'"md"',description:'Token gap between children, shared with other layout primitives. "none" is a DELIBERATE zero for two lines that read as one block \u2014 a name over its role, a weekday over its date, a tab bar with no seam \u2014 not a way to opt out of the token scale.'},{name:"gapRaw",type:"number",description:"ESCAPE HATCH: a gap in pixels, off every step of the scale. Real designs land on 2px, 5px, 6px, 10px, 14px \u2014 rounding to the nearest named step drifts the layout, and writing the literal in a className is blocked by ui-audit. Spend the ten named steps FIRST: `gap={3}` is 12px and follows the user's --scaling, gapRaw does not. It wins over `gap` (which then emits no class, so the two cannot fight over specificity) and leaves data-gap-raw on the DOM, so every escape stays countable."},{name:"pad",type:"number | { inline?, block?, inlineStart?, inlineEnd?, blockStart?, blockEnd? }",description:'Inner padding on the token scale \u2014 one step for all four sides, or an object keyed by LOGICAL side. Exists because a missing padding prop produced 42 of 51 ui-audit errors in one real consumer (gh#408): `<Flex className="p-3">` was the only move left.'},{name:"padRaw",type:"number | { inline?, block?, inlineStart?, inlineEnd?, blockStart?, blockEnd? }",description:"Raw-pixel padding for values off the scale, same contract and same price as gapRaw: it leaves data-pad-raw on the DOM so each escape is countable. Overrides `pad` PER SIDE, not as a whole."},{name:"fill",type:"boolean",defaultValue:"false",description:'Take the space the siblings leave \u2014 the ELASTIC column of a `fixed | elastic | fixed` row (name \xB7 meter \xB7 figures). Also sets min-inline-size: 0, which is what lets a truncating child ellipse instead of pushing the row wider. Without this axis the only move was className="flex-1 min-w-0", which ui-audit blocks (gh#405 \xA72).'},{name:"width",type:"number | string",description:"A FIXED column: number = px, string = any CSS length. Comes with flex: none \u2014 a width a sibling can still squeeze is a suggestion, and stacked rows would start at different x offsets. Leaves data-width-raw on the DOM so the measurement stays countable, like gapRaw/padRaw."},{name:"measure",type:'"narrow" | "medium" | "wide"',description:'CENTRE this box and CAP it at a page measure (--page-measure-narrow 42rem / -medium 48rem / -wide 72rem): margin-inline:auto + inline-size:100% + max-inline-size. THE public answer to "full-bleed outside, measured column inside" \u2014 a marketing <section> paints edge to edge and its inner Flex measure="wide" holds the content on the page measure. Deliberately NOT on PageContainer: that owns page padding and a header/toolbar/footer scaffold, so a full-bleed page cannot consume it, and the refusal left the centred column owned by nobody \u2014 three showcases each hand-wrote the same four declarations (gh#839). It adds NO gutter: the page inset is pad={{ inline: 6 }}, and one band with two padding owners drifts. A MAX, so nothing binds below the cap at 390px. An explicit `width` wins. Do not give a READING column "wide" \u2014 prose stays narrow/medium, which bracket Bringhurst\'s 45-75 characters. Omitted emits no attribute at all.'},{name:"align",type:'"start" | "center" | "end" | "stretch" | "baseline"',description:"Cross-axis alignment, emitted as a data attribute for the layout CSS."},{name:"justify",type:'"start" | "center" | "end" | "between" | "around" | "evenly"',description:"Main-axis distribution, emitted as a data attribute for the layout CSS."},{name:"wrap",type:"boolean",defaultValue:"false",description:"Allows children to wrap onto additional flex lines."},{name:"hideBelow",type:'"sm" | "md" | "lg" | "xl"',description:'Drop this region below a canonical breakpoint step (sm 40rem, md 48rem, lg 64rem, xl 80rem). THE public way to make a region responsive without a page-local media query \u2014 a public header hides its anchor navigation with hideBelow="md". Omitted by default, so no attribute is emitted and no rule matches. display:none also removes it from the a11y tree, so keep its destinations reachable elsewhere (a footer nav) at that width.'},{name:"hideFrom",type:'"sm" | "md" | "lg" | "xl"',description:"Inverse of hideBelow \u2014 drop the region FROM that step upwards, i.e. keep it only on the narrow side (a compact-only affordance)."},{name:"hideBelowRaw",type:"number",description:"ESCAPE HATCH: the same drop, at a width in PIXELS off every step of the scale \u2014 the gapRaw/padRaw contract on the breakpoint axis (gh#528). An off-scale breakpoint is a LOCAL EXCEPTION, not a new tier: sm/md/lg/xl are shared with collapseBelow and --master-detail-collapse-below, so two regions asked to fold at the same step really do fold together, while a raw width folds one region only. Spend the four steps first; reach here when the canonical design specifies a width the scale has not got (a nav that becomes a hamburger at 900px). It leaves data-hide-below-raw on the DOM so every escape stays countable, and prints one deduped media rule per distinct width (a media query cannot read a var()). It wins over hideBelow, which then emits nothing."},{name:"hideFromRaw",type:"number",description:"Inverse of hideBelowRaw, same contract and same price (data-hide-from-raw). THE SEAM: hideBelowRaw hides while width < N and hideFromRaw hides while width >= N \u2014 the same comparisons as the token steps, so the pair is exact complements and at exactly N the hideBelowRaw region is the visible one. Never hand-roll this with an inclusive max-width: `<= N` paired with `>= N` hides BOTH at exactly N, the 1px hole a consumer measured on a hand-rolled max-[900px]: pair."}],usage:['DO import from `@godxjp/ui/layout` and reach for Flex when the axis, alignment, justification, or wrap behavior is part of the component contract: `import { Flex } from "@godxjp/ui/layout"`.',"DO keep spacing on the `gap` prop instead of raw `gap-*`, `space-*`, or padding utilities. Flex uses the same token scale as other layout primitives, so spacing remains tied to the design system.",'DO use `direction="row"` with `wrap` for responsive control rows, chip clusters, and action groups that need more control than simple row composition.','DO use `direction="col"` for vertical groupings that need explicit `align` or `justify` behavior. For pure vertical stacking without alignment control, `direction="col"` is sufficient.',"DON'T override the axis with `className` after choosing a direction prop. Keep the layout intent in props so catalog guidance and data attributes stay accurate.",'FULL-BLEED BAND: a marketing/landing section is a `<section>` carrying the edge-to-edge paint (background, border, halo) around ONE `<Flex direction="col" measure="wide" pad={{ inline: 6, block: 20 }}>`. The measure centres and caps the column, `pad` owns the gutter and the band rhythm (`block: 20` = 80px, `block: 24` = 96px \u2014 the two band steps). Never a page-local `max-width: 1200px` + `margin-inline: auto` class, and never an inline style saying the same thing: that four-declaration idiom is what this prop replaced (gh#839).','Flex is a plain div with React.HTMLAttributes<HTMLDivElement>; pass `id`, `role`, `aria-*`, `data-*`, and structural className values as needed, but do not use it as a semantic form or button wrapper. When the parent only accepts phrasing content \u2014 a TabsTrigger, PopoverTrigger or Button, all of which render a <button> \u2014 pass `as="span"` rather than reaching for a raw `<span className="flex \u2026">`.','SEMANTIC LIST: a list of rows is `<Flex as="ul" marker="none" direction="col" gap="none">` with `<ListRow as="li">` children \u2014 never a raw `<ul>` (no gap token), never `<div role="list">` + `<div role="listitem">` (ARIA re-describing markup HTML already has), and never a wrapper around each row: the divider is `:not(:last-child)` among SIBLINGS, so a row alone in its own wrapper loses it silently. `ui-audit` flags all three as `no-hand-rolled-list`.',"NAMED FLEX = GROUP: a role-less div may not carry a naming attribute (axe aria-allowed-attr), so a Flex given `aria-label`/`aria-labelledby` \u2014 e.g. by FormField wrapping a composite range/\u5E74\u6708 field \u2014 automatically renders `role='group'`, folds `aria-errormessage` into `aria-describedby`, and drops the widget-only `aria-required`/`aria-invalid`. Passing an explicit `role` opts out of all of this and the caller owns the attribute set.",'ATTACHED: DO reach for it when two or more controls must read as ONE field \u2014 a number + a unit ("\u6BCE [2] [\u9031 \u25BE] \u3054\u3068"), a currency Select welded to an amount Input, a search field with an attached filter Select. `ResponsiveGrid columns={2}` puts them in separate cells (which collapses to ONE column on a narrow form card); `Flex attached` keeps them fused on one line regardless of the grid.','ATTACHED: ONE label for the pair vs per-control: wrap the WHOLE `Flex attached` in a single `FormField label="\u2026"` when the pair reads as one field ("\u7E70\u308A\u8FD4\u3057\u9593\u9694" over a number+unit row) \u2014 a role-less `<div>` cannot carry a cloned `aria-label`/`aria-labelledby` (axe `aria-allowed-attr`), so a NAMED `Flex attached` with no explicit `role` promotes itself to `role="group"` automatically, the same contract `Flex` already honours for a range/\u5E74\u6708 pair. Give each CHILD its own `aria-label` instead only when the two controls are independently meaningful outside the row (rare \u2014 prefer the one-label pattern for a welded control).',"ATTACHED: DON'T reach for `className=\"rounded-none\"` / `[&>*:not(:first-child)]` utilities to join controls yourself \u2014 `ui-audit`'s `no-utility-layout` rule blocks exactly that, and it is precisely the corner-radius seam this component owns.","ATTACHED: DO set `size` on each CHILD individually, not on `Flex attached` \u2014 the row has no size prop of its own by design (see `density`); every control already owns its own `size` axis (`xs|sm|md|lg`).","ATTACHED: DO use `fullWidth` inside a narrow form card so the joined row spans the field column, exactly like a lone Input would.",'ATTACHED: `fullWidth` is antd `Space.Compact block` (gh#1062): in a row, a FIELD child (Input and its affix/Password/Search forms, NumberInput, Textarea, TagInput, the Date/Time pickers, and the Select/Cascader/TreeSelect/SearchSelect trigger) grows to fill the row, and every other child \u2014 a Button, an icon button \u2014 keeps its content width. So `[Input][+ Add]` is a full-width field with its submit at content width, and two fields (NumberInput + Select) share the row evenly between them. Deviation from antd, written down: antd grows only its Input family (`width: 100%`); Select/InputNumber/DatePicker keep their own width there. Here every field grows, so two fields never leave an empty tail. `direction="col"` + `fullWidth` stacks full-width children as before.','ATTACHED: DON\'T expect corner-radius welding on `direction="col"` yet \u2014 the shared border still collapses, but each child keeps all four of its own corners rounded until a block-axis radius knob exists on the Input/trigger families (documented gap, not a silent one).'],useCases:["Toolbar internals where controls should sit in a row, wrap on narrow widths, and stay vertically centered.","Card headers that need title content on the left and actions on the right via `justify='between'` without hand-rolling flex utility classes.","Empty-state or loading blocks that center content on both axes using `align='center'` and `justify='center'`.","Form sub-sections where a vertical group needs stretched children or centered helper content beyond what a plain column Flex provides.","Badge, chip, or tag clusters where wrapping is required but the caller also needs explicit gap control.","Low-level layout composition inside custom components where raw flex classes would duplicate the primitive.",'ATTACHED: a recurring-issue interval row, "\u6BCE [NumberInput] [Select \u9031/\u6708/\u65E5 \u25BE] \u3054\u3068", fused on one line inside a FormField, inside a 2-column ResponsiveGrid form card that collapses to one column.',"ATTACHED: A currency amount: [Select \u901A\u8CA8 \u25BE][NumberInput \u91D1\u984D] welded so the currency reads as part of the amount field, not a separate control beside it.","ATTACHED: A filtered search bar: [Select scope][SearchInput query] as one visual field, `fullWidth` inside a page toolbar."],related:["Flex `direction='col'` \u2014 the standard pattern for ordinary vertical block spacing; use explicit `align`, `justify`, or `wrap` props when you need more control.","Flex `direction='row'` \u2014 the standard pattern for simple horizontal groups; add `wrap` and `align='center'` for the typical row with wrapped centered items.","ResponsiveGrid \u2014 use for equal-width, multi-column tile layouts. Flex arranges children on one flex axis and does not provide column-count behavior.","PageContainer \u2014 page scaffold and padding context. Flex is an inner layout primitive used inside page sections, cards, dialogs, and toolbars. PageContainer `measure` bounds an APP page (header and body together, narrow | medium); Flex `measure` bounds ONE centred column inside a full-bleed band, and is the only one that reaches the marketing `wide` step."],example:`import { Flex } from "@godxjp/ui/layout";
50
+ </PageContainer>`,docPath:"docs/layout/page-cover.tsx",storyPath:"layout/page-cover.tsx",rules:[]},{name:"Flex",absorbed:["SpaceCompact"],group:"layout",tagline:"Token-spaced flex primitive with explicit direction, alignment, justification, and wrapping controls \u2014 and, with `attached`, a row of controls welded into ONE visual unit (antd Space.Compact).",props:[{name:"attached",type:"boolean",defaultValue:"false",description:'Weld the children into one control \u2014 antd Space.Compact (v32 folded `SpaceCompact` in here). Each child gets its own flex-item wrapper, inner corner radii are zeroed and the shared border collapses to one hairline; each child keeps its own focus ring, name and `size`. `direction` picks the axis ("row" default, "col"); `gap`/`wrap`/`pad` and the other layout knobs do not apply (a seam has no gap). Named (aria-label/-labelledby, e.g. by a wrapping FormField) it becomes role="group".'},{name:"fullWidth",type:"boolean",defaultValue:"false",description:"`attached` only. The joined row fills its parent's inline size (antd `block`, renamed to match Button.fullWidth). Field children grow to fill it; a Button keeps its content width (gh#1062)."},{name:"density",type:'"compact" | "default" | "comfortable"',description:"`attached` only. Scoped control density for the whole joined row (antd Space.Compact `size`). Each child still carries its OWN `size` prop."},{name:"reveal",type:'"hover"',description:"Floating child actions shown on parent hover/focus-within; always visible on touch."},{name:"bleed",type:"GapProp",description:"Negative inline inset on the token scale."},{name:"surface",type:'"muted" | "popover" | "warning"',description:"Lightweight surface, without Card structure."},{name:"shrink",type:"boolean",description:"false prevents shrinking."},{name:"grow",type:"boolean",description:"Grow into remaining flex space."},{name:"as",type:'"div" | "span" | "ul" | "ol" | "li"',description:'Semantic element. A list keeps its marker and indentation unless marker="none" says otherwise.'},{name:"marker",type:'"disc" | "decimal" | "none"',defaultValue:'as="ul" \u2192 "disc", as="ol" \u2192 "decimal"',description:'Marker for a LIST element; ignored by every other tag. marker="none" emits NO data-list, so the list keeps its <ul>/<ol>, its <li> semantics and its gap token, and loses the bullet AND the --space-5 indent \u2014 that is the container a short entity list needs: <Flex as="ul" marker="none" direction="col" gap="none"> with <ListRow as="li"> rows. Before it, the bullet was unconditional and .ui-flex[data-list] > li { display: list-item } outranked [data-slot="list-row"] { display: flex }, so rows fell out of flex layout (94.58px tall instead of 69.98px) and the only move left was a raw <ul>, which carries no gap token (gh#714). disc/decimal stay available so an <ol> can be bulleted, or a <ul> numbered, without a list-style-type in a className.'},{name:"direction",type:'"row" | "col" | {base?: "row" | "col"; sm?: "row" | "col"; md?: "row" | "col"; lg?: "row" | "col"; xl?: "row" | "col"}',description:"Responsive axis; omitted steps inherit."},{name:"gap",type:'"none" | "xs" | "sm" | "md" | "lg" | "xl"',defaultValue:'"md"',description:'Token gap between children, shared with other layout primitives. "none" is a DELIBERATE zero for two lines that read as one block \u2014 a name over its role, a weekday over its date, a tab bar with no seam \u2014 not a way to opt out of the token scale.'},{name:"gapRaw",type:"number",description:"ESCAPE HATCH: a gap in pixels, off every step of the scale. Real designs land on 2px, 5px, 6px, 10px, 14px \u2014 rounding to the nearest named step drifts the layout, and writing the literal in a className is blocked by ui-audit. Spend the ten named steps FIRST: `gap={3}` is 12px and follows the user's --scaling, gapRaw does not. It wins over `gap` (which then emits no class, so the two cannot fight over specificity) and leaves data-gap-raw on the DOM, so every escape stays countable."},{name:"pad",type:"number | { inline?, block?, inlineStart?, inlineEnd?, blockStart?, blockEnd? }",description:'Inner padding on the token scale \u2014 one step for all four sides, or an object keyed by LOGICAL side. Exists because a missing padding prop produced 42 of 51 ui-audit errors in one real consumer (gh#408): `<Flex className="p-3">` was the only move left.'},{name:"padRaw",type:"number | { inline?, block?, inlineStart?, inlineEnd?, blockStart?, blockEnd? }",description:"Raw-pixel padding for values off the scale, same contract and same price as gapRaw: it leaves data-pad-raw on the DOM so each escape is countable. Overrides `pad` PER SIDE, not as a whole."},{name:"fill",type:"boolean",defaultValue:"false",description:'Take the space the siblings leave \u2014 the ELASTIC column of a `fixed | elastic | fixed` row (name \xB7 meter \xB7 figures). Also sets min-inline-size: 0, which is what lets a truncating child ellipse instead of pushing the row wider. Without this axis the only move was className="flex-1 min-w-0", which ui-audit blocks (gh#405 \xA72).'},{name:"width",type:"WidthProp",description:"A FIXED column: number = px, string = any CSS length. Comes with flex: none \u2014 a width a sibling can still squeeze is a suggestion, and stacked rows would start at different x offsets. Leaves data-width-raw on the DOM so the measurement stays countable, like gapRaw/padRaw."},{name:"measure",type:'"narrow" | "medium" | "wide"',description:'CENTRE this box and CAP it at a page measure (--page-measure-narrow 42rem / -medium 48rem / -wide 72rem): margin-inline:auto + inline-size:100% + max-inline-size. THE public answer to "full-bleed outside, measured column inside" \u2014 a marketing <section> paints edge to edge and its inner Flex measure="wide" holds the content on the page measure. Deliberately NOT on PageContainer: that owns page padding and a header/toolbar/footer scaffold, so a full-bleed page cannot consume it, and the refusal left the centred column owned by nobody \u2014 three showcases each hand-wrote the same four declarations (gh#839). It adds NO gutter: the page inset is pad={{ inline: 6 }}, and one band with two padding owners drifts. A MAX, so nothing binds below the cap at 390px. An explicit `width` wins. Do not give a READING column "wide" \u2014 prose stays narrow/medium, which bracket Bringhurst\'s 45-75 characters. Omitted emits no attribute at all.'},{name:"align",type:'"start" | "center" | "end" | "stretch" | "baseline"',description:"Cross-axis alignment, emitted as a data attribute for the layout CSS."},{name:"justify",type:'"start" | "center" | "end" | "between" | "around" | "evenly"',description:"Main-axis distribution, emitted as a data attribute for the layout CSS."},{name:"wrap",type:"boolean",defaultValue:"false",description:"Allows children to wrap onto additional flex lines."},{name:"hideBelow",type:'"sm" | "md" | "lg" | "xl"',description:'Drop this region below a canonical breakpoint step (sm 40rem, md 48rem, lg 64rem, xl 80rem). THE public way to make a region responsive without a page-local media query \u2014 a public header hides its anchor navigation with hideBelow="md". Omitted by default, so no attribute is emitted and no rule matches. display:none also removes it from the a11y tree, so keep its destinations reachable elsewhere (a footer nav) at that width.'},{name:"hideFrom",type:'"sm" | "md" | "lg" | "xl"',description:"Inverse of hideBelow \u2014 drop the region FROM that step upwards, i.e. keep it only on the narrow side (a compact-only affordance)."},{name:"hideBelowRaw",type:"number",description:"ESCAPE HATCH: the same drop, at a width in PIXELS off every step of the scale \u2014 the gapRaw/padRaw contract on the breakpoint axis (gh#528). An off-scale breakpoint is a LOCAL EXCEPTION, not a new tier: sm/md/lg/xl are shared with collapseBelow and --master-detail-collapse-below, so two regions asked to fold at the same step really do fold together, while a raw width folds one region only. Spend the four steps first; reach here when the canonical design specifies a width the scale has not got (a nav that becomes a hamburger at 900px). It leaves data-hide-below-raw on the DOM so every escape stays countable, and prints one deduped media rule per distinct width (a media query cannot read a var()). It wins over hideBelow, which then emits nothing."},{name:"hideFromRaw",type:"number",description:"Inverse of hideBelowRaw, same contract and same price (data-hide-from-raw). THE SEAM: hideBelowRaw hides while width < N and hideFromRaw hides while width >= N \u2014 the same comparisons as the token steps, so the pair is exact complements and at exactly N the hideBelowRaw region is the visible one. Never hand-roll this with an inclusive max-width: `<= N` paired with `>= N` hides BOTH at exactly N, the 1px hole a consumer measured on a hand-rolled max-[900px]: pair."}],usage:['DO import from `@godxjp/ui/layout` and reach for Flex when the axis, alignment, justification, or wrap behavior is part of the component contract: `import { Flex } from "@godxjp/ui/layout"`.',"DO keep spacing on the `gap` prop instead of raw `gap-*`, `space-*`, or padding utilities. Flex uses the same token scale as other layout primitives, so spacing remains tied to the design system.",'DO use `direction="row"` with `wrap` for responsive control rows, chip clusters, and action groups that need more control than simple row composition.','DO use `direction="col"` for vertical groupings that need explicit `align` or `justify` behavior. For pure vertical stacking without alignment control, `direction="col"` is sufficient.',"DON'T override the axis with `className` after choosing a direction prop. Keep the layout intent in props so catalog guidance and data attributes stay accurate.",'FULL-BLEED BAND: a marketing/landing section is a `<section>` carrying the edge-to-edge paint (background, border, halo) around ONE `<Flex direction="col" measure="wide" pad={{ inline: 6, block: 20 }}>`. The measure centres and caps the column, `pad` owns the gutter and the band rhythm (`block: 20` = 80px, `block: 24` = 96px \u2014 the two band steps). Never a page-local `max-width: 1200px` + `margin-inline: auto` class, and never an inline style saying the same thing: that four-declaration idiom is what this prop replaced (gh#839).','Flex is a plain div with React.HTMLAttributes<HTMLDivElement>; pass `id`, `role`, `aria-*`, `data-*`, and structural className values as needed, but do not use it as a semantic form or button wrapper. When the parent only accepts phrasing content \u2014 a TabsTrigger, PopoverTrigger or Button, all of which render a <button> \u2014 pass `as="span"` rather than reaching for a raw `<span className="flex \u2026">`.','SEMANTIC LIST: a list of rows is `<Flex as="ul" marker="none" direction="col" gap="none">` with `<ListRow as="li">` children \u2014 never a raw `<ul>` (no gap token), never `<div role="list">` + `<div role="listitem">` (ARIA re-describing markup HTML already has), and never a wrapper around each row: the divider is `:not(:last-child)` among SIBLINGS, so a row alone in its own wrapper loses it silently. `ui-audit` flags all three as `no-hand-rolled-list`.',"NAMED FLEX = GROUP: a role-less div may not carry a naming attribute (axe aria-allowed-attr), so a Flex given `aria-label`/`aria-labelledby` \u2014 e.g. by FormField wrapping a composite range/\u5E74\u6708 field \u2014 automatically renders `role='group'`, folds `aria-errormessage` into `aria-describedby`, and drops the widget-only `aria-required`/`aria-invalid`. Passing an explicit `role` opts out of all of this and the caller owns the attribute set.",'ATTACHED: DO reach for it when two or more controls must read as ONE field \u2014 a number + a unit ("\u6BCE [2] [\u9031 \u25BE] \u3054\u3068"), a currency Select welded to an amount Input, a search field with an attached filter Select. `ResponsiveGrid columns={2}` puts them in separate cells (which collapses to ONE column on a narrow form card); `Flex attached` keeps them fused on one line regardless of the grid.','ATTACHED: ONE label for the pair vs per-control: wrap the WHOLE `Flex attached` in a single `FormField label="\u2026"` when the pair reads as one field ("\u7E70\u308A\u8FD4\u3057\u9593\u9694" over a number+unit row) \u2014 a role-less `<div>` cannot carry a cloned `aria-label`/`aria-labelledby` (axe `aria-allowed-attr`), so a NAMED `Flex attached` with no explicit `role` promotes itself to `role="group"` automatically, the same contract `Flex` already honours for a range/\u5E74\u6708 pair. Give each CHILD its own `aria-label` instead only when the two controls are independently meaningful outside the row (rare \u2014 prefer the one-label pattern for a welded control).',"ATTACHED: DON'T reach for `className=\"rounded-none\"` / `[&>*:not(:first-child)]` utilities to join controls yourself \u2014 `ui-audit`'s `no-utility-layout` rule blocks exactly that, and it is precisely the corner-radius seam this component owns.","ATTACHED: DO set `size` on each CHILD individually, not on `Flex attached` \u2014 the row has no size prop of its own by design (see `density`); every control already owns its own `size` axis (`xs|sm|md|lg`).","ATTACHED: DO use `fullWidth` inside a narrow form card so the joined row spans the field column, exactly like a lone Input would.",'ATTACHED: `fullWidth` is antd `Space.Compact block` (gh#1062): in a row, a FIELD child (Input and its affix/Password/Search forms, NumberInput, Textarea, TagInput, the Date/Time pickers, and the Select/Cascader/TreeSelect/SearchSelect trigger) grows to fill the row, and every other child \u2014 a Button, an icon button \u2014 keeps its content width. So `[Input][+ Add]` is a full-width field with its submit at content width, and two fields (NumberInput + Select) share the row evenly between them. Deviation from antd, written down: antd grows only its Input family (`width: 100%`); Select/InputNumber/DatePicker keep their own width there. Here every field grows, so two fields never leave an empty tail. `direction="col"` + `fullWidth` stacks full-width children as before.','ATTACHED: DON\'T expect corner-radius welding on `direction="col"` yet \u2014 the shared border still collapses, but each child keeps all four of its own corners rounded until a block-axis radius knob exists on the Input/trigger families (documented gap, not a silent one).'],useCases:["Toolbar internals where controls should sit in a row, wrap on narrow widths, and stay vertically centered.","Card headers that need title content on the left and actions on the right via `justify='between'` without hand-rolling flex utility classes.","Empty-state or loading blocks that center content on both axes using `align='center'` and `justify='center'`.","Form sub-sections where a vertical group needs stretched children or centered helper content beyond what a plain column Flex provides.","Badge, chip, or tag clusters where wrapping is required but the caller also needs explicit gap control.","Low-level layout composition inside custom components where raw flex classes would duplicate the primitive.",'ATTACHED: a recurring-issue interval row, "\u6BCE [NumberInput] [Select \u9031/\u6708/\u65E5 \u25BE] \u3054\u3068", fused on one line inside a FormField, inside a 2-column ResponsiveGrid form card that collapses to one column.',"ATTACHED: A currency amount: [Select \u901A\u8CA8 \u25BE][NumberInput \u91D1\u984D] welded so the currency reads as part of the amount field, not a separate control beside it.","ATTACHED: A filtered search bar: [Select scope][SearchInput query] as one visual field, `fullWidth` inside a page toolbar."],related:["Flex `direction='col'` \u2014 the standard pattern for ordinary vertical block spacing; use explicit `align`, `justify`, or `wrap` props when you need more control.","Flex `direction='row'` \u2014 the standard pattern for simple horizontal groups; add `wrap` and `align='center'` for the typical row with wrapped centered items.","ResponsiveGrid \u2014 use for equal-width, multi-column tile layouts. Flex arranges children on one flex axis and does not provide column-count behavior.","PageContainer \u2014 page scaffold and padding context. Flex is an inner layout primitive used inside page sections, cards, dialogs, and toolbars. PageContainer `measure` bounds an APP page (header and body together, narrow | medium); Flex `measure` bounds ONE centred column inside a full-bleed band, and is the only one that reaches the marketing `wide` step."],example:`import { Flex } from "@godxjp/ui/layout";
51
51
  import { Button } from "@godxjp/ui/general";
52
52
 
53
53
  <Flex direction="row" gap="sm" align="center" justify="between" wrap>
@@ -986,13 +986,13 @@ const q = useInfiniteQuery<{ items: Activity[]; cursor?: string }>({
986
986
 
987
987
  <InfiniteQueryState query={q} skeleton={<SkeletonRows />} flatten={flattenItemPages} isEmpty={(it) => it.length === 0}>
988
988
  {(items) => items.map((a) => <ActivityRow key={a.id} activity={a} />)}
989
- </InfiniteQueryState>`,storyPath:"query/infinite-query-state.tsx",rules:[]},{name:"Form",group:"data-entry",tagline:"Ant-style layout container \u2014 renders <form> and pushes layout (vertical/horizontal), labelWidth/controlWidth, label alignment, responsive collapse, and multi-column grid down to every FormField (overridable per field).",props:[{name:"layout",type:'"vertical" | "horizontal" | "inline"',defaultValue:'"vertical"',description:"Label position relative to control; applied to all FormFields."},{name:"labelWidth",type:"number | string",description:"Label column width in horizontal layout (number\u2192px). e.g. 120 or '8rem'."},{name:"controlWidth",type:"number | string",description:"Cap the control width (number\u2192px). Omit to fill the column. Caps the control only \u2014 the helper and error still span the field column."},{name:"labelAlign",type:'"start" | "end"',defaultValue:'"end"',description:"Horizontal alignment of the label within its column."},{name:"collapseBelow",type:'"sm" | "md" | "lg" | "xl" | false',defaultValue:'"md"',description:"Breakpoint below which horizontal collapses to vertical (mobile-first). false = always horizontal."},{name:"columns",type:"number | { sm?: number; md?: number; lg?: number }",description:"Lay fields out in a responsive grid (reuses ResponsiveGrid; 1 col on small)."},{name:"errors",type:"Partial<Record<string, string | string[]>>",description:"Server validation error bag (e.g. Inertia's form.errors). Each FormField name='\u2026' inside resolves its own message from the bag and CLAIMS its key; <FormErrors /> renders the unclaimed remainder (errors on hidden/derived fields). Works in both <form> and asChild modes."},{name:"density",type:'"compact" | "default" | "comfortable"',description:"Apply a density to controls inside the form."},{name:"disabled",type:"boolean",description:"Disable controls inside FormField, including nested native controls."},{name:"requiredMark",type:'boolean | "optional"',description:"Show required marks, hide them, or mark optional fields."}],usage:["DO set `layout`, `labelWidth`, `controlWidth` ONCE on `<Form>` \u2014 every `<FormField>` inside inherits them. Override a single field by passing the same prop on that `<FormField>` (Form \u2192 FormField priority).","DO rely on mobile-first collapse: `layout='horizontal'` automatically stacks to vertical below `collapseBelow` (default `md`). Pass `collapseBelow={false}` only when a field MUST stay label-beside-control even on phones.","DO use `columns` for multi-field forms (e.g. `columns={2}`) \u2014 it reuses ResponsiveGrid (1 column on small screens, more on md/lg). Span a wide field across columns with `<FormField colSpan={2}>`.","ROW RHYTHM IS THE SAME ON EVERY PATH: a grid of FormFields hands its row spacing to the grid's own `row-gap` (--form-grid-row-gap, defaulting to --form-field-row-gap) instead of the per-field margin a stacked Form uses. So `columns={1}` \u2014 and any `columns={n}` form once a narrow container collapses it to one column \u2014 is pixel-identical to a Form with no `columns`, and a hand-written `<ResponsiveGrid columns={2}>` of FormFields inside a `CardContent` (what a form with several titled Card sections has to write) matches `columns={2}` exactly. Retune --form-field-row-gap to move every path together; --form-grid-row-gap / --form-grid-column-gap to retune the grid rows / gutter alone. Never add margin to a FormField to space a grid row: a per-item margin inside a grid misaligns row 1 and double-counts the track gap.","ACTION ROW in a horizontal form (gh#1271): the submit/cancel buttons go in `<FormField label={false}><Flex gap=\"sm\" wrap>\u2026buttons\u2026</Flex></FormField>` as the LAST field. A label-less field renders no label cell and its control is pinned to the control column (gh#709), so the first button's left edge is the inputs' left edge, it follows `labelWidth`, and it collapses with the fields below `collapseBelow`; `wrap` lets the row break onto a second line on a phone. Requires `labelWidth` on the Form \u2014 unset, each label column is as wide as its own text and nothing can align with it. DON'T use `staticText` for buttons (it is the read-only VALUE slot), DON'T push the row with a hand-written padding, and DON'T float it to the far end of the card, away from the column the eye just went down. This is the row for a form INSIDE a card or section; a form that is the whole page puts its primary + cancel in the PageContainer footer instead (docs/general/button/examples/form-actions.tsx).","DON'T hand-roll a `<form>` + Flex stack for spacing \u2014 `<Form>` provides the vertical rhythm and the layout context FormField reads. Wire react-hook-form by spreading `onSubmit={handleSubmit(...)}` onto `<Form>`.","SERVER ERROR BAG: pass `errors={form.errors}` (Inertia) ONCE on `<Form>`, give each field a `name`, and put `<FormErrors />` at the top of the form. A named field resolves its message from the bag automatically (no per-field `error={errors.x}`), and FormErrors catches validation errors on hidden/derived keys (`action_mode`, `page`, a source-record id) that no visible field could display \u2014 without it those submits fail SILENTLY.","SIBLING FORMS: an edit screen split into several Card+Form sections shares ONE bag by wrapping the region in `<FormErrorsProvider errors={form.errors}>` instead of passing `errors` to each Form \u2014 the section Forms (without their own `errors`) join the shared registry, and one `<FormErrors />` anywhere in the region renders the unclaimed remainder."],useCases:["A settings page form where every label sits in a fixed 120px column to the left of its control (horizontal), collapsing to stacked labels on mobile.","A two-column entity-edit form (`columns={2}`) where the address field spans both columns (`colSpan={2}`).","A compact filter form (`layout='horizontal' density='compact'`) above a DataTable.","An Inertia edit screen passing `errors={form.errors}` so every `FormField name='\u2026'` self-binds its server validation message and `<FormErrors />` surfaces the hidden-field remainder."],related:["FormField \u2014 the per-field wrapper (label + control + helper/error) that reads Form's layout context; use one per control inside a Form.","FormErrors \u2014 renders the error-bag entries no mounted FormField claims (validation errors on hidden/derived fields); place inside a `Form errors={\u2026}`.","ResponsiveGrid \u2014 Form `columns` reuses it; use ResponsiveGrid directly for non-form card grids."],example:`import { Form, FormField, Input } from "@godxjp/ui/data-entry";
989
+ </InfiniteQueryState>`,storyPath:"query/infinite-query-state.tsx",rules:[]},{name:"Form",group:"data-entry",tagline:"Ant-style layout container \u2014 renders <form> and pushes layout (vertical/horizontal), labelWidth/controlWidth, label alignment, responsive collapse, and multi-column grid down to every FormField (overridable per field).",props:[{name:"layout",type:'"vertical" | "horizontal" | "inline"',defaultValue:'"vertical"',description:"Label position relative to control; applied to all FormFields."},{name:"labelWidth",type:"WidthProp",description:"Label column width in horizontal layout (number\u2192px). e.g. 120 or '8rem'."},{name:"controlWidth",type:"WidthProp",description:"Cap the control width: number\u2192px, or a CSS length ('20rem', '50%', 'calc(\u2026)'). Omit to fill the column. Caps the control only \u2014 the helper and error still span the field column. A size word ('md', 'lg') is a type error, not a width (gh#1431)."},{name:"labelAlign",type:'"start" | "end"',defaultValue:'"end"',description:"Horizontal alignment of the label within its column."},{name:"collapseBelow",type:'"sm" | "md" | "lg" | "xl" | false',defaultValue:'"md"',description:"Breakpoint below which horizontal collapses to vertical (mobile-first). false = always horizontal."},{name:"columns",type:"number | { sm?: number; md?: number; lg?: number }",description:"Lay fields out in a responsive grid (reuses ResponsiveGrid; 1 col on small)."},{name:"errors",type:"Partial<Record<string, string | string[]>>",description:"Server validation error bag (e.g. Inertia's form.errors). Each FormField name='\u2026' inside resolves its own message from the bag and CLAIMS its key; <FormErrors /> renders the unclaimed remainder (errors on hidden/derived fields). Works in both <form> and asChild modes."},{name:"density",type:'"compact" | "default" | "comfortable"',description:"Apply a density to controls inside the form."},{name:"disabled",type:"boolean",description:"Disable controls inside FormField, including nested native controls."},{name:"requiredMark",type:'boolean | "optional"',description:"Show required marks, hide them, or mark optional fields."}],usage:["DO set `layout`, `labelWidth`, `controlWidth` ONCE on `<Form>` \u2014 every `<FormField>` inside inherits them. Override a single field by passing the same prop on that `<FormField>` (Form \u2192 FormField priority).","DO rely on mobile-first collapse: `layout='horizontal'` automatically stacks to vertical below `collapseBelow` (default `md`). Pass `collapseBelow={false}` only when a field MUST stay label-beside-control even on phones.","DO use `columns` for multi-field forms (e.g. `columns={2}`) \u2014 it reuses ResponsiveGrid (1 column on small screens, more on md/lg). Span a wide field across columns with `<FormField colSpan={2}>`.","ROW RHYTHM IS THE SAME ON EVERY PATH: a grid of FormFields hands its row spacing to the grid's own `row-gap` (--form-grid-row-gap, defaulting to --form-field-row-gap) instead of the per-field margin a stacked Form uses. So `columns={1}` \u2014 and any `columns={n}` form once a narrow container collapses it to one column \u2014 is pixel-identical to a Form with no `columns`, and a hand-written `<ResponsiveGrid columns={2}>` of FormFields inside a `CardContent` (what a form with several titled Card sections has to write) matches `columns={2}` exactly. Retune --form-field-row-gap to move every path together; --form-grid-row-gap / --form-grid-column-gap to retune the grid rows / gutter alone. Never add margin to a FormField to space a grid row: a per-item margin inside a grid misaligns row 1 and double-counts the track gap.","ACTION ROW in a horizontal form (gh#1271): the submit/cancel buttons go in `<FormField label={false}><Flex gap=\"sm\" wrap>\u2026buttons\u2026</Flex></FormField>` as the LAST field. A label-less field renders no label cell and its control is pinned to the control column (gh#709), so the first button's left edge is the inputs' left edge, it follows `labelWidth`, and it collapses with the fields below `collapseBelow`; `wrap` lets the row break onto a second line on a phone. Requires `labelWidth` on the Form \u2014 unset, each label column is as wide as its own text and nothing can align with it. DON'T use `staticText` for buttons (it is the read-only VALUE slot), DON'T push the row with a hand-written padding, and DON'T float it to the far end of the card, away from the column the eye just went down. This is the row for a form INSIDE a card or section; a form that is the whole page puts its primary + cancel in the PageContainer footer instead (docs/general/button/examples/form-actions.tsx).","DON'T hand-roll a `<form>` + Flex stack for spacing \u2014 `<Form>` provides the vertical rhythm and the layout context FormField reads. Wire react-hook-form by spreading `onSubmit={handleSubmit(...)}` onto `<Form>`.","SERVER ERROR BAG: pass `errors={form.errors}` (Inertia) ONCE on `<Form>`, give each field a `name`, and put `<FormErrors />` at the top of the form. A named field resolves its message from the bag automatically (no per-field `error={errors.x}`), and FormErrors catches validation errors on hidden/derived keys (`action_mode`, `page`, a source-record id) that no visible field could display \u2014 without it those submits fail SILENTLY.","SIBLING FORMS: an edit screen split into several Card+Form sections shares ONE bag by wrapping the region in `<FormErrorsProvider errors={form.errors}>` instead of passing `errors` to each Form \u2014 the section Forms (without their own `errors`) join the shared registry, and one `<FormErrors />` anywhere in the region renders the unclaimed remainder."],useCases:["A settings page form where every label sits in a fixed 120px column to the left of its control (horizontal), collapsing to stacked labels on mobile.","A two-column entity-edit form (`columns={2}`) where the address field spans both columns (`colSpan={2}`).","A compact filter form (`layout='horizontal' density='compact'`) above a DataTable.","An Inertia edit screen passing `errors={form.errors}` so every `FormField name='\u2026'` self-binds its server validation message and `<FormErrors />` surfaces the hidden-field remainder."],related:["FormField \u2014 the per-field wrapper (label + control + helper/error) that reads Form's layout context; use one per control inside a Form.","FormErrors \u2014 renders the error-bag entries no mounted FormField claims (validation errors on hidden/derived fields); place inside a `Form errors={\u2026}`.","ResponsiveGrid \u2014 Form `columns` reuses it; use ResponsiveGrid directly for non-form card grids."],example:`import { Form, FormField, Input } from "@godxjp/ui/data-entry";
990
990
 
991
991
  <Form layout="horizontal" labelWidth={120} columns={2} onSubmit={onSubmit}>
992
992
  <FormField id="first" label="\u59D3"><Input id="first" /></FormField>
993
993
  <FormField id="last" label="\u540D"><Input id="last" /></FormField>
994
994
  <FormField id="address" label="\u4F4F\u6240" colSpan={2}><Input id="address" /></FormField>
995
- </Form>`,storyPath:"data-entry/form.tsx",rules:[23,24]},{name:"FormField",group:"data-entry",tagline:"Wraps a control with label, helper, and error; injects the accessible name (aria-labelledby), description (aria-describedby) and validation (aria-errormessage/aria-invalid/aria-required) contract onto the child, which forwards it to its real semantic focus target. Reads the parent Form's layout (vertical/horizontal) \u2014 overridable per field.",props:[{name:"field",type:"string",description:"T\xEAn tr\u01B0\u1EDDng c\u1EE7a form \u2014 d\xF9ng khi `id` kh\xF4ng \u0111\u1EE7 \u0111\u1EC3 n\u1ED1i control v\u1EDBi error/aria."},{name:"labelAddon",type:"ReactNode",description:"N\u1ED9i dung ph\u1EE5 c\u1EA1nh nh\xE3n: g\u1EE3i \xFD, badge b\u1EAFt bu\u1ED9c, n\xFAt tr\u1EE3 gi\xFAp, action ch\u1EEF ng\u1EAFn. N\u1EB1m TRONG h\xE0ng nh\xE3n n\xEAn kh\xF4ng ph\xE1 nh\u1ECBp tr\u01B0\u1EDDng. \u1EDE layout horizontal/inline h\xE0ng nh\xE3n xu\u1ED1ng d\xF2ng: addon kh\xF4ng v\u1EEBa c\u1EA1nh nh\xE3n th\xEC r\u01A1i xu\u1ED1ng d\xF2ng ri\xEAng d\u01B0\u1EDBi nh\xE3n, trong c\u1ED9t nh\xE3n, kh\xF4ng tr\xE0n sang c\u1ED9t control."},{name:"id",type:"string",required:!0,description:"Forwarded to Label htmlFor + builds helper/error ids."},{name:"name",type:"string",description:"Error-bag key of this field. When the surrounding Form carries `errors`, the field resolves its message from `errors[name]` automatically (an explicit `error` prop wins) and CLAIMS the key so <FormErrors /> does not repeat it. NOT injected into the child \u2014 pass `name` on the control itself for native form submission."},{name:"label",type:"ReactNode",required:!0,description:"Field label above the control. `false` renders no label row; in a horizontal form the content still sits in the control column \u2014 the action row (gh#1271)."},{name:"required",type:"boolean",defaultValue:"false",description:"Red asterisk + aria-required on the child."},{name:"helper",type:"string",description:"Muted hint shown when there is no error."},{name:"helperPlacement",type:'"before" | "after"',defaultValue:'"after"',description:"Which side of the control the helper sits on. `before` puts it between the label and the input, for a hint the reader needs before answering (a bilingual form's second line, a unit or format note). Paint only \u2014 the helper keeps its id and stays on aria-describedby. Prefer it over stuffing a second line into `labelAddon` (a label-row slot for a chip, help button or short action) or into a ReactNode `label` (which loses the string-label aria fallbacks)."},{name:"error",type:"string",description:"Destructive error message (role=alert); overrides helper."},{name:"layout",type:'"vertical" | "horizontal" | "inline"',description:"Override the parent Form's layout for this field only."},{name:"labelWidth",type:"number | string",description:"Override the Form's label width for this field."},{name:"controlWidth",type:"number | string",description:"Override the Form's control width for this field. Caps the control only \u2014 the helper and error still span the field column."},{name:"colSpan",type:"number",description:"Span N columns when inside a `columns` Form grid."},{name:"children",type:"ReactNode",description:"The single interactive control to render. Mutually exclusive with `staticText` \u2014 pass exactly one of the two."},{name:"staticText",type:"ReactNode",description:"Read-only VALUE instead of an interactive control \u2014 renders as plain text styled to match `Descriptions.Item`'s value typography byte-for-byte (`text-sm break-all`), skipping all of FormField's id/aria-* control wiring (there is nothing to label). Mutually exclusive with `children`. Use this to put a read-only field (name, email \u2014 anything immutable) on the SAME `<Form>` as editable fields, so it inherits the exact same layout/labelAlign/row-gap automatically instead of reaching for a separate `Descriptions` block that needs its own props reconciled to match."},{name:"validateStatus",type:'"success" | "warning" | "error" | "validating"',description:"Validation state; an actual error takes priority. Warnings do not mark values invalid."},{name:"hasFeedback",type:"boolean",description:"Show a localized accessible validation status beside its feedback icon."},{name:"feedback",type:"React.ReactNode",description:"Custom feedback content; the localized status remains available."}],usage:["DO pass the same string to both `id` on `<FormField>` and `id` on the child control \u2014 the component wires `<Label htmlFor={id}>`, and builds `{id}-helper` / `{id}-error` ids for `aria-describedby`. If the ids diverge the label click and screen-reader announcements break.",'NO LABEL: `label={false}` renders no label row and reserves no label space; in a horizontal form the content still sits in the CONTROL column (gh#709). That is the canonical action row under a horizontal form (gh#1271): `<FormField label={false}><Flex gap="sm" wrap><Button type="submit">Save</Button><Button variant="outline">Cancel</Button></Flex></FormField>`. A label-less field around a CONTROL must name the control itself (a `<Checkbox>label</Checkbox>`, an `aria-label`).',"DO pass a SINGLE React element as `children`. FormField calls `React.cloneElement` on it to inject `aria-describedby`, `aria-required`, and `aria-invalid` \u2014 if you pass a fragment or multiple nodes, cloneElement silently skips the injection and a11y attributes are lost.","COMPOSITE CHILD: when the single child is a layout wrapper \u2014 a `Flex` holding a range from/to pair or a \u5E74/\u6708 input+select combo \u2014 the label still reaches every control inside. FormField publishes its label through FieldNameContext and each control's semantic focus target (Input's `<input>`, Select's `role=combobox` trigger, and everything composed on them) adopts it as a LAST-RESORT accessible name; a control's own `aria-label`/`aria-labelledby` always wins, so set a per-control `aria-label` (e.g. \u958B\u59CB\u65E5/\u7D42\u4E86\u65E5) when the two halves should announce distinct names. The wrapper itself renders as a named `role='group'` (see Flex).","DO reach for `staticText` (not `children` with a bare string/span) for a read-only field mixed into an otherwise-editable Form \u2014 e.g. an immutable name/email row above an editable role Select on the same Members-edit card. It renders with the exact typography `Descriptions.Item`'s value uses, and \u2014 because it IS a FormField reading the same Form context \u2014 it lines up with every other field's label column, `labelAlign`, and row-to-row gap automatically. A bare string as `children` instead triggers the dev-mode 'expected a single React element child' warning and has no typography contract at all.","WIDTH: a FormField FILLS its container in vertical/horizontal layout \u2014 like the conventional Form.Item (vertical \u2192 width:100%). It works full-width inside `<Form>`, a `ResponsiveGrid` cell, a bare `<Flex direction='col'>`, or a plain block; you do NOT need to wrap it in a grid to get full width. `layout='inline'` is the only content-width exception (compact, side-by-side). To narrow just the control (keeping the label row full-width), set `controlWidth` \u2014 never constrain the FormField itself.","DO use the `error` prop (not a hand-rolled `<p>`) for validation messages \u2014 it renders with `role='alert'` and `text-destructive` styling and overrides `helper` automatically. Never render an error paragraph alongside FormField.","DO use `labelAddon` (a ReactNode rendered after the label text, in the label row) for supplementary controls such as a tooltip trigger, a 'copy' icon button or a short text action ('Assign to myself'); in a horizontal/inline layout the label row wraps, so an addon that does not fit beside the label drops under it inside the label column rather than overlapping the control \u2014 never insert such controls as siblings outside FormField, which breaks layout.",'DON\'T wrap `Switch` in FormField \u2014 use `Field` instead. Field owns the inline row: `label`, `labelAddon`, `description`, and `error` (which wires aria-invalid / aria-errormessage / aria-describedby onto the control, gh#812). It renders no hidden input of its own \u2014 `Switch name="\u2026"` is what submits natively \u2014 and it has no `required`, `helper` or layout knobs.',"DON'T use FormField for checkbox-beside-label or radio-beside-label patterns \u2014 use `Field` (single checkbox/radio with description) or `CheckboxGroup` / `RadioGroup` (multiple options), which have their own integrated labelling.","CONTRACT (which element owns each ARIA relationship): every data-entry control accepts and FORWARDS the injected props to its real semantic focus target, not a wrapper div \u2014 Input/Textarea/NumberInput \u2192 the `<input>/<textarea>`; Select/Cascader/TreeSelect \u2192 the `role=combobox` trigger (with aria-expanded + aria-haspopup + aria-controls per the WAI-ARIA APG combobox pattern); DatePicker/TimePicker \u2192 the typeable `role=combobox` input (aria-haspopup=dialog); ColorPicker \u2192 the `<input type=color>` swatch; SearchInput \u2192 the `role=searchbox` input. GROUP controls own the relationship on their container: RadioGroup \u2192 `role=radiogroup` (full validation incl. aria-invalid/-errormessage/-required); CheckboxGroup, `DatePicker range` (two inputs), and Transfer \u2192 `role=group` \u2014 per ARIA 1.2 a group is not a widget, so the error id is folded into aria-describedby instead of aria-invalid/-errormessage. Upload forwards the label/description onto its native `<input type=file>`; its visible dropzone/button keeps its own action label. This forwarding is implemented once in `src/lib/field-a11y.ts` (`pickFieldA11y` / `pickGroupFieldA11y` / `resolveFieldA11y`) \u2014 do not reinvent it per control.","FIELD IDENTITY / AUTOMATION: FormField also injects a `data-field` \u2014 the field's stable MACHINE key, resolved as `field` \u2192 `name` \u2192 `id` \u2014 onto the same semantic focus target the ARIA relationships land on, and onto every option of a RadioGroup/CheckboxGroup. Use it (not a generated id, and never the visible Japanese label) as the selector in e2e tests and screen automation. It reaches NESTED controls too: when the direct child is a layout wrapper (a Flex holding a from/to pair, a \u5E74/\u6708 combo, a value beside a \u300C\u4E0D\u660E\u300D checkbox) cloneElement stops on that wrapper, so FormField also publishes the field through context and each control inside resolves its own key from its OWN `id` \u2014 which is what keeps `search_billing_date_from` and `..._to` distinct instead of collapsing onto one shared key. A nested control with NO id of its own deliberately gets nothing: a fabricated key is worse than a missing one, because automation binds to it and breaks silently. Two companion pieces: a `Select`'s trigger also carries `data-value` = the selected CODE (the trigger shows the option LABEL, and Radix keeps the value in an aria-hidden 1x1px native `<select>`), and each RadioGroup/CheckboxGroup option gets a deterministic `{groupId}-{optionValue}` id instead of a per-mount `React.useId()` token. Nothing here is opt-in and no DOM structure changed. A `data-field` written on the control itself always wins.","NATIVE `name` IS OPT-IN: FormField emits the same key as a real `name` attribute ONLY when the app set `<AppProvider emitFieldNames>`. It is off by default because `name` decides what a native `<form>` submit sends \u2014 turning it on globally in a shared package would make every consumer start posting new keys to its backend on an upgrade. Turn it on in apps that need native form posts or a screen-automation contract; a `name` written on the control itself always wins.","NATIVE FORM PARTICIPATION: pass `name` to a control for HTML form submission \u2014 Input/Textarea/NumberInput/Select submit natively; a searchable Select submits via a hidden input; DatePicker/TimePicker emit ISO strings (`yyyy-MM-dd` / 24h `HH:mm`); the range pickers emit `${name}_from` / `${name}_to`. `required`/`readOnly`/`disabled` map to the underlying control. Cascader/TreeSelect/Transfer submit named values via hidden inputs; Upload appends staged local files to FormData when named. Disabled controls are excluded.","ERROR TIMING & RECOVERY: pass `error` only after a field is dirty or the form is submitted (don't show errors on pristine mount). The error node renders with `role='alert'` so it is announced live the moment it appears; clearing `error` (e.g. after the user corrects the value or a server round-trip succeeds) removes aria-invalid and restores the helper. On submit, focus the first invalid control and/or render an error summary that links to each field by `id`."],useCases:["Labelling a text `Input` or `Textarea` in an invoice-entry form, showing a red asterisk for required fields and surfacing server validation errors returned from a Laravel FormRequest.","Wrapping a `Select` or `DatePicker` inside a multi-field filter panel where each control needs a visible label, helper hint (e.g. 'YYYY/MM/DD'), and inline error state.","Adding a `labelAddon` tooltip button next to a 'Tax rate' label in an accounting form to explain when different rates apply, without breaking the label\u2013control association.","Enclosing a `DatePicker range` or `TimePicker` in an admin settings page where the field needs a label, a muted hint ('Inclusive of start and end date'), and conditional error display.","Wrapping a `Select` (with `showSearch`) control for vendor/account lookup in a journal-entry form where the `id` must be kept consistent for programmatic focus management.","Providing structured error feedback for a `Cascader` or `TreeSelect` in a multi-level category assignment screen, replacing ad-hoc error rendering with the standardised `role='alert'` pattern."],related:["Label \u2014 the bare label component. Use directly only when you are building a fully custom layout that cannot accept FormField's stack wrapper, and you will manage aria-describedby/aria-invalid yourself. FormField is always preferred for standard form controls.",'Field \u2014 the inline row for a boolean control: label and control side by side, with `labelAddon`, `description` and `error` (gh#812 added the last two slots; `error` wires aria-invalid / aria-errormessage / aria-describedby onto the control, so a validated boolean no longer has to be hand-wired). It still renders NO hidden `<input name>` \u2014 `Switch name="\u2026"` submits itself \u2014 and it has no `required`, `helper`, error-bag `name` binding or layout/width knobs. Still: never wrap a bare `Switch` in FormField.',"Field \u2014 pairs a single checkbox or radio with a label and optional description in a horizontal layout (control beside text). Use Field instead of FormField when the control and its label sit side-by-side rather than stacked.","CheckboxGroup / RadioGroup \u2014 for groups of options where FormField is not needed per-item; the group component handles its own legend/label and option layout."],example:`import { FormField, Input } from "@godxjp/ui/data-entry";
995
+ </Form>`,storyPath:"data-entry/form.tsx",rules:[23,24]},{name:"FormField",group:"data-entry",tagline:"Wraps a control with label, helper, and error; injects the accessible name (aria-labelledby), description (aria-describedby) and validation (aria-errormessage/aria-invalid/aria-required) contract onto the child, which forwards it to its real semantic focus target. Reads the parent Form's layout (vertical/horizontal) \u2014 overridable per field.",props:[{name:"field",type:"string",description:"T\xEAn tr\u01B0\u1EDDng c\u1EE7a form \u2014 d\xF9ng khi `id` kh\xF4ng \u0111\u1EE7 \u0111\u1EC3 n\u1ED1i control v\u1EDBi error/aria."},{name:"labelAddon",type:"ReactNode",description:"N\u1ED9i dung ph\u1EE5 c\u1EA1nh nh\xE3n: g\u1EE3i \xFD, badge b\u1EAFt bu\u1ED9c, n\xFAt tr\u1EE3 gi\xFAp, action ch\u1EEF ng\u1EAFn. N\u1EB1m TRONG h\xE0ng nh\xE3n n\xEAn kh\xF4ng ph\xE1 nh\u1ECBp tr\u01B0\u1EDDng. \u1EDE layout horizontal/inline h\xE0ng nh\xE3n xu\u1ED1ng d\xF2ng: addon kh\xF4ng v\u1EEBa c\u1EA1nh nh\xE3n th\xEC r\u01A1i xu\u1ED1ng d\xF2ng ri\xEAng d\u01B0\u1EDBi nh\xE3n, trong c\u1ED9t nh\xE3n, kh\xF4ng tr\xE0n sang c\u1ED9t control."},{name:"id",type:"string",required:!0,description:"Forwarded to Label htmlFor + builds helper/error ids."},{name:"name",type:"string",description:"Error-bag key of this field. When the surrounding Form carries `errors`, the field resolves its message from `errors[name]` automatically (an explicit `error` prop wins) and CLAIMS the key so <FormErrors /> does not repeat it. NOT injected into the child \u2014 pass `name` on the control itself for native form submission."},{name:"label",type:"ReactNode",required:!0,description:"Field label above the control. `false` renders no label row; in a horizontal form the content still sits in the control column \u2014 the action row (gh#1271)."},{name:"required",type:"boolean",defaultValue:"false",description:"Red asterisk + aria-required on the child."},{name:"helper",type:"string",description:"Muted hint shown when there is no error."},{name:"helperPlacement",type:'"before" | "after"',defaultValue:'"after"',description:"Which side of the control the helper sits on. `before` puts it between the label and the input, for a hint the reader needs before answering (a bilingual form's second line, a unit or format note). Paint only \u2014 the helper keeps its id and stays on aria-describedby. Prefer it over stuffing a second line into `labelAddon` (a label-row slot for a chip, help button or short action) or into a ReactNode `label` (which loses the string-label aria fallbacks)."},{name:"error",type:"string",description:"Destructive error message (role=alert); overrides helper."},{name:"layout",type:'"vertical" | "horizontal" | "inline"',description:"Override the parent Form's layout for this field only."},{name:"labelWidth",type:"WidthProp",description:"Override the Form's label width for this field."},{name:"controlWidth",type:"WidthProp",description:"Override the Form's control width for this field. Caps the control only \u2014 the helper and error still span the field column."},{name:"colSpan",type:"number",description:"Span N columns when inside a `columns` Form grid."},{name:"children",type:"ReactNode",description:"The single interactive control to render. Mutually exclusive with `staticText` \u2014 pass exactly one of the two."},{name:"staticText",type:"ReactNode",description:"Read-only VALUE instead of an interactive control \u2014 renders as plain text styled to match `Descriptions.Item`'s value typography byte-for-byte (`text-sm break-all`), skipping all of FormField's id/aria-* control wiring (there is nothing to label). Mutually exclusive with `children`. Use this to put a read-only field (name, email \u2014 anything immutable) on the SAME `<Form>` as editable fields, so it inherits the exact same layout/labelAlign/row-gap automatically instead of reaching for a separate `Descriptions` block that needs its own props reconciled to match."},{name:"validateStatus",type:'"success" | "warning" | "error" | "validating"',description:"Validation state; an actual error takes priority. Warnings do not mark values invalid."},{name:"hasFeedback",type:"boolean",description:"Show a localized accessible validation status beside its feedback icon."},{name:"feedback",type:"React.ReactNode",description:"Custom feedback content; the localized status remains available."}],usage:["DO pass the same string to both `id` on `<FormField>` and `id` on the child control \u2014 the component wires `<Label htmlFor={id}>`, and builds `{id}-helper` / `{id}-error` ids for `aria-describedby`. If the ids diverge the label click and screen-reader announcements break.",'NO LABEL: `label={false}` renders no label row and reserves no label space; in a horizontal form the content still sits in the CONTROL column (gh#709). That is the canonical action row under a horizontal form (gh#1271): `<FormField label={false}><Flex gap="sm" wrap><Button type="submit">Save</Button><Button variant="outline">Cancel</Button></Flex></FormField>`. A label-less field around a CONTROL must name the control itself (a `<Checkbox>label</Checkbox>`, an `aria-label`).',"DO pass a SINGLE React element as `children`. FormField calls `React.cloneElement` on it to inject `aria-describedby`, `aria-required`, and `aria-invalid` \u2014 if you pass a fragment or multiple nodes, cloneElement silently skips the injection and a11y attributes are lost.","COMPOSITE CHILD: when the single child is a layout wrapper \u2014 a `Flex` holding a range from/to pair or a \u5E74/\u6708 input+select combo \u2014 the label still reaches every control inside. FormField publishes its label through FieldNameContext and each control's semantic focus target (Input's `<input>`, Select's `role=combobox` trigger, and everything composed on them) adopts it as a LAST-RESORT accessible name; a control's own `aria-label`/`aria-labelledby` always wins, so set a per-control `aria-label` (e.g. \u958B\u59CB\u65E5/\u7D42\u4E86\u65E5) when the two halves should announce distinct names. The wrapper itself renders as a named `role='group'` (see Flex).","DO reach for `staticText` (not `children` with a bare string/span) for a read-only field mixed into an otherwise-editable Form \u2014 e.g. an immutable name/email row above an editable role Select on the same Members-edit card. It renders with the exact typography `Descriptions.Item`'s value uses, and \u2014 because it IS a FormField reading the same Form context \u2014 it lines up with every other field's label column, `labelAlign`, and row-to-row gap automatically. A bare string as `children` instead triggers the dev-mode 'expected a single React element child' warning and has no typography contract at all.","WIDTH: a FormField FILLS its container in vertical/horizontal layout \u2014 like the conventional Form.Item (vertical \u2192 width:100%). It works full-width inside `<Form>`, a `ResponsiveGrid` cell, a bare `<Flex direction='col'>`, or a plain block; you do NOT need to wrap it in a grid to get full width. `layout='inline'` is the only content-width exception (compact, side-by-side). To narrow just the control (keeping the label row full-width), set `controlWidth` \u2014 never constrain the FormField itself.","DO use the `error` prop (not a hand-rolled `<p>`) for validation messages \u2014 it renders with `role='alert'` and `text-destructive` styling and overrides `helper` automatically. Never render an error paragraph alongside FormField.","DO use `labelAddon` (a ReactNode rendered after the label text, in the label row) for supplementary controls such as a tooltip trigger, a 'copy' icon button or a short text action ('Assign to myself'); in a horizontal/inline layout the label row wraps, so an addon that does not fit beside the label drops under it inside the label column rather than overlapping the control \u2014 never insert such controls as siblings outside FormField, which breaks layout.",'DON\'T wrap `Switch` in FormField \u2014 use `Field` instead. Field owns the inline row: `label`, `labelAddon`, `description`, and `error` (which wires aria-invalid / aria-errormessage / aria-describedby onto the control, gh#812). It renders no hidden input of its own \u2014 `Switch name="\u2026"` is what submits natively \u2014 and it has no `required`, `helper` or layout knobs.',"DON'T use FormField for checkbox-beside-label or radio-beside-label patterns \u2014 use `Field` (single checkbox/radio with description) or `CheckboxGroup` / `RadioGroup` (multiple options), which have their own integrated labelling.","CONTRACT (which element owns each ARIA relationship): every data-entry control accepts and FORWARDS the injected props to its real semantic focus target, not a wrapper div \u2014 Input/Textarea/NumberInput \u2192 the `<input>/<textarea>`; Select/Cascader/TreeSelect \u2192 the `role=combobox` trigger (with aria-expanded + aria-haspopup + aria-controls per the WAI-ARIA APG combobox pattern); DatePicker/TimePicker \u2192 the typeable `role=combobox` input (aria-haspopup=dialog); ColorPicker \u2192 the `<input type=color>` swatch; SearchInput \u2192 the `role=searchbox` input. GROUP controls own the relationship on their container: RadioGroup \u2192 `role=radiogroup` (full validation incl. aria-invalid/-errormessage/-required); CheckboxGroup, `DatePicker range` (two inputs), and Transfer \u2192 `role=group` \u2014 per ARIA 1.2 a group is not a widget, so the error id is folded into aria-describedby instead of aria-invalid/-errormessage. Upload forwards the label/description onto its native `<input type=file>`; its visible dropzone/button keeps its own action label. This forwarding is implemented once in `src/lib/field-a11y.ts` (`pickFieldA11y` / `pickGroupFieldA11y` / `resolveFieldA11y`) \u2014 do not reinvent it per control.","FIELD IDENTITY / AUTOMATION: FormField also injects a `data-field` \u2014 the field's stable MACHINE key, resolved as `field` \u2192 `name` \u2192 `id` \u2014 onto the same semantic focus target the ARIA relationships land on, and onto every option of a RadioGroup/CheckboxGroup. Use it (not a generated id, and never the visible Japanese label) as the selector in e2e tests and screen automation. It reaches NESTED controls too: when the direct child is a layout wrapper (a Flex holding a from/to pair, a \u5E74/\u6708 combo, a value beside a \u300C\u4E0D\u660E\u300D checkbox) cloneElement stops on that wrapper, so FormField also publishes the field through context and each control inside resolves its own key from its OWN `id` \u2014 which is what keeps `search_billing_date_from` and `..._to` distinct instead of collapsing onto one shared key. A nested control with NO id of its own deliberately gets nothing: a fabricated key is worse than a missing one, because automation binds to it and breaks silently. Two companion pieces: a `Select`'s trigger also carries `data-value` = the selected CODE (the trigger shows the option LABEL, and Radix keeps the value in an aria-hidden 1x1px native `<select>`), and each RadioGroup/CheckboxGroup option gets a deterministic `{groupId}-{optionValue}` id instead of a per-mount `React.useId()` token. Nothing here is opt-in and no DOM structure changed. A `data-field` written on the control itself always wins.","NATIVE `name` IS OPT-IN: FormField emits the same key as a real `name` attribute ONLY when the app set `<AppProvider emitFieldNames>`. It is off by default because `name` decides what a native `<form>` submit sends \u2014 turning it on globally in a shared package would make every consumer start posting new keys to its backend on an upgrade. Turn it on in apps that need native form posts or a screen-automation contract; a `name` written on the control itself always wins.","NATIVE FORM PARTICIPATION: pass `name` to a control for HTML form submission \u2014 Input/Textarea/NumberInput/Select submit natively; a searchable Select submits via a hidden input; DatePicker/TimePicker emit ISO strings (`yyyy-MM-dd` / 24h `HH:mm`); the range pickers emit `${name}_from` / `${name}_to`. `required`/`readOnly`/`disabled` map to the underlying control. Cascader/TreeSelect/Transfer submit named values via hidden inputs; Upload appends staged local files to FormData when named. Disabled controls are excluded.","ERROR TIMING & RECOVERY: pass `error` only after a field is dirty or the form is submitted (don't show errors on pristine mount). The error node renders with `role='alert'` so it is announced live the moment it appears; clearing `error` (e.g. after the user corrects the value or a server round-trip succeeds) removes aria-invalid and restores the helper. On submit, focus the first invalid control and/or render an error summary that links to each field by `id`."],useCases:["Labelling a text `Input` or `Textarea` in an invoice-entry form, showing a red asterisk for required fields and surfacing server validation errors returned from a Laravel FormRequest.","Wrapping a `Select` or `DatePicker` inside a multi-field filter panel where each control needs a visible label, helper hint (e.g. 'YYYY/MM/DD'), and inline error state.","Adding a `labelAddon` tooltip button next to a 'Tax rate' label in an accounting form to explain when different rates apply, without breaking the label\u2013control association.","Enclosing a `DatePicker range` or `TimePicker` in an admin settings page where the field needs a label, a muted hint ('Inclusive of start and end date'), and conditional error display.","Wrapping a `Select` (with `showSearch`) control for vendor/account lookup in a journal-entry form where the `id` must be kept consistent for programmatic focus management.","Providing structured error feedback for a `Cascader` or `TreeSelect` in a multi-level category assignment screen, replacing ad-hoc error rendering with the standardised `role='alert'` pattern."],related:["Label \u2014 the bare label component. Use directly only when you are building a fully custom layout that cannot accept FormField's stack wrapper, and you will manage aria-describedby/aria-invalid yourself. FormField is always preferred for standard form controls.",'Field \u2014 the inline row for a boolean control: label and control side by side, with `labelAddon`, `description` and `error` (gh#812 added the last two slots; `error` wires aria-invalid / aria-errormessage / aria-describedby onto the control, so a validated boolean no longer has to be hand-wired). It still renders NO hidden `<input name>` \u2014 `Switch name="\u2026"` submits itself \u2014 and it has no `required`, `helper`, error-bag `name` binding or layout/width knobs. Still: never wrap a bare `Switch` in FormField.',"Field \u2014 pairs a single checkbox or radio with a label and optional description in a horizontal layout (control beside text). Use Field instead of FormField when the control and its label sit side-by-side rather than stacked.","CheckboxGroup / RadioGroup \u2014 for groups of options where FormField is not needed per-item; the group component handles its own legend/label and option layout."],example:`import { FormField, Input } from "@godxjp/ui/data-entry";
996
996
 
997
997
  <FormField id="coupon-name" label="\u30AF\u30FC\u30DD\u30F3\u540D" required error={errors.name} helper="\u6700\u592750\u6587\u5B57">
998
998
  <Input id="coupon-name" placeholder="\u6625\u306E\u82B1\u7C89\u75C7\u5BFE\u7B5615%OFF" value={name} onValueChange={(v) => setName(v)} />
@@ -1264,7 +1264,7 @@ function CreateDialog() {
1264
1264
  setOpen(false);
1265
1265
  }}
1266
1266
  variant="destructive"
1267
- />`,storyPath:"feedback/alert-dialog.tsx",rules:[23,3]},{name:"Sheet",subParts:["SheetBody","SheetClose","SheetContent","SheetDescription","SheetFooter","SheetHeader","SheetOverlay","SheetPortal","SheetTitle","SheetTrigger"],group:"feedback",tagline:"Side-panel drawer / responsive detail panel (React Aria modal dialog). Parts: Sheet/SheetTrigger/SheetContent(side=right|left|top|bottom, responsive=auto|side|bottom)/SheetHeader/SheetBody/SheetTitle/SheetFooter.",props:[{name:"open",type:"boolean",description:"Controlled open state."},{name:"onOpenChange",type:"(open: boolean) => void",description:"Open-state change handler."},{name:"modal",type:"boolean",defaultValue:"true",description:"On Sheet (root). `false` renders a NON-MODAL sheet (WAI-ARIA APG allows non-modal dialogs): the page behind stays interactive and in the accessibility tree (no inert/aria-hidden), no scroll lock, no scrim, an outside press does NOT close it, and there is no `aria-modal`. The panel keeps role=dialog + its title as name, and the same side placement, width, responsive presentation and tokens. Focus moves into it on open, Tab can leave it, Escape closes it while focus is inside, and focus returns to the trigger on close (only if focus was still inside). Same contract as Dialog `modal={false}`. gh#701."},{name:"width",type:"number | string",description:"On SheetContent (side left/right): desired panel width (number\u2192px). Default w-3/4 sm:max-w-md."},{name:"onCloseAutoFocus",type:"(event: Event) => void",description:"On SheetContent (same name as on DialogContent): fires on every close before focus returns to the trigger. Call event.preventDefault() and focus your own target (e.g. the new page's heading after a drawer navigation) to send focus there instead (gh#1134)."},{name:"responsive",type:'"auto" | "side" | "bottom"',defaultValue:'"side"',description:'On SheetContent: the responsive drawer / detail-panel contract. "side" (default) always renders the physical `side` you named. "auto" renders the desktop side panel above --sheet-responsive-breakpoint-width (48rem/768px) and the mobile BOTTOM sheet at/below it, capped by --sheet-bottom-max-height (85dvh). "bottom" pins the bottom-sheet presentation.'},{name:"title / subtitle / extra / tone",type:"ReactNode / ReactNode / ReactNode / ToneProp",description:"On SheetHeader (Ant-style): title (\u2192 SheetTitle, accessible name), subtitle (\u2192 SheetDescription), right-aligned extra actions, and a soft semantic `tone` background band. Children still supported."}],usage:["DO build the panel with SheetHeader (pass `title`/`subtitle`/`extra`/`tone` OR children) > SheetBody (scrollable, ring-safe) > SheetFooter (pinned). SheetTitle is required for a11y \u2014 the `title` prop renders it for you. Never skip the title.","DO set `width` on SheetContent for a wider/narrower panel (e.g. width={480}); it caps at the viewport so small screens still get a full-width panel.",'DO use responsive="auto" for a record detail panel / drawer that must be a desktop side panel and a mobile bottom sheet \u2014 ONE <Sheet>, no page-local media query. The breakpoint is the --sheet-responsive-breakpoint-width token, so a service moves the line once for every overlay. `width` is ignored while the bottom presentation is active (a bottom sheet is full-bleed).',`DON'T hardcode an overlay breakpoint in app code (useMediaQuery("(max-width: 390px)")). If a composite must swap a desktop surface for a mobile sheet (a Popover\u2192Sheet switcher, for example), call the exported useSheetResponsiveMode("auto") hook so it reads the same themeable token.`,"DO use all named sub-parts in order: Sheet (root) > SheetTrigger (opener) > SheetContent (panel) > SheetHeader > SheetTitle (required for a11y \u2014 it is the dialog's heading, announced as the accessible name) > optional SheetDescription > body content > SheetFooter. Never skip SheetTitle inside an open SheetContent.","DO control state explicitly with open + onOpenChange on Sheet root when you need to close programmatically (e.g. after form submit). Uncontrolled (no props) works for simple trigger-only cases but gives you no hook to reset form state on close.","DO use SheetTrigger asChild to wrap a Button or other interactive element \u2014 this avoids a nested <button> in the DOM. Never render a raw <button> as a direct child of SheetTrigger.","DO wrap a long/scrolling body in SheetBody (between SheetHeader and a pinned SheetFooter). It is the ring-safe scroll slot: a hand-rolled <div className='overflow-y-auto'> clips the 3px focus ring of a full-width Input/Select at the scroll edges \u2014 SheetBody insets the content so the ring never clips.","DO use SheetFooter (renders at the bottom via mt-auto, symmetric 16/24 padding, full-bleed top border) for primary/cancel action Buttons. Never float action Buttons inside the body \u2014 they will not stick to the panel bottom.",'DO put one <form> around SheetBody + SheetFooter when the footer holds the submit button (`<Form asChild errors={\u2026}><form onSubmit={\u2026}><SheetBody>\u2026</SheetBody><SheetFooter><Button type="submit">\u2026</Button></SheetFooter></form></Form>`). A <form> that wraps SheetBody is transparent to the panel layout (same in Dialog), so the body still scrolls and the footer stays pinned (gh#1239); no className on the form is needed.',"DON'T set showCloseButton={false} on SheetContent unless you provide your own SheetClose element; omitting both leaves users with no keyboard-accessible close path and breaks a11y.","DO set `modal={false}` on Sheet when the user must keep working on the page behind the open panel (edit a list while a detail panel stays open). Control `open` yourself: an outside press no longer closes it, so keep the \u2715 or a footer close action. Escape closes it only while focus is inside the panel.","DON'T put a Sheet inside a Dialog (nested modal overlays conflict). If you need a slide-over triggered from within a modal, close the Dialog first, then open the Sheet."],useCases:["Filter/search panel: slide in from the right with filter FormFields (Select, `DatePicker range`, CheckboxGroup) that affect a DataTable \u2014 preferred over a Dialog because filters do not require confirmation and benefit from seeing the table behind the overlay.","Quick-edit drawer: open an entity's editable fields (e.g. invoice line items, account settings) without navigating away, with Save/Cancel in SheetFooter \u2014 use side='right' and keep the main page visible as context.","Detail peek panel: show read-only Descriptions / Timeline of a selected record (e.g. a journal entry or invoice) from a DataTable row click, using side='right' with showCloseButton={true}. Add responsive='auto' so the same panel becomes a bottom sheet on a phone instead of a 100%-wide slab.","Non-modal side panel: `modal={false}` keeps a list behind the sheet editable while the panel stays open (change order lines while their running total stays visible in the panel).","Mobile-first navigation drawer: side='left' sheet acting as a slide-in nav menu on small viewports when the AppShell Sidebar is hidden \u2014 triggered by a hamburger Button.","Step-by-step wizard side panel: multi-step form (Steps component inside SheetContent) for onboarding or import flows where full-page navigation would lose list context."],related:["Dialog \u2014 use Dialog (centered modal) when the action is destructive, requires full user focus, or needs a confirm/alertdialog (mode='confirm'). Use Sheet when the user benefits from seeing the page content behind the slide-over (filters, detail peek, quick-edit).","Toolbar/ToolbarGroup \u2014 use Toolbar for inline persistent filter controls above a DataTable (no overlay). Use Sheet when the filter set is large (>4 controls) or on mobile where inline controls collapse poorly.","Popover \u2014 use Popover for lightweight, anchor-positioned context menus or single-control overlays (date picker, color picker). Use Sheet when the panel has a header, multiple fields, or footer actions that need a dedicated panel.","SplitPane \u2014 use SplitPane for a persistent side-by-side layout where both panes are always visible. Use Sheet when the secondary panel is transient and should overlay the primary content."],example:`import { Sheet, SheetTrigger, SheetContent, SheetHeader, SheetTitle } from "@godxjp/ui/feedback";
1267
+ />`,storyPath:"feedback/alert-dialog.tsx",rules:[23,3]},{name:"Sheet",subParts:["SheetBody","SheetClose","SheetContent","SheetDescription","SheetFooter","SheetHeader","SheetOverlay","SheetPortal","SheetTitle","SheetTrigger"],group:"feedback",tagline:"Side-panel drawer / responsive detail panel (React Aria modal dialog). Parts: Sheet/SheetTrigger/SheetContent(side=right|left|top|bottom, responsive=auto|side|bottom)/SheetHeader/SheetBody/SheetTitle/SheetFooter.",props:[{name:"open",type:"boolean",description:"Controlled open state."},{name:"onOpenChange",type:"(open: boolean) => void",description:"Open-state change handler."},{name:"modal",type:"boolean",defaultValue:"true",description:"On Sheet (root). `false` renders a NON-MODAL sheet (WAI-ARIA APG allows non-modal dialogs): the page behind stays interactive and in the accessibility tree (no inert/aria-hidden), no scroll lock, no scrim, an outside press does NOT close it, and there is no `aria-modal`. The panel keeps role=dialog + its title as name, and the same side placement, width, responsive presentation and tokens. Focus moves into it on open, Tab can leave it, Escape closes it while focus is inside, and focus returns to the trigger on close (only if focus was still inside). Same contract as Dialog `modal={false}`. gh#701."},{name:"width",type:"WidthProp",description:"On SheetContent (side left/right): desired panel width (number\u2192px). Default w-3/4 sm:max-w-md."},{name:"onCloseAutoFocus",type:"(event: Event) => void",description:"On SheetContent (same name as on DialogContent): fires on every close before focus returns to the trigger. Call event.preventDefault() and focus your own target (e.g. the new page's heading after a drawer navigation) to send focus there instead (gh#1134)."},{name:"responsive",type:'"auto" | "side" | "bottom"',defaultValue:'"side"',description:'On SheetContent: the responsive drawer / detail-panel contract. "side" (default) always renders the physical `side` you named. "auto" renders the desktop side panel above --sheet-responsive-breakpoint-width (48rem/768px) and the mobile BOTTOM sheet at/below it, capped by --sheet-bottom-max-height (85dvh). "bottom" pins the bottom-sheet presentation.'},{name:"title / subtitle / extra / tone",type:"ReactNode / ReactNode / ReactNode / ToneProp",description:"On SheetHeader (Ant-style): title (\u2192 SheetTitle, accessible name), subtitle (\u2192 SheetDescription), right-aligned extra actions, and a soft semantic `tone` background band. Children still supported."}],usage:["DO build the panel with SheetHeader (pass `title`/`subtitle`/`extra`/`tone` OR children) > SheetBody (scrollable, ring-safe) > SheetFooter (pinned). SheetTitle is required for a11y \u2014 the `title` prop renders it for you. Never skip the title.","DO set `width` on SheetContent for a wider/narrower panel (e.g. width={480}); it caps at the viewport so small screens still get a full-width panel.",'DO use responsive="auto" for a record detail panel / drawer that must be a desktop side panel and a mobile bottom sheet \u2014 ONE <Sheet>, no page-local media query. The breakpoint is the --sheet-responsive-breakpoint-width token, so a service moves the line once for every overlay. `width` is ignored while the bottom presentation is active (a bottom sheet is full-bleed).',`DON'T hardcode an overlay breakpoint in app code (useMediaQuery("(max-width: 390px)")). If a composite must swap a desktop surface for a mobile sheet (a Popover\u2192Sheet switcher, for example), call the exported useSheetResponsiveMode("auto") hook so it reads the same themeable token.`,"DO use all named sub-parts in order: Sheet (root) > SheetTrigger (opener) > SheetContent (panel) > SheetHeader > SheetTitle (required for a11y \u2014 it is the dialog's heading, announced as the accessible name) > optional SheetDescription > body content > SheetFooter. Never skip SheetTitle inside an open SheetContent.","DO control state explicitly with open + onOpenChange on Sheet root when you need to close programmatically (e.g. after form submit). Uncontrolled (no props) works for simple trigger-only cases but gives you no hook to reset form state on close.","DO use SheetTrigger asChild to wrap a Button or other interactive element \u2014 this avoids a nested <button> in the DOM. Never render a raw <button> as a direct child of SheetTrigger.","DO wrap a long/scrolling body in SheetBody (between SheetHeader and a pinned SheetFooter). It is the ring-safe scroll slot: a hand-rolled <div className='overflow-y-auto'> clips the 3px focus ring of a full-width Input/Select at the scroll edges \u2014 SheetBody insets the content so the ring never clips.","DO use SheetFooter (renders at the bottom via mt-auto, symmetric 16/24 padding, full-bleed top border) for primary/cancel action Buttons. Never float action Buttons inside the body \u2014 they will not stick to the panel bottom.",'DO put one <form> around SheetBody + SheetFooter when the footer holds the submit button (`<Form asChild errors={\u2026}><form onSubmit={\u2026}><SheetBody>\u2026</SheetBody><SheetFooter><Button type="submit">\u2026</Button></SheetFooter></form></Form>`). A <form> that wraps SheetBody is transparent to the panel layout (same in Dialog), so the body still scrolls and the footer stays pinned (gh#1239); no className on the form is needed.',"DON'T set showCloseButton={false} on SheetContent unless you provide your own SheetClose element; omitting both leaves users with no keyboard-accessible close path and breaks a11y.","DO set `modal={false}` on Sheet when the user must keep working on the page behind the open panel (edit a list while a detail panel stays open). Control `open` yourself: an outside press no longer closes it, so keep the \u2715 or a footer close action. Escape closes it only while focus is inside the panel.","DON'T put a Sheet inside a Dialog (nested modal overlays conflict). If you need a slide-over triggered from within a modal, close the Dialog first, then open the Sheet."],useCases:["Filter/search panel: slide in from the right with filter FormFields (Select, `DatePicker range`, CheckboxGroup) that affect a DataTable \u2014 preferred over a Dialog because filters do not require confirmation and benefit from seeing the table behind the overlay.","Quick-edit drawer: open an entity's editable fields (e.g. invoice line items, account settings) without navigating away, with Save/Cancel in SheetFooter \u2014 use side='right' and keep the main page visible as context.","Detail peek panel: show read-only Descriptions / Timeline of a selected record (e.g. a journal entry or invoice) from a DataTable row click, using side='right' with showCloseButton={true}. Add responsive='auto' so the same panel becomes a bottom sheet on a phone instead of a 100%-wide slab.","Non-modal side panel: `modal={false}` keeps a list behind the sheet editable while the panel stays open (change order lines while their running total stays visible in the panel).","Mobile-first navigation drawer: side='left' sheet acting as a slide-in nav menu on small viewports when the AppShell Sidebar is hidden \u2014 triggered by a hamburger Button.","Step-by-step wizard side panel: multi-step form (Steps component inside SheetContent) for onboarding or import flows where full-page navigation would lose list context."],related:["Dialog \u2014 use Dialog (centered modal) when the action is destructive, requires full user focus, or needs a confirm/alertdialog (mode='confirm'). Use Sheet when the user benefits from seeing the page content behind the slide-over (filters, detail peek, quick-edit).","Toolbar/ToolbarGroup \u2014 use Toolbar for inline persistent filter controls above a DataTable (no overlay). Use Sheet when the filter set is large (>4 controls) or on mobile where inline controls collapse poorly.","Popover \u2014 use Popover for lightweight, anchor-positioned context menus or single-control overlays (date picker, color picker). Use Sheet when the panel has a header, multiple fields, or footer actions that need a dedicated panel.","SplitPane \u2014 use SplitPane for a persistent side-by-side layout where both panes are always visible. Use Sheet when the secondary panel is transient and should overlay the primary content."],example:`import { Sheet, SheetTrigger, SheetContent, SheetHeader, SheetTitle } from "@godxjp/ui/feedback";
1268
1268
  import { Button } from "@godxjp/ui/general";
1269
1269
 
1270
1270
  <Sheet open={open} onOpenChange={setOpen}>
@@ -7981,7 +7981,7 @@ export default function Demo() {
7981
7981
  </PageContainer>
7982
7982
  );
7983
7983
  }
7984
- `};var p={name:"@godxjp/ui-mcp",version:"33.18.0",godxUiCompatibility:"33.18.x",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).",type:"module",main:"./dist/index.js",module:"./dist/index.js",types:"./dist/index.d.ts",bin:{"godx-ui-mcp":"./dist/index.js"},files:["dist","README.md"],publishConfig:{registry:"https://registry.npmjs.org/",access:"public"},repository:{type:"git",url:"git+https://github.com/godx-jp/godxjp-ui.git",directory:"mcp"},homepage:"https://github.com/godx-jp/godxjp-ui/tree/main/mcp#readme",license:"Apache-2.0",scripts:{build:"tsup",dev:"tsup --watch",start:"node dist/index.js",inspect:"npx @modelcontextprotocol/inspector node dist/index.js","type-check":"tsc --noEmit",test:"vitest run",prepublishOnly:"npm run build"},dependencies:{"@modelcontextprotocol/sdk":"^1.29.0",zod:"^4.4.3"},devDependencies:{"@types/node":"^22.10.0",tsup:"^8.5.1",typescript:"^6.0.3",vitest:"^4.1.6"},keywords:["mcp","model-context-protocol","godxjp","ui","design-system","react","claude","cursor"],author:"GoDX (https://godx.jp)",bugs:{url:"https://github.com/godx-jp/godxjp-ui/issues"}};var O=[{name:"list_skills",description:"List every design/taste skill bundled by this MCP (id + name + whenToUse + section ids). Use FIRST to discover skills; then `get_skill_section` to drill in.",inputSchema:{type:"object",properties:{}}},{name:"list_primitives",description:'List every @godxjp/ui primitive/composite/shell (group + tagline per entry). Optionally filter by group. Then `get_component` for one\'s full API. Core only by default \u2014 pass tier="lab" for the opt-in @godxjp/ui/lab components.',inputSchema:{type:"object",properties:{tier:{type:"string",enum:["core","lab","all"],description:'Default "core". "lab" lists the opt-in `@godxjp/ui/lab` components (niche, kept and tested, not in the default context); "all" lists both.'},group:{type:"string",enum:["general","layout","data-display","data-entry","feedback","navigation","composites","shell","providers"]}}}},{name:"list_utilities",description:'List every NON-component public export of @godxjp/ui \u2014 hooks, helper functions and constants (cn, formatDate, formatCurrency, toast, useDebouncedValue, buttonVariants, CHART_COLORS, SHOW_PARENT \u2026). Reach for this before hand-writing a className merger, a date/money formatter, a debounce hook or a chart palette: two products in this org each re-implemented `cn` because it could not be found. Optionally filter by kind. Then `get_component name="<name>"` for its signature, usage and example.',inputSchema:{type:"object",properties:{kind:{type:"string",enum:["hook","function","value"],description:"hook = only legal inside a component body; function = callable anywhere; value = a constant to read."}}}},{name:"list_patterns",description:"List every canonical copy-paste code pattern (signup-form, settings-page, data-table-page, async-data-state, confirm-destructive, \u2026); common aliases resolve too. Use before `get_pattern`.",inputSchema:{type:"object",properties:{}}},{name:"list_anti_ai_tells",description:"List every AI-tell pattern to AVOID (optionally by category). Use to self-audit a design before shipping; then `get_anti_ai_tell` for the fix.",inputSchema:{type:"object",properties:{category:{type:"string",enum:["visual","layout","copy","interaction","imagery","structure"]}}}},{name:"list_redesign_checks",description:"List the redesign audit checklist (50+ checks; optionally by category). Use when auditing an existing project; then `get_redesign_check` for a symptom's fix.",inputSchema:{type:"object",properties:{category:{type:"string",enum:["typography","color-surface","layout","interactivity","content","components","iconography","code-quality","omissions"]}}}},{name:"list_audit_rules",description:"List the LOCAL static ui-audit rules (scripts/ui-audit.mjs) to run BEFORE any visual review \u2014 each cites the standard it enforces (WCAG/WAI-ARIA/Intl/ISO/IANA/CSS-Logical) + a fix + the run command. Optionally by category.",inputSchema:{type:"object",properties:{category:{type:"string",enum:["tokens","composition","api","a11y","i18n","rtl","copy"]}}}},{name:"list_visual_checks",description:"List the RUNTIME visual-audit checks (scripts/visual-audit.mjs \u2014 Playwright + axe-core) to run against the RUNNING app: contrast/ARIA (axe), target size, rendered-accent chroma, DOM emoji, banner layout. Needs a browser (vs list_audit_rules, static). Optionally by category.",inputSchema:{type:"object",properties:{category:{type:"string",enum:["a11y","color","i18n","layout"]}}}},{name:"get_anti_ai_tell",description:"Fetch ONE anti-AI-tell \u2014 full body + concrete fix. Use after `list_anti_ai_tells`.",inputSchema:{type:"object",properties:{name:{type:"string",description:"Exact tell name from list_anti_ai_tells."}},required:["name"]}},{name:"get_redesign_check",description:"Fetch redesign check(s) matching a symptom snippet. Returns full fix + UI note. Use after `list_redesign_checks`.",inputSchema:{type:"object",properties:{symptom:{type:"string",description:"Fragment of the symptom text (e.g. 'Inter everywhere' / '100vh')."}},required:["symptom"]}},{name:"get_skill_section",description:"Fetch ONE section of ONE skill \u2014 token-efficient. E.g. `skill='soft', section='double-bezel'`. Use after `list_skills` narrowed the relevant skill + section.",inputSchema:{type:"object",properties:{skill:{type:"string",description:"Skill id (e.g. 'soft', 'minimalist', 'taste')."},section:{type:"string",description:"Section id within that skill."}},required:["skill","section"]}},{name:"get_component",description:"Full guide for one @godxjp/ui component \u2014 import path, props/types/defaults, HOW to use it (DO/DON'T), WHEN to reach for it (use cases), related components (don't reinvent/confuse), a copy-paste example, story path, and cardinal rules. Use this before hand-rolling anything. Design-token knobs are listed compactly (name+default); pass `verbose:true` for what each token controls.",inputSchema:{type:"object",properties:{name:{type:"string",description:"Component name (e.g. 'Button', 'DataTable')."},verbose:{type:"boolean",description:"Include the full design-token table with a 'what it controls' description per token. Default false (compact token+default only) to save context."}},required:["name"]}},{name:"get_pattern",description:"Full code snippet for one canonical pattern \u2014 copy-paste-ready.",inputSchema:{type:"object",properties:{name:{type:"string",description:"Pattern slug (use list_patterns first)."}},required:["name"]}},{name:"get_rule",description:"Read one cardinal rule from CLAUDE.md (by number) OR all if no number.",inputSchema:{type:"object",properties:{number:{type:"number",description:"Rule number (1-N)."}}}},{name:"get_vocab",description:"Read shared prop-vocabulary type (`SizeProp`, `StatusProp`, `ColorProp`, `LoadingProp`, etc.) OR all if no name.",inputSchema:{type:"object",properties:{name:{type:"string",description:"Vocab type name."}}}},{name:"get_tokens",description:"Read design tokens, optionally filtered by tier category (primitive / semantic / component).",inputSchema:{type:"object",properties:{category:{type:"string",enum:["primitive","semantic","component"]}}}},{name:"list_consumer_skills",description:"List the design skills relevant to an app-dev BUILDING WITH @godxjp/ui (audience consumer/both). Hides core library-maintenance skills. START HERE if you import @godxjp/ui and want guidance (design-to-page, compose-a-screen, taste, \u2026). Returns id + name + whenToUse + section ids.",inputSchema:{type:"object",properties:{}}},{name:"get_consumer_skill",description:"Fetch ONE section of ONE consumer-facing skill. Same as get_skill_section but refuses core-only skills (steers app-devs away from library-maintenance material). Use after list_consumer_skills / route_consumer_task.",inputSchema:{type:"object",properties:{skill:{type:"string",description:"Consumer skill id (e.g. 'design-to-page', 'compose-a-screen')."},section:{type:"string",description:"Section id within that skill."}},required:["skill"]}},{name:"route_consumer_task",description:"Natural-language task \u2192 consumer skill+section pointer. Like route_task but only points to consumer-facing skills (never core library-maintenance). Use FIRST when you're building an app with @godxjp/ui.",inputSchema:{type:"object",properties:{task:{type:"string",description:"Describe what you want to build."}},required:["task"]}},{name:"draft_bug_report",description:"When @godxjp/ui ITSELF is at fault (missing token, a primitive lacking the controlled-vocabulary prop, a real a11y/behaviour bug, a wrong catalog example) and you cannot follow a rule \u2014 DON'T fake a workaround. This drafts a detailed GitHub issue body + a copy-paste `gh issue create` command so you can report it. Prints the command only; never runs gh.",inputSchema:{type:"object",properties:{summary:{type:"string",description:"One-line title of the bug / blocked rule."},repro:{type:"string",description:"Minimal steps or code to reproduce."},expected:{type:"string",description:"What SHOULD happen (per the rule/spec)."},actual:{type:"string",description:"What actually happens."},component:{type:"string",description:"Affected component name, if any (links to get_component)."},rule:{type:"number",description:"Cardinal rule number that can't be followed, if any."},version:{type:"string",description:"Installed @godxjp/ui version (e.g. '12.1.0')."},env:{type:"string",description:"Environment (browser/OS/framework), if relevant."}},required:["summary"]}},{name:"check_compatibility",description:"Report whether the @godxjp/ui version installed in the target project matches THIS catalog (which describes one release train). A mismatched minor means the props/tokens/patterns may describe a build they never installed (#140). Pass the installed version (`npm ls @godxjp/ui`); call it at the START of a consumer session.",inputSchema:{type:"object",properties:{version:{type:"string",description:"Installed @godxjp/ui version in the target project, e.g. '16.10.0'. Omit to just read the catalog's own version + compatible range."}}}},{name:"route_task",description:"Natural-language task \u2192 skill+section pointer (e.g. 'design a premium agency hero' \u2192 soft/vibe-archetypes). Use FIRST when you don't know which skill applies.",inputSchema:{type:"object",properties:{task:{type:"string",description:"Describe what you want to build."}},required:["task"]}},{name:"suggest_primitive",description:"Use case \u2192 primitive recommendation. E.g. 'confirm a destructive delete' \u2192 DangerZone pattern + Dialog suggestion.",inputSchema:{type:"object",properties:{use_case:{type:"string"}},required:["use_case"]}},{name:"search_components",description:'Fuzzy-search primitives by name / tagline / prop. Returns ranked matches. Core only by default; pass tier="lab" or "all" to include the opt-in @godxjp/ui/lab components.',inputSchema:{type:"object",properties:{query:{type:"string"},tier:{type:"string",enum:["core","lab","all"],description:'Default "core". "lab" lists the opt-in `@godxjp/ui/lab` components (niche, kept and tested, not in the default context); "all" lists both.'}},required:["query"]}},{name:"get_frame_coverage",description:"Verified preview-contract coverage for a component (issue #163). Answers 'is this state actually PROVEN?' \u2014 returns, per contract dimension (variants, tones, sizes, shapes, density, controlled/uncontrolled ownership, disabled/read-only/loading/empty/error/success, async retry/cancel/offline, responsive viewport matrix, RTL, long/localized content, keyboard/focus, accessible name/description/error, reduced motion / coarse touch), whether an EXECUTED case proves it (covered), whether nothing proves it (UNTESTED), or whether it cannot exist (not-applicable, with a reason). UNTESTED IS NOT A PASS: never infer that a component supports a state because an example renders. Call this before telling a user a component 'supports' anything. Omit `name` for the repo-wide summary and the tracked known gaps.",inputSchema:{type:"object",properties:{name:{type:"string",description:"Public export name (e.g. 'Button', 'DataTable', 'CardFooter'). Omit for the repo-wide coverage summary."}}}},{name:"get_design",description:"DESIGN.md \u2014 the visual spec for screens built with @godxjp/ui: real tokens (YAML front matter), colour scarcity rules, typography, layout & density, elevation, components, ADMIN SCREEN ANATOMY (list / detail / form / settings / dashboard / approval queue), do's and don'ts, responsive, iteration guide, known gaps. Read before composing a screen. Pass `section` for one section; omit it for the whole document (~12 KB).",inputSchema:{type:"object",properties:{section:{type:"string",description:"Section id or heading word, e.g. 'tokens', 'colors', 'admin-screen-anatomy', 'dos-and-donts', 'iteration-guide'. Unknown ids list the valid ones."}}}},{name:"get_exemplar",description:"A reference screen to match for an admin archetype: its anatomy notes from DESIGN.md, the full source of the showcase built from real @godxjp/ui primitives, and its live preview URL for screenshot comparison. Archetypes: "+E.map(e=>e.archetype).join(", ")+". Omit `archetype` to list them.",inputSchema:{type:"object",properties:{archetype:{type:"string",description:E.map(e=>e.archetype).join(" | ")+" (aliases: "+E.flatMap(e=>e.aliases??[]).join(", ")+")."}}}},{name:"lint_jsx",description:"Heuristic check of a JSX snippet for common violations \u2014 raw `<button>` / `<input>`, `color='error'` on Tag/Badge, missing aria-label, missing source.code override on stories with cell renderers (rule 34), etc.",inputSchema:{type:"object",properties:{jsx:{type:"string"}},required:["jsx"]}}],Ze=new Set(O.map(e=>e.name));function et(e=X()){let t=p.godxUiCompatibility??p.version,a=`@godxjp/ui-mcp ${p.version} (catalog for @godxjp/ui ${t})`;if(!e)return a;let n=e.source==="node_modules"?"read from node_modules at answer time":"from GODX_UI_VERSION at launch \u2014 node_modules/@godxjp/ui not resolved";return`${a} \u2014 installed @godxjp/ui ${e.version} (${n})`}function tt(e=X()){let t=e?V(e.version):null,a=V(p.version);return!e||!t||!a?null:dt(t,a)>0?`\u26A0\uFE0F SERVER OLDER THAN INSTALLED PACKAGE: this server is @godxjp/ui-mcp ${p.version}, the project has @godxjp/ui ${e.version} installed \u2014 this catalog is BEHIND the package and may be missing props and components that exist. Do not conclude from this answer that a prop is unavailable. Restart the session so the server relaunches on the installed version (run \`npx @godxjp/ui sync-rules\` first if the project's .mcp.json still pins an older @godxjp/ui-mcp).`:t.major===a.major?null:`\u26A0\uFE0F MAJOR MISMATCH: this server is @godxjp/ui-mcp ${p.version}, the project has @godxjp/ui ${e.version} installed \u2014 this catalog may describe components that do not exist in the installed package. Pin the MCP to @godxjp/ui-mcp@${e.version} (\`npx @godxjp/ui sync-rules\` updates the project's .mcp.json; a registration outside the project needs \`claude mcp remove <key>\`), then restart the agent.`}async function G(e,t){let a=await at(e,t);if(!Ze.has(e))return a;let n=X(),o=tt(n);return`${et(n)}
7984
+ `};var p={name:"@godxjp/ui-mcp",version:"33.19.0",godxUiCompatibility:"33.19.x",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).",type:"module",main:"./dist/index.js",module:"./dist/index.js",types:"./dist/index.d.ts",bin:{"godx-ui-mcp":"./dist/index.js"},files:["dist","README.md"],publishConfig:{registry:"https://registry.npmjs.org/",access:"public"},repository:{type:"git",url:"git+https://github.com/godx-jp/godxjp-ui.git",directory:"mcp"},homepage:"https://github.com/godx-jp/godxjp-ui/tree/main/mcp#readme",license:"Apache-2.0",scripts:{build:"tsup",dev:"tsup --watch",start:"node dist/index.js",inspect:"npx @modelcontextprotocol/inspector node dist/index.js","type-check":"tsc --noEmit",test:"vitest run",prepublishOnly:"npm run build"},dependencies:{"@modelcontextprotocol/sdk":"^1.29.0",zod:"^4.4.3"},devDependencies:{"@types/node":"^22.10.0",tsup:"^8.5.1",typescript:"^6.0.3",vitest:"^4.1.6"},keywords:["mcp","model-context-protocol","godxjp","ui","design-system","react","claude","cursor"],author:"GoDX (https://godx.jp)",bugs:{url:"https://github.com/godx-jp/godxjp-ui/issues"}};var O=[{name:"list_skills",description:"List every design/taste skill bundled by this MCP (id + name + whenToUse + section ids). Use FIRST to discover skills; then `get_skill_section` to drill in.",inputSchema:{type:"object",properties:{}}},{name:"list_primitives",description:'List every @godxjp/ui primitive/composite/shell (group + tagline per entry). Optionally filter by group. Then `get_component` for one\'s full API. Core only by default \u2014 pass tier="lab" for the opt-in @godxjp/ui/lab components.',inputSchema:{type:"object",properties:{tier:{type:"string",enum:["core","lab","all"],description:'Default "core". "lab" lists the opt-in `@godxjp/ui/lab` components (niche, kept and tested, not in the default context); "all" lists both.'},group:{type:"string",enum:["general","layout","data-display","data-entry","feedback","navigation","composites","shell","providers"]}}}},{name:"list_utilities",description:'List every NON-component public export of @godxjp/ui \u2014 hooks, helper functions and constants (cn, formatDate, formatCurrency, toast, useDebouncedValue, buttonVariants, CHART_COLORS, SHOW_PARENT \u2026). Reach for this before hand-writing a className merger, a date/money formatter, a debounce hook or a chart palette: two products in this org each re-implemented `cn` because it could not be found. Optionally filter by kind. Then `get_component name="<name>"` for its signature, usage and example.',inputSchema:{type:"object",properties:{kind:{type:"string",enum:["hook","function","value"],description:"hook = only legal inside a component body; function = callable anywhere; value = a constant to read."}}}},{name:"list_patterns",description:"List every canonical copy-paste code pattern (signup-form, settings-page, data-table-page, async-data-state, confirm-destructive, \u2026); common aliases resolve too. Use before `get_pattern`.",inputSchema:{type:"object",properties:{}}},{name:"list_anti_ai_tells",description:"List every AI-tell pattern to AVOID (optionally by category). Use to self-audit a design before shipping; then `get_anti_ai_tell` for the fix.",inputSchema:{type:"object",properties:{category:{type:"string",enum:["visual","layout","copy","interaction","imagery","structure"]}}}},{name:"list_redesign_checks",description:"List the redesign audit checklist (50+ checks; optionally by category). Use when auditing an existing project; then `get_redesign_check` for a symptom's fix.",inputSchema:{type:"object",properties:{category:{type:"string",enum:["typography","color-surface","layout","interactivity","content","components","iconography","code-quality","omissions"]}}}},{name:"list_audit_rules",description:"List the LOCAL static ui-audit rules (scripts/ui-audit.mjs) to run BEFORE any visual review \u2014 each cites the standard it enforces (WCAG/WAI-ARIA/Intl/ISO/IANA/CSS-Logical) + a fix + the run command. Optionally by category.",inputSchema:{type:"object",properties:{category:{type:"string",enum:["tokens","composition","api","a11y","i18n","rtl","copy"]}}}},{name:"list_visual_checks",description:"List the RUNTIME visual-audit checks (scripts/visual-audit.mjs \u2014 Playwright + axe-core) to run against the RUNNING app: contrast/ARIA (axe), target size, rendered-accent chroma, DOM emoji, banner layout. Needs a browser (vs list_audit_rules, static). Optionally by category.",inputSchema:{type:"object",properties:{category:{type:"string",enum:["a11y","color","i18n","layout"]}}}},{name:"get_anti_ai_tell",description:"Fetch ONE anti-AI-tell \u2014 full body + concrete fix. Use after `list_anti_ai_tells`.",inputSchema:{type:"object",properties:{name:{type:"string",description:"Exact tell name from list_anti_ai_tells."}},required:["name"]}},{name:"get_redesign_check",description:"Fetch redesign check(s) matching a symptom snippet. Returns full fix + UI note. Use after `list_redesign_checks`.",inputSchema:{type:"object",properties:{symptom:{type:"string",description:"Fragment of the symptom text (e.g. 'Inter everywhere' / '100vh')."}},required:["symptom"]}},{name:"get_skill_section",description:"Fetch ONE section of ONE skill \u2014 token-efficient. E.g. `skill='soft', section='double-bezel'`. Use after `list_skills` narrowed the relevant skill + section.",inputSchema:{type:"object",properties:{skill:{type:"string",description:"Skill id (e.g. 'soft', 'minimalist', 'taste')."},section:{type:"string",description:"Section id within that skill."}},required:["skill","section"]}},{name:"get_component",description:"Full guide for one @godxjp/ui component \u2014 import path, props/types/defaults, HOW to use it (DO/DON'T), WHEN to reach for it (use cases), related components (don't reinvent/confuse), a copy-paste example, story path, and cardinal rules. Use this before hand-rolling anything. Design-token knobs are listed compactly (name+default); pass `verbose:true` for what each token controls.",inputSchema:{type:"object",properties:{name:{type:"string",description:"Component name (e.g. 'Button', 'DataTable')."},verbose:{type:"boolean",description:"Include the full design-token table with a 'what it controls' description per token. Default false (compact token+default only) to save context."}},required:["name"]}},{name:"get_pattern",description:"Full code snippet for one canonical pattern \u2014 copy-paste-ready.",inputSchema:{type:"object",properties:{name:{type:"string",description:"Pattern slug (use list_patterns first)."}},required:["name"]}},{name:"get_rule",description:"Read one cardinal rule from CLAUDE.md (by number) OR all if no number.",inputSchema:{type:"object",properties:{number:{type:"number",description:"Rule number (1-N)."}}}},{name:"get_vocab",description:"Read shared prop-vocabulary type (`SizeProp`, `StatusProp`, `ColorProp`, `LoadingProp`, etc.) OR all if no name.",inputSchema:{type:"object",properties:{name:{type:"string",description:"Vocab type name."}}}},{name:"get_tokens",description:"Read design tokens, optionally filtered by tier category (primitive / semantic / component).",inputSchema:{type:"object",properties:{category:{type:"string",enum:["primitive","semantic","component"]}}}},{name:"list_consumer_skills",description:"List the design skills relevant to an app-dev BUILDING WITH @godxjp/ui (audience consumer/both). Hides core library-maintenance skills. START HERE if you import @godxjp/ui and want guidance (design-to-page, compose-a-screen, taste, \u2026). Returns id + name + whenToUse + section ids.",inputSchema:{type:"object",properties:{}}},{name:"get_consumer_skill",description:"Fetch ONE section of ONE consumer-facing skill. Same as get_skill_section but refuses core-only skills (steers app-devs away from library-maintenance material). Use after list_consumer_skills / route_consumer_task.",inputSchema:{type:"object",properties:{skill:{type:"string",description:"Consumer skill id (e.g. 'design-to-page', 'compose-a-screen')."},section:{type:"string",description:"Section id within that skill."}},required:["skill"]}},{name:"route_consumer_task",description:"Natural-language task \u2192 consumer skill+section pointer. Like route_task but only points to consumer-facing skills (never core library-maintenance). Use FIRST when you're building an app with @godxjp/ui.",inputSchema:{type:"object",properties:{task:{type:"string",description:"Describe what you want to build."}},required:["task"]}},{name:"draft_bug_report",description:"When @godxjp/ui ITSELF is at fault (missing token, a primitive lacking the controlled-vocabulary prop, a real a11y/behaviour bug, a wrong catalog example) and you cannot follow a rule \u2014 DON'T fake a workaround. This drafts a detailed GitHub issue body + a copy-paste `gh issue create` command so you can report it. Prints the command only; never runs gh.",inputSchema:{type:"object",properties:{summary:{type:"string",description:"One-line title of the bug / blocked rule."},repro:{type:"string",description:"Minimal steps or code to reproduce."},expected:{type:"string",description:"What SHOULD happen (per the rule/spec)."},actual:{type:"string",description:"What actually happens."},component:{type:"string",description:"Affected component name, if any (links to get_component)."},rule:{type:"number",description:"Cardinal rule number that can't be followed, if any."},version:{type:"string",description:"Installed @godxjp/ui version (e.g. '12.1.0')."},env:{type:"string",description:"Environment (browser/OS/framework), if relevant."}},required:["summary"]}},{name:"check_compatibility",description:"Report whether the @godxjp/ui version installed in the target project matches THIS catalog (which describes one release train). A mismatched minor means the props/tokens/patterns may describe a build they never installed (#140). Pass the installed version (`npm ls @godxjp/ui`); call it at the START of a consumer session.",inputSchema:{type:"object",properties:{version:{type:"string",description:"Installed @godxjp/ui version in the target project, e.g. '16.10.0'. Omit to just read the catalog's own version + compatible range."}}}},{name:"route_task",description:"Natural-language task \u2192 skill+section pointer (e.g. 'design a premium agency hero' \u2192 soft/vibe-archetypes). Use FIRST when you don't know which skill applies.",inputSchema:{type:"object",properties:{task:{type:"string",description:"Describe what you want to build."}},required:["task"]}},{name:"suggest_primitive",description:"Use case \u2192 primitive recommendation. E.g. 'confirm a destructive delete' \u2192 DangerZone pattern + Dialog suggestion.",inputSchema:{type:"object",properties:{use_case:{type:"string"}},required:["use_case"]}},{name:"search_components",description:'Fuzzy-search primitives by name / tagline / prop. Returns ranked matches. Core only by default; pass tier="lab" or "all" to include the opt-in @godxjp/ui/lab components.',inputSchema:{type:"object",properties:{query:{type:"string"},tier:{type:"string",enum:["core","lab","all"],description:'Default "core". "lab" lists the opt-in `@godxjp/ui/lab` components (niche, kept and tested, not in the default context); "all" lists both.'}},required:["query"]}},{name:"get_frame_coverage",description:"Verified preview-contract coverage for a component (issue #163). Answers 'is this state actually PROVEN?' \u2014 returns, per contract dimension (variants, tones, sizes, shapes, density, controlled/uncontrolled ownership, disabled/read-only/loading/empty/error/success, async retry/cancel/offline, responsive viewport matrix, RTL, long/localized content, keyboard/focus, accessible name/description/error, reduced motion / coarse touch), whether an EXECUTED case proves it (covered), whether nothing proves it (UNTESTED), or whether it cannot exist (not-applicable, with a reason). UNTESTED IS NOT A PASS: never infer that a component supports a state because an example renders. Call this before telling a user a component 'supports' anything. Omit `name` for the repo-wide summary and the tracked known gaps.",inputSchema:{type:"object",properties:{name:{type:"string",description:"Public export name (e.g. 'Button', 'DataTable', 'CardFooter'). Omit for the repo-wide coverage summary."}}}},{name:"get_design",description:"DESIGN.md \u2014 the visual spec for screens built with @godxjp/ui: real tokens (YAML front matter), colour scarcity rules, typography, layout & density, elevation, components, ADMIN SCREEN ANATOMY (list / detail / form / settings / dashboard / approval queue), do's and don'ts, responsive, iteration guide, known gaps. Read before composing a screen. Pass `section` for one section; omit it for the whole document (~12 KB).",inputSchema:{type:"object",properties:{section:{type:"string",description:"Section id or heading word, e.g. 'tokens', 'colors', 'admin-screen-anatomy', 'dos-and-donts', 'iteration-guide'. Unknown ids list the valid ones."}}}},{name:"get_exemplar",description:"A reference screen to match for an admin archetype: its anatomy notes from DESIGN.md, the full source of the showcase built from real @godxjp/ui primitives, and its live preview URL for screenshot comparison. Archetypes: "+E.map(e=>e.archetype).join(", ")+". Omit `archetype` to list them.",inputSchema:{type:"object",properties:{archetype:{type:"string",description:E.map(e=>e.archetype).join(" | ")+" (aliases: "+E.flatMap(e=>e.aliases??[]).join(", ")+")."}}}},{name:"lint_jsx",description:"Heuristic check of a JSX snippet for common violations \u2014 raw `<button>` / `<input>`, `color='error'` on Tag/Badge, missing aria-label, missing source.code override on stories with cell renderers (rule 34), etc.",inputSchema:{type:"object",properties:{jsx:{type:"string"}},required:["jsx"]}}],Ze=new Set(O.map(e=>e.name));function et(e=X()){let t=p.godxUiCompatibility??p.version,a=`@godxjp/ui-mcp ${p.version} (catalog for @godxjp/ui ${t})`;if(!e)return a;let n=e.source==="node_modules"?"read from node_modules at answer time":"from GODX_UI_VERSION at launch \u2014 node_modules/@godxjp/ui not resolved";return`${a} \u2014 installed @godxjp/ui ${e.version} (${n})`}function tt(e=X()){let t=e?V(e.version):null,a=V(p.version);return!e||!t||!a?null:dt(t,a)>0?`\u26A0\uFE0F SERVER OLDER THAN INSTALLED PACKAGE: this server is @godxjp/ui-mcp ${p.version}, the project has @godxjp/ui ${e.version} installed \u2014 this catalog is BEHIND the package and may be missing props and components that exist. Do not conclude from this answer that a prop is unavailable. Restart the session so the server relaunches on the installed version (run \`npx @godxjp/ui sync-rules\` first if the project's .mcp.json still pins an older @godxjp/ui-mcp).`:t.major===a.major?null:`\u26A0\uFE0F MAJOR MISMATCH: this server is @godxjp/ui-mcp ${p.version}, the project has @godxjp/ui ${e.version} installed \u2014 this catalog may describe components that do not exist in the installed package. Pin the MCP to @godxjp/ui-mcp@${e.version} (\`npx @godxjp/ui sync-rules\` updates the project's .mcp.json; a registration outside the project needs \`claude mcp remove <key>\`), then restart the agent.`}async function G(e,t){let a=await at(e,t);if(!Ze.has(e))return a;let n=X(),o=tt(n);return`${et(n)}
7985
7985
  ${o?`${o}
7986
7986
  `:""}
7987
7987
  ${a}`}async function at(e,t){switch(e){case"list_skills":return it();case"list_primitives":return Pe(t.group,t.tier);case"list_utilities":return Tt(t.kind);case"list_patterns":return ut();case"list_anti_ai_tells":return bt(t.category);case"list_redesign_checks":return vt(t.category);case"list_audit_rules":return gt(t.category);case"list_visual_checks":return mt(t.category);case"get_anti_ai_tell":return ft(String(t.name??""));case"get_redesign_check":return yt(String(t.symptom??""));case"get_skill_section":return Le(String(t.skill??""),String(t.section??""));case"get_component":return St(String(t.name??""),t.verbose===!0);case"get_pattern":return Dt(String(t.name??""));case"get_rule":return Et(typeof t.number=="number"?t.number:void 0);case"get_vocab":return Ot(t.name==null?void 0:String(t.name));case"get_tokens":return Nt(t.category);case"list_consumer_skills":return rt();case"get_consumer_skill":return st(String(t.skill??""),String(t.section??""));case"route_consumer_task":return Oe(String(t.task??""),{consumerOnly:!0});case"draft_bug_report":return lt(t);case"check_compatibility":return ze(t.version==null?void 0:String(t.version));case"route_task":return Oe(String(t.task??""));case"suggest_primitive":return Rt(String(t.use_case??""));case"search_components":return It(String(t.query??""),t.tier);case"get_frame_coverage":return At(t.name===void 0?void 0:String(t.name));case"get_design":return nt(t.section==null?void 0:String(t.section));case"get_exemplar":return ot(t.archetype==null?"":String(t.archetype));case"lint_jsx":return zt(String(t.jsx??""));default:return`Unknown tool: ${e}`}}function nt(e){if(e===void 0||e.trim()==="")return U;let t=ke(e);if(t)return t.body;let a=j().map(n=>`- \`${n.id}\` \u2014 ${n.title}`).join(`
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@godxjp/ui-mcp",
3
- "version": "33.18.0",
4
- "godxUiCompatibility": "33.18.x",
3
+ "version": "33.19.0",
4
+ "godxUiCompatibility": "33.19.x",
5
5
  "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).",
6
6
  "type": "module",
7
7
  "main": "./dist/index.js",