@godxjp/ui-mcp 31.22.0 → 31.22.1
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 +3 -3
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -2434,7 +2434,7 @@ import { Text } from "@godxjp/ui/general";
|
|
|
2434
2434
|
nameKey="category"
|
|
2435
2435
|
numberFormat={{ style: "currency", currency: "JPY" }}
|
|
2436
2436
|
donut
|
|
2437
|
-
/>`,storyPath:"charts/PieChart.stories.tsx",rules:[]},{name:"CommandPalette",group:"data-entry",tagline:"Searchable command dialog with controlled or uncontrolled open state and consumer-owned selection.",props:[{name:"groups",type:"CommandPaletteGroup[]",required:!0,description:"Grouped command items."},{name:"labels",type:"CommandPaletteLabels",required:!0,description:"Localized dialog and search copy."},{name:"onSelect",type:"(item: CommandPaletteItem, modifiers: { metaKey, ctrlKey, shiftKey, altKey }) => void",required:!0,description:'Consumer-owned selection handler. The second argument carries the modifier keys held on the Enter or click that chose the item \u2014 build "open in split / new tab" on \u2318/Ctrl/Shift (gh#1126).'},{name:"shortcut",type:"boolean | string",defaultValue:"true",description:'The global toggle shortcut. `true` = \u2318K / Ctrl+K, `false` = none, or a combo string \u2014 `"mod+o"`, `"mod+p"`, `"mod+shift+p"` \u2014 so a quick switcher and a command palette can live side by side. `mod` is \u2318
|
|
2437
|
+
/>`,storyPath:"charts/PieChart.stories.tsx",rules:[]},{name:"CommandPalette",group:"data-entry",tagline:"Searchable command dialog with controlled or uncontrolled open state and consumer-owned selection.",props:[{name:"groups",type:"CommandPaletteGroup[]",required:!0,description:"Grouped command items."},{name:"labels",type:"CommandPaletteLabels",required:!0,description:"Localized dialog and search copy."},{name:"onSelect",type:"(item: CommandPaletteItem, modifiers: { metaKey, ctrlKey, shiftKey, altKey }) => void",required:!0,description:'Consumer-owned selection handler. The second argument carries the modifier keys held on the Enter or click that chose the item \u2014 build "open in split / new tab" on \u2318/Ctrl/Shift (gh#1126).'},{name:"shortcut",type:"boolean | string",defaultValue:"true",description:'The global toggle shortcut. `true` = \u2318K / Ctrl+K, `false` = none, or a combo string \u2014 `"mod+o"`, `"mod+p"`, `"mod+shift+p"` \u2014 so a quick switcher and a command palette can live side by side. `mod` is \u2318 on Apple platforms and Ctrl elsewhere \u2014 never both, so Ctrl+O / Ctrl+P keep their editing meaning on a Mac (gh#1129); Shift / Alt must match exactly. Never fires during IME composition; the default trigger shows the combo (gh#1126).'},{name:"open",type:"boolean",description:"Controlled open state."},{name:"defaultOpen",type:"boolean",defaultValue:"false",description:"Initial uncontrolled open state."},{name:"onOpenChange",type:"(open: boolean) => void",description:"Open-state callback."},{name:"search",type:"string",description:"Controlled search-box query. Pairs with `onSearchChange`."},{name:"defaultSearch",type:"string",defaultValue:'""',description:"Initial uncontrolled query, and the value the palette resets to when it closes."},{name:"onSearchChange",type:"(query: string) => void",description:"Fires on every keystroke with the current query \u2014 the seam for search-as-you-type. Also fires with `defaultSearch` when the palette closes."},{name:"shouldFilter",type:"boolean",defaultValue:"true",description:"Whether the palette filters `groups` itself. Set false for server-side search, which also hands the empty node to the palette (derived from `groups`)."},{name:"loading",type:"boolean",defaultValue:"false",description:"Shows the supplied loading content."},{name:"error",type:"ReactNode",description:"Consumer-supplied error content."}],usage:["Provide localized labels and real command groups; the component does not fetch commands.","Use either `open` plus `onOpenChange` or `defaultOpen`; do not mirror both state models.","Search-as-you-type against an API: read the query from `onSearchChange`, pass the results back as `groups`, and set `shouldFilter={false}` so the rows are not scored a second time against the same string.","The empty-state contract: with `shouldFilter` (default) cmdk decides \u2014 items exist, the query matches none. With `shouldFilter={false}` the PALETTE decides from props \u2014 `labels.empty` renders when `groups` carries no items, and never while `loading` or `error` is set. Hold `loading` for the whole in-flight window: a request that has not answered yet is not an empty result, and asserting over cmdk's own empty node races an async group that populates a frame late."],example:`import { CommandPalette } from "@godxjp/ui/data-entry";
|
|
2438
2438
|
|
|
2439
2439
|
<CommandPalette
|
|
2440
2440
|
groups={[{ id: "pages", label: "Pages", items: [{ id: "home", label: "Home" }] }]}
|
|
@@ -2591,7 +2591,7 @@ const messages: ChatMessageProp[] = [
|
|
|
2591
2591
|
system: { placement: "start", variant: "borderless", tone: "info", size: "sm" },
|
|
2592
2592
|
}}
|
|
2593
2593
|
/>`,docPath:"data-display/chat-bubble.tsx",storyPath:"data-display/ChatBubbleList.stories.tsx",rules:[6,23,44,45]},{name:"ChatComposer",group:"data-entry",tagline:"The message input of a conversation (Ant Design X Sender): an auto-growing Textarea plus exactly ONE trailing action \u2014 send, or cancel while a response streams. Enter / Shift+Enter / \u2318-or-Ctrl+Enter is configurable and never fires during an IME conversion.",props:[{name:"value",type:"string",description:"Controlled draft text. Pair with onValueChange or the box freezes."},{name:"defaultValue",type:"string",description:"Uncontrolled initial draft text."},{name:"onValueChange",type:"(value: string) => void",description:"Draft-text change handler; fires on every keystroke, including during an IME conversion."},{name:"onSubmit",type:"(value: string) => void",description:'Send the draft. Never fires for empty or whitespace-only text (unless allowEmptySubmit, which passes ""), nor while loading/disabled/readOnly.'},{name:"onCancel",type:"() => void",description:"Stop the in-flight response. Only reachable while loading."},{name:"loading",type:"boolean",defaultValue:"false",description:"A response is streaming: the trailing action BECOMES cancel. Send and cancel never render together."},{name:"submitType",type:'"enter" | "shiftEnter" | "modEnter"',defaultValue:'"enter"',description:'"enter": Enter sends, Shift+Enter breaks the line. "shiftEnter": the inverse, for long deliberate drafts. "modEnter" (library extension; antd X Sender has only the first two): \u2318+Enter on Apple platforms, Ctrl+Enter elsewhere sends, while Enter and Shift+Enter both break the line \u2014 the record-comment convention (GitHub, Jira, Linear).'},{name:"allowEmptySubmit",type:"boolean",defaultValue:"false",description:'Let an empty or whitespace-only draft be sent when header/footer carry payload of their own (a status change on a record). The send button stays enabled and the button and keyboard submit call onSubmit(""). Still blocked while loading/disabled/readOnly.'},{name:"placeholder",type:"string",description:"Empty-state text of the draft box \u2014 pass it through t() at the call site."},{name:"disabled",type:"boolean",defaultValue:"false",description:"Disable the composer and every action."},{name:"readOnly",type:"boolean",defaultValue:"false",description:"Show the draft without allowing an edit; still focusable."},{name:"header",type:"React.ReactNode",description:"Slot ABOVE the draft row \u2014 attachments, a reply-to banner, a model picker."},{name:"prefix",type:"React.ReactNode",description:"Slot at the inline START of the draft row \u2014 an attach Button, an Avatar."},{name:"footer",type:"React.ReactNode | ((info: { components: ChatComposerActionComponents }) => React.ReactNode)",description:"Slot BELOW the draft row \u2014 a hint line, a token counter, OR (Ant Design X Sender NodeRender) a function that receives the real SubmitButton/CancelButton components, pre-wired, so they can be rendered in the footer instead of beside the draft box. Pair with actions={false} to hide the inline pair."},{name:"actions",type:"React.ReactNode | false",description:"Extra trailing actions, rendered BEFORE the send/cancel action \u2014 or false (Ant Design X Sender suffix semantics) to hide the ENTIRE inline trailing-action cell, built-in send/cancel button included, once footer has taken it over. Omitted renders exactly as before."},{name:"size",type:'"xs" | "sm" | "md" | "lg"',defaultValue:'"md"',description:"Height tier on the shared --control-height ladder; moves both auto-grow bounds together."},{name:"maxLength",type:"number",description:"Hard ceiling on the draft length, forwarded to the textarea."},{name:"status",type:'"error" | "warning"',description:"Validation state the frame paints. error also reports aria-invalid (colour alone fails WCAG 1.4.1)."},{name:"submitLabel",type:"string",description:"Accessible name override for the send action (localized default otherwise)."},{name:"cancelLabel",type:"string",description:"Accessible name override for the cancel action (localized default otherwise)."},{name:"onKeyDown",type:"React.KeyboardEventHandler<HTMLTextAreaElement>",description:"Keydown on the draft box \u2014 how ChatSuggestion drives its list. A handler that calls preventDefault() owns the key, and the composer will not treat it as a send."},{name:"name",type:"string",description:"Native form name, forwarded to the textarea."},{name:"id",type:"string",description:"DOM id of the textarea (the semantic focus target FormField labels)."}],usage:["DO pair a controlled `value` with `onValueChange` \u2014 a controlled value with no synchronised handler is the classic frozen-input bug, and it freezes the whole conversation.","DO wrap it in FormField when the composer is a labelled field; the label/helper/error contract lands on the <textarea>, which is the semantic focus target (ref goes there too).","DON'T hand-roll Enter-to-send. An IME conversion (ja/vi) fires a real Enter to ACCEPT a candidate; ChatComposer already guards compositionstart/compositionend, and skipping that guard makes Japanese and Vietnamese input impossible.","DON'T render your own stop button beside the send button \u2014 set `loading` and the trailing action becomes cancel. Exactly one trailing action exists at a time (the picker trailing-action discipline).","DO put a hint in `footer` (t('dataEntry.chatComposer.hintEnter') / 'hintShiftEnter') when you flip `submitType` \u2014 the keystroke contract is invisible otherwise. For submitType=\"modEnter\" use t('dataEntry.chatComposer.hintModEnter', { modifier: isApplePlatform() ? '\u2318' : 'Ctrl' }) with isApplePlatform from @godxjp/ui/lib/utils \u2014 the same platform test the composer uses to pick metaKey vs ctrlKey.",'DO set `allowEmptySubmit` (not a hidden fake draft) when the composer also submits field changes from `header`/`footer`; your onSubmit receives "" and decides whether anything changed.',"DON'T size it with a className height: the box grows between --chat-composer-min-height and --chat-composer-max-height, both derived from the --control-height tier. Use `size`, or re-tune the two tokens in your theme.",'DO move the toolbar BELOW a full-width draft box with `actions={false}` + a function `footer` \u2014 the function receives `{ components: { SubmitButton, CancelButton } }`, both already wired to onSubmit/onCancel/disabled/the loading swap, so nothing about the send contract is reimplemented at the call site. Put the attach control and a keyboard hint on the START side of the footer row and `<SubmitButton />` on the END side (a `Flex justify="between"`), exactly like the record-comment box case. Leaving `actions` unset keeps today\'s inline row \u2014 this is opt-in, not a breaking change.'],useCases:["The message box of an AI assistant or support chat, under a ChatBubbleList feed.","A comment composer on a record detail screen (prefix = attach Button, footer = character counter).",'A record-detail comment box with a full-width textarea and a toolbar row BELOW it \u2014 attach on the start side, a keyboard hint in the middle, clear/send on the end side: `actions={false}` + `footer={({ components }) => <Flex justify="between">\u2026<components.SubmitButton /></Flex>}`.','A long-form reply box where Enter must break the line: submitType="shiftEnter".','A comment bar on an issue/record where Enter breaks the line and \u2318/Ctrl+Enter posts, and a status change may be posted without text: submitType="modEnter" + allowEmptySubmit.',"A streaming answer the user can stop: loading + onCancel."],related:["Textarea \u2014 the primitive underneath. Use it directly for an ordinary multi-line form field with no send action.","ChatSuggestion \u2014 wraps ChatComposer to add trigger-character (/) autocomplete.","ChatBubbleList \u2014 the feed the composer sends into.","SearchInput \u2014 a single-line query field; a composer is multi-line and holds a draft."],example:['import { ChatComposer } from "@godxjp/ui/data-entry";',"",'const [draft, setDraft] = useState("");',"const [streaming, setStreaming] = useState(false);","","<ChatComposer"," value={draft}"," onValueChange={setDraft}",' onSubmit={(text) => { send(text); setDraft(""); }}'," loading={streaming}"," onCancel={() => setStreaming(false)}",' placeholder={t("chat.placeholder")}',' footer={t("dataEntry.chatComposer.hintEnter")}',"/>"].join(`
|
|
2594
|
-
`),docPath:"data-entry/chat-composer.tsx",storyPath:"data-entry/ChatComposer.stories.tsx",rules:[2,6,43,45]},{name:"ChatSuggestion",group:"data-entry",tagline:"Trigger-character autocomplete over a ChatComposer (Ant Design X Suggestion): type / at a word boundary and a Command list opens against the composer, driven from the textarea without ever taking focus off it.",props:[{name:"items",type:"ChatSuggestionItemProp[]",required:!0,description:"The rows to offer: { value, label?, description?, icon?, disabled?, children? }. One level of children is honoured \u2014 picking a parent drills into it instead of emitting."},{name:"onValueChange",type:"(value: string) => void",description:"Fires with the picked row's value. The CALLER owns what that does to the draft text \u2014 the component never rewrites the textarea behind your back."},{name:"triggerCharacter",type:"string",defaultValue:'"/"',description:'The character(s) that open the list when typed at a boundary \u2014 the start, whitespace, or any non-ASCII character, so
|
|
2594
|
+
`),docPath:"data-entry/chat-composer.tsx",storyPath:"data-entry/ChatComposer.stories.tsx",rules:[2,6,43,45]},{name:"ChatSuggestion",group:"data-entry",tagline:"Trigger-character autocomplete over a ChatComposer (Ant Design X Suggestion): type / at a word boundary and a Command list opens against the composer, driven from the textarea without ever taking focus off it.",props:[{name:"items",type:"ChatSuggestionItemProp[]",required:!0,description:"The rows to offer: { value, label?, description?, icon?, disabled?, children? }. One level of children is honoured \u2014 picking a parent drills into it instead of emitting."},{name:"onValueChange",type:"(value: string) => void",description:"Fires with the picked row's value. The CALLER owns what that does to the draft text \u2014 the component never rewrites the textarea behind your back."},{name:"triggerCharacter",type:"string",defaultValue:'"/"',description:'The character(s) that open the list when typed at a boundary \u2014 the start, whitespace, or any non-ASCII character, so `/` opens right after Japanese text (gh#1127); an ASCII letter still blocks a ONE-character trigger, so `https://x` opens nothing. A multi-character trigger (`[[`) opens anywhere, `abc[[` included (gh#1129). After Escape the list stays shut until a new trigger is typed. Use "@" for mentions, "[[" for a link picker.'},{name:"allowSpaces",type:"boolean",defaultValue:"false",description:'Spaces may appear inside the query (a `[[` link picker searching "Meeting notes"); a line break still ends it (gh#1127).'},{name:"terminator",type:"string",description:"Typing this inside the query finishes the token and closes the list, e.g. `]]` (gh#1127)."},{name:"shouldFilter",type:"boolean",defaultValue:"true",description:"`false` when the host answers the query itself (async, via `onQueryChange`) and `items` already holds the matches \u2014 they are shown as given, not filtered again (gh#1127)."},{name:"onQueryChange",type:"(query: string) => void",description:"The query typed after the trigger, on every change while the list is open \u2014 the seam for server-side search (gh#1127)."},{name:"open",type:"boolean",description:"Controlled open state of the list."},{name:"defaultOpen",type:"boolean",description:"Uncontrolled initial open state."},{name:"onOpenChange",type:"(open: boolean) => void",description:"Open-state change handler."},{name:"children",type:"(props: { onTrigger: (value?: string | false) => void; onKeyDown: React.KeyboardEventHandler<HTMLTextAreaElement> }) => React.ReactNode",required:!0,description:"Render prop wrapping the composer. Call onTrigger from the composer's onValueChange and forward onKeyDown to its onKeyDown."},{name:"emptyMessage",type:"string",description:"Shown when the query matches nothing (localized default otherwise)."},{name:"listLabel",type:"string",description:"Accessible name of the listbox (localized default otherwise)."},{name:"id",type:"string",description:"DOM id of the anchor wrapping the composer."}],usage:["DO wire BOTH halves of the render prop: `onTrigger` from the composer's onValueChange and `onKeyDown` from its onKeyDown. With only one wired the list either never opens or cannot be driven.","DO decide yourself what a pick does to the draft \u2014 onValueChange hands you the value; the typed /query is still in the box, so replace it or append to it as your screen needs.","DON'T hand-roll a listbox next to a textarea. This composes the real Command (cmdk) inside a Popover, which already ships the listbox/option roles, active-row bookkeeping and scroll-into-view.","DO rely on Escape: it closes the list, returns focus to the textarea and leaves the typed text intact. It also stops propagating, so a composer inside a Dialog does not close the Dialog too.","DON'T expect it to filter server-side \u2014 filtering is a plain substring match over label/value/description. For a remote list, filter `items` yourself as the query changes."],useCases:["Slash commands over an assistant composer (/summarize, /translate, /explain).",'Mention picker in a comment composer (triggerCharacter="@").',"Prompt-template inserter grouped one level deep (a category row that drills into its templates)."],related:["ChatComposer \u2014 the control it wraps; use it alone when there is nothing to suggest.","Command / CommandPalette \u2014 a full-screen command surface opened by a shortcut, not by a character in a draft.","Select (showSearch) \u2014 the searchable single-select; a suggestion list edits free text, it does not hold a value."],example:['import { ChatComposer, ChatSuggestion } from "@godxjp/ui/data-entry";',"",'const [draft, setDraft] = useState("");',"","<ChatSuggestion"," items={[",' { value: "summarize", label: "\u8981\u7D04\u3059\u308B", description: "Summarize the thread" },',' { value: "translate", label: "\u7FFB\u8A33\u3059\u308B" },'," ]}",' onValueChange={(value) => setDraft("/" + value + " ")}',">"," {({ onTrigger, onKeyDown }) => ("," <ChatComposer"," value={draft}"," onValueChange={(next) => { setDraft(next); onTrigger(next); }}"," onKeyDown={onKeyDown}"," onSubmit={(text) => send(text)}"," />"," )}","</ChatSuggestion>"].join(`
|
|
2595
2595
|
`),docPath:"data-entry/chat-composer.tsx",storyPath:"data-entry/ChatSuggestion.stories.tsx",rules:[2,3,6]},{name:"Conversations",group:"navigation",tagline:"The session rail of a chat surface (Ant Design X Conversations): past conversations, the current one marked with aria-current, a per-row overflow menu, and recency buckets \u2014 the whole rail one roving-tabindex tab stop, not one tab stop per conversation.",props:[{name:"items",type:"(ConversationsItemProp | ConversationsDividerProp)[]",description:'The rows. A conversation is { key, label?, group?, icon?, disabled? }; a rule between runs is { type: "divider", key?, dashed? }. Ant Design X `items`.'},{name:"activeKey",type:"string",description:"Controlled selection \u2014 the key of the conversation on screen. Ant Design X `activeKey`."},{name:"defaultActiveKey",type:"string",description:"Uncontrolled initial selection. Ant Design X `defaultActiveKey`."},{name:"onActiveChange",type:"(key: string, item?: ConversationsItemProp | ConversationsDividerProp) => void",description:"Fires with the picked key and the entry behind it. Ant Design X `onActiveChange`."},{name:"menu",type:"ConversationsMenuProp | ((conversation: ConversationsItemProp) => ConversationsMenuProp | undefined)",description:"The per-row overflow menu: { items: [{ key, label, icon?, danger?, disabled? }], onClick?, triggerLabel? }. Pass a function to vary it per row, or return undefined for a row that has no menu. Ant Design X `menu` (antd MenuProps there)."},{name:"groupable",type:"boolean | ConversationsGroupableProp",description:"Bucket rows by their `group` field. The object form takes label (node or (group) => node), collapsible (boolean or (group) => boolean), defaultExpandedKeys, expandedKeys and onExpand. Ant Design X `groupable`."},{name:"creation",type:"ConversationsCreationProp",description:'The "new conversation" button pinned above the rail: { label?, icon?, disabled?, onClick? }. Ant Design X `creation`.'},{name:"label",type:"string",description:"Accessible name of the rail (a plain string \u2014 it lands on aria-label). Localized default otherwise."},{name:"id",type:"string",description:"DOM id of the rail root."}],usage:["DO give every conversation a stable `key` \u2014 it is what activeKey, onActiveChange and the menu callback all address. A key that changes on re-render moves the selection.","DO reach for `menu` for rename/delete instead of adding a second Button to each row. The trigger is keyboard-reachable with the forward arrow (\u2192 in LTR, \u2190 in RTL), so a row's second action costs no extra tab stop.",'DO pass `menu.triggerLabel` when the rows are user content: the default names the row, and twelve identical "More actions" buttons are indistinguishable in a screen reader\'s element list.',"DON'T hand-roll the rail out of full-width Buttons plus aria-current. That is one tab stop PER conversation; this is one for the whole rail, with \u2191/\u2193/Home/End inside it.","DON'T expect `styles`/`classNames` from Ant Design X \u2014 they are deliberately not ported. Retune the rail through the --conversations-* tokens (rules #44/#45).",'DO use `groupable={{ collapsible: true }}` for "Today / Previous 7 days": the bucket headings join the same roving order, so collapsing a bucket is reachable without leaving the rail.'],useCases:["The assistant rail of a chat product \u2014 past sessions, the current one marked, rename and delete per row.","Recency buckets over a long history (Today / Yesterday / Previous 7 days) with the older buckets collapsed.","A rail beside ChatBubbleList and ChatComposer: the three are one surface, and Conversations is the half that used to be missing."],related:["ChatBubbleList \u2014 the feed beside this rail; Conversations picks WHICH feed is shown.","ListRow \u2014 a single-line entity row with a trailing action, for short lists inside a Card. It has no selection, no roving focus and no grouping.","Sidebar / NavList \u2014 route navigation. Use those when a row changes the URL; use Conversations when a row changes which conversation the surface is on.","DropdownMenu \u2014 what the per-row `menu` renders; compose it directly when the menu is not attached to a conversation row."],example:['import { Conversations } from "@godxjp/ui/navigation";',"",'const [active, setActive] = useState("c1");',"","<Conversations"," activeKey={active}"," onActiveChange={setActive}"," groupable={{ collapsible: true }}"," creation={{ onClick: () => startNewChat() }}"," items={[",' { key: "c1", label: "\u8ACB\u6C42\u66F8\u306E\u4E0B\u66F8\u304D", group: "today" },',' { key: "c2", label: "\u7D4C\u8CBB\u7CBE\u7B97\u306E\u898F\u5247", group: "today" },',' { key: "c3", label: "\u51FA\u5F35\u624B\u5F53\u306E\u78BA\u8A8D", group: "earlier" },'," ]}"," menu={{"," items: [",' { key: "rename", label: "\u540D\u524D\u3092\u5909\u66F4" },',' { key: "delete", label: "\u524A\u9664", danger: true },'," ],"," onClick: ({ key, conversation }) => run(key, conversation.key),"," }}","/>"].join(`
|
|
2596
2596
|
`),docPath:"navigation/conversations.tsx",storyPath:"navigation/Conversations.stories.tsx",rules:[2,6,23,44,45]},{name:"MegaMenu",group:"navigation",tagline:'A primary site navigation whose top-level items disclose a full-width panel of grouped links (Ant Design `Menu mode="horizontal"` whose SubMenu renders through popupRender). Implements the WAI-ARIA APG Disclosure Navigation pattern \u2014 NOT menu/menubar roles \u2014 with a roving tabindex across the bar, hover intent, Escape-to-trigger, and a narrow layout where the same disclosure lays out in flow.',props:[{name:"items",type:"MegaMenuItemProp[]",description:"The bar. An item WITH a `panel` is a disclosure button (antd SubMenuType); an item WITHOUT one is a plain link (antd MenuItemType). { key, label, href?, icon?, disabled?, panel? } where panel is { groups: [{ key, label?, description?, icon?, links: [{ key, label, href?, description?, icon?, disabled? }] }], footer? }. Ant Design `items`."},{name:"open",type:"string | null",description:"Key of the OPEN PANEL, or null for none. Ant Design `openKeys` collapsed to one level \u2014 a megamenu bar is one level deep, so at most one panel is open and the array would only ever hold zero or one key."},{name:"defaultOpen",type:"string | null",description:"Initial uncontrolled open panel. Ant Design `defaultOpenKeys`.",defaultValue:"null"},{name:"onOpenChange",type:"(key: string | null) => void",description:"Fires with the newly open panel's key, or null when everything closed. Ant Design `onOpenChange`."},{name:"value",type:"string",description:'Key of the item for the CURRENT ROUTE \u2014 renders aria-current="page" on the bar item and on the matching panel link. Ant Design `selectedKeys`, singular because a route is singular.'},{name:"defaultValue",type:"string",description:"Uncontrolled initial current route. Ant Design `defaultSelectedKeys`."},{name:"onValueChange",type:"(key: string) => void",description:"Fires with the activated key (a top-level link or a panel link). Activation always closes the open panel. Ant Design `onClick`."},{name:"size",type:"xs | sm | md | lg",description:"Bar density. The trigger box tracks the matching --control-height tier.",defaultValue:"md"},{name:"triggerAction",type:"click | hover",description:"Ant Design `triggerSubMenuAction`. Default is `click` here where antd defaults to `hover`, because a hover-only trigger has no equivalent on a touch screen; `hover` still accepts click, so touch is never stranded. antd's third value `contextMenu` is not ported.",defaultValue:"click"},{name:"openDelay",type:"number",description:"Ant Design `subMenuOpenDelay`, in MILLISECONDS (antd uses seconds). `hover` only.",defaultValue:"0"},{name:"closeDelay",type:"number",description:"Ant Design `subMenuCloseDelay`, in MILLISECONDS. The hover-intent grace period: the pointer may cross a diagonal toward the panel for this long before anything closes. `hover` only.",defaultValue:"100"},{name:"expandIcon",type:"React.ReactNode | false",description:"Ant Design `expandIcon`, verbatim including its `false` to remove the chevron."},{name:"linkComponent",type:"React.ComponentType<AnchorHTMLAttributes & { href?: string }>",description:"Router link component for every href in the bar and the panels \u2014 same contract and same spelling as Sidebar.linkComponent / NavList.linkComponent."},{name:"label",type:"string",description:"Accessible name of the <nav> landmark (a plain string \u2014 it lands on aria-label). Localized default otherwise."},{name:"id",type:"string",description:"DOM id of the nav root."}],usage:['DO reach for this INSTEAD of DropdownMenu for a site nav. DropdownMenu is react-aria-components Menu, i.e. role="menu" / role="menuitem": a row of them announces a desktop application menubar for what is actually a set of links, and Tab then leaves the whole widget instead of walking the links. That is the classic megamenu a11y defect and it is why this component exists.',"DO give the bar its landmark name through `label` when a page has more than one nav (a primary bar plus a footer nav): two unnamed <nav> landmarks are indistinguishable in a landmark list.","DO drive `value` from your router. A change to it CLOSES the open panel, which is the close-on-route-change half of the contract and needs no router dependency here.","DO use `linkComponent` for a client-side router; the library composes the row and your component renders only the <a>.","DON'T nest a second level inside a panel. A panel is exactly one level deep by construction (`groups[].links[]`) \u2014 antd's arbitrary SubMenu nesting is `Sidebar`/`NavList` territory, not a bar.","DON'T set `triggerAction=\"hover\"` and then also hide the trigger's own affordance: hover still opens on click here precisely so a touch user is not stranded, and WCAG 1.4.13 applies to anything hover-revealed.","DON'T add a `theme=\"dark\"` prop expecting antd's. This library inverts by role scoping ([data-tenant] / per-region), and every surface here is a --mega-menu-* token (rules #44/#45).","KNOW that the open panel is `position: fixed` and its geometry is MEASURED from the bar, not inherited. That is not a preference: an absolutely-positioned panel is clipped away by both surfaces a megamenu lives in (`Topbar`'s slots are `overflow: clip`, `Card` is `overflow: hidden` \u2014 measured at 331px of 348px gone, and not hit-testable). The consequence for you is that an open panel OVERLAYS what is beneath it, so do not leave one open by default in the middle of a scrolling page."],useCases:["A marketing or product site's primary navigation, where Products / Solutions / Resources each open a panel of grouped links rather than a narrow list.","An admin console with several product areas: a top bar where a section opens a panel of its screens, grouped with headings and one-line descriptions.","A documentation site's top bar, where the current page is marked with aria-current in both the bar and the open panel."],related:['DropdownMenu \u2014 a menu of COMMANDS on a trigger (role="menu"). Use it for actions; use MegaMenu for navigation to places.','NavList \u2014 the same idea laid out vertically inside a page (a settings nav). antd\'s `Menu mode="inline"` is Sidebar; `mode="vertical"` is NavList.',"Topbar / TopbarItem \u2014 the APP shell's bar, and NOT where this goes. Measured, both slots break it: `topbar-center` is `display: none` below roughly 1280px (flex at 1440, none at 1024) so the nav vanishes on a laptop, and `topbar-start` is one `overflow: clip` / `flex-wrap: nowrap` row, so the narrow accordion runs out of it (58 elements past the viewport at 375). Put MegaMenu in the site header's own row beside the logo, and give phone width a `Sheet` behind a trigger \u2014 which is what real sites do anyway.","Tabs \u2014 switches which panel of the SAME page is shown. A nav goes somewhere else.","Breadcrumb \u2014 where you are in the hierarchy, not where you can go."],example:['import { MegaMenu } from "@godxjp/ui/navigation";',"","<MegaMenu",' label="\u30E1\u30A4\u30F3\u30CA\u30D3\u30B2\u30FC\u30B7\u30E7\u30F3"'," value={route}"," onValueChange={setRoute}",' triggerAction="hover"'," items={["," {",' key: "products",',' label: "\u88FD\u54C1",'," panel: {"," groups: ["," {",' key: "core",',' label: "\u30B3\u30A2",',' description: "\u6BCE\u65E5\u4F7F\u3046\u696D\u52D9\u30A2\u30D7\u30EA",'," links: [",' { key: "hr", label: "\u4EBA\u4E8B\u7BA1\u7406", href: "/hr", description: "\u5F93\u696D\u54E1\u53F0\u5E33\u3068\u7570\u52D5" },',' { key: "payroll", label: "\u7D66\u4E0E\u8A08\u7B97", href: "/payroll" },'," ],"," },"," ],",' footer: <a href="/products">\u3059\u3079\u3066\u306E\u88FD\u54C1\u3092\u898B\u308B</a>,'," },"," },",' { key: "pricing", label: "\u6599\u91D1", href: "/pricing" },'," ]}","/>"].join(`
|
|
2597
2597
|
`),docPath:"navigation/mega-menu.tsx",storyPath:"navigation/MegaMenu.stories.tsx",rules:[2,6,23,44,45]},{name:"Welcome",group:"data-display",tagline:"The greeting block at the head of an empty conversation (Ant Design X Welcome): glyph, greeting, one line under it, and a trailing slot ON THE TITLE ROW \u2014 which is the placement a hand-roll gets wrong.",props:[{name:"icon",type:"React.ReactNode | string",description:'Leading glyph. A STRING beginning with http(s) is rendered as a decorative <img alt=""> (Ant Design X does the same, with alt="icon"); any other string renders as text.'},{name:"title",type:"React.ReactNode",description:"The greeting. Renders as an <h4>, which is Ant Design X's hardcoded Typography.Title level={4}."},{name:"description",type:"React.ReactNode",description:"The line under the greeting."},{name:"extra",type:"React.ReactNode",description:"Trailing slot on the TITLE row \u2014 a dismiss button, a model picker. Not under the description."},{name:"variant",type:'"filled" | "borderless"',defaultValue:'"filled"',description:"filled gives the block its own tinted ground and hairline; borderless lets it sit on the page."},{name:"id",type:"string",description:"DOM id of the block."}],usage:["DO put it above the composer on an empty chat, with ChatSuggestion or a Prompts row beneath it \u2014 that is the surface it belongs to.","DO pass `extra` for the one action the greeting carries (dismiss, switch model). It lands beside the title, top-aligned, so a two-line title does not float it.","DON'T reach for it as a generic page header \u2014 that is PageContainer's title/subtitle/extra, which owns the page rhythm.","DON'T expect a heading-level prop: Ant Design X hardcodes level 4 and this ports that. Wrap it in your own heading hierarchy if the page needs a different rung.","DON'T expect `styles`/`classNames` from Ant Design X \u2014 retune through the --welcome-* tokens."],useCases:["The first screen of an assistant, before the first message.","The head of a fresh conversation started from the Conversations rail.","A feature introduction card inside a chat surface, dismissed through `extra`."],related:["EmptyState \u2014 the general 'nothing here yet' block for a list or a table. Welcome is the chat surface's greeting and carries an icon/title/description/extra shape of its own.","PageContainer \u2014 owns the PAGE header; Welcome sits inside the page body.","ChatSuggestion / ChatBubbleList \u2014 the rest of the same surface."],example:['import { Welcome } from "@godxjp/ui/data-display";','import { Button } from "@godxjp/ui/general";','import { Bot } from "lucide-react";',"","<Welcome"," icon={<Bot />}",' title="\u3053\u3093\u306B\u3061\u306F"',' description="\u8ACB\u6C42\u3001\u7D4C\u8CBB\u3001\u52E4\u6020\u306E\u3053\u3068\u306A\u3089\u304A\u624B\u4F1D\u3044\u3067\u304D\u307E\u3059\u3002"',' extra={<Button variant="ghost" size="sm">\u9589\u3058\u308B</Button>}',"/>"].join(`
|
|
@@ -4982,7 +4982,7 @@ A block with no reason is IGNORED and the finding stands. An unclosed block runs
|
|
|
4982
4982
|
The class-shaped rules (gap-*/p-*/m-*, bg-<palette>-*, w-[\u2026], pr-*, dark:*) only read class
|
|
4983
4983
|
expressions \u2014 a className/class attribute, a class-named binding (\`baseClass\`, \`statusStyles\`,
|
|
4984
4984
|
\`badgeVariants\`) or a cn()/clsx()/cva() call \u2014 so prose that merely spells a utility is not a
|
|
4985
|
-
finding and needs no suppression.`,oe=[{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:"formfield-needs-form",severity:"error",category:"composition",standard:"@godxjp/ui Form (gh#998)",fix:'Wrap FormFields in <Form layout="horizontal" labelWidth controlWidth>; a row of fields is <SpaceCompact> or <Form columns>, never a hand-rolled <Flex>. A field component whose whole output is one FormField is exempt.'},{id:"mixed-button-size",severity:"error",category:"composition",standard:null,fix:'Sibling <Button>s under one parent (through fragments, {cond && \u2026}, ternaries, Tooltip wrappers) share ONE size; a missing size is default; icon-sm pairs with sm, icon-xs with xs, icon with default. Never `size="sm"` beside a default Button in one action row.'},{id:"dialog-form-too-big",severity:"error",category:"composition",standard:"@godxjp/ui form placement (gh#998)",fix:"Three or more FormFields in a Dialog body is a page: give the form its own route. Dialogs hold a confirmation or one or two fields; a side Sheet (drawer) may hold a filter or edit form."},{id:"select-width-hint",severity:"warn",category:"composition",standard:"GOV.UK Design System \xB7 text input width",fix:"Size a Select for its content \u2014 `controlWidth` on the FormField, or once on the <Form>."},{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-hand-rolled-scrollport",severity:"warn",category:"a11y",standard:"WCAG 2.2 SC 2.1.1 (Keyboard) \xB7 WAI-ARIA 1.2 (group) \xB7 Deque axe-core scrollable-region-focusable",fix:'Replace className="overflow-auto / overflow-y-auto / overflow-x-auto / overflow-scroll" on your own element with <ScrollArea label={t("\u2026")} orientation>, which is the tab stop, the role and the localized name \u2014 and withholds all three while there is nothing to scroll. A browser audit only fails a scrollport whose content has NO focusable child, so the same markup is clean or broken depending on the data; this reads the markup instead (gh#825). overflow-hidden is a clipping box, not a scrollport, and is not flagged.'},{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.'},{id:"no-hand-rolled-break-anywhere",severity:"warn",category:"composition",standard:"CSS Text 3 \xA75.5 (overflow-wrap) \xB7 WCAG 2.2 SC 1.4.10 (Reflow)",fix:`Replace className="[overflow-wrap:anywhere] break-words whitespace-normal" (or wrap-anywhere) with <Text break="anywhere">, which emits overflow-wrap: anywhere AND releases a table cell's inherited nowrap, so an email, code or id shrinks its column to the viewport. Not whitespace="pre-wrap": its break-word does not lower min-content, so a table cell stays wide (gh#927).`}];function re(e){return e?oe.filter(t=>t.category===e):oe}var le="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)",se=[{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 \u2014 86 KB instead of 367 KB gzip, since the bundled @font-face declarations are most of the CSS, gh#971); 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:"mixed-button-height",severity:"error",category:"layout",standard:"@godxjp/ui Button size (one size per row) \xB7 Nielsen consistency heuristic",fix:"Buttons in one flex row must render at one height (within 0.5px): one `size` per row; icon-sm pairs with sm, icon-xs with xs, icon with default. Runtime twin of the static mixed-button-size rule."},{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. The accent @godxjp/ui itself ships is exempt (gh#823) \u2014 this finding is always a colour someone chose."},{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 de(e){return e?se.filter(t=>t.category===e):se}var h={name:"@godxjp/ui-mcp",version:"31.22.0",godxUiCompatibility:"31.22.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 H=[{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_utilities",description:'List every NON-component public export of @godxjp/ui \u2014 hooks, helper functions and constants (cn, formatDate, formatCurrency, toast, useDebouncedValue, buttonVariants, CHART_COLORS, SHOW_PARENT \u2026). Reach for this before hand-writing a className merger, a date/money formatter, a debounce hook or a chart palette: two products in this org each re-implemented `cn` because it could not be found. Optionally filter by kind. Then `get_component name="<name>"` for its signature, usage and example.',inputSchema:{type:"object",properties:{kind:{type:"string",enum:["hook","function","value"],description:"hook = only legal inside a component body; function = callable anywhere; value = a constant to read."}}}},{name:"list_patterns",description:"List every canonical copy-paste code pattern (signup-form, settings-page, data-table-page, async-data-state, confirm-destructive, \u2026); common aliases resolve too. Use before `get_pattern`.",inputSchema:{type:"object",properties:{}}},{name:"list_anti_ai_tells",description:"List every AI-tell pattern to AVOID (optionally by category). Use to self-audit a design before shipping; then `get_anti_ai_tell` for the fix.",inputSchema:{type:"object",properties:{category:{type:"string",enum:["visual","layout","copy","interaction","imagery","structure"]}}}},{name:"list_redesign_checks",description:"List the redesign audit checklist (50+ checks; optionally by category). Use when auditing an existing project; then `get_redesign_check` for a symptom's fix.",inputSchema:{type:"object",properties:{category:{type:"string",enum:["typography","color-surface","layout","interactivity","content","components","iconography","code-quality","omissions"]}}}},{name:"list_audit_rules",description:"List the LOCAL static ui-audit rules (scripts/ui-audit.mjs) to run BEFORE any visual review \u2014 each cites the standard it enforces (WCAG/WAI-ARIA/Intl/ISO/IANA/CSS-Logical) + a fix + the run command. Optionally by category.",inputSchema:{type:"object",properties:{category:{type:"string",enum:["tokens","composition","api","a11y","i18n","rtl","copy"]}}}},{name:"list_visual_checks",description:"List the RUNTIME visual-audit checks (scripts/visual-audit.mjs \u2014 Playwright + axe-core) to run against the RUNNING app: contrast/ARIA (axe), target size, rendered-accent chroma, DOM emoji, banner layout. Needs a browser (vs list_audit_rules, static). Optionally by category.",inputSchema:{type:"object",properties:{category:{type:"string",enum:["a11y","color","i18n","layout"]}}}},{name:"get_anti_ai_tell",description:"Fetch ONE anti-AI-tell \u2014 full body + concrete fix. Use after `list_anti_ai_tells`.",inputSchema:{type:"object",properties:{name:{type:"string",description:"Exact tell name from list_anti_ai_tells."}},required:["name"]}},{name:"get_redesign_check",description:"Fetch redesign check(s) matching a symptom snippet. Returns full fix + UI note. Use after `list_redesign_checks`.",inputSchema:{type:"object",properties:{symptom:{type:"string",description:"Fragment of the symptom text (e.g. 'Inter everywhere' / '100vh')."}},required:["symptom"]}},{name:"get_skill_section",description:"Fetch ONE section of ONE skill \u2014 token-efficient. E.g. `skill='soft', section='double-bezel'`. Use after `list_skills` narrowed the relevant skill + section.",inputSchema:{type:"object",properties:{skill:{type:"string",description:"Skill id (e.g. 'soft', 'minimalist', 'taste')."},section:{type:"string",description:"Section id within that skill."}},required:["skill","section"]}},{name:"get_component",description:"Full guide for one @godxjp/ui component \u2014 import path, props/types/defaults, HOW to use it (DO/DON'T), WHEN to reach for it (use cases), related components (don't reinvent/confuse), a copy-paste example, story path, and cardinal rules. Use this before hand-rolling anything. Design-token knobs are listed compactly (name+default); pass `verbose:true` for what each token controls.",inputSchema:{type:"object",properties:{name:{type:"string",description:"Component name (e.g. 'Button', 'DataTable')."},verbose:{type:"boolean",description:"Include the full design-token table with a 'what it controls' description per token. Default false (compact token+default only) to save context."}},required:["name"]}},{name:"get_pattern",description:"Full code snippet for one canonical pattern \u2014 copy-paste-ready.",inputSchema:{type:"object",properties:{name:{type:"string",description:"Pattern slug (use list_patterns first)."}},required:["name"]}},{name:"get_rule",description:"Read one cardinal rule from CLAUDE.md (by number) OR all if no number.",inputSchema:{type:"object",properties:{number:{type:"number",description:"Rule number (1-N)."}}}},{name:"get_vocab",description:"Read shared prop-vocabulary type (`SizeProp`, `StatusProp`, `ColorProp`, `LoadingProp`, etc.) OR all if no name.",inputSchema:{type:"object",properties:{name:{type:"string",description:"Vocab type name."}}}},{name:"get_tokens",description:"Read design tokens, optionally filtered by tier category (primitive / semantic / component).",inputSchema:{type:"object",properties:{category:{type:"string",enum:["primitive","semantic","component"]}}}},{name:"list_consumer_skills",description:"List the design skills relevant to an app-dev BUILDING WITH @godxjp/ui (audience consumer/both). Hides core library-maintenance skills. START HERE if you import @godxjp/ui and want guidance (design-to-page, compose-a-screen, taste, \u2026). Returns id + name + whenToUse + section ids.",inputSchema:{type:"object",properties:{}}},{name:"get_consumer_skill",description:"Fetch ONE section of ONE consumer-facing skill. Same as get_skill_section but refuses core-only skills (steers app-devs away from library-maintenance material). Use after list_consumer_skills / route_consumer_task.",inputSchema:{type:"object",properties:{skill:{type:"string",description:"Consumer skill id (e.g. 'design-to-page', 'compose-a-screen')."},section:{type:"string",description:"Section id within that skill."}},required:["skill"]}},{name:"route_consumer_task",description:"Natural-language task \u2192 consumer skill+section pointer. Like route_task but only points to consumer-facing skills (never core library-maintenance). Use FIRST when you're building an app with @godxjp/ui.",inputSchema:{type:"object",properties:{task:{type:"string",description:"Describe what you want to build."}},required:["task"]}},{name:"draft_bug_report",description:"When @godxjp/ui ITSELF is at fault (missing token, a primitive lacking the controlled-vocabulary prop, a real a11y/behaviour bug, a wrong catalog example) and you cannot follow a rule \u2014 DON'T fake a workaround. This drafts a detailed GitHub issue body + a copy-paste `gh issue create` command so you can report it. Prints the command only; never runs gh.",inputSchema:{type:"object",properties:{summary:{type:"string",description:"One-line title of the bug / blocked rule."},repro:{type:"string",description:"Minimal steps or code to reproduce."},expected:{type:"string",description:"What SHOULD happen (per the rule/spec)."},actual:{type:"string",description:"What actually happens."},component:{type:"string",description:"Affected component name, if any (links to get_component)."},rule:{type:"number",description:"Cardinal rule number that can't be followed, if any."},version:{type:"string",description:"Installed @godxjp/ui version (e.g. '12.1.0')."},env:{type:"string",description:"Environment (browser/OS/framework), if relevant."}},required:["summary"]}},{name:"check_compatibility",description:"Report whether the @godxjp/ui version installed in the target project matches THIS catalog (which describes one release train). A mismatched minor means the props/tokens/patterns may describe a build they never installed (#140). Pass the installed version (`npm ls @godxjp/ui`); call it at the START of a consumer session.",inputSchema:{type:"object",properties:{version:{type:"string",description:"Installed @godxjp/ui version in the target project, e.g. '16.10.0'. Omit to just read the catalog's own version + compatible range."}}}},{name:"route_task",description:"Natural-language task \u2192 skill+section pointer (e.g. 'design a premium agency hero' \u2192 soft/vibe-archetypes). Use FIRST when you don't know which skill applies.",inputSchema:{type:"object",properties:{task:{type:"string",description:"Describe what you want to build."}},required:["task"]}},{name:"suggest_primitive",description:"Use case \u2192 primitive recommendation. E.g. 'confirm a destructive delete' \u2192 DangerZone pattern + Dialog suggestion.",inputSchema:{type:"object",properties:{use_case:{type:"string"}},required:["use_case"]}},{name:"search_components",description:"Fuzzy-search primitives by name / tagline / prop. Returns ranked matches.",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"]}}],Ie=new Set(H.map(e=>e.name));function ze(e=V()){let t=h.godxUiCompatibility??h.version,a=`@godxjp/ui-mcp ${h.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 Pe(e=V()){let t=e?L(e.version):null,a=L(h.version);return!e||!t||!a?null:Ue(t,a)>0?`\u26A0\uFE0F SERVER OLDER THAN INSTALLED PACKAGE: this server is @godxjp/ui-mcp ${h.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 ${h.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 me(e,t){let a=await Le(e,t);if(!Ie.has(e))return a;let o=V(),n=Pe(o);return`${ze(o)}
|
|
4985
|
+
finding and needs no suppression.`,oe=[{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:"formfield-needs-form",severity:"error",category:"composition",standard:"@godxjp/ui Form (gh#998)",fix:'Wrap FormFields in <Form layout="horizontal" labelWidth controlWidth>; a row of fields is <SpaceCompact> or <Form columns>, never a hand-rolled <Flex>. A field component whose whole output is one FormField is exempt.'},{id:"mixed-button-size",severity:"error",category:"composition",standard:null,fix:'Sibling <Button>s under one parent (through fragments, {cond && \u2026}, ternaries, Tooltip wrappers) share ONE size; a missing size is default; icon-sm pairs with sm, icon-xs with xs, icon with default. Never `size="sm"` beside a default Button in one action row.'},{id:"dialog-form-too-big",severity:"error",category:"composition",standard:"@godxjp/ui form placement (gh#998)",fix:"Three or more FormFields in a Dialog body is a page: give the form its own route. Dialogs hold a confirmation or one or two fields; a side Sheet (drawer) may hold a filter or edit form."},{id:"select-width-hint",severity:"warn",category:"composition",standard:"GOV.UK Design System \xB7 text input width",fix:"Size a Select for its content \u2014 `controlWidth` on the FormField, or once on the <Form>."},{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-hand-rolled-scrollport",severity:"warn",category:"a11y",standard:"WCAG 2.2 SC 2.1.1 (Keyboard) \xB7 WAI-ARIA 1.2 (group) \xB7 Deque axe-core scrollable-region-focusable",fix:'Replace className="overflow-auto / overflow-y-auto / overflow-x-auto / overflow-scroll" on your own element with <ScrollArea label={t("\u2026")} orientation>, which is the tab stop, the role and the localized name \u2014 and withholds all three while there is nothing to scroll. A browser audit only fails a scrollport whose content has NO focusable child, so the same markup is clean or broken depending on the data; this reads the markup instead (gh#825). overflow-hidden is a clipping box, not a scrollport, and is not flagged.'},{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.'},{id:"no-hand-rolled-break-anywhere",severity:"warn",category:"composition",standard:"CSS Text 3 \xA75.5 (overflow-wrap) \xB7 WCAG 2.2 SC 1.4.10 (Reflow)",fix:`Replace className="[overflow-wrap:anywhere] break-words whitespace-normal" (or wrap-anywhere) with <Text break="anywhere">, which emits overflow-wrap: anywhere AND releases a table cell's inherited nowrap, so an email, code or id shrinks its column to the viewport. Not whitespace="pre-wrap": its break-word does not lower min-content, so a table cell stays wide (gh#927).`}];function re(e){return e?oe.filter(t=>t.category===e):oe}var le="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)",se=[{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 \u2014 86 KB instead of 367 KB gzip, since the bundled @font-face declarations are most of the CSS, gh#971); 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:"mixed-button-height",severity:"error",category:"layout",standard:"@godxjp/ui Button size (one size per row) \xB7 Nielsen consistency heuristic",fix:"Buttons in one flex row must render at one height (within 0.5px): one `size` per row; icon-sm pairs with sm, icon-xs with xs, icon with default. Runtime twin of the static mixed-button-size rule."},{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. The accent @godxjp/ui itself ships is exempt (gh#823) \u2014 this finding is always a colour someone chose."},{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 de(e){return e?se.filter(t=>t.category===e):se}var h={name:"@godxjp/ui-mcp",version:"31.22.1",godxUiCompatibility:"31.22.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 H=[{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_utilities",description:'List every NON-component public export of @godxjp/ui \u2014 hooks, helper functions and constants (cn, formatDate, formatCurrency, toast, useDebouncedValue, buttonVariants, CHART_COLORS, SHOW_PARENT \u2026). Reach for this before hand-writing a className merger, a date/money formatter, a debounce hook or a chart palette: two products in this org each re-implemented `cn` because it could not be found. Optionally filter by kind. Then `get_component name="<name>"` for its signature, usage and example.',inputSchema:{type:"object",properties:{kind:{type:"string",enum:["hook","function","value"],description:"hook = only legal inside a component body; function = callable anywhere; value = a constant to read."}}}},{name:"list_patterns",description:"List every canonical copy-paste code pattern (signup-form, settings-page, data-table-page, async-data-state, confirm-destructive, \u2026); common aliases resolve too. Use before `get_pattern`.",inputSchema:{type:"object",properties:{}}},{name:"list_anti_ai_tells",description:"List every AI-tell pattern to AVOID (optionally by category). Use to self-audit a design before shipping; then `get_anti_ai_tell` for the fix.",inputSchema:{type:"object",properties:{category:{type:"string",enum:["visual","layout","copy","interaction","imagery","structure"]}}}},{name:"list_redesign_checks",description:"List the redesign audit checklist (50+ checks; optionally by category). Use when auditing an existing project; then `get_redesign_check` for a symptom's fix.",inputSchema:{type:"object",properties:{category:{type:"string",enum:["typography","color-surface","layout","interactivity","content","components","iconography","code-quality","omissions"]}}}},{name:"list_audit_rules",description:"List the LOCAL static ui-audit rules (scripts/ui-audit.mjs) to run BEFORE any visual review \u2014 each cites the standard it enforces (WCAG/WAI-ARIA/Intl/ISO/IANA/CSS-Logical) + a fix + the run command. Optionally by category.",inputSchema:{type:"object",properties:{category:{type:"string",enum:["tokens","composition","api","a11y","i18n","rtl","copy"]}}}},{name:"list_visual_checks",description:"List the RUNTIME visual-audit checks (scripts/visual-audit.mjs \u2014 Playwright + axe-core) to run against the RUNNING app: contrast/ARIA (axe), target size, rendered-accent chroma, DOM emoji, banner layout. Needs a browser (vs list_audit_rules, static). Optionally by category.",inputSchema:{type:"object",properties:{category:{type:"string",enum:["a11y","color","i18n","layout"]}}}},{name:"get_anti_ai_tell",description:"Fetch ONE anti-AI-tell \u2014 full body + concrete fix. Use after `list_anti_ai_tells`.",inputSchema:{type:"object",properties:{name:{type:"string",description:"Exact tell name from list_anti_ai_tells."}},required:["name"]}},{name:"get_redesign_check",description:"Fetch redesign check(s) matching a symptom snippet. Returns full fix + UI note. Use after `list_redesign_checks`.",inputSchema:{type:"object",properties:{symptom:{type:"string",description:"Fragment of the symptom text (e.g. 'Inter everywhere' / '100vh')."}},required:["symptom"]}},{name:"get_skill_section",description:"Fetch ONE section of ONE skill \u2014 token-efficient. E.g. `skill='soft', section='double-bezel'`. Use after `list_skills` narrowed the relevant skill + section.",inputSchema:{type:"object",properties:{skill:{type:"string",description:"Skill id (e.g. 'soft', 'minimalist', 'taste')."},section:{type:"string",description:"Section id within that skill."}},required:["skill","section"]}},{name:"get_component",description:"Full guide for one @godxjp/ui component \u2014 import path, props/types/defaults, HOW to use it (DO/DON'T), WHEN to reach for it (use cases), related components (don't reinvent/confuse), a copy-paste example, story path, and cardinal rules. Use this before hand-rolling anything. Design-token knobs are listed compactly (name+default); pass `verbose:true` for what each token controls.",inputSchema:{type:"object",properties:{name:{type:"string",description:"Component name (e.g. 'Button', 'DataTable')."},verbose:{type:"boolean",description:"Include the full design-token table with a 'what it controls' description per token. Default false (compact token+default only) to save context."}},required:["name"]}},{name:"get_pattern",description:"Full code snippet for one canonical pattern \u2014 copy-paste-ready.",inputSchema:{type:"object",properties:{name:{type:"string",description:"Pattern slug (use list_patterns first)."}},required:["name"]}},{name:"get_rule",description:"Read one cardinal rule from CLAUDE.md (by number) OR all if no number.",inputSchema:{type:"object",properties:{number:{type:"number",description:"Rule number (1-N)."}}}},{name:"get_vocab",description:"Read shared prop-vocabulary type (`SizeProp`, `StatusProp`, `ColorProp`, `LoadingProp`, etc.) OR all if no name.",inputSchema:{type:"object",properties:{name:{type:"string",description:"Vocab type name."}}}},{name:"get_tokens",description:"Read design tokens, optionally filtered by tier category (primitive / semantic / component).",inputSchema:{type:"object",properties:{category:{type:"string",enum:["primitive","semantic","component"]}}}},{name:"list_consumer_skills",description:"List the design skills relevant to an app-dev BUILDING WITH @godxjp/ui (audience consumer/both). Hides core library-maintenance skills. START HERE if you import @godxjp/ui and want guidance (design-to-page, compose-a-screen, taste, \u2026). Returns id + name + whenToUse + section ids.",inputSchema:{type:"object",properties:{}}},{name:"get_consumer_skill",description:"Fetch ONE section of ONE consumer-facing skill. Same as get_skill_section but refuses core-only skills (steers app-devs away from library-maintenance material). Use after list_consumer_skills / route_consumer_task.",inputSchema:{type:"object",properties:{skill:{type:"string",description:"Consumer skill id (e.g. 'design-to-page', 'compose-a-screen')."},section:{type:"string",description:"Section id within that skill."}},required:["skill"]}},{name:"route_consumer_task",description:"Natural-language task \u2192 consumer skill+section pointer. Like route_task but only points to consumer-facing skills (never core library-maintenance). Use FIRST when you're building an app with @godxjp/ui.",inputSchema:{type:"object",properties:{task:{type:"string",description:"Describe what you want to build."}},required:["task"]}},{name:"draft_bug_report",description:"When @godxjp/ui ITSELF is at fault (missing token, a primitive lacking the controlled-vocabulary prop, a real a11y/behaviour bug, a wrong catalog example) and you cannot follow a rule \u2014 DON'T fake a workaround. This drafts a detailed GitHub issue body + a copy-paste `gh issue create` command so you can report it. Prints the command only; never runs gh.",inputSchema:{type:"object",properties:{summary:{type:"string",description:"One-line title of the bug / blocked rule."},repro:{type:"string",description:"Minimal steps or code to reproduce."},expected:{type:"string",description:"What SHOULD happen (per the rule/spec)."},actual:{type:"string",description:"What actually happens."},component:{type:"string",description:"Affected component name, if any (links to get_component)."},rule:{type:"number",description:"Cardinal rule number that can't be followed, if any."},version:{type:"string",description:"Installed @godxjp/ui version (e.g. '12.1.0')."},env:{type:"string",description:"Environment (browser/OS/framework), if relevant."}},required:["summary"]}},{name:"check_compatibility",description:"Report whether the @godxjp/ui version installed in the target project matches THIS catalog (which describes one release train). A mismatched minor means the props/tokens/patterns may describe a build they never installed (#140). Pass the installed version (`npm ls @godxjp/ui`); call it at the START of a consumer session.",inputSchema:{type:"object",properties:{version:{type:"string",description:"Installed @godxjp/ui version in the target project, e.g. '16.10.0'. Omit to just read the catalog's own version + compatible range."}}}},{name:"route_task",description:"Natural-language task \u2192 skill+section pointer (e.g. 'design a premium agency hero' \u2192 soft/vibe-archetypes). Use FIRST when you don't know which skill applies.",inputSchema:{type:"object",properties:{task:{type:"string",description:"Describe what you want to build."}},required:["task"]}},{name:"suggest_primitive",description:"Use case \u2192 primitive recommendation. E.g. 'confirm a destructive delete' \u2192 DangerZone pattern + Dialog suggestion.",inputSchema:{type:"object",properties:{use_case:{type:"string"}},required:["use_case"]}},{name:"search_components",description:"Fuzzy-search primitives by name / tagline / prop. Returns ranked matches.",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"]}}],Ie=new Set(H.map(e=>e.name));function ze(e=V()){let t=h.godxUiCompatibility??h.version,a=`@godxjp/ui-mcp ${h.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 Pe(e=V()){let t=e?L(e.version):null,a=L(h.version);return!e||!t||!a?null:Ue(t,a)>0?`\u26A0\uFE0F SERVER OLDER THAN INSTALLED PACKAGE: this server is @godxjp/ui-mcp ${h.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 ${h.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 me(e,t){let a=await Le(e,t);if(!Ie.has(e))return a;let o=V(),n=Pe(o);return`${ze(o)}
|
|
4986
4986
|
${n?`${n}
|
|
4987
4987
|
`:""}
|
|
4988
4988
|
${a}`}async function Le(e,t){switch(e){case"list_skills":return Fe();case"list_primitives":return ve(t.group);case"list_utilities":return et(t.kind);case"list_patterns":return qe();case"list_anti_ai_tells":return _e(t.category);case"list_redesign_checks":return $e(t.category);case"list_audit_rules":return Ke(t.category);case"list_visual_checks":return We(t.category);case"get_anti_ai_tell":return Ye(String(t.name??""));case"get_redesign_check":return Xe(String(t.symptom??""));case"get_skill_section":return ye(String(t.skill??""),String(t.section??""));case"get_component":return tt(String(t.name??""),t.verbose===!0);case"get_pattern":return nt(String(t.name??""));case"get_rule":return it(typeof t.number=="number"?t.number:void 0);case"get_vocab":return rt(t.name==null?void 0:String(t.name));case"get_tokens":return st(t.category);case"list_consumer_skills":return Me();case"get_consumer_skill":return Be(String(t.skill??""),String(t.section??""));case"route_consumer_task":return pe(String(t.task??""),{consumerOnly:!0});case"draft_bug_report":return He(t);case"check_compatibility":return fe(t.version==null?void 0:String(t.version));case"route_task":return pe(String(t.task??""));case"suggest_primitive":return lt(String(t.use_case??""));case"search_components":return dt(String(t.query??""));case"get_frame_coverage":return ot(t.name===void 0?void 0:String(t.name));case"lint_jsx":return ct(String(t.jsx??""));default:return`Unknown tool: ${e}`}}function Fe(){let e=`# Available skills (${T.length})
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@godxjp/ui-mcp",
|
|
3
|
-
"version": "31.22.
|
|
3
|
+
"version": "31.22.1",
|
|
4
4
|
"godxUiCompatibility": "31.22.x",
|
|
5
5
|
"description": "Model Context Protocol server for @godxjp/ui \u2014 gives Claude Code / Codex CLI / Cursor / any MCP-aware agent live access to the component catalog, prop vocabulary, design tokens, 45 cardinal rules, copy-paste-ready patterns, 12 design / taste skills synthesised from Leonxlnx/taste-skill, 20+ anti-AI-tell patterns, and a 50-check redesign audit \u2014 token-efficient (list \u2192 drill-down).",
|
|
6
6
|
"type": "module",
|