@godxjp/ui-mcp 27.10.0 → 27.12.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +12 -12
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -597,7 +597,7 @@ export default function InvoiceList({
|
|
|
597
597
|
</DataTable.Toolbar>
|
|
598
598
|
</DataTable>
|
|
599
599
|
);
|
|
600
|
-
}`,storyPath:"data-display/DataTable.stories.tsx",rules:[24,31,35,37]},{name:"Card",subParts:["CardAction","CardCover","CardDescription","CardFooter","CardHeader","CardTitle"],group:"data-display",tagline:"Surface container with optional accent stripe, variant fill (including the Ant Design borderless edge), hoverable lift, and density. \u26A0\uFE0F The bare <Card> has NO inner padding \u2014 body content MUST be wrapped in <CardContent> (titles in <CardHeader>), or it sits FLUSH against the card edges. Never hand-roll padding with className=\"p-4\"; use <CardContent>. Compose with CardHeader/CardTitle/CardContent/CardFooter. For Ant Design's card-head TAB STRIP (tabs under the title, inside the card border) use the `tabList`/`activeTabKey`/`defaultActiveTabKey`/`onTabChange`/`extra`/`tabProps` props \u2014 the Card renders the strip and the children become the selected tab's body. For a non-tab toolbar/filter strip (list controls, filter chips) use <CardBar extra={\u2026}> \u2014 a positionable bar that auto-draws its separator from its position (top\u2192bottom border, bottom\u2192top border, middle\u2192both) and pins `extra` content to the inline-end edge; place it as first/last child of the Card.",props:[{name:"accent",type:'"primary" | "success" | "warning" | "info" | "attention" | "destructive"',description:"Semantic accent TONE. Where it is drawn is `accentPlacement`'s job \u2014 by default a leading-edge stripe on `border-inline-start` at the `--card-accent-rail-width` measure (6px)."},{name:"accentPlacement",type:'"edge" | "perimeter"',defaultValue:'"edge"',description:'Where `accent` is drawn. "edge" is the classic leading rail. "perimeter" is the FULL attention border \u2014 the whole edge in the accent tone, at the same optical weight as `variant="featured"` but tone-owned, so a card can read as "action required" (accent="attention") or "failed" (accent="destructive") without borrowing the brand colour. Inert without `accent`.'},{name:"variant",type:'"default" | "muted" | "outline" | "borderless" | "featured"',defaultValue:'"default"',description:'Surface fill AND edge. `outline` is Ant Design\'s `outlined` \u2014 no fill, hairline kept. `borderless` is Ant Design\'s `variant="borderless"` (its deprecated `bordered={false}`) \u2014 no hairline, fill kept. The two are mirror images and neither substitutes for the other. `featured` is the BRAND perimeter; its colour is the `--card-featured-border-color` knob rather than a hard-coded `--primary`. For a perimeter in a semantic tone use `accent` + `accentPlacement="perimeter"` instead.'},{name:"hoverable",type:"boolean",description:'Ant Design `hoverable` \u2014 the card lifts to `--card-hover-shadow` on hover and takes a pointer cursor. PRESENTATION ONLY: it announces nothing and binds no handler, so pair it with a real control (a Link/Button inside, or the whole card rendered as one). Never with a bare onClick on the Card div \u2014 a keyboard or screen-reader user cannot reach that. Composes with `accent`/`accentPlacement="perimeter"`: the hover raises the shadow TOKEN, so the attention ring survives the hover.'},{name:"density",type:'"tight" | "cozy"',description:"Internal padding density (base 16 / tight 12 / cozy 20). This IS Ant Design's `size` axis; there is deliberately no `size` prop (removed 2026-08-24) \u2014 see docs/DESIGN-AUTHORITY.md, a capability this library already has keeps its own name."},{name:"tabList",type:"{ key: string; tab: ReactNode; disabled?: boolean }[]",description:"Ant Design `tabList` \u2014 the tab strip that lives IN THE CARD'S HEAD: under the title, on the same surface, inside the same border, so the card and its tabs read as ONE object. The entry keeps antd's own field names (`key`/`tab`/`disabled`), NOT the Tabs component's `value`/`label`/`content` \u2014 a card tab carries only the trigger, because the panel is the card body. The Card's children become the selected tab's body; wrap them in <CardContent> (or <CardContent flush> for an edge-to-edge DataTable, which still reaches the card edge inside a tab)."},{name:"activeTabKey",type:"string",description:"Ant Design `activeTabKey` \u2014 the CONTROLLED selection. With it set the card never moves itself; pair it with `onTabChange` and swap the children yourself, exactly as in antd."},{name:"defaultActiveTabKey",type:"string",description:"Ant Design `defaultActiveTabKey` \u2014 the uncontrolled initial selection. Without it the first selectable entry of `tabList` opens (antd's own fallback); a disabled tab is never the open one."},{name:"onTabChange",type:"(key: string) => void",description:"Ant Design `onTabChange` \u2014 fires with the newly selected `key`, however the selection moved (pointer or keyboard)."},{name:"extra",type:"ReactNode | { start?: ReactNode; end?: ReactNode }",description:"Ant Design `tabBarExtraContent`, RENAMED to `extra` and made logical \u2014 the same precedent `Tabs.extra` already set in this package, and antd's `left`/`right` keys are `start`/`end` here so an RTL locale gets the slot on the correct edge. It rides the TAB BAR beside the strip, so it is inert without `tabList`; a header-level action is <CardAction> inside <CardHeader>."},{name:"tabProps",type:"Omit<TabsProps, 'items' | 'value' | 'defaultValue' | 'onValueChange' | 'extra' | 'children'>",description:"Ant Design `tabProps` \u2014 passed straight to the Tabs that draws the strip, so `variant`, `size`, `centered`, `overflow`, `indicator` and the rest are reachable. The fields the CARD owns are omitted rather than silently overwritten: `items` comes from `tabList`, `value`/`defaultValue`/`onValueChange` from `activeTabKey`/`defaultActiveTabKey`/`onTabChange`, and `extra` is the Card's own slot. antd drops the same fields \u2014 it writes its own over `tabProps` \u2014 so this is that behaviour made visible in the type."}],usage:['DO always wrap body content in <CardContent> \u2014 the bare <Card> div has zero inner padding; content renders flush against card edges without it. Never add className="p-4" directly on <Card> as a substitute.',"DO put titles/descriptions in <CardHeader>/<CardTitle>/<CardDescription>. Use <CardHeader banded> for a visually separated muted-background header band (mirrors <CardFooter separated>). Pair with <CardAction> inside a flex-row CardHeader for header-level action buttons.",'DO set <CardTitle level={n}> to keep a valid document outline (h1 \u2192 h2 \u2192 h3, no skipped levels): CardTitle renders <h3> by default, so a section card directly under a page <h1> needs level={2}. Pick the level by OUTLINE position, NEVER for visual size \u2014 the title size is fixed by tokens and does not change with level. When the card title is a styled label rather than a section heading, use <CardTitle as="p"> so it is not announced as a heading.',"DO use <CardContent flush> for edge-to-edge children such as DataTable, Table, or a Tabs list \u2014 this removes horizontal padding. Combine with <CardContent tight> when there is no visual gap needed after the header, and <CardContent solo> when there is no CardHeader above (top padding matches the card shell).","DO use <CardFooter separated> to render a top-bordered action band (Save/Cancel buttons, table summary row). Use <CardFooter flush> for a full-bleed footer bar.","DO use <CardFooter actions> for Ant Design's `actions` row \u2014 N EQUAL-WIDTH cells split by vertical hairlines (\u8907\u88FD / \u5171\u6709 / \u524A\u9664 under a profile or entity card). It is a different band from `separated`, which packs children at the inline end at their natural widths: that is the right shape for a Save/Cancel pair and the wrong one for a divided strip. `actions` is self-sufficient \u2014 it draws its own top rule and full-bleed edges, so it needs neither `separated` nor `flush` beside it. The dividers are logical (border-inline-start), so the strip mirrors under RTL.","DO use <CardCover> as the first child for full-bleed cover media \u2014 the header below it uses card-section top spacing, not the card shell.",'ANT DESIGN PROPS THIS FAMILY ANSWERS BY COMPOSITION, not by a prop of the same name \u2014 do not ask for these to be added: `title` is <CardHeader> + <CardTitle> (and CardTitle.level emits a real heading, which antd does not); a header-level action is <CardAction> inside <CardHeader>. `cover` is <CardCover>. `actions` is <CardFooter actions>. `loading` is a Skeleton in the body \u2014 antd renders a Skeleton with paragraph rows and no title, so the equivalent is <CardContent solo><SkeletonRows rows={4} /></CardContent>. `type="inner"` is variant="muted" plus <CardHeader banded>. `size` is `density`. `Card.Grid` is <ResponsiveGrid>; `Card.Meta` is <ListRow leading title description trailing>.',"DO use `tabList` for a tab strip that belongs to the CARD \u2014 antd's card-head tabs, ported name for name (gh#570): `tabList={[{ key, tab, disabled? }]}` plus `activeTabKey`/`defaultActiveTabKey`/`onTabChange`, with `extra` for antd's `tabBarExtraContent` and `tabProps` for everything else on the Tabs underneath. The strip renders INSIDE the card head, under the title, on the same surface and inside the same border, and the Card's children become the selected tab's body (wrap them in <CardContent>, or <CardContent flush> for an edge-to-edge DataTable). DON'T hand-roll it as a <Tabs> parked on the page above the card (the strip floats off the card and the two read as two objects) or as a <Card> repeated inside each tab (the shell is copied per view). A <Tabs> INSIDE <CardContent tight flush> is still correct for a strip that belongs to the BODY rather than to the card head.",'DO reach for `accentPlacement="perimeter"` when the whole card needs attention, not one edge: `<Card accent="attention" accentPlacement="perimeter">` is the semantic-tone equivalent of `variant="featured"` (which is brand-toned by definition). Never hand-roll it with `className="border-2 border-[--attention]"` or a page-local `.card--attention` rule \u2014 the placement owns the border weight, the outer ring AND the slot-padding compensation, so text stays on the same column as an unaccented sibling.',"DON'T hand-roll a stat/KPI tile with <Card> + raw divs \u2014 use <StatCard> (label, value, hint, delta, layout, inverse props) which is already a Card internally with correct token-driven layout.","SPACING IS BORDER-AWARE & token-driven (theme via src/tokens/components/card.css, never hard-code padding on slots): `--card-space-inset` is the shared horizontal column every slot (header/content/footer) aligns to. A DIVIDED section \u2014 a `banded` header or a `separated` footer, i.e. one carrying a divider border \u2014 pads SYMMETRICALLY top+bottom from `--card-space-divided-y` (a band reads as its own region). A PLAIN header flows into the body instead: top `--card-space-shell-y`, no bottom, and the body supplies the gap via `--card-space-body-y`. THE TWO AXES ARE INDEPENDENT: `--card-space-inset` is inline-only, while `--card-space-shell-y` owns the BLOCK shell edges (plain-header top, `solo` body top, terminal slot bottom) and defaults to the inset \u2014 so a shell/theme can make a card SHORTER without narrowing its column by overriding `--card-space-shell-y` alone (this is how AuthShell's `--auth-shell-card-padding-block-compact` reaches CardContent). Never bridge it with a consumer selector on the card-content slot. Special case: `<CardContent flush>` zeroes BOTH of its block edges \u2014 for ANY full-bleed body, not only one containing a <Table>` gate left a flush file LIST floating 18px off its header while the flush table beside it sat at 0) \u2014 so the plain header above it supplies the gap from its own `--card-space-body-y` bottom padding instead. `tight` and `solo` still own that axis themselves. `--card-space-gap` is the in-slot stack gap (title\u2195description). Tune the band rhythm once at `--card-space-divided-y`; tune the accent stripe width at `--card-accent-rail-width` (default 6px)."],useCases:['Dashboard KPI summary row: wrap each metric in <StatCard> (or a plain <Card density="tight"> with <CardContent>) to render a uniform grid of labeled value tiles with optional trend deltas.','Invoice or order detail panel: <Card accent="primary"> with <CardHeader banded><CardTitle>, <CardContent> body rows (use <Descriptions> inside), and <CardFooter separated> holding approve/reject buttons.',"Section container on a settings or form page: a single <Card> wrapping a <CardHeader><CardTitle> plus <CardContent> containing <FormField> groups, with <CardFooter separated> for Save/Cancel.","Data table with toolbar: <Card> + <CardHeader> (title + filter controls in <CardAction>) + <CardContent flush> containing <DataTable> \u2014 <CardContent flush> removes horizontal padding so the table header spans full width.","Detail screen with views: <Card tabList={[{key,tab}]} activeTabKey onTabChange extra={<Button/>}> with <CardHeader><CardTitle> above the strip and <CardContent flush><DataTable/></CardContent> as the body \u2014 one card, tabs in its head, and a table that reaches the card edge inside the tab (docs/data-display/card/examples/tab-list.tsx).",'Featured announcement or alert card: <Card variant="featured"> with an accent stripe (<accent="warning">) to visually elevate a card above sibling cards on the page.',"Media/cover card (e.g. entity profile): <CardCover> first (full-bleed image), then <CardHeader> + <CardContent> below it for structured metadata."],related:["StatCard \u2014 use instead of a plain Card when rendering a KPI/metric tile (label + value + optional delta/hint). StatCard is a Card internally; do not re-wrap it in another Card.","CardContent \u2014 mandatory inner wrapper for all body content inside Card. Provides the correct padding and supports flush/tight/solo variants. The only correct way to put padded content inside Card.","Descriptions \u2014 use inside <CardContent> when body content is a label-value metadata list (e.g. entity details, invoice fields); do not hand-roll a dl/dt/dd grid.","DataState / InfiniteQueryState \u2014 use instead of Card when the content is a TanStack Query-driven list that needs automatic skeleton, empty, and error states; Card does not manage loading lifecycle."],example:`import { Card, CardHeader, CardTitle, CardContent } from "@godxjp/ui/data-display";
|
|
600
|
+
}`,storyPath:"data-display/DataTable.stories.tsx",rules:[24,31,35,37]},{name:"Card",subParts:["CardAction","CardCover","CardDescription","CardFooter","CardHeader","CardTitle"],group:"data-display",tagline:"Surface container with optional accent stripe, variant fill (including the Ant Design borderless edge), hoverable lift, and density. \u26A0\uFE0F The bare <Card> has NO inner padding \u2014 body content MUST be wrapped in <CardContent> (titles in <CardHeader>), or it sits FLUSH against the card edges. Never hand-roll padding with className=\"p-4\"; use <CardContent>. Compose with CardHeader/CardTitle/CardContent/CardFooter. For Ant Design's card-head TAB STRIP (tabs under the title, inside the card border) use the `tabList`/`activeTabKey`/`defaultActiveTabKey`/`onTabChange`/`extra`/`tabProps` props \u2014 the Card renders the strip and the children become the selected tab's body. For a non-tab toolbar/filter strip (list controls, filter chips) use <CardBar extra={\u2026}> \u2014 a positionable bar that auto-draws its separator from its position (top\u2192bottom border, bottom\u2192top border, middle\u2192both) and pins `extra` content to the inline-end edge; place it as first/last child of the Card.",props:[{name:"accent",type:'"primary" | "success" | "warning" | "info" | "attention" | "destructive"',description:"Semantic accent TONE. Where it is drawn is `accentPlacement`'s job \u2014 by default a leading-edge stripe on `border-inline-start` at the `--card-accent-rail-width` measure (6px)."},{name:"accentPlacement",type:'"edge" | "perimeter"',defaultValue:'"edge"',description:'Where `accent` is drawn. "edge" is the classic leading rail. "perimeter" is the FULL attention border \u2014 the whole edge in the accent tone, at the same optical weight as `variant="featured"` but tone-owned, so a card can read as "action required" (accent="attention") or "failed" (accent="destructive") without borrowing the brand colour. Inert without `accent`.'},{name:"variant",type:'"default" | "muted" | "outline" | "borderless" | "featured"',defaultValue:'"default"',description:'Surface fill AND edge. `outline` is Ant Design\'s `outlined` \u2014 no fill, hairline kept. `borderless` is Ant Design\'s `variant="borderless"` (its deprecated `bordered={false}`) \u2014 no hairline, fill kept. The two are mirror images and neither substitutes for the other. `featured` is the BRAND perimeter; its colour is the `--card-featured-border-color` knob rather than a hard-coded `--primary`. For a perimeter in a semantic tone use `accent` + `accentPlacement="perimeter"` instead.'},{name:"hoverable",type:"boolean",description:'Ant Design `hoverable` \u2014 the card lifts to `--card-hover-shadow` on hover and takes a pointer cursor. PRESENTATION ONLY: it announces nothing and binds no handler, so pair it with a real control (a Link/Button inside, or the whole card rendered as one via `asChild`). Never with a bare onClick on the Card div \u2014 a keyboard or screen-reader user cannot reach that. Composes with `accent`/`accentPlacement="perimeter"`: the hover raises the shadow TOKEN, so the attention ring survives the hover.'},{name:"asChild",type:"boolean",defaultValue:"false",description:'Borrow the child\'s element for the card BOX instead of rendering a div \u2014 the standard Slot passthrough (Button, AspectRatio, ListRow). This is the other half of `hoverable`: `<Card asChild hoverable><a href="\u2026">` IS "the whole card rendered as one control" \u2014 one tab stop, announced as one link, with the focus ring on the card box (measured in Chromium: `<div>`, `<a>` and `<button>` identical on box, border, radius, fill, padding inset, shadow and cursor at 1440 and 390). For a click-only card hand it your router\'s Link component as the child. NESTING CAVEAT: the card is now ONE control, so it may not contain another \u2014 an <a>/<Button>/menu trigger inside a card-as-link or card-as-button is invalid HTML, and `tabList` (a strip of button triggers) is for the same reason not drawn under `asChild` and warns in development. A card that needs interactive children is not one control: drop `asChild` and put the Link/Button inside it, which is the other branch `hoverable` names. Exactly one child \u2014 two throws React.Children.only, the same error `Button asChild` throws.'},{name:"density",type:'"tight" | "cozy"',description:"Internal padding density (base 16 / tight 12 / cozy 20). This IS Ant Design's `size` axis; there is deliberately no `size` prop (removed 2026-08-24) \u2014 see docs/DESIGN-AUTHORITY.md, a capability this library already has keeps its own name."},{name:"tabList",type:"{ key: string; tab: ReactNode; disabled?: boolean }[]",description:"Ant Design `tabList` \u2014 the tab strip that lives IN THE CARD'S HEAD: under the title, on the same surface, inside the same border, so the card and its tabs read as ONE object. The entry keeps antd's own field names (`key`/`tab`/`disabled`), NOT the Tabs component's `value`/`label`/`content` \u2014 a card tab carries only the trigger, because the panel is the card body. The Card's children become the selected tab's body; wrap them in <CardContent> (or <CardContent flush> for an edge-to-edge DataTable, which still reaches the card edge inside a tab)."},{name:"activeTabKey",type:"string",description:"Ant Design `activeTabKey` \u2014 the CONTROLLED selection. With it set the card never moves itself; pair it with `onTabChange` and swap the children yourself, exactly as in antd."},{name:"defaultActiveTabKey",type:"string",description:"Ant Design `defaultActiveTabKey` \u2014 the uncontrolled initial selection. Without it the first selectable entry of `tabList` opens (antd's own fallback); a disabled tab is never the open one."},{name:"onTabChange",type:"(key: string) => void",description:"Ant Design `onTabChange` \u2014 fires with the newly selected `key`, however the selection moved (pointer or keyboard)."},{name:"extra",type:"ReactNode | { start?: ReactNode; end?: ReactNode }",description:"Ant Design `tabBarExtraContent`, RENAMED to `extra` and made logical \u2014 the same precedent `Tabs.extra` already set in this package, and antd's `left`/`right` keys are `start`/`end` here so an RTL locale gets the slot on the correct edge. It rides the TAB BAR beside the strip, so it is inert without `tabList`; a header-level action is <CardAction> inside <CardHeader>."},{name:"tabProps",type:"Omit<TabsProps, 'items' | 'value' | 'defaultValue' | 'onValueChange' | 'extra' | 'children'>",description:"Ant Design `tabProps` \u2014 passed straight to the Tabs that draws the strip, so `variant`, `size`, `centered`, `overflow`, `indicator` and the rest are reachable. The fields the CARD owns are omitted rather than silently overwritten: `items` comes from `tabList`, `value`/`defaultValue`/`onValueChange` from `activeTabKey`/`defaultActiveTabKey`/`onTabChange`, and `extra` is the Card's own slot. antd drops the same fields \u2014 it writes its own over `tabProps` \u2014 so this is that behaviour made visible in the type."}],usage:['DO always wrap body content in <CardContent> \u2014 the bare <Card> div has zero inner padding; content renders flush against card edges without it. Never add className="p-4" directly on <Card> as a substitute.',"DO put titles/descriptions in <CardHeader>/<CardTitle>/<CardDescription>. Use <CardHeader banded> for a visually separated muted-background header band (mirrors <CardFooter separated>). Pair with <CardAction> inside a flex-row CardHeader for header-level action buttons.",'DO set <CardTitle level={n}> to keep a valid document outline (h1 \u2192 h2 \u2192 h3, no skipped levels): CardTitle renders <h3> by default, so a section card directly under a page <h1> needs level={2}. Pick the level by OUTLINE position, NEVER for visual size \u2014 the title size is fixed by tokens and does not change with level. When the card title is a styled label rather than a section heading, use <CardTitle as="p"> so it is not announced as a heading.',"DO use <CardContent flush> for edge-to-edge children such as DataTable, Table, or a Tabs list \u2014 this removes horizontal padding. Combine with <CardContent tight> when there is no visual gap needed after the header, and <CardContent solo> when there is no CardHeader above (top padding matches the card shell).","DO use <CardFooter separated> to render a top-bordered action band (Save/Cancel buttons, table summary row). Use <CardFooter flush> for a full-bleed footer bar.","DO use <CardFooter actions> for Ant Design's `actions` row \u2014 N EQUAL-WIDTH cells split by vertical hairlines (\u8907\u88FD / \u5171\u6709 / \u524A\u9664 under a profile or entity card). It is a different band from `separated`, which packs children at the inline end at their natural widths: that is the right shape for a Save/Cancel pair and the wrong one for a divided strip. `actions` is self-sufficient \u2014 it draws its own top rule and full-bleed edges, so it needs neither `separated` nor `flush` beside it. The dividers are logical (border-inline-start), so the strip mirrors under RTL.","DO use <CardCover> as the first child for full-bleed cover media \u2014 the header below it uses card-section top spacing, not the card shell.","DO make the WHOLE card the control with `asChild` when the whole card is the click target: `<Card asChild hoverable><a href={href}><CardHeader><CardTitle level={2}>\u2026</CardTitle></CardHeader><CardContent>\u2026</CardContent></a></Card>` (or your router's Link as the child when there is no href, e.g. a nav.push handler). One tab stop, announced as one link, focus ring on the card box. DON'T wrap the card in a raw <button> (that is a `no-raw-button` error) and DON'T put a bare onClick on the Card div (unreachable by keyboard and screen reader \u2014 `hoverable`'s own docblock forbids it). NESTING CAVEAT: a card-as-link/button may not CONTAIN another control \u2014 an <a>, a <Button>, a DropdownMenu trigger or a `tabList` strip inside it is invalid HTML (`tabList` is dropped with a development warning). When the card needs interactive children it is not one control: drop `asChild` and use the other branch \u2014 `hoverable` plus a real Link/Button inside <CardHeader>/<CardAction>/<CardFooter>.",'ANT DESIGN PROPS THIS FAMILY ANSWERS BY COMPOSITION, not by a prop of the same name \u2014 do not ask for these to be added: `title` is <CardHeader> + <CardTitle> (and CardTitle.level emits a real heading, which antd does not); a header-level action is <CardAction> inside <CardHeader>. `cover` is <CardCover>. `actions` is <CardFooter actions>. `loading` is a Skeleton in the body \u2014 antd renders a Skeleton with paragraph rows and no title, so the equivalent is <CardContent solo><SkeletonRows rows={4} /></CardContent>. `type="inner"` is variant="muted" plus <CardHeader banded>. `size` is `density`. `Card.Grid` is <ResponsiveGrid>; `Card.Meta` is <ListRow leading title description trailing>.',"DO use `tabList` for a tab strip that belongs to the CARD \u2014 antd's card-head tabs, ported name for name (gh#570): `tabList={[{ key, tab, disabled? }]}` plus `activeTabKey`/`defaultActiveTabKey`/`onTabChange`, with `extra` for antd's `tabBarExtraContent` and `tabProps` for everything else on the Tabs underneath. The strip renders INSIDE the card head, under the title, on the same surface and inside the same border, and the Card's children become the selected tab's body (wrap them in <CardContent>, or <CardContent flush> for an edge-to-edge DataTable). DON'T hand-roll it as a <Tabs> parked on the page above the card (the strip floats off the card and the two read as two objects) or as a <Card> repeated inside each tab (the shell is copied per view). A <Tabs> INSIDE <CardContent tight flush> is still correct for a strip that belongs to the BODY rather than to the card head.",'DO reach for `accentPlacement="perimeter"` when the whole card needs attention, not one edge: `<Card accent="attention" accentPlacement="perimeter">` is the semantic-tone equivalent of `variant="featured"` (which is brand-toned by definition). Never hand-roll it with `className="border-2 border-[--attention]"` or a page-local `.card--attention` rule \u2014 the placement owns the border weight, the outer ring AND the slot-padding compensation, so text stays on the same column as an unaccented sibling.',"DON'T hand-roll a stat/KPI tile with <Card> + raw divs \u2014 use <StatCard> (label, value, hint, delta, layout, inverse props) which is already a Card internally with correct token-driven layout.","SPACING IS BORDER-AWARE & token-driven (theme via src/tokens/components/card.css, never hard-code padding on slots): `--card-space-inset` is the shared horizontal column every slot (header/content/footer) aligns to. A DIVIDED section \u2014 a `banded` header or a `separated` footer, i.e. one carrying a divider border \u2014 pads SYMMETRICALLY top+bottom from `--card-space-divided-y` (a band reads as its own region). A PLAIN header flows into the body instead: top `--card-space-shell-y`, no bottom, and the body supplies the gap via `--card-space-body-y`. THE TWO AXES ARE INDEPENDENT: `--card-space-inset` is inline-only, while `--card-space-shell-y` owns the BLOCK shell edges (plain-header top, `solo` body top, terminal slot bottom) and defaults to the inset \u2014 so a shell/theme can make a card SHORTER without narrowing its column by overriding `--card-space-shell-y` alone (this is how AuthShell's `--auth-shell-card-padding-block-compact` reaches CardContent). Never bridge it with a consumer selector on the card-content slot. Special case: `<CardContent flush>` zeroes BOTH of its block edges \u2014 for ANY full-bleed body, not only one containing a <Table>` gate left a flush file LIST floating 18px off its header while the flush table beside it sat at 0) \u2014 so the plain header above it supplies the gap from its own `--card-space-body-y` bottom padding instead. `tight` and `solo` still own that axis themselves. `--card-space-gap` is the in-slot stack gap (title\u2195description). Tune the band rhythm once at `--card-space-divided-y`; tune the accent stripe width at `--card-accent-rail-width` (default 6px)."],useCases:['Dashboard KPI summary row: wrap each metric in <StatCard> (or a plain <Card density="tight"> with <CardContent>) to render a uniform grid of labeled value tiles with optional trend deltas.','Invoice or order detail panel: <Card accent="primary"> with <CardHeader banded><CardTitle>, <CardContent> body rows (use <Descriptions> inside), and <CardFooter separated> holding approve/reject buttons.',"Section container on a settings or form page: a single <Card> wrapping a <CardHeader><CardTitle> plus <CardContent> containing <FormField> groups, with <CardFooter separated> for Save/Cancel.","Data table with toolbar: <Card> + <CardHeader> (title + filter controls in <CardAction>) + <CardContent flush> containing <DataTable> \u2014 <CardContent flush> removes horizontal padding so the table header spans full width.","Detail screen with views: <Card tabList={[{key,tab}]} activeTabKey onTabChange extra={<Button/>}> with <CardHeader><CardTitle> above the strip and <CardContent flush><DataTable/></CardContent> as the body \u2014 one card, tabs in its head, and a table that reaches the card edge inside the tab (docs/data-display/card/examples/tab-list.tsx).",'Featured announcement or alert card: <Card variant="featured"> with an accent stripe (<accent="warning">) to visually elevate a card above sibling cards on the page.',"Media/cover card (e.g. entity profile): <CardCover> first (full-bleed image), then <CardHeader> + <CardContent> below it for structured metadata."],related:["StatCard \u2014 use instead of a plain Card when rendering a KPI/metric tile (label + value + optional delta/hint). StatCard is a Card internally; do not re-wrap it in another Card.","CardContent \u2014 mandatory inner wrapper for all body content inside Card. Provides the correct padding and supports flush/tight/solo variants. The only correct way to put padded content inside Card.","Descriptions \u2014 use inside <CardContent> when body content is a label-value metadata list (e.g. entity details, invoice fields); do not hand-roll a dl/dt/dd grid.","DataState / InfiniteQueryState \u2014 use instead of Card when the content is a TanStack Query-driven list that needs automatic skeleton, empty, and error states; Card does not manage loading lifecycle."],example:`import { Card, CardHeader, CardTitle, CardContent } from "@godxjp/ui/data-display";
|
|
601
601
|
|
|
602
602
|
<Card accent="success">
|
|
603
603
|
<CardHeader><CardTitle>\u6CE8\u6587\u30B5\u30DE\u30EA\u30FC</CardTitle></CardHeader>
|
|
@@ -2072,7 +2072,7 @@ import { Separator } from "@godxjp/ui/layout";
|
|
|
2072
2072
|
countLabel={t("common.items")}
|
|
2073
2073
|
>
|
|
2074
2074
|
{t("inbox.unread")}
|
|
2075
|
-
</Toggle>`,storyPath:"data-entry/Toggle.stories.tsx",rules:[3,13,45]},{name:"ToggleGroup",subParts:["ToggleGroupItem"],group:"data-entry",tagline:"Radix ToggleGroup wrapper for single or multiple toggle selection.",props:[{name:"type",type:'"single" | "multiple"',required:!0,description:"Selection mode."},{name:"value",type:"string | string[]",description:"Controlled selected value(s)."},{name:"defaultValue",type:"string | string[]",description:"Uncontrolled initial value(s)."},{name:"onValueChange",type:"(value: string | string[]) => void",description:"Selection callback."},{name:"variant",type:'"default" | "outline" | "soft"',defaultValue:'"default"',description:"Visual style, PROVIDED TO EVERY ITEM via context \u2014 set it once on the group, not on each ToggleGroupItem. An explicit `variant` on an item still wins. The default is applied per item by toggleVariants, so an unset group emits no `data-variant` at all. `soft` (gh#734) is the chip fill: use it for a tag-filter panel, where `default`/`outline` leave the unselected chips reading as transparent."},{name:"shape",type:'"default" | "pill" | "sharp"',defaultValue:'"default"',description:"Corner shape, PROVIDED TO EVERY ITEM via context exactly as `variant`/`size` are \u2014 a chip row is a row of pills, so the decision belongs to the row (gh#734). An explicit `shape` on an item still wins. Same three values and same radius tokens as Button and Badge."},{name:"size",type:'"xs" | "sm" | "md" | "lg"',defaultValue:'"md"',description:"Control size, PROVIDED TO EVERY ITEM via context \u2014 set it once on the group. An explicit `size` on an item still wins. Heights come from the --control-height tier (xs 24px \xB7 sm 28px \xB7 md 32px \xB7 lg 36px). Pick the step the ROW already has: xs is the one that fits a 24px-dense row (gh#716)."},{name:"disabled",type:"boolean",description:"Disables the whole group; individual items also accept `disabled`."},{name:"ToggleGroupItem count / overflowCount / showZero / countLabel",type:"number | number | boolean | string",description:"The counter-pill vocabulary is available PER ITEM, because variant/size are a group decision but the number is per-item data. Same vocabulary and same rendering as Toggle and Button: Intl.NumberFormat on the active locale, `{overflowCount}+` above the cap, and the count folded into that item's own accessible name. This is the faceted filter chip row (Open 42 / Closed 118) and the reaction row."}],usage:["DO choose type='single' for mutually exclusive toolbar modes.","DO choose type='multiple' for independent formatting toggles.","DO set `variant`/`size`/`shape` ONCE on the ToggleGroup \u2014 they propagate to every ToggleGroupItem through context. Repeating them on each item is redundant (it still works, and an explicit item prop overrides the group).",'DO build a tag-filter panel as `<ToggleGroup type="multiple" variant="soft" shape="pill" size="xs">` with one counted `ToggleGroupItem` per tag \u2014 that is the whole antd `Tag.CheckableTag` row, one tab stop per chip, no `Tag` component needed (gh#734).',"DO set `size`/`variant` on an individual ToggleGroupItem only when that ONE item must differ from the group.","DON'T pass size='default' \u2014 it is not a member of the `xs | sm | md | lg` union. Omit `size` for the md default.","DO give the group an accessible name (`aria-label`) \u2014 it renders a radiogroup (single) or a group of toggle buttons (multiple)."],useCases:["Text alignment selector","Formatting toolbar","View density switcher"],related:["Segmented \u2014 the single-select sibling with a shared connected track. ToggleGroup is the generic multi/single toggle set; Segmented is the one-of-N control.","Toggle","RadioGroup"],example:`import { ToggleGroup, ToggleGroupItem } from "@godxjp/ui/data-entry";
|
|
2075
|
+
</Toggle>`,storyPath:"data-entry/Toggle.stories.tsx",rules:[3,13,45]},{name:"ToggleGroup",subParts:["ToggleGroupItem"],group:"data-entry",tagline:"Radix ToggleGroup wrapper for single or multiple toggle selection.",props:[{name:"type",type:'"single" | "multiple"',required:!0,description:"Selection mode."},{name:"value",type:"string | string[]",description:"Controlled selected value(s)."},{name:"defaultValue",type:"string | string[]",description:"Uncontrolled initial value(s)."},{name:"onValueChange",type:"(value: string | string[]) => void",description:"Selection callback."},{name:"variant",type:'"default" | "outline" | "soft"',defaultValue:'"default"',description:"Visual style, PROVIDED TO EVERY ITEM via context \u2014 set it once on the group, not on each ToggleGroupItem. An explicit `variant` on an item still wins. The default is applied per item by toggleVariants, so an unset group emits no `data-variant` at all. `soft` (gh#734) is the chip fill: use it for a tag-filter panel, where `default`/`outline` leave the unselected chips reading as transparent."},{name:"shape",type:'"default" | "pill" | "sharp"',defaultValue:'"default"',description:"Corner shape, PROVIDED TO EVERY ITEM via context exactly as `variant`/`size` are \u2014 a chip row is a row of pills, so the decision belongs to the row (gh#734). An explicit `shape` on an item still wins. Same three values and same radius tokens as Button and Badge."},{name:"size",type:'"xs" | "sm" | "md" | "lg"',defaultValue:'"md"',description:"Control size, PROVIDED TO EVERY ITEM via context \u2014 set it once on the group. An explicit `size` on an item still wins. Heights come from the --control-height tier (xs 24px \xB7 sm 28px \xB7 md 32px \xB7 lg 36px). Pick the step the ROW already has: xs is the one that fits a 24px-dense row (gh#716)."},{name:"disabled",type:"boolean",description:"Disables the whole group; individual items also accept `disabled`."},{name:"wrap",type:"boolean",defaultValue:"false",description:'Let the row break onto further lines instead of running past its rail (gh#741) \u2014 the SAME name, boolean shape and `data-wrap` attribute `Flex` carries. OPT-IN, and the same default for every `variant`, both decided by measurement: a twelve-chip soft/pill xs row in a 320px rail is scrollWidth 644 > clientWidth 320 and 171.5px tall without it (chips squeezed to min-content, labels broken over up to seven lines) and scrollWidth 320 = clientWidth 320, 108px, 4 lines with it \u2014 while forcing wrap on all 18 groups of the docs page changed NONE of the 17 that already fit, at a 320px and a 1358px rail. So a default of true could only reflow rows that overflow today, silently, on an upgrade; and `variant="soft"` gets no different default because forcing wrap changed nothing across default/outline/soft either \u2014 paint is not the axis that decides, content width against the rail is. The wrapped lines keep the group\'s single `gap`, so both axes measure the same 4px, and `flex-wrap` reorders nothing: arrow keys still walk the items in DOM order across lines, in LTR and in RTL.'},{name:"ToggleGroupItem count / overflowCount / showZero / countLabel",type:"number | number | boolean | string",description:"The counter-pill vocabulary is available PER ITEM, because variant/size are a group decision but the number is per-item data. Same vocabulary and same rendering as Toggle and Button: Intl.NumberFormat on the active locale, `{overflowCount}+` above the cap, and the count folded into that item's own accessible name. This is the faceted filter chip row (Open 42 / Closed 118) and the reaction row."}],usage:["DO choose type='single' for mutually exclusive toolbar modes.","DO choose type='multiple' for independent formatting toggles.","DO set `variant`/`size`/`shape` ONCE on the ToggleGroup \u2014 they propagate to every ToggleGroupItem through context. Repeating them on each item is redundant (it still works, and an explicit item prop overrides the group).",'DO build a tag-filter panel as `<ToggleGroup type="multiple" variant="soft" shape="pill" size="xs">` with one counted `ToggleGroupItem` per tag \u2014 that is the whole antd `Tag.CheckableTag` row, one tab stop per chip, no `Tag` component needed (gh#734).',"DO set `size`/`variant` on an individual ToggleGroupItem only when that ONE item must differ from the group.",'DO add `wrap` to a TAG FILTER ROW \u2014 `<ToggleGroup type="multiple" variant="soft" shape="pill" size="xs" wrap>` is the whole folder-tag panel however many tags the folder has. This is what replaces the hand-built `<ul>` of individual `<Toggle>`s a row wider than its rail used to force (gh#741): that list loses exactly what the group owns \u2014 the shared `variant`/`size`/`shape` context, ONE `value`/`onValueChange`, and the group\'s arrow-key traversal, which keeps walking the chips in DOM order across the wrapped lines.',"DON'T set `wrap` on a 3\u20134 item segmented group. Measured at a 320px rail it is one 32px line either way, so the prop buys nothing and only adds a way for a toolbar to reflow.","DON'T pass size='default' \u2014 it is not a member of the `xs | sm | md | lg` union. Omit `size` for the md default.","DO give the group an accessible name (`aria-label`) \u2014 it renders a radiogroup (single) or a group of toggle buttons (multiple)."],useCases:["Text alignment selector","Formatting toolbar","View density switcher","Tag filter row (wrap)"],related:["Segmented \u2014 the single-select sibling with a shared connected track. ToggleGroup is the generic multi/single toggle set; Segmented is the one-of-N control.","Toggle","RadioGroup"],example:`import { ToggleGroup, ToggleGroupItem } from "@godxjp/ui/data-entry";
|
|
2076
2076
|
|
|
2077
2077
|
// size/variant are set ONCE on the group and reach every item.
|
|
2078
2078
|
<ToggleGroup type="single" size="lg" variant="outline" defaultValue="left" aria-label="Alignment">
|
|
@@ -4353,7 +4353,7 @@ Only after sign-off do you move to code. A wireframe skipped = a redesign reliti
|
|
|
4353
4353
|
6. Hand-rolled UI instead of @godxjp/ui primitives (raw nav buttons, styled-div "Card", raw table).
|
|
4354
4354
|
Every run of this skill produces, in order: (1) a stakeholder-confirmed concept/entity artifact \u2192
|
|
4355
4355
|
(2) a layered IA doc \u2192 (3) an approved wireframe Artifact \u2192 (4) a per-route implementation checklist.
|
|
4356
|
-
Do not advance a step until the prior artifact is signed off.`}]}];function D(e){return S.find(t=>t.id===e)}function K(e,t){return D(e)?.sections.find(a=>a.id===t)}function Y(e,t){let a=e.toLowerCase(),o=[],n=(r,s,u,m,g)=>{r.some(w=>a.includes(w))&&o.push({skill:s,section:u,why:m,alsoSee:g})};n(["spacing","gap","kho\u1EA3ng c\xE1ch","padding","margin","layout","b\u1ED1 c\u1EE5c","page","trang","grid","l\u01B0\u1EDBi","form","input","button","control","color","colour","m\xE0u","token","text","ch\u1EEF","typography","component","prop","audit","l\u1ED7i","error","how do i","l\xE0m sao","b\u1EAFt \u0111\u1EA7u","start"],"contract","<see whenToUse>","Lu\u1EADt c\u1EE9ng c\u1EE7a @godxjp/ui, m\u1ED7i lu\u1EADt k\xE8m c\u1ED5ng CI v\xE0 m\xE3 SAI/\u0110\xDANG. \u0110\u1ECDc tr\u01B0\u1EDBc m\u1ECDi skill v\u1EC1 gu.",["contract/loop","contract/spacing","contract/escape"]),n(["premium","awwwards","agency","linear","apple","high-end","luxury"],"soft","vibe-archetypes","Premium tier \u2014 pick a Vibe + Layout archetype + apply Double-Bezel.",["soft/double-bezel","soft/magnetic-hover"]),n(["landing page","marketing","hero","long scroll"],"imagegen-web","hero-composition-bias","Landing pages benefit from hero composition variety + per-section image generation.",["gpt-tasteskill/principles","soft/layout-archetypes"]),n(["mobile app","ios","android","phone screen","onboarding flow"],"imagegen-mobile","principles","Mobile app design \u2014 generate screens first, avoid phone-shaped-website.",["taste/mobile-first"]),n(["workspace","notion","document","editorial","knowledge base"],"minimalist","palette","Editorial workspace = warm monochrome + spot pastels + serif headings.",["minimalist/typography","minimalist/bento-grids"]),n(["dashboard","data heavy","tabular","ops table"],"brutalist","principles","Data-heavy dashboards work with Brutalist (rigid grids, utilitarian color).",["taste/one-intent-per-screen"]),n(["brand","identity","logo","guidelines"],"brandkit","principles","Brand identity work \u2014 boards before screens."),n(["refactor","redesign","upgrade existing","audit"],"redesign","fix-priority","Existing project = run audit first, fix in priority order (font \u2192 palette \u2192 states \u2192 ...).",["redesign/audit-checklist"]),n(["form","validation","submit","sign up","registration"],"taste","form-discipline","Form must have explicit label + help + error wired via FormField (rule 34)."),n(["loading","saving","skeleton","spinner"],"taste","loading-states","Skeleton for INIT fetch, Spinner for active work. Never mix."),n(["mobile first","responsive","breakpoint"],"taste","mobile-first","Default styles target xs. Touch targets \u2265 44px. Use useBreakpoint()."),n(["complete code","full implementation","no placeholder"],"output","banned","Banned: // ..., // TODO, 'for brevity'. Ship complete runnable code."),n(["gsap","scrolltrigger","scroll choreography","pinning"],"gpt-tasteskill","principles","GSAP ScrollTrigger \u2014 pinning, stacking, scrubbing."),n(["from image","image to code","design first"],"image-to-code","workflow","Generate design image first \u2192 analyze \u2192 implement."),n(["handoff","design bundle","claude design","prototype","build the page","implement the design","build this screen","mockup"],"design-to-page","map-to-primitives","Map every block to a real @godxjp/ui primitive (MCP-first), consume existing tokens, apply the reference-design DNA, tables central, gaps \u2192 extend-or-ask, verify.",["design-to-page/read-intent","design-to-page/dna","design-to-page/tables-central"]),n(["compose a screen","new screen","new page","create a page","create a screen","build a view","build a screen","from scratch","screen from a brief"],"compose-a-screen","pick-primitives","Build a new app screen from real @godxjp/ui primitives (MCP-first): one-intent-per-screen, real chrome, every state + a11y + i18n, verify.",["compose-a-screen/assemble-screen","compose-a-screen/state-and-a11y","taste/one-intent-per-screen"]),n(["bug in godx","godx-ui bug","report a bug","file an issue","gh issue","can't follow the rule","library is broken","primitive is broken"],"compose-a-screen","report-bug","If @godxjp/ui itself is at fault, don't fake a workaround \u2014 file a detailed gh issue (use draft_bug_report).",["design-to-page/report-bug"]),n(["slow","performance","perf","violation","long task","lag","janky","re-render","rerender","bundle size","code splitting","tree-shak","ch\u1EADm","l\u1ED7i hi\u1EC7u n\u0103ng","\u91CD\u3044"],"app-performance","measure-first","Measure FIRST (longtask + temporary Profiler), then apply the matching proven fix \u2014 page architecture, not the library, is almost always the culprit.",["app-performance/filter-pane-memo","app-performance/heavy-panels","app-performance/bundle-budget"]),n(["admin console","admin panel","control panel","back-office","back office","management console","management ui","multi-tenant","multi tenant","platform admin","workspace admin","console qu\u1EA3n tr\u1ECB","layered ia","information architecture"],"design-complex-admin","entity-model-first","A complex multi-tier admin console: lock the entity model \u2192 study exemplars \u2192 design a LAYERED IA \u2192 wireframe (Artifact) \u2192 validate \u2192 build route-by-route. Kills the flat-console anti-pattern.",["design-complex-admin/layered-ia","design-complex-admin/wireframe-first","compose-a-screen/pick-primitives"]);let i=t?.consumerOnly?o.filter(r=>{let s=D(r.skill);return!s||s.audience!=="core"}):o;return i.length===0?t?.consumerOnly?[{skill:"compose-a-screen",section:"pick-primitives",why:`No keyword match for "${e}". Default consumer path: compose the screen from real primitives via the MCP.`,alsoSee:["design-to-page/map-to-primitives","taste/one-intent-per-screen"]}]:[{skill:"taste",section:"<see whenToUse>",why:`No keyword match for "${e}". Default to the "taste" baseline \u2014 see whenToUse for sections.`}]:i}var
|
|
4356
|
+
Do not advance a step until the prior artifact is signed off.`}]}];function D(e){return S.find(t=>t.id===e)}function K(e,t){return D(e)?.sections.find(a=>a.id===t)}function Y(e,t){let a=e.toLowerCase(),o=[],n=(r,s,u,m,g)=>{r.some(w=>a.includes(w))&&o.push({skill:s,section:u,why:m,alsoSee:g})};n(["spacing","gap","kho\u1EA3ng c\xE1ch","padding","margin","layout","b\u1ED1 c\u1EE5c","page","trang","grid","l\u01B0\u1EDBi","form","input","button","control","color","colour","m\xE0u","token","text","ch\u1EEF","typography","component","prop","audit","l\u1ED7i","error","how do i","l\xE0m sao","b\u1EAFt \u0111\u1EA7u","start"],"contract","<see whenToUse>","Lu\u1EADt c\u1EE9ng c\u1EE7a @godxjp/ui, m\u1ED7i lu\u1EADt k\xE8m c\u1ED5ng CI v\xE0 m\xE3 SAI/\u0110\xDANG. \u0110\u1ECDc tr\u01B0\u1EDBc m\u1ECDi skill v\u1EC1 gu.",["contract/loop","contract/spacing","contract/escape"]),n(["premium","awwwards","agency","linear","apple","high-end","luxury"],"soft","vibe-archetypes","Premium tier \u2014 pick a Vibe + Layout archetype + apply Double-Bezel.",["soft/double-bezel","soft/magnetic-hover"]),n(["landing page","marketing","hero","long scroll"],"imagegen-web","hero-composition-bias","Landing pages benefit from hero composition variety + per-section image generation.",["gpt-tasteskill/principles","soft/layout-archetypes"]),n(["mobile app","ios","android","phone screen","onboarding flow"],"imagegen-mobile","principles","Mobile app design \u2014 generate screens first, avoid phone-shaped-website.",["taste/mobile-first"]),n(["workspace","notion","document","editorial","knowledge base"],"minimalist","palette","Editorial workspace = warm monochrome + spot pastels + serif headings.",["minimalist/typography","minimalist/bento-grids"]),n(["dashboard","data heavy","tabular","ops table"],"brutalist","principles","Data-heavy dashboards work with Brutalist (rigid grids, utilitarian color).",["taste/one-intent-per-screen"]),n(["brand","identity","logo","guidelines"],"brandkit","principles","Brand identity work \u2014 boards before screens."),n(["refactor","redesign","upgrade existing","audit"],"redesign","fix-priority","Existing project = run audit first, fix in priority order (font \u2192 palette \u2192 states \u2192 ...).",["redesign/audit-checklist"]),n(["form","validation","submit","sign up","registration"],"taste","form-discipline","Form must have explicit label + help + error wired via FormField (rule 34)."),n(["loading","saving","skeleton","spinner"],"taste","loading-states","Skeleton for INIT fetch, Spinner for active work. Never mix."),n(["mobile first","responsive","breakpoint"],"taste","mobile-first","Default styles target xs. Touch targets \u2265 44px. Use useBreakpoint()."),n(["complete code","full implementation","no placeholder"],"output","banned","Banned: // ..., // TODO, 'for brevity'. Ship complete runnable code."),n(["gsap","scrolltrigger","scroll choreography","pinning"],"gpt-tasteskill","principles","GSAP ScrollTrigger \u2014 pinning, stacking, scrubbing."),n(["from image","image to code","design first"],"image-to-code","workflow","Generate design image first \u2192 analyze \u2192 implement."),n(["handoff","design bundle","claude design","prototype","build the page","implement the design","build this screen","mockup"],"design-to-page","map-to-primitives","Map every block to a real @godxjp/ui primitive (MCP-first), consume existing tokens, apply the reference-design DNA, tables central, gaps \u2192 extend-or-ask, verify.",["design-to-page/read-intent","design-to-page/dna","design-to-page/tables-central"]),n(["compose a screen","new screen","new page","create a page","create a screen","build a view","build a screen","from scratch","screen from a brief"],"compose-a-screen","pick-primitives","Build a new app screen from real @godxjp/ui primitives (MCP-first): one-intent-per-screen, real chrome, every state + a11y + i18n, verify.",["compose-a-screen/assemble-screen","compose-a-screen/state-and-a11y","taste/one-intent-per-screen"]),n(["bug in godx","godx-ui bug","report a bug","file an issue","gh issue","can't follow the rule","library is broken","primitive is broken"],"compose-a-screen","report-bug","If @godxjp/ui itself is at fault, don't fake a workaround \u2014 file a detailed gh issue (use draft_bug_report).",["design-to-page/report-bug"]),n(["slow","performance","perf","violation","long task","lag","janky","re-render","rerender","bundle size","code splitting","tree-shak","ch\u1EADm","l\u1ED7i hi\u1EC7u n\u0103ng","\u91CD\u3044"],"app-performance","measure-first","Measure FIRST (longtask + temporary Profiler), then apply the matching proven fix \u2014 page architecture, not the library, is almost always the culprit.",["app-performance/filter-pane-memo","app-performance/heavy-panels","app-performance/bundle-budget"]),n(["admin console","admin panel","control panel","back-office","back office","management console","management ui","multi-tenant","multi tenant","platform admin","workspace admin","console qu\u1EA3n tr\u1ECB","layered ia","information architecture"],"design-complex-admin","entity-model-first","A complex multi-tier admin console: lock the entity model \u2192 study exemplars \u2192 design a LAYERED IA \u2192 wireframe (Artifact) \u2192 validate \u2192 build route-by-route. Kills the flat-console anti-pattern.",["design-complex-admin/layered-ia","design-complex-admin/wireframe-first","compose-a-screen/pick-primitives"]);let i=t?.consumerOnly?o.filter(r=>{let s=D(r.skill);return!s||s.audience!=="core"}):o;return i.length===0?t?.consumerOnly?[{skill:"compose-a-screen",section:"pick-primitives",why:`No keyword match for "${e}". Default consumer path: compose the screen from real primitives via the MCP.`,alsoSee:["design-to-page/map-to-primitives","taste/one-intent-per-screen"]}]:[{skill:"taste",section:"<see whenToUse>",why:`No keyword match for "${e}". Default to the "taste" baseline \u2014 see whenToUse for sections.`}]:i}var O=[{category:"visual",name:"Purple-blue gradient hero",body:`The default LLM color palette \u2014 purple \u2192 blue \u2192 cyan radial /
|
|
4357
4357
|
linear gradient as hero background. Looks like every AI-generated
|
|
4358
4358
|
SaaS landing page from 2023.`,fix:`Use the framework's accent palette (\`data-accent="blue"\` /
|
|
4359
4359
|
"violet" / "cyan" / "green" / "orange" / "rose"). Solid surface
|
|
@@ -4463,7 +4463,7 @@ arrives.`,fix:`Use Skeleton placeholders matching the eventual content shape.
|
|
|
4463
4463
|
Render \`<Skeleton className="h-9 w-full" />\` in place of each control
|
|
4464
4464
|
\u2014 inside the FormField that will hold it, so the labels and grid stay
|
|
4465
4465
|
put. Height and fill are this screen's measurements; never add a
|
|
4466
|
-
\`rounded-*\`, because Skeleton already carries the radius token. Layout stays stable, perceived speed improves.`}];function $(e){return E.filter(t=>t.category===e)}var z=[{category:"typography",symptom:"Inter / Roboto / Open Sans everywhere \u2014 the AI default.",fix:"Pick a font with character: Geist, Outfit, Cabinet Grotesk, Satoshi for sans. For editorial / creative \u2014 pair a serif heading (Newsreader, Lyon, Playfair) with a sans body.",uiNote:"Override --font-sans + --font-serif at the consumer's root CSS. Framework reads from these tokens."},{category:"typography",symptom:"Headlines lack presence \u2014 small + thin + default tracking.",fix:"Increase display size, tighten letter-spacing (-0.02em to -0.04em), reduce line-height (1.1). Headlines should feel HEAVY and INTENTIONAL.",uiNote:"Typography.Title size={1} for hero; override fontFamily + letterSpacing inline."},{category:"typography",symptom:"Body paragraphs full-width \u2014 hard to read.",fix:"Limit paragraph max-width to ~65ch. Increase line-height to 1.6+.",uiNote:"Wrap Typography.Paragraph in `<div style={{ maxWidth: '65ch' }}>`."},{category:"typography",symptom:"Only Regular (400) + Bold (700) weights \u2014 flat hierarchy.",fix:"Introduce Medium (500) + SemiBold (600) for subtle weight contrasts."},{category:"typography",symptom:"Numbers in proportional font \u2014 columns jitter in tables.",fix:"`font-variant-numeric: tabular-nums` for data, or a monospace font like Geist Mono.",uiNote:"Table primitive already uses `tabular-nums` on `.num` cells. For ad-hoc numeric labels, add the CSS prop manually."},{category:"typography",symptom:"Orphaned words \u2014 single word on the last line of a heading.",fix:"`text-wrap: balance` (h1/h2/h3) or `text-wrap: pretty` (body)."},{category:"typography",symptom:"Title Case On Every Header.",fix:"Use sentence case instead. More modern, easier to read."},{category:"color-surface",symptom:"Pure #000000 background.",fix:"Replace with off-black / dark charcoal / tinted dark (deep navy).",uiNote:"Framework dark theme already uses tinted dark values \u2014 verify the consumer's override didn't force pure black."},{category:"color-surface",symptom:"Oversaturated accent colors.",fix:"Keep saturation below 80%. Desaturate so accents BLEND with neutrals rather than scream."},{category:"color-surface",symptom:"More than one accent color competing.",fix:"Pick ONE. Remove the rest. Consistency beats variety in palette.",uiNote:"Set ONE `data-accent` at `<html>` root. Use semantic colors (success / warning / destructive) only for genuinely semantic content."},{category:"color-surface",symptom:"Purple/blue 'AI gradient' aesthetic \u2014 most common AI fingerprint.",fix:"Replace with neutral base + ONE considered accent. Drop the gradient entirely if it has no narrative purpose."},{category:"color-surface",symptom:"Generic black `box-shadow` everywhere.",fix:"Tint shadow to match background hue (e.g. cool gray bg \u2192 cool gray shadow). Colored shadows over pure black."},{category:"color-surface",symptom:"Random dark section breaking an otherwise light page.",fix:"Either commit to full dark mode OR keep light consistently. If contrast needed, use a SLIGHTLY darker shade of the same palette \u2014 not a sudden jump to #111."},{category:"color-surface",symptom:"Empty flat sections with no visual depth.",fix:"Add depth with an ambient gradient at 0.02-0.05 opacity, or background imagery you COMMIT to the repo. Never a hotlinked placeholder service: a third-party image that never settles blocks `networkidle`, which times out a page load outright \u2014 it cost this repo two docs pages failing every browser gate. Empty flat = unfinished."},{category:"layout",symptom:"Everything centered + symmetric.",fix:"Break symmetry: offset margins, mixed aspect ratios, left-aligned header over centered body."},{category:"layout",symptom:"Three equal card columns as feature row \u2014 the most generic AI layout.",fix:"Replace with 2-column zig-zag, asymmetric grid, horizontal scroll, or masonry. The 3-equal-cols pattern is RED FLAG #1.",uiNote:"Use Bento Grid (custom CSS grid with `gridColumn: 'span N'`) instead of `<Grid cols={3}>` for hero sections."},{category:"layout",symptom:"`height: 100vh` causing iOS Safari jump.",fix:"Use `min-height: 100dvh` (dynamic viewport) instead."},{category:"layout",symptom:"No max-width container \u2014 content stretches edge-to-edge.",fix:"Add a container constraint (1200-1440px) with `margin: auto`. Or use `max-w-4xl / max-w-5xl` for content-heavy pages.",uiNote:"Framework's PageContent constrains via `var(--container-max-width)`. Consumer may override."},{category:"layout",symptom:"Cards forced to same height by flexbox.",fix:"Allow variable heights or use masonry when content varies.",uiNote:"Use Masonry primitive \u2014 handles variable heights without flexbox stretch."},{category:"layout",symptom:"Buttons at random vertical positions in card rows.",fix:"Pin CTAs to card bottom \u2014 same Y-position across the row regardless of content above.",uiNote:"Card's `actions` footer slot bottom-aligns automatically."},{category:"layout",symptom:"Feature lists starting at different vertical positions in pricing tables.",fix:"Fixed-height title/price block + consistent spacing above the feature list. Cards align across columns."},{category:"layout",symptom:"Dashboard ALWAYS has a left sidebar.",fix:"Consider top navigation, floating command menu, or collapsible panel. Sidebar isn't the only chrome.",uiNote:"Framework supports both \u2014 AppShell with sidebar slot is optional; can use Topbar-only for some flows."},{category:"interactivity",symptom:"No hover states on buttons.",fix:"Background shift, scale, or translate on hover \u2014 150-200ms ease.",uiNote:"Framework Button has built-in hover. If overridden \u2014 restore."},{category:"interactivity",symptom:"No active/pressed feedback.",fix:"`scale(0.98)` or `translateY(1px)` on `:active`. Simulates a physical click."},{category:"interactivity",symptom:"No focus ring (`outline: none`).",fix:"Restore visible `:focus-visible` ring. Accessibility requirement, not optional."},{category:"interactivity",symptom:"Generic circular spinner for page-level loading.",fix:"Replace with Skeleton placeholders matching the eventual content shape.",uiNote:"Framework Skeleton + Form `loading={{ kind: 'skeleton' }}` handles cascading initial-fetch state."},{category:"interactivity",symptom:"No empty states \u2014 empty dashboard shows nothing.",fix:"Design a composed 'getting started' view: Empty primitive with title + description + next-action button."},{category:"interactivity",symptom:"`window.alert()` for errors.",fix:"Inline error in the relevant Field, OR toast for non-form errors, OR Dialog for blocking errors."},{category:"interactivity",symptom:"Dead links (`href='#'`).",fix:"Either link to real destinations or visually disable the button."},{category:"interactivity",symptom:"No indication of current page in navigation.",fix:"Style the active nav link distinctly.",uiNote:"Sidebar handles via `activeId` \u2014 pass it."},{category:"content",symptom:"Generic names \u2014 'John Doe', 'Jane Smith'.",fix:"Diverse, realistic names. For Japanese apps: \u7530\u4E2D \u592A\u90CE, \u4F50\u85E4 \u7F8E\u54B2, Nguy\u1EC5n Lan, Maria Cruz."},{category:"content",symptom:"Fake round numbers \u2014 '99.99%', '50%', '$100.00'.",fix:"Organic data: '47.2%', '$99.00', '+1 (312) 847-1928'."},{category:"content",symptom:"Placeholder brand names \u2014 Acme, Nexus, SmartFlow.",fix:"Invent contextual believable brands or use the consumer's real brand."},{category:"content",symptom:"AI copy clich\xE9s \u2014 'elevate', 'seamless', 'unleash', 'next-gen', 'game-changer', 'delve', 'tapestry', 'in the world of'.",fix:"Plain specific language. Numbers, nouns, verbs.",uiNote:"Framework's cardinal rule 9 bans this in framework docs; same discipline applies to consumer copy."},{category:"content",symptom:"Exclamation marks in success messages.",fix:"Remove. Be confident, not loud."},{category:"content",symptom:"'Oops!' or apologetic error messages.",fix:"Direct + specific: 'Connection failed. Please try again.' / '\u30E1\u30FC\u30EB\u30A2\u30C9\u30EC\u30B9\u306E\u5F62\u5F0F\u304C\u6B63\u3057\u304F\u3042\u308A\u307E\u305B\u3093'."},{category:"content",symptom:"Lorem Ipsum.",fix:"Real draft copy. Even rough placeholder beats Latin."},{category:"components",symptom:"Generic card look (border + shadow + white).",fix:"Remove border OR shadow OR background \u2014 keep ONE. Cards exist only when elevation communicates hierarchy."},{category:"components",symptom:"Always one filled + one ghost button.",fix:"Add text links / tertiary styles for variety.",uiNote:"Button has `variant='link'` for tertiary actions."},{category:"components",symptom:"3-card carousel testimonials with dots.",fix:"Replace with masonry wall of quotes, embedded social posts, or single rotating quote."},{category:"components",symptom:"Pricing table with 3 equal towers.",fix:"Highlight recommended tier with COLOR and emphasis, not just extra height."},{category:"components",symptom:"Modals for everything.",fix:"Use inline editing, Sheet (slide-over), or expandable Collapse for simple actions. Reserve Dialog for true blocking decisions."},{category:"components",symptom:"Footer link farm with 4 columns.",fix:"Simplify. Main nav paths + legally required links. No marketing kitchen sink."},{category:"iconography",symptom:"Lucide or Feather icons exclusively.",fix:"Use Phosphor (Bold / Fill), Heroicons, or a custom set. AI default tell.",uiNote:"Framework ships with lucide as locked dependency (rule 14). For editorial differentiation, layer Phosphor on top."},{category:"iconography",symptom:"Cliche icon metaphors \u2014 rocketship 'launch', shield 'security'.",fix:"Less obvious: bolt, fingerprint, spark, vault, gem."},{category:"iconography",symptom:"Stock 'diverse team in office' photo.",fix:"Real team photos, candid shots, or a consistent illustration style. Avatar initials fallback > generic stock person."},{category:"code-quality",symptom:"Div soup \u2014 no semantic HTML.",fix:"`<nav>`, `<main>`, `<article>`, `<aside>`, `<section>` for landmarks.",uiNote:"AppShell renders the canonical landmark structure automatically."},{category:"code-quality",symptom:"Inline styles mixed with CSS classes haphazardly.",fix:"Move styling into the project's system. Inline `style={{}}` only for layout / positioning (rule 29)."},{category:"code-quality",symptom:"Missing alt text on images.",fix:"Describe content for SR. Never leave `alt=''` or `alt='image'` on meaningful images."},{category:"code-quality",symptom:"Arbitrary z-index values like `9999`.",fix:"Establish a clean z-index scale in CSS variables."},{category:"omissions",symptom:"No legal links in footer.",fix:"Add Privacy Policy + Terms of Service."},{category:"omissions",symptom:"Dead ends in user flows \u2014 no 'back'.",fix:"Every page has a way back. Breadcrumb, back button, OR clear nav state."},{category:"omissions",symptom:"No custom 404 page.",fix:"Design a helpful branded 404 with a way home and search."},{category:"omissions",symptom:"No form validation.",fix:"Client-side validation via zod schema. Framework's Form + FormField handle field-level errors automatically."},{category:"omissions",symptom:"No 'skip to content' link.",fix:"Hidden skip-link, first focusable element. Essential for keyboard users.",uiNote:"AppShell renders one automatically."}],X=["1. Font swap \u2014 biggest instant improvement, lowest risk","2. Color palette cleanup \u2014 remove clashing / oversaturated colors","3. Hover + active states \u2014 makes the interface feel alive","4. Layout + spacing \u2014 proper grid, max-width, consistent padding","5. Replace generic components \u2014 swap cliche patterns for modern alternatives","6. Add loading, empty, error states \u2014 makes it feel finished","7. Polish typography scale + spacing \u2014 the premium final touch"],Q=["Work with the existing tech stack. Do NOT migrate frameworks or styling libraries.","Do NOT break existing functionality. Test after every change.","Before importing any new library, check `package.json` first.","Keep changes reviewable + focused. Small targeted improvements over big rewrites.","Run the audit before fixing \u2014 listing issues first prevents accidental scope creep."];function J(e){return z.filter(t=>t.category===e)}var ee="node node_modules/@godxjp/ui/scripts/ui-audit.mjs (add --format json for machine output, --rules to print this catalog)",te=`// ui-audit-disable-line <rule-id> \u2014 this line
|
|
4466
|
+
\`rounded-*\`, because Skeleton already carries the radius token. Layout stays stable, perceived speed improves.`}];function $(e){return O.filter(t=>t.category===e)}var z=[{category:"typography",symptom:"Inter / Roboto / Open Sans everywhere \u2014 the AI default.",fix:"Pick a font with character: Geist, Outfit, Cabinet Grotesk, Satoshi for sans. For editorial / creative \u2014 pair a serif heading (Newsreader, Lyon, Playfair) with a sans body.",uiNote:"Override --font-sans + --font-serif at the consumer's root CSS. Framework reads from these tokens."},{category:"typography",symptom:"Headlines lack presence \u2014 small + thin + default tracking.",fix:"Increase display size, tighten letter-spacing (-0.02em to -0.04em), reduce line-height (1.1). Headlines should feel HEAVY and INTENTIONAL.",uiNote:"Typography.Title size={1} for hero; override fontFamily + letterSpacing inline."},{category:"typography",symptom:"Body paragraphs full-width \u2014 hard to read.",fix:"Limit paragraph max-width to ~65ch. Increase line-height to 1.6+.",uiNote:"Wrap Typography.Paragraph in `<div style={{ maxWidth: '65ch' }}>`."},{category:"typography",symptom:"Only Regular (400) + Bold (700) weights \u2014 flat hierarchy.",fix:"Introduce Medium (500) + SemiBold (600) for subtle weight contrasts."},{category:"typography",symptom:"Numbers in proportional font \u2014 columns jitter in tables.",fix:"`font-variant-numeric: tabular-nums` for data, or a monospace font like Geist Mono.",uiNote:"Table primitive already uses `tabular-nums` on `.num` cells. For ad-hoc numeric labels, add the CSS prop manually."},{category:"typography",symptom:"Orphaned words \u2014 single word on the last line of a heading.",fix:"`text-wrap: balance` (h1/h2/h3) or `text-wrap: pretty` (body)."},{category:"typography",symptom:"Title Case On Every Header.",fix:"Use sentence case instead. More modern, easier to read."},{category:"color-surface",symptom:"Pure #000000 background.",fix:"Replace with off-black / dark charcoal / tinted dark (deep navy).",uiNote:"Framework dark theme already uses tinted dark values \u2014 verify the consumer's override didn't force pure black."},{category:"color-surface",symptom:"Oversaturated accent colors.",fix:"Keep saturation below 80%. Desaturate so accents BLEND with neutrals rather than scream."},{category:"color-surface",symptom:"More than one accent color competing.",fix:"Pick ONE. Remove the rest. Consistency beats variety in palette.",uiNote:"Set ONE `data-accent` at `<html>` root. Use semantic colors (success / warning / destructive) only for genuinely semantic content."},{category:"color-surface",symptom:"Purple/blue 'AI gradient' aesthetic \u2014 most common AI fingerprint.",fix:"Replace with neutral base + ONE considered accent. Drop the gradient entirely if it has no narrative purpose."},{category:"color-surface",symptom:"Generic black `box-shadow` everywhere.",fix:"Tint shadow to match background hue (e.g. cool gray bg \u2192 cool gray shadow). Colored shadows over pure black."},{category:"color-surface",symptom:"Random dark section breaking an otherwise light page.",fix:"Either commit to full dark mode OR keep light consistently. If contrast needed, use a SLIGHTLY darker shade of the same palette \u2014 not a sudden jump to #111."},{category:"color-surface",symptom:"Empty flat sections with no visual depth.",fix:"Add depth with an ambient gradient at 0.02-0.05 opacity, or background imagery you COMMIT to the repo. Never a hotlinked placeholder service: a third-party image that never settles blocks `networkidle`, which times out a page load outright \u2014 it cost this repo two docs pages failing every browser gate. Empty flat = unfinished."},{category:"layout",symptom:"Everything centered + symmetric.",fix:"Break symmetry: offset margins, mixed aspect ratios, left-aligned header over centered body."},{category:"layout",symptom:"Three equal card columns as feature row \u2014 the most generic AI layout.",fix:"Replace with 2-column zig-zag, asymmetric grid, horizontal scroll, or masonry. The 3-equal-cols pattern is RED FLAG #1.",uiNote:"Use Bento Grid (custom CSS grid with `gridColumn: 'span N'`) instead of `<Grid cols={3}>` for hero sections."},{category:"layout",symptom:"`height: 100vh` causing iOS Safari jump.",fix:"Use `min-height: 100dvh` (dynamic viewport) instead."},{category:"layout",symptom:"No max-width container \u2014 content stretches edge-to-edge.",fix:"Add a container constraint (1200-1440px) with `margin: auto`. Or use `max-w-4xl / max-w-5xl` for content-heavy pages.",uiNote:"Framework's PageContent constrains via `var(--container-max-width)`. Consumer may override."},{category:"layout",symptom:"Cards forced to same height by flexbox.",fix:"Allow variable heights or use masonry when content varies.",uiNote:"Use Masonry primitive \u2014 handles variable heights without flexbox stretch."},{category:"layout",symptom:"Buttons at random vertical positions in card rows.",fix:"Pin CTAs to card bottom \u2014 same Y-position across the row regardless of content above.",uiNote:"Card's `actions` footer slot bottom-aligns automatically."},{category:"layout",symptom:"Feature lists starting at different vertical positions in pricing tables.",fix:"Fixed-height title/price block + consistent spacing above the feature list. Cards align across columns."},{category:"layout",symptom:"Dashboard ALWAYS has a left sidebar.",fix:"Consider top navigation, floating command menu, or collapsible panel. Sidebar isn't the only chrome.",uiNote:"Framework supports both \u2014 AppShell with sidebar slot is optional; can use Topbar-only for some flows."},{category:"interactivity",symptom:"No hover states on buttons.",fix:"Background shift, scale, or translate on hover \u2014 150-200ms ease.",uiNote:"Framework Button has built-in hover. If overridden \u2014 restore."},{category:"interactivity",symptom:"No active/pressed feedback.",fix:"`scale(0.98)` or `translateY(1px)` on `:active`. Simulates a physical click."},{category:"interactivity",symptom:"No focus ring (`outline: none`).",fix:"Restore visible `:focus-visible` ring. Accessibility requirement, not optional."},{category:"interactivity",symptom:"Generic circular spinner for page-level loading.",fix:"Replace with Skeleton placeholders matching the eventual content shape.",uiNote:"Framework Skeleton + Form `loading={{ kind: 'skeleton' }}` handles cascading initial-fetch state."},{category:"interactivity",symptom:"No empty states \u2014 empty dashboard shows nothing.",fix:"Design a composed 'getting started' view: Empty primitive with title + description + next-action button."},{category:"interactivity",symptom:"`window.alert()` for errors.",fix:"Inline error in the relevant Field, OR toast for non-form errors, OR Dialog for blocking errors."},{category:"interactivity",symptom:"Dead links (`href='#'`).",fix:"Either link to real destinations or visually disable the button."},{category:"interactivity",symptom:"No indication of current page in navigation.",fix:"Style the active nav link distinctly.",uiNote:"Sidebar handles via `activeId` \u2014 pass it."},{category:"content",symptom:"Generic names \u2014 'John Doe', 'Jane Smith'.",fix:"Diverse, realistic names. For Japanese apps: \u7530\u4E2D \u592A\u90CE, \u4F50\u85E4 \u7F8E\u54B2, Nguy\u1EC5n Lan, Maria Cruz."},{category:"content",symptom:"Fake round numbers \u2014 '99.99%', '50%', '$100.00'.",fix:"Organic data: '47.2%', '$99.00', '+1 (312) 847-1928'."},{category:"content",symptom:"Placeholder brand names \u2014 Acme, Nexus, SmartFlow.",fix:"Invent contextual believable brands or use the consumer's real brand."},{category:"content",symptom:"AI copy clich\xE9s \u2014 'elevate', 'seamless', 'unleash', 'next-gen', 'game-changer', 'delve', 'tapestry', 'in the world of'.",fix:"Plain specific language. Numbers, nouns, verbs.",uiNote:"Framework's cardinal rule 9 bans this in framework docs; same discipline applies to consumer copy."},{category:"content",symptom:"Exclamation marks in success messages.",fix:"Remove. Be confident, not loud."},{category:"content",symptom:"'Oops!' or apologetic error messages.",fix:"Direct + specific: 'Connection failed. Please try again.' / '\u30E1\u30FC\u30EB\u30A2\u30C9\u30EC\u30B9\u306E\u5F62\u5F0F\u304C\u6B63\u3057\u304F\u3042\u308A\u307E\u305B\u3093'."},{category:"content",symptom:"Lorem Ipsum.",fix:"Real draft copy. Even rough placeholder beats Latin."},{category:"components",symptom:"Generic card look (border + shadow + white).",fix:"Remove border OR shadow OR background \u2014 keep ONE. Cards exist only when elevation communicates hierarchy."},{category:"components",symptom:"Always one filled + one ghost button.",fix:"Add text links / tertiary styles for variety.",uiNote:"Button has `variant='link'` for tertiary actions."},{category:"components",symptom:"3-card carousel testimonials with dots.",fix:"Replace with masonry wall of quotes, embedded social posts, or single rotating quote."},{category:"components",symptom:"Pricing table with 3 equal towers.",fix:"Highlight recommended tier with COLOR and emphasis, not just extra height."},{category:"components",symptom:"Modals for everything.",fix:"Use inline editing, Sheet (slide-over), or expandable Collapse for simple actions. Reserve Dialog for true blocking decisions."},{category:"components",symptom:"Footer link farm with 4 columns.",fix:"Simplify. Main nav paths + legally required links. No marketing kitchen sink."},{category:"iconography",symptom:"Lucide or Feather icons exclusively.",fix:"Use Phosphor (Bold / Fill), Heroicons, or a custom set. AI default tell.",uiNote:"Framework ships with lucide as locked dependency (rule 14). For editorial differentiation, layer Phosphor on top."},{category:"iconography",symptom:"Cliche icon metaphors \u2014 rocketship 'launch', shield 'security'.",fix:"Less obvious: bolt, fingerprint, spark, vault, gem."},{category:"iconography",symptom:"Stock 'diverse team in office' photo.",fix:"Real team photos, candid shots, or a consistent illustration style. Avatar initials fallback > generic stock person."},{category:"code-quality",symptom:"Div soup \u2014 no semantic HTML.",fix:"`<nav>`, `<main>`, `<article>`, `<aside>`, `<section>` for landmarks.",uiNote:"AppShell renders the canonical landmark structure automatically."},{category:"code-quality",symptom:"Inline styles mixed with CSS classes haphazardly.",fix:"Move styling into the project's system. Inline `style={{}}` only for layout / positioning (rule 29)."},{category:"code-quality",symptom:"Missing alt text on images.",fix:"Describe content for SR. Never leave `alt=''` or `alt='image'` on meaningful images."},{category:"code-quality",symptom:"Arbitrary z-index values like `9999`.",fix:"Establish a clean z-index scale in CSS variables."},{category:"omissions",symptom:"No legal links in footer.",fix:"Add Privacy Policy + Terms of Service."},{category:"omissions",symptom:"Dead ends in user flows \u2014 no 'back'.",fix:"Every page has a way back. Breadcrumb, back button, OR clear nav state."},{category:"omissions",symptom:"No custom 404 page.",fix:"Design a helpful branded 404 with a way home and search."},{category:"omissions",symptom:"No form validation.",fix:"Client-side validation via zod schema. Framework's Form + FormField handle field-level errors automatically."},{category:"omissions",symptom:"No 'skip to content' link.",fix:"Hidden skip-link, first focusable element. Essential for keyboard users.",uiNote:"AppShell renders one automatically."}],X=["1. Font swap \u2014 biggest instant improvement, lowest risk","2. Color palette cleanup \u2014 remove clashing / oversaturated colors","3. Hover + active states \u2014 makes the interface feel alive","4. Layout + spacing \u2014 proper grid, max-width, consistent padding","5. Replace generic components \u2014 swap cliche patterns for modern alternatives","6. Add loading, empty, error states \u2014 makes it feel finished","7. Polish typography scale + spacing \u2014 the premium final touch"],Q=["Work with the existing tech stack. Do NOT migrate frameworks or styling libraries.","Do NOT break existing functionality. Test after every change.","Before importing any new library, check `package.json` first.","Keep changes reviewable + focused. Small targeted improvements over big rewrites.","Run the audit before fixing \u2014 listing issues first prevents accidental scope creep."];function J(e){return z.filter(t=>t.category===e)}var ee="node node_modules/@godxjp/ui/scripts/ui-audit.mjs (add --format json for machine output, --rules to print this catalog)",te=`// ui-audit-disable-line <rule-id> \u2014 this line
|
|
4467
4467
|
// ui-audit-disable-next-line <rule-id> \u2014 the line below
|
|
4468
4468
|
// ui-audit-disable-begin <rule-id> \u2014 <reason, 12+ chars>
|
|
4469
4469
|
// \u2026 the whole region (one marker, however prettier wraps it) \u2026
|
|
@@ -4473,7 +4473,7 @@ A block with no reason is IGNORED and the finding stands. An unclosed block runs
|
|
|
4473
4473
|
The class-shaped rules (gap-*/p-*/m-*, bg-<palette>-*, w-[\u2026], pr-*, dark:*) only read class
|
|
4474
4474
|
expressions \u2014 a className/class attribute, a class-named binding (\`baseClass\`, \`statusStyles\`,
|
|
4475
4475
|
\`badgeVariants\`) or a cn()/clsx()/cva() call \u2014 so prose that merely spells a utility is not a
|
|
4476
|
-
finding and needs no suppression.`,Z=[{id:"dialog-needs-body",severity:"error",category:"composition",standard:null,fix:"Wrap a Dialog/Sheet's middle in <DialogBody>/<SheetBody>. The scroll lives on the body \u2014 the content box is `overflow: hidden` with no max-height \u2014 so an overlay without one clips long content at BOTH ends and takes the footer's buttons with it, leaving Escape as the only way out. It only shows on real data, never on demo data (gh#617)."},{id:"no-utility-spacing",severity:"error",category:"composition",standard:null,fix:"Remove gap-*/p-*/m-* from your own markup; space siblings with <Flex gap> / <ResponsiveGrid>. Page sections are spaced by <PageContainer> (docs/CONSUMER-RULES.md \xA73)."},{id:"no-utility-layout",severity:"error",category:"composition",standard:null,fix:'Replace className="flex \u2026" / "grid \u2026" with <Flex> (row), <Flex direction="col"> (stack) or <ResponsiveGrid columns>.'},{id:"no-hand-rolled-surface",severity:"warn",category:"composition",standard:null,fix:"A rounded+border/bg div is a fake surface \u2014 use Card, Badge, Avatar, ListRow, Descriptions or EmptyState so height, padding and radius come from tokens. A read-only sample of a colour a USER chose is Swatch, which takes that value as a prop (gh#527)."},{id:"sibling-cards-need-flex",severity:"warn",category:"composition",standard:null,fix:'Wrap adjacent <Card>s in <Flex direction="col" gap="lg"> or <ResponsiveGrid>; direct children of PageContainer are spaced by the page already.'},{id:"no-raw-palette-color",severity:"error",category:"tokens",standard:null,fix:"Use semantic tokens (bg-primary, text-muted-foreground), never raw palette (bg-blue-500)."},{id:"no-arbitrary-hex",severity:"error",category:"tokens",standard:null,fix:"No hardcoded hex in className; read design-system color tokens."},{id:"no-arbitrary-spacing",severity:"error",category:"tokens",standard:null,fix:"No p-[13px]/gap-[7px]; use the token scale / <Flex gap> / <PageContainer>."},{id:"no-arbitrary-size",severity:"error",category:"tokens",standard:null,fix:"No w-[37px]/h-[260px]; use token sizes or a sizing prop (min-w-[\u2026] allowed)."},{id:"no-arbitrary-typography",severity:"error",category:"tokens",standard:null,fix:"No text-[20px]/leading-[1.7]; use the golden-ratio type-scale tokens."},{id:"no-arbitrary-radius",severity:"error",category:"tokens",standard:null,fix:"No rounded-[6px]; use rounded-sm/md/lg radius tokens."},{id:"no-off-scale-token-value",severity:"warn",category:"tokens",standard:null,fix:"A design-system knob you override takes a step (style={{ '--card-space-inset': 'var(--space-4)' }}) or a calc() from one (calc(var(--space-4) + 2px)), not a raw 13px. Only axes that HAVE a scale count: space/padding/gap/margin, font-size, radius, icon-size (width/height/size/offset have none yet, so a number there is fine). A value that is genuinely off the grid keeps its literal and says why in place, with a /* scale-exempt: 6px status dot, below --space-1 */ comment on that line or the one above."},{id:"no-dark-color-override",severity:"warn",category:"tokens",standard:null,fix:"Drop dark: color overrides \u2014 semantic tokens already adapt."},{id:"raw-white-black",severity:"warn",category:"tokens",standard:null,fix:"Prefer semantic tokens (text-primary-foreground, bg-background) over raw white/black."},{id:"no-domain-tracking-token",severity:"error",category:"tokens",standard:null,fix:"No package-tracking/domain tokens; use semantic tokens or app theme overrides."},{id:"no-space-xy",severity:"error",category:"tokens",standard:null,fix:"Use <Flex gap> instead of space-x/y-*."},{id:"no-raw-select",severity:"error",category:"composition",standard:"HTML Living Standard (WHATWG)",fix:"Use <Select> from @godxjp/ui, not a raw <select>."},{id:"no-raw-table",severity:"error",category:"composition",standard:"HTML Living Standard (WHATWG)",fix:"Use the <Table>/<DataTable> family, not a raw <table>."},{id:"no-raw-input",severity:"error",category:"composition",standard:"HTML Living Standard (WHATWG)",fix:"Use <Input> from @godxjp/ui, not a raw <input>."},{id:"no-raw-textarea",severity:"warn",category:"composition",standard:"HTML Living Standard (WHATWG)",fix:"Use <Textarea> from @godxjp/ui, not a raw <textarea>."},{id:"no-raw-button",severity:"error",category:"composition",standard:"HTML Living Standard (WHATWG)",fix:"Use <Button> from @godxjp/ui, not a raw <button>."},{id:"card-manual-padding",severity:"error",category:"composition",standard:null,fix:"Wrap the body in <CardContent>; don't hand-roll padding on <Card>."},{id:"card-needs-content",severity:"error",category:"composition",standard:null,fix:"<Card> body must be in <CardContent> (no padding otherwise); flush only for a full-bleed table."},{id:"bare-control-needs-formfield",severity:"warn",category:"composition",standard:"WCAG 2.2 SC 1.3.1 \xB7 3.3.2 \xB7 @godxjp/ui FormField (cardinal rule 227)",fix:"Wrap a labelled control in <FormField label=\u2026> \u2014 it owns label\u2194control id wiring, aria/error, AND the field rhythm; never pair a bare <Label> with an <Input>."},{id:"manual-field-error",severity:"warn",category:"composition",standard:"WCAG 2.2 SC 3.3.1",fix:"Use <FormField error=\u2026>, not a hand-rolled <p class='text-destructive'>."},{id:"manual-field-helper",severity:"warn",category:"composition",standard:null,fix:"Use <FormField helper=\u2026>, not a hand-rolled helper <p>."},{id:"status-tone-not-variant",severity:"error",category:"api",standard:null,fix:"Badge/Tag/StatCard status uses tone, not variant (variant is structural)."},{id:"value-callback-on-value-change",severity:"error",category:"api",standard:null,fix:"Abstract value components use onValueChange, not onChange."},{id:"icon-button-needs-name",severity:"warn",category:"a11y",standard:"WCAG 2.2 SC 4.1.2 \xB7 1.1.1 \xB7 WAI-ARIA 1.2",fix:"Add aria-label={t('\u2026')} to <Button size='icon'>; the glyph is aria-hidden."},{id:"img-needs-alt",severity:"warn",category:"a11y",standard:"WCAG 2.2 SC 1.1.1 \xB7 HTML Living Standard",fix:"Add alt to every <img> (alt='' if decorative); prefer <Avatar>/<AspectRatio>."},{id:"no-positive-tabindex",severity:"warn",category:"a11y",standard:"WCAG 2.2 SC 2.4.3 \xB7 WAI-ARIA APG",fix:"Use tabIndex 0 or -1 only; never positive \u2014 it breaks focus order."},{id:"hand-rolled-close-glyph",severity:"warn",category:"a11y",standard:"WAI-ARIA 1.2 (dialog) \xB7 WCAG 2.2 SC 4.1.2",fix:"Pass onDismiss to <Alert>, or use <Dialog>/<Sheet>'s built-in labelled close \u2014 not a bare \u2715."},{id:"no-emoji-in-ui",severity:"warn",category:"i18n",standard:"Unicode UTS #51 \xB7 WCAG 2.2 SC 1.1.1",fix:"No emoji in product UI; quiet i18n copy + Lucide icon + Badge tone."},{id:"no-emoji-flag",severity:"warn",category:"i18n",standard:"ISO 3166-1 \xB7 ECMA-402 Intl.DisplayNames \xB7 Unicode UTS #51",fix:"Derive country names from Intl.DisplayNames; no emoji flags."},{id:"hardcoded-currency",severity:"warn",category:"i18n",standard:"ISO 4217 \xB7 ECMA-402 Intl.NumberFormat",fix:"Format money with Intl.NumberFormat({ style: 'currency', currency }), not \xA5{amount}."},{id:"raw-intl-date",severity:"warn",category:"i18n",standard:"ISO 8601 \xB7 IANA tz \xB7 ECMA-402 Intl.DateTimeFormat",fix:"Use formatDate from @godxjp/ui/datetime, not hand-built or locale-default dates."},{id:"no-physical-direction",severity:"warn",category:"rtl",standard:"W3C CSS Logical Properties L1 \xB7 WCAG 2.2 (1.3.2)",fix:"Use logical utilities (ms-/me-/ps-/pe-, start-/end-, text-start/end, border-s/e, rounded-s/e)."},{id:"no-em-dash-in-copy",severity:"warn",category:"copy",standard:"@godxjp/ui reference-design typography",fix:"No em-dash (\u2014) in copy; use a middot \xB7 or two calm sentences."},{id:"lucide-icon-needs-size",severity:"warn",category:"composition",standard:"WCAG 2.2 SC 1.4.4 \xB7 @godxjp/ui icon scale (--icon-size-*)",fix:'A lucide glyph outside a sizing context draws at its intrinsic 24px. Render it as <Icon as={Lock} size="sm" tone="muted" /> \u2014 the primitive puts it on the --icon-size-* scale and is aria-hidden unless you pass a label.'},{id:"no-hand-rolled-list",severity:"warn",category:"composition",standard:"WAI-ARIA 1.2 (list / listitem) \xB7 HTML Living Standard (ul/ol/li) \xB7 WCAG 2.2 SC 1.3.1",fix:'Build the list as <Flex as="ul" marker="none" direction="col" gap="none"> with <ListRow as="li"> rows \u2014 not a raw <ul>/<ol> (no gap token), not <div role="list">/<div role="listitem">, 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 (a consumer lost every divider in a settings menu and a dashboard this way). marker="none" keeps the element, the <li> semantics and the gap, and drops the bullet and the --space-5 indent (gh#714). A deliberate exception \u2014 a drag-and-drop Kanban column, an evidence list inside a TableCell \u2014 takes an ui-audit-disable-line that says so.'}];function ae(e){return e?Z.filter(t=>t.category===e):Z}var ne="node node_modules/@godxjp/ui/scripts/visual-audit.mjs <baseUrl> [route \u2026] (optional peers, TESTED range: playwright >=1.55 <2 [1.61.1] + @axe-core/playwright >=4.10 <5 [4.12.1] + axe-core >=4.10 <5 [4.12.1] + a chromium via `playwright install chromium`; --strict for a CI gate, --format json ALWAYS emits valid JSON with a status of ok|partial|error separating infra errors[] from product findings[], --rules to print this catalog)",oe=[{id:"css-layers-missing",severity:"error",category:"layout",standard:"@godxjp/ui styles contract (styles / styles/core are the only entries)",fix:"Import `@godxjp/ui/styles` (or `styles/core` without fonts); never cherry-pick *-layout.css \u2014 a missing layer renders naked menus and unsized Select rows."},{id:"control-height-mismatch",severity:"error",category:"layout",standard:"@godxjp/ui control tier (--control-height) \xB7 Nielsen consistency heuristic",fix:"Every control in one row must share --control-height; replace hand-rolled pills with Avatar/Button/Badge, never restyle a control's height."},{id:"sibling-card-gap",severity:"error",category:"layout",standard:"@godxjp/ui spacing scale (docs/SPACING.md)",fix:'Adjacent Cards need one space step between them \u2014 <Flex direction="col" gap>, <ResponsiveGrid>, or direct children of PageContainer.'},{id:"row-content-starved",severity:"warn",category:"layout",standard:"WCAG 2.2 SC 1.4.10 reflow",fix:`A sibling (a w-full SelectTrigger) takes the row's width and truncates its neighbours \u2014 give the Select width="auto" or move it out of the row.`},{id:"axe-violations",severity:"warn",category:"a11y",standard:"WCAG 2.2 A/AA \xB7 WAI-ARIA 1.2 (axe-core engine)",fix:"Fix each axe node \u2014 contrast (1.4.3), name/role/value (4.1.2), ARIA, landmarks. Runs on the REAL DOM, catching what static analysis cannot."},{id:"target-size-min",severity:"warn",category:"a11y",standard:"WCAG 2.2 SC 2.5.8 (24\xD724 AA) \xB7 2.5.5 (44\xD744 AAA)",fix:"Interactive targets must be \u226524\xD724 CSS px; size from the --control-height tier."},{id:"oversaturated-accent",severity:"warn",category:"color",standard:"@godxjp/ui reference-design \u6E0B\u307F (OKLCH chroma \u2264 0.18)",fix:"Desaturate brand/primary surfaces (OKLCH chroma \u2264 0.18); read --primary tokens, no raw vivid bars."},{id:"emoji-rendered",severity:"warn",category:"i18n",standard:"Unicode UTS #51 \xB7 WCAG 2.2 SC 1.1.1",fix:"Remove emoji from rendered product text; quiet i18n copy + Lucide icon + Badge tone."},{id:"alert-controls-misplaced",severity:"warn",category:"layout",standard:"@godxjp/ui Alert anatomy \xB7 WAI-ARIA 1.2 \xB7 WCAG 2.2 SC 4.1.2",fix:"Use <Alert>: one leading tone icon, <Alert.Actions> trailing-right normal width, onDismiss \xD7 top-right, one horizontal row."}];function ie(e){return e?oe.filter(t=>t.category===e):oe}var l={name:"@godxjp/ui-mcp",version:"27.10.0",godxUiCompatibility:"27.10.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 B=[{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.",inputSchema:{type:"object",properties:{group:{type:"string",enum:["general","layout","data-display","data-entry","feedback","navigation","composites","shell","providers"]}}}},{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.",inputSchema:{type:"object",properties:{query:{type:"string"}},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:"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"]}}],De=new Set(B.map(e=>e.name));function Ee(e=H()){let t=l.godxUiCompatibility??l.version,a=`@godxjp/ui-mcp ${l.version} (catalog for @godxjp/ui ${t})`;if(!e)return a;let o=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} (${o})`}function Oe(e=H()){let t=e?P(e.version):null,a=P(l.version);return!e||!t||!a?null:Le(t,a)>0?`\u26A0\uFE0F SERVER OLDER THAN INSTALLED PACKAGE: this server is @godxjp/ui-mcp ${l.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 ${l.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 ce(e,t){let a=await Ne(e,t);if(!De.has(e))return a;let o=H(),n=Oe(o);return`${Ee(o)}
|
|
4476
|
+
finding and needs no suppression.`,Z=[{id:"dialog-needs-body",severity:"error",category:"composition",standard:null,fix:"Wrap a Dialog/Sheet's middle in <DialogBody>/<SheetBody>. The scroll lives on the body \u2014 the content box is `overflow: hidden` with no max-height \u2014 so an overlay without one clips long content at BOTH ends and takes the footer's buttons with it, leaving Escape as the only way out. It only shows on real data, never on demo data (gh#617)."},{id:"no-utility-spacing",severity:"error",category:"composition",standard:null,fix:"Remove gap-*/p-*/m-* from your own markup; space siblings with <Flex gap> / <ResponsiveGrid>. Page sections are spaced by <PageContainer> (docs/CONSUMER-RULES.md \xA73)."},{id:"no-utility-layout",severity:"error",category:"composition",standard:null,fix:'Replace className="flex \u2026" / "grid \u2026" with <Flex> (row), <Flex direction="col"> (stack) or <ResponsiveGrid columns>.'},{id:"no-hand-rolled-surface",severity:"warn",category:"composition",standard:null,fix:"A rounded+border/bg div is a fake surface \u2014 use Card, Badge, Avatar, ListRow, Descriptions or EmptyState so height, padding and radius come from tokens. A read-only sample of a colour a USER chose is Swatch, which takes that value as a prop (gh#527)."},{id:"sibling-cards-need-flex",severity:"warn",category:"composition",standard:null,fix:'Wrap adjacent <Card>s in <Flex direction="col" gap="lg"> or <ResponsiveGrid>; direct children of PageContainer are spaced by the page already.'},{id:"no-raw-palette-color",severity:"error",category:"tokens",standard:null,fix:"Use semantic tokens (bg-primary, text-muted-foreground), never raw palette (bg-blue-500)."},{id:"no-arbitrary-hex",severity:"error",category:"tokens",standard:null,fix:"No hardcoded hex in className; read design-system color tokens."},{id:"no-arbitrary-spacing",severity:"error",category:"tokens",standard:null,fix:"No p-[13px]/gap-[7px]; use the token scale / <Flex gap> / <PageContainer>."},{id:"no-arbitrary-size",severity:"error",category:"tokens",standard:null,fix:"No w-[37px]/h-[260px]; use token sizes or a sizing prop (min-w-[\u2026] allowed)."},{id:"no-arbitrary-typography",severity:"error",category:"tokens",standard:null,fix:"No text-[20px]/leading-[1.7]; use the golden-ratio type-scale tokens."},{id:"no-arbitrary-radius",severity:"error",category:"tokens",standard:null,fix:"No rounded-[6px]; use rounded-sm/md/lg radius tokens."},{id:"no-off-scale-token-value",severity:"warn",category:"tokens",standard:null,fix:"A design-system knob you override takes a step (style={{ '--card-space-inset': 'var(--space-4)' }}) or a calc() from one (calc(var(--space-4) + 2px)), not a raw 13px. Only axes that HAVE a scale count: space/padding/gap/margin, font-size, radius, icon-size (width/height/size/offset have none yet, so a number there is fine). A value that is genuinely off the grid keeps its literal and says why in place, with a /* scale-exempt: 6px status dot, below --space-1 */ comment on that line or the one above."},{id:"no-dark-color-override",severity:"warn",category:"tokens",standard:null,fix:"Drop dark: color overrides \u2014 semantic tokens already adapt."},{id:"raw-white-black",severity:"warn",category:"tokens",standard:null,fix:"Prefer semantic tokens (text-primary-foreground, bg-background) over raw white/black."},{id:"no-domain-tracking-token",severity:"error",category:"tokens",standard:null,fix:"No package-tracking/domain tokens; use semantic tokens or app theme overrides."},{id:"no-space-xy",severity:"error",category:"tokens",standard:null,fix:"Use <Flex gap> instead of space-x/y-*."},{id:"no-raw-select",severity:"error",category:"composition",standard:"HTML Living Standard (WHATWG)",fix:"Use <Select> from @godxjp/ui, not a raw <select>."},{id:"no-raw-table",severity:"error",category:"composition",standard:"HTML Living Standard (WHATWG)",fix:"Use the <Table>/<DataTable> family, not a raw <table>."},{id:"no-raw-input",severity:"error",category:"composition",standard:"HTML Living Standard (WHATWG)",fix:"Use <Input> from @godxjp/ui, not a raw <input>."},{id:"no-raw-textarea",severity:"warn",category:"composition",standard:"HTML Living Standard (WHATWG)",fix:"Use <Textarea> from @godxjp/ui, not a raw <textarea>."},{id:"no-raw-button",severity:"error",category:"composition",standard:"HTML Living Standard (WHATWG)",fix:"Use <Button> from @godxjp/ui, not a raw <button>."},{id:"card-manual-padding",severity:"error",category:"composition",standard:null,fix:"Wrap the body in <CardContent>; don't hand-roll padding on <Card>."},{id:"card-needs-content",severity:"error",category:"composition",standard:null,fix:"<Card> body must be in <CardContent> (no padding otherwise); flush only for a full-bleed table."},{id:"bare-control-needs-formfield",severity:"warn",category:"composition",standard:"WCAG 2.2 SC 1.3.1 \xB7 3.3.2 \xB7 @godxjp/ui FormField (cardinal rule 227)",fix:"Wrap a labelled control in <FormField label=\u2026> \u2014 it owns label\u2194control id wiring, aria/error, AND the field rhythm; never pair a bare <Label> with an <Input>."},{id:"manual-field-error",severity:"warn",category:"composition",standard:"WCAG 2.2 SC 3.3.1",fix:"Use <FormField error=\u2026>, not a hand-rolled <p class='text-destructive'>."},{id:"manual-field-helper",severity:"warn",category:"composition",standard:null,fix:"Use <FormField helper=\u2026>, not a hand-rolled helper <p>."},{id:"status-tone-not-variant",severity:"error",category:"api",standard:null,fix:"Badge/Tag/StatCard status uses tone, not variant (variant is structural)."},{id:"value-callback-on-value-change",severity:"error",category:"api",standard:null,fix:"Abstract value components use onValueChange, not onChange."},{id:"icon-button-needs-name",severity:"warn",category:"a11y",standard:"WCAG 2.2 SC 4.1.2 \xB7 1.1.1 \xB7 WAI-ARIA 1.2 \xB7 Accessible Name Computation 1.2",fix:"Name <Button size='icon'> with aria-label={t('\u2026')} OR from content \u2014 a <VisuallyHidden>/sr-only child beside the aria-hidden glyph. Text inside an aria-hidden subtree names nothing."},{id:"img-needs-alt",severity:"warn",category:"a11y",standard:"WCAG 2.2 SC 1.1.1 \xB7 HTML Living Standard",fix:"Add alt to every <img> (alt='' if decorative); prefer <Avatar>/<AspectRatio>."},{id:"no-positive-tabindex",severity:"warn",category:"a11y",standard:"WCAG 2.2 SC 2.4.3 \xB7 WAI-ARIA APG",fix:"Use tabIndex 0 or -1 only; never positive \u2014 it breaks focus order."},{id:"hand-rolled-close-glyph",severity:"warn",category:"a11y",standard:"WAI-ARIA 1.2 (dialog) \xB7 WCAG 2.2 SC 4.1.2",fix:"Pass onDismiss to <Alert>, or use <Dialog>/<Sheet>'s built-in labelled close \u2014 not a bare \u2715."},{id:"no-emoji-in-ui",severity:"warn",category:"i18n",standard:"Unicode UTS #51 \xB7 WCAG 2.2 SC 1.1.1",fix:"No emoji in product UI; quiet i18n copy + Lucide icon + Badge tone."},{id:"no-emoji-flag",severity:"warn",category:"i18n",standard:"ISO 3166-1 \xB7 ECMA-402 Intl.DisplayNames \xB7 Unicode UTS #51",fix:"Derive country names from Intl.DisplayNames; no emoji flags."},{id:"hardcoded-currency",severity:"warn",category:"i18n",standard:"ISO 4217 \xB7 ECMA-402 Intl.NumberFormat",fix:"Format money with Intl.NumberFormat({ style: 'currency', currency }), not \xA5{amount}."},{id:"raw-intl-date",severity:"warn",category:"i18n",standard:"ISO 8601 \xB7 IANA tz \xB7 ECMA-402 Intl.DateTimeFormat",fix:"Use formatDate from @godxjp/ui/datetime, not hand-built or locale-default dates."},{id:"no-physical-direction",severity:"warn",category:"rtl",standard:"W3C CSS Logical Properties L1 \xB7 WCAG 2.2 (1.3.2)",fix:"Use logical utilities (ms-/me-/ps-/pe-, start-/end-, text-start/end, border-s/e, rounded-s/e)."},{id:"no-em-dash-in-copy",severity:"warn",category:"copy",standard:"@godxjp/ui reference-design typography",fix:"No em-dash (\u2014) in copy; use a middot \xB7 or two calm sentences."},{id:"lucide-icon-needs-size",severity:"warn",category:"composition",standard:"WCAG 2.2 SC 1.4.4 \xB7 @godxjp/ui icon scale (--icon-size-*)",fix:'A lucide glyph outside a sizing context draws at its intrinsic 24px. Render it as <Icon as={Lock} size="sm" tone="muted" /> \u2014 the primitive puts it on the --icon-size-* scale and is aria-hidden unless you pass a label.'},{id:"no-hand-rolled-list",severity:"warn",category:"composition",standard:"WAI-ARIA 1.2 (list / listitem) \xB7 HTML Living Standard (ul/ol/li) \xB7 WCAG 2.2 SC 1.3.1",fix:'Build the list as <Flex as="ul" marker="none" direction="col" gap="none"> with <ListRow as="li"> rows \u2014 not a raw <ul>/<ol> (no gap token), not <div role="list">/<div role="listitem">, 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 (a consumer lost every divider in a settings menu and a dashboard this way). marker="none" keeps the element, the <li> semantics and the gap, and drops the bullet and the --space-5 indent (gh#714). A deliberate exception \u2014 a drag-and-drop Kanban column, an evidence list inside a TableCell \u2014 takes an ui-audit-disable-line that says so.'}];function ae(e){return e?Z.filter(t=>t.category===e):Z}var ne="node node_modules/@godxjp/ui/scripts/visual-audit.mjs <baseUrl> [route \u2026] (optional peers, TESTED range: playwright >=1.55 <2 [1.61.1] + @axe-core/playwright >=4.10 <5 [4.12.1] + axe-core >=4.10 <5 [4.12.1] + a chromium via `playwright install chromium`; --strict for a CI gate, --format json ALWAYS emits valid JSON with a status of ok|partial|error separating infra errors[] from product findings[], --rules to print this catalog)",oe=[{id:"css-layers-missing",severity:"error",category:"layout",standard:"@godxjp/ui styles contract (styles / styles/core are the only entries)",fix:"Import `@godxjp/ui/styles` (or `styles/core` without fonts); never cherry-pick *-layout.css \u2014 a missing layer renders naked menus and unsized Select rows."},{id:"control-height-mismatch",severity:"error",category:"layout",standard:"@godxjp/ui control tier (--control-height) \xB7 Nielsen consistency heuristic",fix:"Every control in one row must share --control-height; replace hand-rolled pills with Avatar/Button/Badge, never restyle a control's height."},{id:"sibling-card-gap",severity:"error",category:"layout",standard:"@godxjp/ui spacing scale (docs/SPACING.md)",fix:'Adjacent Cards need one space step between them \u2014 <Flex direction="col" gap>, <ResponsiveGrid>, or direct children of PageContainer.'},{id:"row-content-starved",severity:"warn",category:"layout",standard:"WCAG 2.2 SC 1.4.10 reflow",fix:`A sibling (a w-full SelectTrigger) takes the row's width and truncates its neighbours \u2014 give the Select width="auto" or move it out of the row.`},{id:"axe-violations",severity:"warn",category:"a11y",standard:"WCAG 2.2 A/AA \xB7 WAI-ARIA 1.2 (axe-core engine)",fix:"Fix each axe node \u2014 contrast (1.4.3), name/role/value (4.1.2), ARIA, landmarks. Runs on the REAL DOM, catching what static analysis cannot."},{id:"target-size-min",severity:"warn",category:"a11y",standard:"WCAG 2.2 SC 2.5.8 (24\xD724 AA) \xB7 2.5.5 (44\xD744 AAA)",fix:"Interactive targets must be \u226524\xD724 CSS px; size from the --control-height tier."},{id:"oversaturated-accent",severity:"warn",category:"color",standard:"@godxjp/ui reference-design \u6E0B\u307F (OKLCH chroma \u2264 0.18)",fix:"Desaturate brand/primary surfaces (OKLCH chroma \u2264 0.18); read --primary tokens, no raw vivid bars."},{id:"emoji-rendered",severity:"warn",category:"i18n",standard:"Unicode UTS #51 \xB7 WCAG 2.2 SC 1.1.1",fix:"Remove emoji from rendered product text; quiet i18n copy + Lucide icon + Badge tone."},{id:"alert-controls-misplaced",severity:"warn",category:"layout",standard:"@godxjp/ui Alert anatomy \xB7 WAI-ARIA 1.2 \xB7 WCAG 2.2 SC 4.1.2",fix:"Use <Alert>: one leading tone icon, <Alert.Actions> trailing-right normal width, onDismiss \xD7 top-right, one horizontal row."}];function ie(e){return e?oe.filter(t=>t.category===e):oe}var l={name:"@godxjp/ui-mcp",version:"27.12.0",godxUiCompatibility:"27.12.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 B=[{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.",inputSchema:{type:"object",properties:{group:{type:"string",enum:["general","layout","data-display","data-entry","feedback","navigation","composites","shell","providers"]}}}},{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.",inputSchema:{type:"object",properties:{query:{type:"string"}},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:"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"]}}],De=new Set(B.map(e=>e.name));function Oe(e=H()){let t=l.godxUiCompatibility??l.version,a=`@godxjp/ui-mcp ${l.version} (catalog for @godxjp/ui ${t})`;if(!e)return a;let o=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} (${o})`}function Ee(e=H()){let t=e?P(e.version):null,a=P(l.version);return!e||!t||!a?null:Le(t,a)>0?`\u26A0\uFE0F SERVER OLDER THAN INSTALLED PACKAGE: this server is @godxjp/ui-mcp ${l.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 ${l.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 ce(e,t){let a=await Ne(e,t);if(!De.has(e))return a;let o=H(),n=Ee(o);return`${Oe(o)}
|
|
4477
4477
|
${n?`${n}
|
|
4478
4478
|
`:""}
|
|
4479
4479
|
${a}`}async function Ne(e,t){switch(e){case"list_skills":return Re();case"list_primitives":return me(t.group);case"list_patterns":return Ue();case"list_anti_ai_tells":return je(t.category);case"list_redesign_checks":return qe(t.category);case"list_audit_rules":return He(t.category);case"list_visual_checks":return Ve(t.category);case"get_anti_ai_tell":return Ge(String(t.name??""));case"get_redesign_check":return We(String(t.symptom??""));case"get_skill_section":return ge(String(t.skill??""),String(t.section??""));case"get_component":return Ye(String(t.name??""),t.verbose===!0);case"get_pattern":return Qe(String(t.name??""));case"get_rule":return Je(typeof t.number=="number"?t.number:void 0);case"get_vocab":return Ze(t.name==null?void 0:String(t.name));case"get_tokens":return et(t.category);case"list_consumer_skills":return Ie();case"get_consumer_skill":return ze(String(t.skill??""),String(t.section??""));case"route_consumer_task":return le(String(t.task??""),{consumerOnly:!0});case"draft_bug_report":return Pe(t);case"check_compatibility":return ue(t.version==null?void 0:String(t.version));case"route_task":return le(String(t.task??""));case"suggest_primitive":return tt(String(t.use_case??""));case"search_components":return at(String(t.query??""));case"get_frame_coverage":return Xe(t.name===void 0?void 0:String(t.name));case"lint_jsx":return ot(String(t.jsx??""));default:return`Unknown tool: ${e}`}}function Re(){let e=`# Available skills (${S.length})
|
|
@@ -4491,7 +4491,7 @@ _Source: ${S.map(t=>t.source).filter((t,a,o)=>o.indexOf(t)===a).slice(0,3).join(
|
|
|
4491
4491
|
|
|
4492
4492
|
`,t+=`**Sections:** ${a.sections.map(o=>`\`${o.id}\``).join(", ")}
|
|
4493
4493
|
|
|
4494
|
-
`;return t}function ze(e,t){let a=D(e);return a&&!M(a)?`Skill "${e}" is CORE-only (building @godxjp/ui itself) and isn't served to app-devs. Use \`list_consumer_skills\` for consumer-facing guidance${e==="component-discipline"?" \u2014 the standards you need when composing/extending are folded into `compose-a-screen/state-and-a11y` and `design-to-page/verify`.":"."}`:ge(e,t)}function Pe(e){let t=k=>{let T=e[k];return typeof T=="string"?T.trim():""},a=t("summary");if(!a)return"Pass at least `summary` (one-line title). For a useful report also pass `repro`, `expected`, `actual`, and ideally `component` / `rule` / `version` / `env`. A vague report a maintainer can't reproduce is not enough.";let o=t("repro"),n=t("expected"),i=t("actual"),r=t("component"),s=typeof e.rule=="number"?e.rule:void 0,u=t("version"),m=t("env"),g=[];o||g.push("repro"),n||g.push("expected"),i||g.push("actual");let w=(k,T)=>T||`_(TODO: ${k} \u2014 required for a reproducible report)_`,
|
|
4494
|
+
`;return t}function ze(e,t){let a=D(e);return a&&!M(a)?`Skill "${e}" is CORE-only (building @godxjp/ui itself) and isn't served to app-devs. Use \`list_consumer_skills\` for consumer-facing guidance${e==="component-discipline"?" \u2014 the standards you need when composing/extending are folded into `compose-a-screen/state-and-a11y` and `design-to-page/verify`.":"."}`:ge(e,t)}function Pe(e){let t=k=>{let T=e[k];return typeof T=="string"?T.trim():""},a=t("summary");if(!a)return"Pass at least `summary` (one-line title). For a useful report also pass `repro`, `expected`, `actual`, and ideally `component` / `rule` / `version` / `env`. A vague report a maintainer can't reproduce is not enough.";let o=t("repro"),n=t("expected"),i=t("actual"),r=t("component"),s=typeof e.rule=="number"?e.rule:void 0,u=t("version"),m=t("env"),g=[];o||g.push("repro"),n||g.push("expected"),i||g.push("actual");let w=(k,T)=>T||`_(TODO: ${k} \u2014 required for a reproducible report)_`,E=`[bug] ${a}`,d=`## Summary
|
|
4495
4495
|
|
|
4496
4496
|
${a}
|
|
4497
4497
|
|
|
@@ -4521,11 +4521,11 @@ ${w("actual",i)}
|
|
|
4521
4521
|
`,d+=`## Proposed fix
|
|
4522
4522
|
|
|
4523
4523
|
_(optional \u2014 what the library should do instead)_
|
|
4524
|
-
`;let c=k=>`'${k.replace(/'/g,"'\\''")}'`,h=`gh issue create --repo godx-jp/godxjp-ui --label bug --title ${c(
|
|
4524
|
+
`;let c=k=>`'${k.replace(/'/g,"'\\''")}'`,h=`gh issue create --repo godx-jp/godxjp-ui --label bug --title ${c(E)} --body ${c(d)}`,f=`# Draft bug report
|
|
4525
4525
|
|
|
4526
4526
|
`;return g.length&&(f+=`> \u26A0\uFE0F Incomplete \u2014 fill ${g.map(k=>`\`${k}\``).join(", ")} before filing (a report a maintainer can't reproduce will bounce).
|
|
4527
4527
|
|
|
4528
|
-
`),f+=`**Title:** ${
|
|
4528
|
+
`),f+=`**Title:** ${E}
|
|
4529
4529
|
|
|
4530
4530
|
`,f+=`## Issue body (Markdown)
|
|
4531
4531
|
|
|
@@ -4588,14 +4588,14 @@ ${ee}
|
|
|
4588
4588
|
\`\`\`
|
|
4589
4589
|
${te}
|
|
4590
4590
|
\`\`\`
|
|
4591
|
-
`,a}function je(e){let t=e?$(e):
|
|
4591
|
+
`,a}function je(e){let t=e?$(e):O,a=`# AI tells to AVOID${e?` \u2014 ${e}`:""} (${t.length})
|
|
4592
4592
|
|
|
4593
4593
|
`;a+='_Compact list. Use `get_anti_ai_tell name="<name>"` for the full body + fix._\n\n';let o=t.reduce((n,i)=>((n[i.category]??=[]).push(i),n),{});for(let[n,i]of Object.entries(o)){a+=`## ${n}
|
|
4594
4594
|
`;for(let r of i)a+=`- ${r.name}
|
|
4595
4595
|
`;a+=`
|
|
4596
|
-
`}return a}function Ge(e){let t=
|
|
4596
|
+
`}return a}function Ge(e){let t=O.find(a=>a.name.toLowerCase()===e.trim().toLowerCase());if(!t){let a=`Anti-AI-tell "${e}" not found. Use \`list_anti_ai_tells\` to discover. Closest:
|
|
4597
4597
|
|
|
4598
|
-
`;for(let o of
|
|
4598
|
+
`;for(let o of O.slice(0,8))a+=`- ${o.name} (${o.category})
|
|
4599
4599
|
`;return a}return`# ${t.name}
|
|
4600
4600
|
|
|
4601
4601
|
**Category:** ${t.category}
|
|
@@ -4797,7 +4797,7 @@ Values: ${a.values.map(o=>`\`${o}\``).join(" | ")}
|
|
|
4797
4797
|
`);return o+='\nFetch with: `get_skill_section skill="X" section="Y"`',o}function tt(e){let t=e.trim().toLowerCase();if(!t)return"Describe your use case.";let a=[],o=(i,r,s,u=2)=>{i.some(m=>t.includes(m))&&a.push({component:r,rationale:s,score:u})};if(o(["form","submit","validation","register","sign up"],"Form + FormField","RHF + zod composition.",5),o(["table","rows","columns"],"DataTable / Table","DataTable for chrome (toolbar+pagination+batch). Table for slim primitive.",5),o(["modal","dialog","confirm"],"Dialog / AlertDialog","Radix Dialog. AlertDialog for destructive.",4),o(["drawer","side panel","sheet"],"Sheet","Side panel for filters/settings.",4),o(["toast","notification"],"toast / Toaster","Sonner-backed.",4),o(["loading","saving","spinner"],"Spinner / Form loading prop","Spinner=active work, Skeleton=init fetch.",3),o(["alert","banner"],"Alert","5 semantic colors \xD7 outlined/banner.",3),o(["select","dropdown"],"Select / AutoComplete","Select=discrete options, AutoComplete=free-text+suggestions.",3),o(["filter"],"Toolbar/ToolbarGroup + pattern 'filter-bar' (\u2192 data-table-page)","Standalone Toolbar filter bar above a table; see the data-table-page pattern.",4),o(["delete","destructive"],"Pattern 'confirm-destructive'","Card accent='destructive' + typed-name confirm.",4),!a.length)return`No direct match for "${e}". Try \`list_primitives\` or \`search_components\`.`;a.sort((i,r)=>r.score-i.score);let n=`# Suggestions for "${e}"
|
|
4798
4798
|
|
|
4799
4799
|
`;for(let i of a)n+=`- **${i.component}** \u2014 ${i.rationale}
|
|
4800
|
-
`;return n}function at(e){let t=e.trim().toLowerCase();if(!t)return me();let a=t.split(/\s+/).filter(r=>r.length>=2),o=a.length?a:[t],n=v.map(r=>{let s=r.name.toLowerCase(),u=r.tagline.toLowerCase(),m=(r.useCases??[]).join(" ").toLowerCase(),g=(r.usage??[]).join(" ").toLowerCase(),w=(r.related??[]).join(" ").toLowerCase(),
|
|
4800
|
+
`;return n}function at(e){let t=e.trim().toLowerCase();if(!t)return me();let a=t.split(/\s+/).filter(r=>r.length>=2),o=a.length?a:[t],n=v.map(r=>{let s=r.name.toLowerCase(),u=r.tagline.toLowerCase(),m=(r.useCases??[]).join(" ").toLowerCase(),g=(r.usage??[]).join(" ").toLowerCase(),w=(r.related??[]).join(" ").toLowerCase(),E=r.props.map(h=>h.name.toLowerCase()),d=(r.subParts??[]).join(" ").toLowerCase(),c=0;s===t&&(c+=100),d.split(" ").includes(t)&&(c+=90);for(let h of o)s.includes(h)&&(c+=5),d.includes(h)&&(c+=4),u.includes(h)&&(c+=3),m.includes(h)&&(c+=2),g.includes(h)&&(c+=1),w.includes(h)&&(c+=1),r.group.includes(h)&&(c+=1),E.some(f=>f.includes(h))&&(c+=1);return{c:r,score:c}}).filter(r=>r.score>0).sort((r,s)=>s.score-r.score).slice(0,12);if(!n.length)return`No matches for "${e}". Try \`list_primitives\` or a broader term (e.g. a use-case word like "date", "select", "confirm").`;let i=`# Search "${e}" \u2014 ${n.length} match${n.length>1?"es":""}
|
|
4801
4801
|
|
|
4802
4802
|
`;for(let{c:r,score:s}of n)i+=`- **${r.name}** (${r.group}, ${s}) \u2014 ${r.tagline}
|
|
4803
4803
|
`;return i}function ot(e){let t=[],a=(n,i)=>{n.test(e)&&t.push(i)};if(a(/<button[\s>]/,"Use `<Button>` instead of raw `<button>` (rule 29)."),a(/<input[\s>]/,"Use `<Input>` instead of raw `<input>` (rule 29)."),a(/<select[\s>]/,"Use `<Select>` instead of raw `<select>` (rule 29)."),a(/<Select\b[^>]*\bonChange=/,"Select value changes use `onValueChange`, not `onChange`."),a(/<textarea[\s>]/,"Use `<Textarea>` instead of raw `<textarea>` (rule 29)."),a(/<(table|thead|tbody)[\s>]/,"Use `<DataTable>` instead of a hand-rolled `<table>` (rule 29)."),a(/bg-(red|blue|green|yellow|gray|slate|zinc|neutral|stone|orange|amber|lime|emerald|teal|cyan|sky|indigo|violet|purple|fuchsia|pink|rose)-\d{2,3}\b/,"Use semantic token utilities (`bg-primary`/`bg-destructive`) not raw color scales (rule 2)."),a(/\b(?:ml|mr|pl|pr|left|right)-(?:\d|\[|auto|px|full|screen)|\b(?:rounded-[lr]|border-[lr]|text-(?:left|right))\b/,"Physical direction class \u2014 use logical CSS (`ms-/me-`, `ps-/pe-`, `start-/end-`, `rounded-s/e`, `text-start/end`) so the UI flips correctly under RTL (rule: logical CSS)."),a(/size=["']default["']/,'`size="default"` is not in the controlled vocabulary \u2014 use `size` \u2208 xs|sm|md|lg.'),a(/\btext-\[[0-9.]+px\]/,"Arbitrary text size `text-[Npx]` bypasses the golden type scale \u2014 use `<Text size>` / `<Heading level>` (rule 42)."),a(/<Tag[\s\S]*?color=["']error["']/i,'Tag `color="error"` \u2192 `"destructive"` (v5.0, PR #60).'),a(/<Badge[\s\S]*?variant=["']error["']/i,'Badge `variant="error"` \u2192 `"destructive"` (v5.0, PR #63).'),a(/(Flex|Space|Grid|Masonry)[\s\S]*?(gap|size)=["']middle["']/i,'`"middle"` \u2192 `"default"` for Flex/Space/Grid/Masonry (v5.0).'),a(/<IconButton[\s\S]*?size=["']default["']/i,'IconButton `size="default"` \u2192 `"md"` (v5.0).'),a(/<SegmentedControl[\s\S]*?size=["']sm["']/i,'SegmentedControl `size="sm"` \u2192 `"small"` (v5.0).'),a(/<PageContent[\s\S]*?padding=["'](compact|comfortable)["']/i,'PageContent `padding="compact"/"comfortable"` \u2192 `"tight"/"cozy"` (v5.0).'),a(/<Pagination[\s\S]*?justify=["']between["']/i,'Pagination `justify="between"` \u2192 `"space-between"` (v5.0).'),/<IconButton(?![^>]*aria-label)/i.test(e)&&!/asChild/i.test(e)&&t.push("`<IconButton>` should have `aria-label` (rule 6 \u2014 WCAG)."),/cell:\s*\(\{?\s*row\s*\}?\)\s*=>/i.test(e)&&/export\s+const\s+\w+\s*:\s*Story/i.test(e)&&(/parameters[\s\S]{0,200}source[\s\S]{0,100}code:/i.test(e)||t.push("Stories with function-valued cell renderers MUST override `parameters.docs.source.code` (rule 34).")),/text-(red|blue|green|yellow)-\d{2,3}\b/.test(e)&&t.push("Hard-coded color scales \u2014 use semantic tokens. Tells AI-slop palette (rule 2 + anti-AI-tells.visual.rainbow-chip-wall)."),/h-\[?100vh\]?/.test(e)&&t.push("`100vh` causes iOS Safari viewport jump \u2014 use `min-h-[100dvh]` (redesign.layout / soft.absolute-zero)."),/className=["'][^"']*(?:shadow-md|shadow-lg|shadow-xl)["']/.test(e)&&t.push("Tailwind heavy shadows are an AI tell \u2014 use ultra-diffuse low-opacity (< 0.05) or tinted shadows (soft.absolute-zero, minimalist)."),/\b(?:Inter|Roboto|Helvetica|Open\s+Sans)\b/i.test(e)&&t.push("Banned default fonts (Inter/Roboto/Helvetica/Open Sans). Use Geist/Clash Display/PP Editorial New (soft.absolute-zero, minimalist.negative-constraints)."),/Acme|NovaCore|Flowbit|Quantix|VeloPay|John\s+Doe|Jane\s+Smith|Lorem\s+Ipsum/i.test(e)&&t.push("Generic placeholder content (Acme/NovaCore/John Doe/Lorem Ipsum). Use believable real-sounding names (anti-AI-tells.copy)."),t.length===0)return"\u2705 No issues found against the heuristic checks.";let o=`# Lint findings \u2014 ${t.length} issue${t.length===1?"":"s"}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@godxjp/ui-mcp",
|
|
3
|
-
"version": "27.
|
|
4
|
-
"godxUiCompatibility": "27.
|
|
3
|
+
"version": "27.12.0",
|
|
4
|
+
"godxUiCompatibility": "27.12.x",
|
|
5
5
|
"description": "Model Context Protocol server for @godxjp/ui — 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 — token-efficient (list → drill-down).",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"main": "./dist/index.js",
|