@godxjp/ui-mcp 33.12.6 → 33.12.8
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
|
@@ -1034,7 +1034,7 @@ const form = useForm({ customer_nm: "", action_mode: "regist" });
|
|
|
1034
1034
|
selectedOptions={form.approvers} // labels the form already has
|
|
1035
1035
|
value={form.approverIds}
|
|
1036
1036
|
onValueChange={(ids) => form.setApproverIds(ids as string[])}
|
|
1037
|
-
/>`,rules:[]},{name:"Select",absorbed:["Combobox","Autocomplete","CountrySelect","SearchSelect","Typeahead","AsyncSelect","TagInput"],subParts:["SelectContent","SelectGroup","SelectItem","SelectLabel","SelectScrollDownButton","SelectScrollUpButton","SelectSeparator","SelectTrigger","SelectValue"],group:"data-entry",tagline:"Polymorphic single-select: pass options/loadOptions for the data-driven (Ant-style) API, or compose sub-parts manually \u2014 never use a raw <select>.",props:[{name:"mode",type:'"multiple" | "tags"',description:'Select several options; value/defaultValue become string arrays. `tags` additionally ACCEPTS what was typed (a value that is not in the list), which is antd\'s own split between the two. `tags` needs no `options` (`<Select mode="tags" />` works) and only an explicit `disabled` disables it (gh#1063). While text is typed the tags list reads create row, then an exact (case-folded) match, then options, then held values \u2014 the first enabled row is the Enter target, never a held tag (gh#1064). The popup is a picker: compact unruled rows (--search-select-option-line-height), a list capped at --search-select-list-max-height (16rem, antd listHeight 256) that scrolls inside, the search as the panel header line with no ring of its own, and the picked rows marked by a check (menuItemSelectedIcon default) + weight while the row background means pointer/keyboard position only. A facet list that wants ruled rows composes `Command split` (gh#699) itself.'},{name:"maxCount",type:"number",description:"Maximum selected options; selected items remain removable."},{name:"maxTagCount",type:"number",description:`Collapse extra selected labels into a "+N" chip. Without it (mode="multiple"/"tags"), the chips WRAP and the trigger grows to hold them, antd's default \u2014 a chip is never clipped out of sight. Set it when the trigger must stay one line (a dense rail or table cell).`},{name:"options",type:"(SearchSelectOptionProp | { label: string; options: SearchSelectOptionProp[] })[]",description:"Static option list. Passing this (or loadOptions) switches Select from the compound API to the data-driven API. An entry may be one of antd's nested GROUPS ({ label, options }) instead of a row; its heading becomes the same `group` a flat row carries. Rows in a foreign shape ({id,name}) go through fieldNames. Each option has { value, label, sublabel?, icon?, group?, disabled? }. `icon` (avatar / flag / lucide node) renders before the label in the rows AND on the trigger once selected. group buckets the option under an optgroup-style heading."},{name:"loadOptions",type:"(params: SearchSelectLoadParamsProp) => Promise<SearchSelectLoadResultProp>",description:"Async remote fetcher. Receives { query, page } (1-based). Must return { options, hasMore? }. Implies showSearch=true automatically."},{name:"showSearch",type:'boolean | { filterOption?: boolean | ((input, option) => boolean); optionFilterProp?: "label" | "value" | "sublabel"; filterSort?; searchValue?: string; onSearch?: (value: string) => void; autoClearSearchValue?: boolean }',defaultValue:"true when loadOptions is set or mode is multiple/tags, false otherwise",description:"Toggle the searchable combobox mode vs the plain listbox. The OBJECT form is antd's and configures the search in one place (passing it also turns search ON). NOTE the argument order: `showSearch.filterOption(input, option)` is antd's, while the long-standing top-level `filterOption(option, query)` keeps this library's; `filterOption: false` keeps every row, for a list the server already filtered."},{name:"value",type:"string",defaultValue:'""',description:"Controlled selected value (data-driven API). Pass an empty string to represent no selection."},{name:"defaultValue",type:"string",description:"Uncontrolled initial value (data-driven API). The trigger shows the matching option's label at rest \u2014 including in searchable (showSearch) mode \u2014 so an edit form pre-filled from server data renders the label, not the placeholder. Selected option is marked by a background tint (no check icon)."},{name:"onValueChange",type:"(value: string, option?: SearchSelectOptionProp) => void",description:'Change handler for the data-driven API. Receives the new value string and the matching option object. The signature follows `mode` / `labelInValue`, and a bare `(value, option) => \u2026` is inferred for each (no annotation needed under `strict`, gh#679): single `string` / `SelectOption | undefined`; `mode="multiple" | "tags"` `string[]` / `SelectOption[] | undefined`; `labelInValue` the `{ value, label }` shapes.'},{name:"renderOption",type:"(option: SearchSelectOptionProp) => React.ReactNode",description:"Custom per-option renderer for the dropdown ROWS. Defaults to label + optional sublabel. Does not change the trigger \u2014 use `labelRender` for that."},{name:"labelRender",type:"(selected: { value: string; label: React.ReactNode; option?: SearchSelectOptionProp }) => React.ReactNode",description:"Custom renderer for the SELECTED value shown on the TRIGGER (`labelRender`) \u2014 avatar + name + role badge, etc. `option` is undefined for an async preset whose page hasn't loaded. Only used while a value is selected; the placeholder still shows when empty."},{name:"selectedLabel",type:"string",description:"Display label for the current value when its option is not in the loaded page (async). Prevents a flash of the raw id."},{name:"selectedIcon",type:"React.ReactNode",description:"Leading icon shown on the trigger for the current value when its option isn't loaded yet (async preset) \u2014 the trigger counterpart of `selectedLabel`, so an edit form pre-filled from the server shows the avatar/flag at rest."},{name:"placeholder",type:"string",description:"Placeholder shown in the trigger when no value is selected."},{name:"searchPlaceholder",type:"string",description:"Placeholder inside the search input (combobox mode only)."},{name:"emptyMessage",type:"string",description:"Message rendered when the filtered list is empty."},{name:"loadingMessage",type:"string",description:"Message rendered while loadOptions is resolving."},{name:"errorMessage",type:"string",description:"Message rendered when an async loadOptions REJECTS \u2014 a distinct state from empty/loading. Defaults to a localized 'Couldn\u2019t load options'. The panel shows this instead of a blank surface or a misleading 'no results'."},{name:"clearable",type:"boolean",defaultValue:"false",description:"Show the clear \u2715 when a value is selected (data-driven API). Off by default, as antd `allowClear` \u2014 a required select is never one click from empty. Pass it (or `allowClear`) on an optional field whose empty state is a valid answer."},{name:"clearLabel",type:"string",description:"Label for the clear row (data-driven combobox mode)."},{name:"disabled",type:"boolean",description:"Disables the entire select."},{name:"readOnly",type:"boolean",defaultValue:"false",description:"Searchable mode only (showSearch/loadOptions). Value is shown (and the clear affordance hidden) but the popover cannot be opened \u2014 no new pick, no search. Mirrors the Input/NumberInput readOnly contract: stays focusable and still submits its value, unlike disabled."},{name:"size",type:'"xs" | "sm" | "md" | "lg"',description:"Searchable mode only. Height tier forwarded to the SearchSelect trigger Button. For the compound API use SelectTrigger's own size prop instead (below)."},{name:"width",type:'"full" | "auto" | "bounded"',defaultValue:'"full"',description:"Trigger width on the data-driven API (options / loadOptions), searchable or not \u2014 the same axis SelectTrigger carries on the compound API. `full` is what a form field wants; `auto` is what a filter bar wants, so two Selects share one row instead of stacking (CONSUMER-RULES rule 5); `bounded` holds one width from --control-bounded-width for a trigger whose value varies in length. Never wrap a Select in a fixed-width Flex to get this."},{name:"open",type:"boolean",description:'Searchable mode only. Controlled popover open state (uncontrolled by default). Pair with onOpenChange. With `mode="tags"`, `open={false}` (antd\'s spelling of "a tags field whose list never opens") renders the INLINE chip field instead \u2014 no popup, no combobox: type + Enter or a `tokenSeparators` character adds a tag, Backspace on an empty draft drops the last, a pasted "a, b, c" becomes three tags, the draft commits on blur, and `name` submits the tags comma-joined in one hidden input. `onValueChange` then receives the tag array only. This is what the retired `TagInput` was (v32 #1223).'},{name:"onOpenChange",type:"(open: boolean) => void",description:"Searchable mode only. Fires on every open/close attempt \u2014 including ones ignored because open is externally pinned \u2014 so a controlled consumer stays in sync."},{name:"search",type:"string",description:"Searchable mode only. Controlled search-box query (uncontrolled by default). Pair with onSearchChange."},{name:"onSearchChange",type:"(query: string) => void",description:"Searchable mode only. Fires on every keystroke in the search box."},{name:"filterOption",type:"(option: SearchSelectOptionProp, query: string) => boolean",description:"Searchable mode only, static options (ignored with loadOptions, which owns its own server-side filtering). Overrides the default label/value substring filter. Only consulted while the query is non-empty."},{name:"renderError",type:"(params: { message: string; retry: () => void }) => React.ReactNode",description:"Searchable mode only. Custom error slot, overriding the default errorMessage row. retry() reloads from the first page."},{name:"renderLoadMore",type:"(params: { hasMore: boolean; loading: boolean; loadMore: () => void }) => React.ReactNode",description:"Searchable mode only. Custom 'load more' affordance appended below the list while another page is available \u2014 pairs with (does not replace) the built-in scroll-triggered pagination."},{name:"name",type:"string",description:"Form field name. Submits the selected value via a hidden input (data-driven API). Required for uncontrolled form submission."},{name:"id",type:"string",description:"HTML id for the trigger element. Wire to a <label htmlFor> for a11y."},{name:"className",type:"string",description:"Additional CSS classes applied to the trigger."},{name:"data-testid",type:"string",description:"Test id on the trigger. Option items get ${data-testid}-option-${value} automatically."},{name:"SelectTrigger size",type:'"sm" | "md"',defaultValue:'"md"',description:"Compound API only. Size variant on the SelectTrigger sub-component."},{name:"SelectTrigger width",type:'"full" | "auto"',defaultValue:'"full"',description:"Compound API only. `full` fills the field column (inside FormField). `auto` sizes the trigger to its label \u2014 use it in a PageContainer `extra` slot, a toolbar or a footer row, where a full-width trigger swallows the row and truncates its siblings."},{name:"SelectTrigger showIndicator",type:"boolean",defaultValue:"true",description:"Compound API only. Set false to omit the built-in chevron disclosure indicator from the DOM entirely (not a CSS hide) \u2014 for specialized triggers (icon-only, etc.) that render their own affordance, so no consumer descendant CSS is needed."},{name:"status",type:'"error" | "warning"',description:"antd `status`. `error` recolours the control AND sets aria-invalid (a colour-only error fails WCAG 2.2 SC 1.4.1); `warning` recolours only. An aria-invalid injected by FormField always wins."},{name:"variant",type:'"outlined" | "filled" | "borderless"',description:"antd `variant` \u2014 the control surface. Default `outlined`. Drawn from --control-{surface,filled,borderless}-* tokens, so a theme retunes all three at once."},{name:"loading",type:"boolean",description:"antd `loading` \u2014 the FIELD is in flight: the trailing chevron becomes a spinner and the trigger reports aria-busy. Distinct from the list-level spinner an async loadOptions shows inside the popup."},{name:"defaultOpen",type:"boolean",description:"antd `defaultOpen` \u2014 uncontrolled initial popup state. The popup opens once every running ancestor animation has finished (a Popover sliding in), so inside a Popover the listbox is placed below its settled trigger exactly like a click-open (gh#708); with nothing animating it is open on the first render. onOpenChange is not called for this initial open."},{name:"allowClear",type:"boolean | { clearIcon?: React.ReactNode; label?: string }",defaultValue:"false",description:"antd `allowClear` \u2014 the clear \u2715 on the trigger while a value is selected. Default false, as in antd. The object form replaces the \u2715 icon and/or its accessible label. Beats `clearable` when both are given."},{name:"onClear",type:"() => void",description:"antd `onClear` \u2014 fires after the value is cleared through the \u2715."},{name:"notFoundContent",type:"React.ReactNode",description:"antd `notFoundContent` \u2014 the node shown when the popup has nothing to list. Outranks the string-only emptyMessage."},{name:"autoClearSearchValue",type:"boolean",description:"antd `autoClearSearchValue` (default true) \u2014 clear the search box after a pick / on close. Set false to resume the same filtered list on the next open."},{name:"filterSort",type:"(a: SearchSelectOptionProp, b: SearchSelectOptionProp, info: { searchValue: string }) => number",description:"antd `filterSort` \u2014 orders what filterOption kept. Static options only; with loadOptions the server owns the order. Never mutates the caller's array."},{name:"optionRender",type:"(option: SearchSelectOptionProp, info: { index: number }) => React.ReactNode",description:"antd `optionRender` \u2014 per-option renderer in antd's own (option, { index }) shape. Outranks the older renderOption."},{name:"menuItemSelectedIcon",type:"React.ReactNode",description:"antd `menuItemSelectedIcon` \u2014 a decorative mark on the picked row. In mode multiple / tags it defaults to a check (as in antd), because there the row background means pointer/keyboard position, not selection; pass `null` to drop it. A single-value Select shows none by default."},{name:"popupMatchSelectWidth",type:"boolean | number",description:"antd `popupMatchSelectWidth`. true (default) pins the popup to the trigger width, false lets it hug its rows, a number pins it to that many pixels."},{name:"fieldNames",type:"{ label?: string; value?: string; options?: string; groupLabel?: string; disabled?: string }",description:"antd `fieldNames` \u2014 read rows in a FOREIGN shape ({id,name,children}) without copying them into a second array first. The same spelling Cascader and TreeSelect take. A foreign row needs a cast at the call site, exactly as theirs does."},{name:"labelInValue",type:"boolean",description:"antd `labelInValue` \u2014 value and onValueChange speak {value,label} instead of a bare string (an array of them in multiple/tags). It earns its place on the async EDIT form: a record holding {value:'52',label:'\u6771\u4EAC\u672C\u793E'} renders the pick immediately, with no options page loaded and no flash of the raw id."},{name:"prefix",type:"React.ReactNode",description:"antd `prefix` \u2014 a node pinned BEFORE the value on the trigger (a currency mark, an icon). Deliberately not aria-hidden: for role=combobox the trigger's text is the VALUE, and a prefix that is part of the value belongs in it. The NAME still comes from the label."},{name:"suffixIcon",type:"React.ReactNode",description:"antd `suffixIcon` \u2014 replaces the trailing chevron; `null` removes the indicator entirely (antd's own replacement for the deprecated showArrow) \u2014 and, with no clear and no loading, the trigger stops reserving the chevron's end padding, so a `width=\"auto\"` trigger ends at its value. While a value is clearable the \u2715 owns that seat, as in antd."},{name:"placement",type:'"bottomStart" | "bottomEnd" | "topStart" | "topEnd"',description:"antd `placement`, spelled on the LOGICAL inline axis (antd's bottomLeft/topRight cannot mirror for an RTL layout). Absent = below, start-aligned, with collision flipping \u2014 what a picker wants."},{name:"popupRender",type:"(originNode: React.ReactNode) => React.ReactNode",description:"antd `popupRender` \u2014 wrap the popup's own node to add a footer, a 'create' action or a hint line. It must still render originNode: dropping it leaves a popup with no options."},{name:"listHeight",type:"number",description:"antd `listHeight` \u2014 the option list's max height in px for THIS instance. It overrides the --select-content-max-height token rather than hard-coding a height, so the token stays the default everywhere else."},{name:"onPopupScroll",type:"(event: React.UIEvent<HTMLElement>) => void",description:"antd `onPopupScroll` \u2014 fires on the option list's own scroll. It runs BESIDE the built-in infinite scroll (loadOptions paging), never instead of it."},{name:"optionFilterProp",type:'"label" | "value" | "sublabel"',description:"antd `optionFilterProp` \u2014 which field the default filter matches while searching. Unset matches BOTH label and value (this library's long-standing behaviour); antd's own default is value alone."},{name:"tokenSeparators",type:"string[]",description:"antd `tokenSeparators` (multiple/tags) \u2014 characters that commit what has been typed. Typing or PASTING 'a,b,c' commits three values in ONE onValueChange. A pasted run is read off the clipboard, so a '\\n' separator works even though a single-line input strips newlines."},{name:"allowCreate",type:"boolean | ((text: string) => boolean)",defaultValue:"true",description:'mode="tags" \u2014 whether typed text may become a NEW value (gh#1052). false, or a predicate returning false for the text, hides the create row and drops unknown tokenSeparators tokens; values already held stay listed so they can be removed. Not an antd prop.'},{name:"createLabel",type:"(text: string) => React.ReactNode",description:`mode="tags" \u2014 the create row's content (gh#1052). Default is the localised Create \u201Ctext\u201D / \u300Ctext\u300D\u3092\u4F5C\u6210 / T\u1EA1o \u201Ctext\u201D. The committed value is the typed text either way. antd shows the bare text instead \u2014 a documented deviation.`},{name:"onCreate",type:"(text: string) => void",description:'mode="tags" \u2014 fires when a value that NO option carries joins the selection (create row, Enter on it, or a tokenSeparators run), beside onSelect/onValueChange. The way to tell invented text from an option id. Not an antd prop.'},{name:"caseSensitive",type:"boolean",defaultValue:"false",description:'Compare typed text case-sensitively (gh#1053). Default false: the built-in filter, the tags create row and a tokenSeparators run all case-fold, so typing "bug" when "Bug" exists finds Bug instead of offering a duplicate. antd folds its filter but compares the create row exactly; true restores that. A custom filterOption is unaffected.'},{name:"maxTagTextLength",type:"number",description:"antd `maxTagTextLength` (multiple/tags) \u2014 cut each chip's TEXT to this many characters (an ellipsis marks the cut). The value keeps its whole label."},{name:"needConfirm",type:"boolean",defaultValue:"false",description:"multiple/tags \u2014 hold the panel's picks as a DRAFT until OK commits them (gh#1248; antd's `needConfirm`, the same word TimePicker/DatePicker use). Row toggles move a pending set and report nothing; the footer's OK (Button size sm) fires ONE onValueChange with the whole set and closes; its Clear empties the pending set; Escape or an outside click discards the draft and the trigger keeps the committed values. onSelect/onDeselect do not fire for draft toggles. A chip's \u2715 and Backspace on the closed trigger still commit at once. Default false: every toggle commits."},{name:"tagRender",type:"(props: { value: string; label: React.ReactNode; onClose: () => void; index: number; disabled: boolean }) => React.ReactNode",description:"antd `tagRender` (multiple/tags) \u2014 render one chip yourself. Exactly the shape TagInput's tagRender takes. The onClose handed in is the same remover the built-in \u2715 calls, so a custom chip cannot end up unremovable; supplying tagRender withdraws the built-in \u2715."},{name:"onSelect / onDeselect",type:"(value: string, option: SearchSelectOptionProp) => void",description:"antd `onSelect` / `onDeselect` \u2014 fires as one option JOINS or LEAVES the selection, beside onValueChange (which reports the whole value)."},{name:"maxTagPlaceholder",type:"React.ReactNode | ((omitted: { value: string; label: React.ReactNode }[]) => React.ReactNode)",description:"antd `maxTagPlaceholder` \u2014 the node standing in for the values maxTagCount hid. A function receives the omitted values, so '+3 \u4EF6' or a tooltip listing them is possible."}],usage:["Coarse pointers: affix actions use --control-affix-touch-target-size (44px by default); text space is reserved separately. Fine-pointer geometry is unchanged.",'FREE-TEXT TAGS WITH NO LIST (keywords, email recipients, labels typed from scratch): `<Select mode="tags" open={false} value={tags} onValueChange={setTags} />` \u2014 the inline chip field. Use plain `mode="tags"` (popup) only when there is a list of existing tags to pick from. There is no `TagInput` component.',"DO use the data-driven API (options/loadOptions) for straightforward selects \u2014 it handles grouping, search, async, and custom rendering automatically. Only reach for the compound API when you need to inject arbitrary content into the trigger or listbox.","DO pass name= on the data-driven Select so the value is submitted with a native form or Inertia useForm. Without name= the value is React-only and will not appear in form data.","NAMING A SELECT WITH NO VISIBLE LABEL: put `aria-label` on `<Select>`, NOT on `<SelectTrigger>`. Both render the identical button attribute \u2014 Select forwards its name down through SelectFieldA11yContext and the trigger writes last \u2014 but only the root spelling also names the react-aria field, and a root that cannot see a name warns once per render (gh#869). Inside a FormField or Field, pass nothing: the label id reaches both levels on its own. `aria-labelledby` pointing at your own element works on either level and is the right spelling when a visible heading already names the control.","READING THE SELECTED CODE FROM THE DOM: the trigger publishes `data-value` = the selected VALUE, alongside the `data-field` key it inherits from FormField. Use that in e2e tests and screen automation \u2014 the trigger's visible text is the option LABEL (\u6771\u4EAC\u672C\u793E), and the only other place the code lives is the aria-hidden, 1px-clipped native <select> react-aria renders so a native submit (and browser autofill) carries the value. `data-value` is absent while nothing is selected, and it tracks uncontrolled picks too.","DO use loadOptions + selectedLabel together for async selects: selectedLabel prevents a flash of the raw id string while the first page loads.","A Select is safe inside a draggable element (a Kanban card with draggable=true) and inside a `contain: paint` / `transform` app region: the aria-hidden native <select> fallback is held at its static position beside the trigger (position: absolute, 1px clipped), so the browser's drag image stays the card's own box instead of reaching to the region's corner (gh#708). No wrapper or consumer CSS is needed.","DO name the control with FormField, aria-label, or a <label htmlFor> pointing at the trigger id \u2014 all three work. (An earlier version of this entry said htmlFor does NOT name the trigger. That was wrong: the trigger is a <button>, which is a labelable element, so <label for> does name it \u2014 src/components/data-entry/__tests__/select-rac.test.tsx pins it on both the old Radix base and the react-aria one, because 17 godx-task files name their Selects exactly that way.) What role=combobox does NOT do is take a name from its own content, so the visible value is the VALUE, never the name \u2014 a Select with no label of any kind is anonymous. Wrapping in <FormField label=\u2026> stays the route that also wires helper, error and required. This holds for BOTH APIs; anything set directly on SelectTrigger wins.","DO treat loading / no-options / error / disabled as DISTINCT states. A data-driven Select never opens a blank popover: a static options=[] list auto-disables the trigger (opening it would show nothing), while an async loadOptions shows a loading row, then either the options, a localized empty affordance (override with emptyMessage), or an error affordance if the fetch rejects (override with errorMessage). Disable the Select when there is nothing to pick AND no async loader; keep it enabled (it opens to load/search) whenever loadOptions is set.","DON'T mix the two APIs: once you pass options or loadOptions, Select is data-driven \u2014 all compound sub-parts (SelectTrigger, SelectContent, SelectItem) are rendered internally. Do not wrap them manually.","DON'T use a raw <select> element. Select is the one control for all single-select use cases. The only allowed raw <select> is a hidden aria-hidden sr-only element kept as an e2e hook paired with a visible Select.","COMPOUND API sub-parts (when NOT using options/loadOptions): Select \u2192 SelectTrigger (contains SelectValue) \u2192 SelectContent \u2192 SelectItem. Optionally wrap items in SelectGroup + SelectLabel for headings, or add SelectSeparator between sections.","DO reach for open/onOpenChange (searchable mode) to drive the popover from outside \u2014 e.g. opening it programmatically after a validation error \u2014 and search/onSearchChange to seed or read the query text. Both fall back to internal state when omitted; onOpenChange/onSearchChange still fire either way so a controlled consumer stays in sync.","DO use readOnly (searchable mode) for a value that must stay visible and submittable but not editable in this view \u2014 it differs from disabled: the control stays focusable and its value still submits. allowClear / clearable is ignored while readOnly.","DO use filterOption (searchable mode, static options) when the default label/value substring match isn't right \u2014 e.g. filtering by a hidden code field. It is NOT consulted when loadOptions is set (that fetcher owns its own filtering).","DO use renderError + renderLoadMore (searchable mode) to replace the default error row with a branded retry affordance, or to pair a manual 'load more' button with (not instead of) the built-in scroll-triggered pagination.","DO set SelectTrigger showIndicator={false} (compound API) on a specialized trigger \u2014 icon-only, or one with its own affordance \u2014 instead of hiding [data-slot=select-chevron] with consumer CSS."],useCases:["Status filter on an invoice list \u2014 pass options=[{value:'draft',label:'Draft'},{value:'paid',label:'Paid'}] with onChange to drive a query param; no search needed so omit showSearch.","Legal-entity switcher \u2014 static options list with showSearch=true for client-side filtering when there are many entities; use selectedLabel to show the entity name before the full list loads.","Account category picker backed by an API \u2014 pass loadOptions to stream pages of accounts as the user types; use renderOption to show account code + name side by side; pass selectedLabel so the trigger shows the name on first render.","Grouped currency picker \u2014 set option.group='Asia' / 'Europe' on each option; the plain (non-search) data-driven mode renders SelectGroup headings automatically.","Form field in an accounting entry \u2014 use the compound API when the trigger must show a currency flag icon alongside the SelectValue; wire SelectTrigger size='sm' for dense table rows.","Required department select in a HR form \u2014 leave allowClear off (the default) so the user cannot clear the field once set; pair with name='department_id' for Inertia useForm submission. An OPTIONAL filter select passes allowClear so the user can return to 'no filter'.","Async account picker whose API can fail \u2014 pass loadOptions plus errorMessage so a rejected fetch shows a clear error affordance in the panel (not a blank surface or a false 'no results'); the loading and empty states are handled automatically."],related:["Segmented \u2014 the same choice when the option set is small and worth showing at once. Select hides its options behind a trigger; Segmented lays them out, which reads better for 2-4 mutually exclusive options.","Select showSearch / loadOptions \u2014 the searchable combobox is a MODE of this component (an internal engine, not a public SearchSelect export); never build your own.","TreeSelect \u2014 use when options are hierarchical (parent/child tree). Not a drop-in for Select; has expand/collapse and a separate treeData prop.","Select with showSearch \u2014 use Select (with the `showSearch` prop) for typeahead/autocomplete lookup patterns instead of the removed Autocomplete component.","RadioGroup \u2014 use instead of Select when there are 2-4 mutually exclusive choices that must all be visible at once without opening a popover.","Command \u2014 the cmdk-powered list for free-text command search (a palette, a slash menu); a value-picking combobox is Select showSearch \u2014 there is no Combobox component."],example:`import {
|
|
1037
|
+
/>`,rules:[]},{name:"Select",absorbed:["Combobox","Autocomplete","CountrySelect","SearchSelect","Typeahead","AsyncSelect","TagInput"],subParts:["SelectContent","SelectGroup","SelectItem","SelectLabel","SelectScrollDownButton","SelectScrollUpButton","SelectSeparator","SelectTrigger","SelectValue"],group:"data-entry",tagline:"Polymorphic single-select: pass options/loadOptions for the data-driven (Ant-style) API, or compose sub-parts manually \u2014 never use a raw <select>.",props:[{name:"mode",type:'"multiple" | "tags"',description:'Select several options; value/defaultValue become string arrays. `tags` additionally ACCEPTS what was typed (a value that is not in the list), which is antd\'s own split between the two. `tags` needs no `options` (`<Select mode="tags" />` works) and only an explicit `disabled` disables it (gh#1063). While text is typed the tags list reads create row, then an exact (case-folded) match, then options, then held values \u2014 the first enabled row is the Enter target, never a held tag (gh#1064). The popup is a picker: compact unruled rows (--search-select-option-line-height), a list capped at --search-select-list-max-height (16rem, antd listHeight 256) that scrolls inside, the search as the panel header line with no ring of its own, and the picked rows marked by a check (menuItemSelectedIcon default) + weight while the row background means pointer/keyboard position only. A facet list that wants ruled rows composes `Command split` (gh#699) itself.'},{name:"maxCount",type:"number",description:"Maximum selected options; selected items remain removable."},{name:"maxTagCount",type:"number",description:`Collapse extra selected labels into a "+N" chip. Without it (mode="multiple"/"tags"), the chips WRAP and the trigger grows to hold them, antd's default \u2014 a chip is never clipped out of sight. Set it when the trigger must stay one line (a dense rail or table cell).`},{name:"options",type:"(SearchSelectOptionProp | { label: string; options: SearchSelectOptionProp[] })[]",description:"Static option list. Passing this (or loadOptions) switches Select from the compound API to the data-driven API. An entry may be one of antd's nested GROUPS ({ label, options }) instead of a row; its heading becomes the same `group` a flat row carries. Rows in a foreign shape ({id,name}) go through fieldNames. Each option has { value, label, sublabel?, icon?, group?, disabled? }. `icon` (avatar / flag / lucide node) renders before the label in the rows AND on the trigger once selected. group buckets the option under an optgroup-style heading."},{name:"loadOptions",type:"(params: SearchSelectLoadParamsProp) => Promise<SearchSelectLoadResultProp>",description:"Async remote fetcher. Receives { query, page } (1-based). Must return { options, hasMore? }. Implies showSearch=true automatically."},{name:"showSearch",type:'boolean | { filterOption?: boolean | ((input, option) => boolean); optionFilterProp?: "label" | "value" | "sublabel"; filterSort?; searchValue?: string; onSearch?: (value: string) => void; autoClearSearchValue?: boolean }',defaultValue:"true when loadOptions is set or mode is multiple/tags, false otherwise",description:"Toggle the searchable combobox mode vs the plain listbox. The OBJECT form is antd's and configures the search in one place (passing it also turns search ON). NOTE the argument order: `showSearch.filterOption(input, option)` is antd's, while the long-standing top-level `filterOption(option, query)` keeps this library's; `filterOption: false` keeps every row, for a list the server already filtered."},{name:"value",type:"string",defaultValue:'""',description:"Controlled selected value (data-driven API). Pass an empty string to represent no selection."},{name:"defaultValue",type:"string",description:"Uncontrolled initial value (data-driven API). The trigger shows the matching option's label at rest \u2014 including in searchable (showSearch) mode \u2014 so an edit form pre-filled from server data renders the label, not the placeholder. Selected option is marked by a background tint (no check icon)."},{name:"onValueChange",type:"(value: string, option?: SearchSelectOptionProp) => void",description:'Change handler for the data-driven API. Receives the new value string and the matching option object. The signature follows `mode` / `labelInValue`, and a bare `(value, option) => \u2026` is inferred for each (no annotation needed under `strict`, gh#679): single `string` / `SelectOption | undefined`; `mode="multiple" | "tags"` `string[]` / `SelectOption[] | undefined`; `labelInValue` the `{ value, label }` shapes.'},{name:"renderOption",type:"(option: SearchSelectOptionProp) => React.ReactNode",description:"Custom per-option renderer for the dropdown ROWS. Defaults to label + optional sublabel. Does not change the trigger \u2014 use `labelRender` for that."},{name:"labelRender",type:"(selected: { value: string; label: React.ReactNode; option?: SearchSelectOptionProp }) => React.ReactNode",description:"Custom renderer for the SELECTED value shown on the TRIGGER (`labelRender`) \u2014 avatar + name + role badge, etc. `option` is undefined for an async preset whose page hasn't loaded. Only used while a value is selected; the placeholder still shows when empty."},{name:"selectedLabel",type:"string",description:"Display label for the current value when its option is not in the loaded page (async). Prevents a flash of the raw id."},{name:"selectedIcon",type:"React.ReactNode",description:"Leading icon shown on the trigger for the current value when its option isn't loaded yet (async preset) \u2014 the trigger counterpart of `selectedLabel`, so an edit form pre-filled from the server shows the avatar/flag at rest."},{name:"placeholder",type:"string",description:"Placeholder shown in the trigger when no value is selected. Default: the catalogue's \u300C\u9078\u629E\u2026\u300D / 'Ch\u1ECDn\u2026' / 'Select\u2026' \u2014 the same string with or without `showSearch`, so an unselected field never shows an empty trigger. Only a placeholder YOU pass can name an unlabelled trigger; the default never becomes the accessible name."},{name:"searchPlaceholder",type:"string",description:"Placeholder inside the search input (combobox mode only)."},{name:"emptyMessage",type:"string",description:"Message rendered when the filtered list is empty."},{name:"loadingMessage",type:"string",description:"Message rendered while loadOptions is resolving."},{name:"errorMessage",type:"string",description:"Message rendered when an async loadOptions REJECTS \u2014 a distinct state from empty/loading. Defaults to a localized 'Couldn\u2019t load options'. The panel shows this instead of a blank surface or a misleading 'no results'."},{name:"clearable",type:"boolean",defaultValue:"false",description:"Show the clear \u2715 when a value is selected (data-driven API). Off by default, as antd `allowClear` \u2014 a required select is never one click from empty. Pass it (or `allowClear`) on an optional field whose empty state is a valid answer."},{name:"clearLabel",type:"string",description:"Label for the clear row (data-driven combobox mode)."},{name:"disabled",type:"boolean",description:"Disables the entire select."},{name:"readOnly",type:"boolean",defaultValue:"false",description:"Searchable mode only (showSearch/loadOptions). Value is shown (and the clear affordance hidden) but the popover cannot be opened \u2014 no new pick, no search. Mirrors the Input/NumberInput readOnly contract: stays focusable and still submits its value, unlike disabled."},{name:"size",type:'"xs" | "sm" | "md" | "lg"',description:"Searchable mode only. Height tier forwarded to the SearchSelect trigger Button. For the compound API use SelectTrigger's own size prop instead (below)."},{name:"width",type:'"full" | "auto" | "bounded"',defaultValue:'"full"',description:"Trigger width on the data-driven API (options / loadOptions), searchable or not \u2014 the same axis SelectTrigger carries on the compound API. `full` is what a form field wants; `auto` is what a filter bar wants, so two Selects share one row instead of stacking (CONSUMER-RULES rule 5); `bounded` holds one width from --control-bounded-width for a trigger whose value varies in length. Never wrap a Select in a fixed-width Flex to get this."},{name:"open",type:"boolean",description:'Searchable mode only. Controlled popover open state (uncontrolled by default). Pair with onOpenChange. With `mode="tags"`, `open={false}` (antd\'s spelling of "a tags field whose list never opens") renders the INLINE chip field instead \u2014 no popup, no combobox: type + Enter or a `tokenSeparators` character adds a tag, Backspace on an empty draft drops the last, a pasted "a, b, c" becomes three tags, the draft commits on blur, and `name` submits the tags comma-joined in one hidden input. `onValueChange` then receives the tag array only. This is what the retired `TagInput` was (v32 #1223).'},{name:"onOpenChange",type:"(open: boolean) => void",description:"Searchable mode only. Fires on every open/close attempt \u2014 including ones ignored because open is externally pinned \u2014 so a controlled consumer stays in sync."},{name:"search",type:"string",description:"Searchable mode only. Controlled search-box query (uncontrolled by default). Pair with onSearchChange."},{name:"onSearchChange",type:"(query: string) => void",description:"Searchable mode only. Fires on every keystroke in the search box."},{name:"filterOption",type:"(option: SearchSelectOptionProp, query: string) => boolean",description:"Searchable mode only, static options (ignored with loadOptions, which owns its own server-side filtering). Overrides the default label/value substring filter. Only consulted while the query is non-empty."},{name:"renderError",type:"(params: { message: string; retry: () => void }) => React.ReactNode",description:"Searchable mode only. Custom error slot, overriding the default errorMessage row. retry() reloads from the first page."},{name:"renderLoadMore",type:"(params: { hasMore: boolean; loading: boolean; loadMore: () => void }) => React.ReactNode",description:"Searchable mode only. Custom 'load more' affordance appended below the list while another page is available \u2014 pairs with (does not replace) the built-in scroll-triggered pagination."},{name:"name",type:"string",description:"Form field name. Submits the selected value via a hidden input (data-driven API). Required for uncontrolled form submission."},{name:"id",type:"string",description:"HTML id for the trigger element. Wire to a <label htmlFor> for a11y."},{name:"className",type:"string",description:"Additional CSS classes applied to the trigger."},{name:"data-testid",type:"string",description:"Test id on the trigger. Option items get ${data-testid}-option-${value} automatically."},{name:"SelectTrigger size",type:'"sm" | "md"',defaultValue:'"md"',description:"Compound API only. Size variant on the SelectTrigger sub-component."},{name:"SelectTrigger width",type:'"full" | "auto"',defaultValue:'"full"',description:"Compound API only. `full` fills the field column (inside FormField). `auto` sizes the trigger to its label \u2014 use it in a PageContainer `extra` slot, a toolbar or a footer row, where a full-width trigger swallows the row and truncates its siblings."},{name:"SelectTrigger showIndicator",type:"boolean",defaultValue:"true",description:"Compound API only. Set false to omit the built-in chevron disclosure indicator from the DOM entirely (not a CSS hide) \u2014 for specialized triggers (icon-only, etc.) that render their own affordance, so no consumer descendant CSS is needed."},{name:"status",type:'"error" | "warning"',description:"antd `status`. `error` recolours the control AND sets aria-invalid (a colour-only error fails WCAG 2.2 SC 1.4.1); `warning` recolours only. An aria-invalid injected by FormField always wins."},{name:"variant",type:'"outlined" | "filled" | "borderless"',description:"antd `variant` \u2014 the control surface. Default `outlined`. Drawn from --control-{surface,filled,borderless}-* tokens, so a theme retunes all three at once."},{name:"loading",type:"boolean",description:"antd `loading` \u2014 the FIELD is in flight: the trailing chevron becomes a spinner and the trigger reports aria-busy. Distinct from the list-level spinner an async loadOptions shows inside the popup."},{name:"defaultOpen",type:"boolean",description:"antd `defaultOpen` \u2014 uncontrolled initial popup state. The popup opens once every running ancestor animation has finished (a Popover sliding in), so inside a Popover the listbox is placed below its settled trigger exactly like a click-open (gh#708); with nothing animating it is open on the first render. onOpenChange is not called for this initial open."},{name:"allowClear",type:"boolean | { clearIcon?: React.ReactNode; label?: string }",defaultValue:"false",description:"antd `allowClear` \u2014 the clear \u2715 on the trigger while a value is selected. Default false, as in antd. The object form replaces the \u2715 icon and/or its accessible label. Beats `clearable` when both are given."},{name:"onClear",type:"() => void",description:"antd `onClear` \u2014 fires after the value is cleared through the \u2715."},{name:"notFoundContent",type:"React.ReactNode",description:"antd `notFoundContent` \u2014 the node shown when the popup has nothing to list. Outranks the string-only emptyMessage."},{name:"autoClearSearchValue",type:"boolean",description:"antd `autoClearSearchValue` (default true) \u2014 clear the search box after a pick / on close. Set false to resume the same filtered list on the next open."},{name:"filterSort",type:"(a: SearchSelectOptionProp, b: SearchSelectOptionProp, info: { searchValue: string }) => number",description:"antd `filterSort` \u2014 orders what filterOption kept. Static options only; with loadOptions the server owns the order. Never mutates the caller's array."},{name:"optionRender",type:"(option: SearchSelectOptionProp, info: { index: number }) => React.ReactNode",description:"antd `optionRender` \u2014 per-option renderer in antd's own (option, { index }) shape. Outranks the older renderOption."},{name:"menuItemSelectedIcon",type:"React.ReactNode",description:"antd `menuItemSelectedIcon` \u2014 a decorative mark on the picked row. In mode multiple / tags it defaults to a check (as in antd), because there the row background means pointer/keyboard position, not selection; pass `null` to drop it. A single-value Select shows none by default."},{name:"popupMatchSelectWidth",type:"boolean | number",description:"antd `popupMatchSelectWidth`. true (default) pins the popup to the trigger width, false lets it hug its rows, a number pins it to that many pixels."},{name:"fieldNames",type:"{ label?: string; value?: string; options?: string; groupLabel?: string; disabled?: string }",description:"antd `fieldNames` \u2014 read rows in a FOREIGN shape ({id,name,children}) without copying them into a second array first. The same spelling Cascader and TreeSelect take. A foreign row needs a cast at the call site, exactly as theirs does."},{name:"labelInValue",type:"boolean",description:"antd `labelInValue` \u2014 value and onValueChange speak {value,label} instead of a bare string (an array of them in multiple/tags). It earns its place on the async EDIT form: a record holding {value:'52',label:'\u6771\u4EAC\u672C\u793E'} renders the pick immediately, with no options page loaded and no flash of the raw id."},{name:"prefix",type:"React.ReactNode",description:"antd `prefix` \u2014 a node pinned BEFORE the value on the trigger (a currency mark, an icon). Deliberately not aria-hidden: for role=combobox the trigger's text is the VALUE, and a prefix that is part of the value belongs in it. The NAME still comes from the label."},{name:"suffixIcon",type:"React.ReactNode",description:"antd `suffixIcon` \u2014 replaces the trailing chevron; `null` removes the indicator entirely (antd's own replacement for the deprecated showArrow) \u2014 and, with no clear and no loading, the trigger stops reserving the chevron's end padding, so a `width=\"auto\"` trigger ends at its value. While a value is clearable the \u2715 owns that seat, as in antd."},{name:"placement",type:'"bottomStart" | "bottomEnd" | "topStart" | "topEnd"',description:"antd `placement`, spelled on the LOGICAL inline axis (antd's bottomLeft/topRight cannot mirror for an RTL layout). Absent = below, start-aligned, with collision flipping \u2014 what a picker wants."},{name:"popupRender",type:"(originNode: React.ReactNode) => React.ReactNode",description:"antd `popupRender` \u2014 wrap the popup's own node to add a footer, a 'create' action or a hint line. It must still render originNode: dropping it leaves a popup with no options."},{name:"listHeight",type:"number",description:"antd `listHeight` \u2014 the option list's max height in px for THIS instance. It overrides the --select-content-max-height token rather than hard-coding a height, so the token stays the default everywhere else."},{name:"onPopupScroll",type:"(event: React.UIEvent<HTMLElement>) => void",description:"antd `onPopupScroll` \u2014 fires on the option list's own scroll. It runs BESIDE the built-in infinite scroll (loadOptions paging), never instead of it."},{name:"optionFilterProp",type:'"label" | "value" | "sublabel"',description:"antd `optionFilterProp` \u2014 which field the default filter matches while searching. Unset matches BOTH label and value (this library's long-standing behaviour); antd's own default is value alone."},{name:"tokenSeparators",type:"string[]",description:"antd `tokenSeparators` (multiple/tags) \u2014 characters that commit what has been typed. Typing or PASTING 'a,b,c' commits three values in ONE onValueChange. A pasted run is read off the clipboard, so a '\\n' separator works even though a single-line input strips newlines."},{name:"allowCreate",type:"boolean | ((text: string) => boolean)",defaultValue:"true",description:'mode="tags" \u2014 whether typed text may become a NEW value (gh#1052). false, or a predicate returning false for the text, hides the create row and drops unknown tokenSeparators tokens; values already held stay listed so they can be removed. Not an antd prop.'},{name:"createLabel",type:"(text: string) => React.ReactNode",description:`mode="tags" \u2014 the create row's content (gh#1052). Default is the localised Create \u201Ctext\u201D / \u300Ctext\u300D\u3092\u4F5C\u6210 / T\u1EA1o \u201Ctext\u201D. The committed value is the typed text either way. antd shows the bare text instead \u2014 a documented deviation.`},{name:"onCreate",type:"(text: string) => void",description:'mode="tags" \u2014 fires when a value that NO option carries joins the selection (create row, Enter on it, or a tokenSeparators run), beside onSelect/onValueChange. The way to tell invented text from an option id. Not an antd prop.'},{name:"caseSensitive",type:"boolean",defaultValue:"false",description:'Compare typed text case-sensitively (gh#1053). Default false: the built-in filter, the tags create row and a tokenSeparators run all case-fold, so typing "bug" when "Bug" exists finds Bug instead of offering a duplicate. antd folds its filter but compares the create row exactly; true restores that. A custom filterOption is unaffected.'},{name:"maxTagTextLength",type:"number",description:"antd `maxTagTextLength` (multiple/tags) \u2014 cut each chip's TEXT to this many characters (an ellipsis marks the cut). The value keeps its whole label."},{name:"needConfirm",type:"boolean",defaultValue:"false",description:"multiple/tags \u2014 hold the panel's picks as a DRAFT until OK commits them (gh#1248; antd's `needConfirm`, the same word TimePicker/DatePicker use). Row toggles move a pending set and report nothing; the footer's OK (Button size sm) fires ONE onValueChange with the whole set and closes; its Clear empties the pending set; Escape or an outside click discards the draft and the trigger keeps the committed values. onSelect/onDeselect do not fire for draft toggles. A chip's \u2715 and Backspace on the closed trigger still commit at once. Default false: every toggle commits."},{name:"tagRender",type:"(props: { value: string; label: React.ReactNode; onClose: () => void; index: number; disabled: boolean }) => React.ReactNode",description:"antd `tagRender` (multiple/tags) \u2014 render one chip yourself. Exactly the shape TagInput's tagRender takes. The onClose handed in is the same remover the built-in \u2715 calls, so a custom chip cannot end up unremovable; supplying tagRender withdraws the built-in \u2715."},{name:"onSelect / onDeselect",type:"(value: string, option: SearchSelectOptionProp) => void",description:"antd `onSelect` / `onDeselect` \u2014 fires as one option JOINS or LEAVES the selection, beside onValueChange (which reports the whole value)."},{name:"maxTagPlaceholder",type:"React.ReactNode | ((omitted: { value: string; label: React.ReactNode }[]) => React.ReactNode)",description:"antd `maxTagPlaceholder` \u2014 the node standing in for the values maxTagCount hid. A function receives the omitted values, so '+3 \u4EF6' or a tooltip listing them is possible."}],usage:["Coarse pointers: affix actions use --control-affix-touch-target-size (44px by default); text space is reserved separately. Fine-pointer geometry is unchanged.",'FREE-TEXT TAGS WITH NO LIST (keywords, email recipients, labels typed from scratch): `<Select mode="tags" open={false} value={tags} onValueChange={setTags} />` \u2014 the inline chip field. Use plain `mode="tags"` (popup) only when there is a list of existing tags to pick from. There is no `TagInput` component.',"DO use the data-driven API (options/loadOptions) for straightforward selects \u2014 it handles grouping, search, async, and custom rendering automatically. Only reach for the compound API when you need to inject arbitrary content into the trigger or listbox.","DO pass name= on the data-driven Select so the value is submitted with a native form or Inertia useForm. Without name= the value is React-only and will not appear in form data.","NAMING A SELECT WITH NO VISIBLE LABEL: put `aria-label` on `<Select>`, NOT on `<SelectTrigger>`. Both render the identical button attribute \u2014 Select forwards its name down through SelectFieldA11yContext and the trigger writes last \u2014 but only the root spelling also names the react-aria field, and a root that cannot see a name warns once per render (gh#869). Inside a FormField or Field, pass nothing: the label id reaches both levels on its own. `aria-labelledby` pointing at your own element works on either level and is the right spelling when a visible heading already names the control.","READING THE SELECTED CODE FROM THE DOM: the trigger publishes `data-value` = the selected VALUE, alongside the `data-field` key it inherits from FormField. Use that in e2e tests and screen automation \u2014 the trigger's visible text is the option LABEL (\u6771\u4EAC\u672C\u793E), and the only other place the code lives is the aria-hidden, 1px-clipped native <select> react-aria renders so a native submit (and browser autofill) carries the value. `data-value` is absent while nothing is selected, and it tracks uncontrolled picks too.","DO use loadOptions + selectedLabel together for async selects: selectedLabel prevents a flash of the raw id string while the first page loads.","A Select is safe inside a draggable element (a Kanban card with draggable=true) and inside a `contain: paint` / `transform` app region: the aria-hidden native <select> fallback is held at its static position beside the trigger (position: absolute, 1px clipped), so the browser's drag image stays the card's own box instead of reaching to the region's corner (gh#708). No wrapper or consumer CSS is needed.","DO name the control with FormField, aria-label, or a <label htmlFor> pointing at the trigger id \u2014 all three work. (An earlier version of this entry said htmlFor does NOT name the trigger. That was wrong: the trigger is a <button>, which is a labelable element, so <label for> does name it \u2014 src/components/data-entry/__tests__/select-rac.test.tsx pins it on both the old Radix base and the react-aria one, because 17 godx-task files name their Selects exactly that way.) What role=combobox does NOT do is take a name from its own content, so the visible value is the VALUE, never the name \u2014 a Select with no label of any kind is anonymous. Wrapping in <FormField label=\u2026> stays the route that also wires helper, error and required. This holds for BOTH APIs; anything set directly on SelectTrigger wins.","DO treat loading / no-options / error / disabled as DISTINCT states. A data-driven Select never opens a blank popover: a static options=[] list auto-disables the trigger (opening it would show nothing), while an async loadOptions shows a loading row, then either the options, a localized empty affordance (override with emptyMessage), or an error affordance if the fetch rejects (override with errorMessage). Disable the Select when there is nothing to pick AND no async loader; keep it enabled (it opens to load/search) whenever loadOptions is set.","DON'T mix the two APIs: once you pass options or loadOptions, Select is data-driven \u2014 all compound sub-parts (SelectTrigger, SelectContent, SelectItem) are rendered internally. Do not wrap them manually.","DON'T use a raw <select> element. Select is the one control for all single-select use cases. The only allowed raw <select> is a hidden aria-hidden sr-only element kept as an e2e hook paired with a visible Select.","COMPOUND API sub-parts (when NOT using options/loadOptions): Select \u2192 SelectTrigger (contains SelectValue) \u2192 SelectContent \u2192 SelectItem. Optionally wrap items in SelectGroup + SelectLabel for headings, or add SelectSeparator between sections.","DO reach for open/onOpenChange (searchable mode) to drive the popover from outside \u2014 e.g. opening it programmatically after a validation error \u2014 and search/onSearchChange to seed or read the query text. Both fall back to internal state when omitted; onOpenChange/onSearchChange still fire either way so a controlled consumer stays in sync.","DO use readOnly (searchable mode) for a value that must stay visible and submittable but not editable in this view \u2014 it differs from disabled: the control stays focusable and its value still submits. allowClear / clearable is ignored while readOnly.","DO use filterOption (searchable mode, static options) when the default label/value substring match isn't right \u2014 e.g. filtering by a hidden code field. It is NOT consulted when loadOptions is set (that fetcher owns its own filtering).","DO use renderError + renderLoadMore (searchable mode) to replace the default error row with a branded retry affordance, or to pair a manual 'load more' button with (not instead of) the built-in scroll-triggered pagination.","DO set SelectTrigger showIndicator={false} (compound API) on a specialized trigger \u2014 icon-only, or one with its own affordance \u2014 instead of hiding [data-slot=select-chevron] with consumer CSS."],useCases:["Status filter on an invoice list \u2014 pass options=[{value:'draft',label:'Draft'},{value:'paid',label:'Paid'}] with onChange to drive a query param; no search needed so omit showSearch.","Legal-entity switcher \u2014 static options list with showSearch=true for client-side filtering when there are many entities; use selectedLabel to show the entity name before the full list loads.","Account category picker backed by an API \u2014 pass loadOptions to stream pages of accounts as the user types; use renderOption to show account code + name side by side; pass selectedLabel so the trigger shows the name on first render.","Grouped currency picker \u2014 set option.group='Asia' / 'Europe' on each option; the plain (non-search) data-driven mode renders SelectGroup headings automatically.","Form field in an accounting entry \u2014 use the compound API when the trigger must show a currency flag icon alongside the SelectValue; wire SelectTrigger size='sm' for dense table rows.","Required department select in a HR form \u2014 leave allowClear off (the default) so the user cannot clear the field once set; pair with name='department_id' for Inertia useForm submission. An OPTIONAL filter select passes allowClear so the user can return to 'no filter'.","Async account picker whose API can fail \u2014 pass loadOptions plus errorMessage so a rejected fetch shows a clear error affordance in the panel (not a blank surface or a false 'no results'); the loading and empty states are handled automatically."],related:["Segmented \u2014 the same choice when the option set is small and worth showing at once. Select hides its options behind a trigger; Segmented lays them out, which reads better for 2-4 mutually exclusive options.","Select showSearch / loadOptions \u2014 the searchable combobox is a MODE of this component (an internal engine, not a public SearchSelect export); never build your own.","TreeSelect \u2014 use when options are hierarchical (parent/child tree). Not a drop-in for Select; has expand/collapse and a separate treeData prop.","Select with showSearch \u2014 use Select (with the `showSearch` prop) for typeahead/autocomplete lookup patterns instead of the removed Autocomplete component.","RadioGroup \u2014 use instead of Select when there are 2-4 mutually exclusive choices that must all be visible at once without opening a popover.","Command \u2014 the cmdk-powered list for free-text command search (a palette, a slash menu); a value-picking combobox is Select showSearch \u2014 there is no Combobox component."],example:`import {
|
|
1038
1038
|
Select,
|
|
1039
1039
|
SelectContent,
|
|
1040
1040
|
SelectGroup,
|
|
@@ -1186,7 +1186,7 @@ const [description, setDescription] = React.useState<TranslatableValue>({});
|
|
|
1186
1186
|
<RadioGroup value={trigger} onValueChange={setTrigger} orientation="horizontal" options={[
|
|
1187
1187
|
{ label: "\u521D\u56DE\u8CFC\u5165", value: "first_purchase" },
|
|
1188
1188
|
{ label: "\u8A95\u751F\u65E5", value: "birthday" },
|
|
1189
|
-
]} />`,storyPath:"data-entry/radio-group.tsx",rules:[23]},{name:"DatePicker",absorbed:["DateRangePicker"],group:"data-entry",tagline:"ONE date control: `picker` sets the granularity (day \xB7 week \xB7 month \xB7 quarter \xB7 year), `range` makes it a two-endpoint field, `multiple` a set. A real typeable input holds the value and submits ISO-8601 at the picker's own precision; the panel is the visual-only affordance.",props:[{name:"open",type:"boolean",description:"Controlled panel visibility."},{name:"defaultOpen",type:"boolean",description:"Initial panel visibility."},{name:"onOpenChange",type:"(open: boolean) => void",description:"Panel visibility changes."},{name:"status",type:'"error" | "warning"',description:"Validation appearance; error announces invalid state."},{name:"variant",type:'"outlined" | "filled" | "borderless" | "underlined"',description:"Shared control surface."},{name:"size",type:'"sm" | "md" | "lg"',description:"Shared control sizing."},{name:"inputReadOnly",type:"boolean",description:"antd `inputReadOnly` \u2014 sets the readonly attribute on the input so the mobile virtual keyboard stays down. The PANEL STILL OPENS: this is 'pick from the panel, do not type', not a second `disabled`. Use `disabled` to make the control inert."},{name:"preserveInvalidOnBlur",type:"boolean",description:"Keep invalid draft text on blur; never submit it as a committed value."},{name:"placement",type:'"bottom-start" | "bottom-end" | "top-start" | "top-end"',description:"Logical popup placement."},{name:"renderExtraFooter",type:"() => ReactNode",description:"Additional panel footer content."},{name:"ref",type:"Ref<HTMLInputElement>",description:"Ref to the editable input (with `range`, the start edge)."},{name:"format",type:"string | Intl.DateTimeFormatOptions | ((date: Date) => string)",description:"Display using date-fns patterns, Intl options (Japanese era supported), or a callback. Submission stays ISO."},{name:"parseFormat",type:"(text: string) => Date | undefined",description:"Parser for custom or era display. Complete ISO input always works."},{name:"minDate",type:"Date",description:"Earliest selectable date, inclusive, enforced on BOTH routes into the value \u2014 the panel greys the cell out and a typed date is rejected. The ONLY lower bound: the removed MonthPicker's `fromYear` is `minDate={new Date(year, 0, 1)}`. Alias of fromDate."},{name:"maxDate",type:"Date",description:"Latest selectable date, inclusive, enforced on both routes. `toYear={y}` becomes `maxDate={new Date(y, 11, 31)}`. Alias of toDate."},{name:"showWeek",type:"boolean",description:"Show week numbers."},{name:"captionLayout",type:'"label" | "dropdown" | "dropdown-months" | "dropdown-years"',description:"How the day panel's month caption is drawn (react-day-picker `captionLayout`, forwarded to Calendar). Default `label`. `dropdown` turns month and year into selects; without minDate/maxDate the year list spans 100 years back to the current year."},{name:"defaultPickerValue",type:"Date",description:"Which period the PANEL opens on, independently of the value (antd `defaultPickerValue`), and \u2014 as in antd \u2014 RE-APPLIED every time the panel opens, not only at mount. Use it for 'open on the fiscal year's start month' or 'open on the month of the row being edited'."},{name:"pickerValue",type:"Date",description:"Controlled panel period (antd `pickerValue`). Wins over `defaultPickerValue` and over the value, and freezes the panel's own navigation \u2014 the parent owns which period is shown."},{name:"needConfirm",type:"boolean",description:"Stage choices until confirmed; defaults on with showTime."},{name:"showTime",type:"boolean | object",description:"Include time editing; object takes TimePicker steps/hour-cycle/disabledTime. Not available with `range` or `multiple`."},{name:"presets",type:"{ label: ReactNode; value: T | (() => T) }[]",description:"Quick choices resolved on click and checked against the constraints. `T` follows the cardinality: `Date` normally, `DateRange` with `range`."},{name:"picker",type:'"date" | "week" | "month" | "quarter" | "year"',description:"GRANULARITY of one selection (antd `picker`). `date`/`week` show the day grid; `month`/`quarter`/`year` show a period grid. The value is always the START of the chosen period, and `name` submits the matching reduced ISO form."},{name:"range",type:"boolean",description:'CARDINALITY: two endpoints in one control (antd `DatePicker.RangePicker`). value/defaultValue and the callback become `DateRange`; the pair submits as `${name}_from` / `${name}_to`. Composes with `picker`, so a month range is `<DatePicker range picker="month" />`. Never place two DatePickers side by side to fake this.'},{name:"multiple",type:"boolean",description:"Select several dates; value/defaultValue and the callback use Date[]. Incompatible with showTime and with range."},{name:"allowEmpty",type:"[boolean, boolean]",description:"With `range`: which of the two endpoints may stay empty (antd `allowEmpty`). Default `[true, true]`."},{name:"showSummary",type:"boolean",defaultValue:"true",description:'With `range`: a polite live summary (`aria-live="polite"`, always mounted) under the DAY grid \u2014 the start date alone while only the start is held, then `Intl.DateTimeFormat#formatRange` of both edges plus the INCLUSIVE day count through `Intl.PluralRules` (1 \u2192 7 reads "Mar 1 \u2013 7, 2026 \xB7 7 days"; ja \u300C7\u65E5\u9593\u300D). Muted `Text size="xs" tabular`, no new token. The month / quarter / year period grids ignore it. Independently of this flag, while only the start is chosen the `to` edge\'s placeholder becomes "Select end date" (`dataEntry.dateRangePicker.selectEnd`). `false` removes the summary.'},{name:"order",type:"boolean",defaultValue:"true",description:"Normalise the selection into ascending order (antd `order`). ONE rule seen through two value shapes: a `range` picked backwards is SWAPPED, a `multiple` selection is SORTED. Pass false to keep pick order."},{name:"cellRender",type:"(date: Date, info: { originNode: ReactNode }) => ReactNode",description:"Decorate a day cell \u2014 \u795D\u65E5, a booked day, a deadline. It WRAPS the library's own day button rather than replacing it: `originNode` already carries the selection state, `aria-selected`, the disabled handling and its place in the grid's roving tabindex. Write `<>{originNode}<Badge \u2026/></>` \u2014 decorate, never rebuild, or every marker re-derives all of that and most get it wrong."},{name:"bordered",type:"boolean",defaultValue:"true",description:'Rule the popup\'s DAY grid \u2014 forwarded to `Calendar bordered`, on by default like it. Applies to `picker="date"` / `"week"` in single, `multiple` and `range`; the month / quarter / year period grid has no day cells and ignores it. `bordered={false}` opts out. Line colour: `--calendar-grid-border-color` (default `hsl(var(--border))`, the same tier as the popover edge and a table row rule \u2014 lightened from `hsl(var(--input) / 0.5)` in gh#730). The caption\u2192weekday-row step is ONE token now, `--calendar-grid-space-block-start` (space-3, measured 32px \u2192 12px): it used to stack with the month column gap.'},{name:"disabledDate",type:"(date: Date) => boolean",description:"Forbid individual dates by predicate \u2014 a business rule the `minDate`/`maxDate` window cannot express (holidays, blackout days, a \u958B\u59CB date already chosen). A forbidden day is refused on BOTH routes into the value: it cannot be clicked and it is rejected when typed."},{name:"showToday",type:"boolean",defaultValue:"false",description:"Footer action that jumps to the current month and selects today (single), fills the open end of the range (range) or adds today (multiple). Disabled when today is outside minDate / maxDate or matches `disabledDate`."},{name:"showClose",type:"boolean",defaultValue:"false",description:"Footer action that calls `onClose`."},{name:"onClose",type:"() => void",description:"Invoked by the showClose footer action."},{name:"value",type:"Date | Date[] | DateRange | undefined",description:"Controlled selection. `Date` by default, `Date[]` with `multiple`, `DateRange` with `range`. The input text and the panel stay in sync with it."},{name:"defaultValue",type:"Date | Date[] | DateRange | undefined",description:"Uncontrolled initial selection, same shape as `value`."},{name:"onValueChange",type:"(value: Date | Date[] | DateRange | undefined) => void",description:"Fires when the user commits \u2014 a panel pick, a complete typed entry, Enter, or a clear (undefined). The argument type follows the cardinality, so no narrowing is needed at the call site."},{name:"name",type:"string",description:"Form field name. Submits ISO-8601 at the precision `picker` selects: `2026-03-01` for date/week, `2026-03` for month and quarter, `2026` for year. With `range` the pair submits as `${name}_from` / `${name}_to`."},{name:"id",type:"string",description:"HTML `id` for the input (the group, with `range`). Auto-generated when omitted, so the field always has one."},{name:"placeholder",type:"string",description:"Placeholder shown while empty. Defaults to the i18n string for the cardinality and granularity in play."},{name:"disabled",type:"boolean | [boolean, boolean]",defaultValue:"false",description:"Makes the control inert: the input, the clear button and the panel trigger all go dead, and a controlled `open` cannot force the panel up. With `range`, the TUPLE form `[from, to]` locks ONE endpoint and leaves the other editable (antd's RangePicker `disabled`) \u2014 the locked edge keeps its committed value whatever is typed or picked, and the \u2715 is withdrawn because clearing would wipe it."},{name:"className",type:"string",description:"Extra CSS classes on the outermost wrapper. Use for width/margin overrides."},{name:"locale",type:'DayPickerProps["locale"]',description:"Locale object (from `date-fns/locale`) forwarded to the panel. Controls month/day names and the week start. The input always accepts the ISO form regardless of locale."},{name:"fromDate",type:"Date",description:"Alias of minDate, kept for the antd v4 spelling."},{name:"toDate",type:"Date",description:"Alias of maxDate, kept for the antd v4 spelling."},{name:"allowClear",type:"boolean | { clearIcon?: ReactNode; label?: string }",defaultValue:"true",description:"Inline \u2715 that resets the value when one is set (antd `allowClear`). The object form replaces the icon and/or the accessible label. Pass `false` on a required field."},{name:"triggerLabel",type:"string",description:"Accessible NAME of the calendar button. The default (\u300C\u30AB\u30EC\u30F3\u30C0\u30FC\u3092\u958B\u304F\u300D / 'Open calendar') is right for one picker on a page and useless for three: a screen-reader user hears the same sentence three times with nothing to say which field each button belongs to (WCAG 2.2 SC 2.4.6). Name it after the FIELD \u2014 `\u958B\u59CB\u65E5\u306E\u30AB\u30EC\u30F3\u30C0\u30FC\u3092\u958B\u304F`. Same axis and same reason as Select's `clearLabel`."}],usage:["Coarse pointers: affix actions use --control-affix-touch-target-size (44px by default); text space is reserved separately. Fine-pointer geometry is unchanged.",'ONE component covers every date-shaped field. `picker` is the granularity axis, `range` and `multiple` are the cardinality axis, and they compose: `<DatePicker range picker="month" />` is a month range.',"DO use `name` to make the field form-submittable \u2014 it emits ISO-8601 at the picker's own precision (`2026-03` for a month, `2026` for a year, `2026-03-01` for a day). No hidden input of your own is needed.","DO wrap it in FormField like every other labelled control; FormField injects the id/aria wiring onto the input.","DO pass `triggerLabel` whenever a screen has MORE THAN ONE date field. Without it every calendar button on the page carries the identical name and a screen-reader user cannot tell which field each one opens.","DO test by filling the input directly: `await user.type(screen.getByRole('combobox'), '2026-04-15')`. With `range`, the two edges are named textboxes (From / To). The panel is secondary and not required for testing.","DO use `minDate` / `maxDate` to restrict what is selectable \u2014 they are enforced on the panel AND on typed entry, so the keyboard is not a way around the rule the mouse obeys.","DON'T place two DatePickers side by side to fake a from~to pair \u2014 that is `range`, which is one control, one shell and one value.",'DO use captionLayout="dropdown" for a birth date or any far-away date \u2014 the year select reaches 1999 in one pick instead of ~320 arrow clicks; also set `maxDate` when the date can lie in the future (the year list stops at the current year).',"DO use `defaultPickerValue` when the panel should open somewhere other than the value \u2014 it is the only way to say it, and it re-applies on every open.","DON'T reach for `inputReadOnly` to switch the control off; it only sets the input's readonly attribute (the panel still opens). `disabled` is the inert one.","DON'T hand-roll a date text input + calendar popover \u2014 this component IS that pattern at WAI-ARIA combobox spec level."],useCases:["Invoice due-date field in an accounting form \u2014 attach `name='due_date'` and submit natively.",'A \u5BFE\u8C61\u6708 / \u7DE0\u3081\u5E74\u6708 field where the day is meaningless \u2014 `picker="month"`, which submits `2026-03`.',"A \u4F1A\u8A08\u671F\u9593 from~to pair \u2014 `range`, submitting `period_from` / `period_to`.",'A quarterly or fiscal-year reporting filter \u2014 `picker="quarter"` or `picker="year"`.',"Restricting a closing date to future days with `minDate={new Date()}`.","Locale-aware picker in a multi-language admin panel \u2014 pass a `date-fns` locale for the panel while the input keeps its ISO form."],related:["TimePicker \u2014 companion for HH:mm time selection; same form-submittable-input pattern with a `name` prop.","Calendar \u2014 the bare calendar grid used inside DatePicker; reach for it only when you need an always-visible month grid with no input.",'MonthPicker / MonthRangePicker / DateRangePicker were separate components until 22.0.0. They are now `picker="month"`, `range picker="month"` and `range` on this component.'],example:`import { useState } from "react";
|
|
1189
|
+
]} />`,storyPath:"data-entry/radio-group.tsx",rules:[23]},{name:"DatePicker",absorbed:["DateRangePicker"],group:"data-entry",tagline:"ONE date control: `picker` sets the granularity (day \xB7 week \xB7 month \xB7 quarter \xB7 year), `range` makes it a two-endpoint field, `multiple` a set. A real typeable input holds the value and submits ISO-8601 at the picker's own precision; the panel is the visual-only affordance.",props:[{name:"open",type:"boolean",description:"Controlled panel visibility."},{name:"defaultOpen",type:"boolean",description:"Initial panel visibility."},{name:"onOpenChange",type:"(open: boolean) => void",description:"Panel visibility changes."},{name:"status",type:'"error" | "warning"',description:"Validation appearance; error announces invalid state."},{name:"variant",type:'"outlined" | "filled" | "borderless" | "underlined"',description:"Shared control surface."},{name:"size",type:'"sm" | "md" | "lg"',description:"Shared control sizing."},{name:"inputReadOnly",type:"boolean",description:"antd `inputReadOnly` \u2014 sets the readonly attribute on the input so the mobile virtual keyboard stays down. The PANEL STILL OPENS: this is 'pick from the panel, do not type', not a second `disabled`. Use `disabled` to make the control inert."},{name:"preserveInvalidOnBlur",type:"boolean",description:"Keep invalid draft text on blur; never submit it as a committed value."},{name:"placement",type:'"bottom-start" | "bottom-end" | "top-start" | "top-end"',description:"Logical popup placement."},{name:"renderExtraFooter",type:"() => ReactNode",description:"Additional panel footer content."},{name:"ref",type:"Ref<HTMLInputElement>",description:"Ref to the editable input (with `range`, the start edge)."},{name:"format",type:"string | Intl.DateTimeFormatOptions | ((date: Date) => string)",description:"Display using date-fns patterns, Intl options (Japanese era supported), or a callback. Submission stays ISO."},{name:"parseFormat",type:"(text: string) => Date | undefined",description:"Parser for custom or era display. Complete ISO input always works."},{name:"minDate",type:"Date",description:"Earliest selectable date, inclusive, enforced on BOTH routes into the value \u2014 the panel greys the cell out and a typed date is rejected. The ONLY lower bound: the removed MonthPicker's `fromYear` is `minDate={new Date(year, 0, 1)}`. Alias of fromDate."},{name:"maxDate",type:"Date",description:"Latest selectable date, inclusive, enforced on both routes. `toYear={y}` becomes `maxDate={new Date(y, 11, 31)}`. Alias of toDate."},{name:"showWeek",type:"boolean",description:"Show week numbers."},{name:"captionLayout",type:'"label" | "dropdown" | "dropdown-months" | "dropdown-years"',description:"How the day panel's month caption is drawn (react-day-picker `captionLayout`, forwarded to Calendar). Default `label`. `dropdown` turns month and year into selects; without minDate/maxDate the year list spans 100 years back to the current year."},{name:"defaultPickerValue",type:"Date",description:"Which period the PANEL opens on, independently of the value (antd `defaultPickerValue`), and \u2014 as in antd \u2014 RE-APPLIED every time the panel opens, not only at mount. Use it for 'open on the fiscal year's start month' or 'open on the month of the row being edited'."},{name:"pickerValue",type:"Date",description:"Controlled panel period (antd `pickerValue`). Wins over `defaultPickerValue` and over the value, and freezes the panel's own navigation \u2014 the parent owns which period is shown."},{name:"needConfirm",type:"boolean",description:"Stage choices until confirmed; defaults on with showTime."},{name:"showTime",type:"boolean | object",description:"Include time editing; object takes TimePicker steps/hour-cycle/disabledTime. Not available with `range` or `multiple`."},{name:"presets",type:"{ label: ReactNode; value: T | (() => T) }[]",description:"Quick choices resolved on click and checked against the constraints. `T` follows the cardinality: `Date` normally, `DateRange` with `range`."},{name:"picker",type:'"date" | "week" | "month" | "quarter" | "year"',description:"GRANULARITY of one selection (antd `picker`). `date`/`week` show the day grid; `month`/`quarter`/`year` show a period grid. The value is always the START of the chosen period, and `name` submits the matching reduced ISO form."},{name:"range",type:"boolean",description:'CARDINALITY: two endpoints in one control (antd `DatePicker.RangePicker`). value/defaultValue and the callback become `DateRange`; the pair submits as `${name}_from` / `${name}_to`. Composes with `picker`, so a month range is `<DatePicker range picker="month" />`. Never place two DatePickers side by side to fake this.'},{name:"multiple",type:"boolean",description:"Select several dates; value/defaultValue and the callback use Date[]. Incompatible with showTime and with range."},{name:"allowEmpty",type:"[boolean, boolean]",description:"With `range`: which of the two endpoints may stay empty (antd `allowEmpty`). Default `[true, true]`."},{name:"showSummary",type:"boolean",defaultValue:"true",description:'With `range`: a polite live summary (`aria-live="polite"`, always mounted) under the DAY grid \u2014 the start date alone while only the start is held, then `Intl.DateTimeFormat#formatRange` of both edges plus the INCLUSIVE day count through `Intl.PluralRules` (1 \u2192 7 reads "Mar 1 \u2013 7, 2026 \xB7 7 days"; ja \u300C7\u65E5\u9593\u300D). Muted `Text size="xs" tabular`, no new token. The month / quarter / year period grids ignore it. Independently of this flag, while only the start is chosen the `to` edge\'s placeholder becomes "Select end date" (`dataEntry.dateRangePicker.selectEnd`). `false` removes the summary.'},{name:"order",type:"boolean",defaultValue:"true",description:"Normalise the selection into ascending order (antd `order`). ONE rule seen through two value shapes: a `range` picked backwards is SWAPPED, a `multiple` selection is SORTED. Pass false to keep pick order."},{name:"cellRender",type:"(date: Date, info: { originNode: ReactNode }) => ReactNode",description:"Decorate a day cell \u2014 \u795D\u65E5, a booked day, a deadline. It WRAPS the library's own day button rather than replacing it: `originNode` already carries the selection state, `aria-selected`, the disabled handling and its place in the grid's roving tabindex. Write `<>{originNode}<Badge \u2026/></>` \u2014 decorate, never rebuild, or every marker re-derives all of that and most get it wrong."},{name:"bordered",type:"boolean",defaultValue:"true",description:'Rule the popup\'s DAY grid \u2014 forwarded to `Calendar bordered`, on by default like it. Applies to `picker="date"` / `"week"` in single, `multiple` and `range`; the month / quarter / year period grid has no day cells and ignores it. `bordered={false}` opts out. Line colour: `--calendar-grid-border-color` (default `hsl(var(--border))`, the same tier as the popover edge and a table row rule \u2014 lightened from `hsl(var(--input) / 0.5)` in gh#730). The caption\u2192weekday-row step is ONE token now, `--calendar-grid-space-block-start` (space-3, measured 32px \u2192 12px): it used to stack with the month column gap.'},{name:"disabledDate",type:"(date: Date) => boolean",description:"Forbid individual dates by predicate \u2014 a business rule the `minDate`/`maxDate` window cannot express (holidays, blackout days, a \u958B\u59CB date already chosen). A forbidden day is refused on BOTH routes into the value: it cannot be clicked and it is rejected when typed."},{name:"showToday",type:"boolean",defaultValue:"false",description:"Footer action that jumps to the current month and selects today (single), fills the open end of the range (range) or adds today (multiple). Disabled when today is outside minDate / maxDate or matches `disabledDate`."},{name:"showClose",type:"boolean",defaultValue:"false",description:"Footer action that calls `onClose`."},{name:"onClose",type:"() => void",description:"Invoked by the showClose footer action."},{name:"value",type:"Date | Date[] | DateRange | undefined",description:"Controlled selection. `Date` by default, `Date[]` with `multiple`, `DateRange` with `range`. The input text and the panel stay in sync with it."},{name:"defaultValue",type:"Date | Date[] | DateRange | undefined",description:"Uncontrolled initial selection, same shape as `value`."},{name:"onValueChange",type:"(value: Date | Date[] | DateRange | undefined) => void",description:"Fires when the user commits \u2014 a panel pick, a complete typed entry, Enter, or a clear (undefined). The argument type follows the cardinality, so no narrowing is needed at the call site."},{name:"name",type:"string",description:"Form field name. Submits ISO-8601 at the precision `picker` selects: `2026-03-01` for date/week, `2026-03` for month and quarter, `2026` for year. With `range` the pair submits as `${name}_from` / `${name}_to`."},{name:"id",type:"string",description:"HTML `id` for the input (the group, with `range`). Auto-generated when omitted, so the field always has one."},{name:"placeholder",type:"string",description:"Placeholder shown while empty. Defaults to the i18n string for the cardinality and granularity in play."},{name:"disabled",type:"boolean | [boolean, boolean]",defaultValue:"false",description:"Makes the control inert: the input, the clear button and the panel trigger all go dead, and a controlled `open` cannot force the panel up. With `range`, the TUPLE form `[from, to]` locks ONE endpoint and leaves the other editable (antd's RangePicker `disabled`) \u2014 the locked edge keeps its committed value whatever is typed or picked, and the \u2715 is withdrawn because clearing would wipe it."},{name:"className",type:"string",description:"Extra CSS classes on the outermost wrapper. Use for width/margin overrides."},{name:"locale",type:'DayPickerProps["locale"]',description:"Locale object (from `date-fns/locale`) forwarded to the panel. Controls month/day names and the week start. The input always accepts the ISO form regardless of locale."},{name:"fromDate",type:"Date",description:"Alias of minDate, kept for the antd v4 spelling."},{name:"toDate",type:"Date",description:"Alias of maxDate, kept for the antd v4 spelling."},{name:"allowClear",type:"boolean | { clearIcon?: ReactNode; label?: string }",defaultValue:"true",description:"Inline \u2715 that resets the value when one is set (antd `allowClear`). The object form replaces the icon and/or the accessible label. Pass `false` on a required field."},{name:"triggerLabel",type:"string",description:"Accessible NAME of the calendar button. The default (\u300C\u30AB\u30EC\u30F3\u30C0\u30FC\u3092\u958B\u304F\u300D / 'Open calendar') is right for one picker on a page and useless for three: a screen-reader user hears the same sentence three times with nothing to say which field each button belongs to (WCAG 2.2 SC 2.4.6). Name it after the FIELD \u2014 `\u958B\u59CB\u65E5\u306E\u30AB\u30EC\u30F3\u30C0\u30FC\u3092\u958B\u304F`. Same axis and same reason as Select's `clearLabel`. The calendar DIALOG is named after the field too: the FormField label (or your `aria-labelledby` / `aria-label`) first, then `triggerLabel`, then the default."}],usage:["Coarse pointers: affix actions use --control-affix-touch-target-size (44px by default); text space is reserved separately. Fine-pointer geometry is unchanged.",'ONE component covers every date-shaped field. `picker` is the granularity axis, `range` and `multiple` are the cardinality axis, and they compose: `<DatePicker range picker="month" />` is a month range.',"DO use `name` to make the field form-submittable \u2014 it emits ISO-8601 at the picker's own precision (`2026-03` for a month, `2026` for a year, `2026-03-01` for a day). No hidden input of your own is needed.","DO wrap it in FormField like every other labelled control; FormField injects the id/aria wiring onto the input.","DO pass `triggerLabel` whenever a screen has MORE THAN ONE date field. Without it every calendar button on the page carries the identical name and a screen-reader user cannot tell which field each one opens.","DO test by filling the input directly: `await user.type(screen.getByRole('combobox'), '2026-04-15')`. With `range`, the two edges are named textboxes (From / To). The panel is secondary and not required for testing.","DO use `minDate` / `maxDate` to restrict what is selectable \u2014 they are enforced on the panel AND on typed entry, so the keyboard is not a way around the rule the mouse obeys.","DON'T place two DatePickers side by side to fake a from~to pair \u2014 that is `range`, which is one control, one shell and one value.",'DO use captionLayout="dropdown" for a birth date or any far-away date \u2014 the year select reaches 1999 in one pick instead of ~320 arrow clicks; also set `maxDate` when the date can lie in the future (the year list stops at the current year).',"DO use `defaultPickerValue` when the panel should open somewhere other than the value \u2014 it is the only way to say it, and it re-applies on every open.","DON'T reach for `inputReadOnly` to switch the control off; it only sets the input's readonly attribute (the panel still opens). `disabled` is the inert one.","DON'T hand-roll a date text input + calendar popover \u2014 this component IS that pattern at WAI-ARIA combobox spec level."],useCases:["Invoice due-date field in an accounting form \u2014 attach `name='due_date'` and submit natively.",'A \u5BFE\u8C61\u6708 / \u7DE0\u3081\u5E74\u6708 field where the day is meaningless \u2014 `picker="month"`, which submits `2026-03`.',"A \u4F1A\u8A08\u671F\u9593 from~to pair \u2014 `range`, submitting `period_from` / `period_to`.",'A quarterly or fiscal-year reporting filter \u2014 `picker="quarter"` or `picker="year"`.',"Restricting a closing date to future days with `minDate={new Date()}`.","Locale-aware picker in a multi-language admin panel \u2014 pass a `date-fns` locale for the panel while the input keeps its ISO form."],related:["TimePicker \u2014 companion for HH:mm time selection; same form-submittable-input pattern with a `name` prop.","Calendar \u2014 the bare calendar grid used inside DatePicker; reach for it only when you need an always-visible month grid with no input.",'MonthPicker / MonthRangePicker / DateRangePicker were separate components until 22.0.0. They are now `picker="month"`, `range picker="month"` and `range` on this component.'],example:`import { useState } from "react";
|
|
1190
1190
|
import { DatePicker, FormField } from "@godxjp/ui/data-entry";
|
|
1191
1191
|
import { Flex } from "@godxjp/ui/layout";
|
|
1192
1192
|
import type { DateRange } from "react-day-picker";
|
|
@@ -7977,7 +7977,7 @@ export default function Demo() {
|
|
|
7977
7977
|
</PageContainer>
|
|
7978
7978
|
);
|
|
7979
7979
|
}
|
|
7980
|
-
`};var p={name:"@godxjp/ui-mcp",version:"33.12.6",godxUiCompatibility:"33.12.x",description:"Model Context Protocol server for @godxjp/ui \u2014 gives Claude Code / Codex CLI / Cursor / any MCP-aware agent live access to the component catalog, prop vocabulary, design tokens, 45 cardinal rules, copy-paste-ready patterns, 12 design / taste skills synthesised from Leonxlnx/taste-skill, 20+ anti-AI-tell patterns, and a 50-check redesign audit \u2014 token-efficient (list \u2192 drill-down).",type:"module",main:"./dist/index.js",module:"./dist/index.js",types:"./dist/index.d.ts",bin:{"godx-ui-mcp":"./dist/index.js"},files:["dist","README.md"],publishConfig:{registry:"https://registry.npmjs.org/",access:"public"},repository:{type:"git",url:"git+https://github.com/godx-jp/godxjp-ui.git",directory:"mcp"},homepage:"https://github.com/godx-jp/godxjp-ui/tree/main/mcp#readme",license:"Apache-2.0",scripts:{build:"tsup",dev:"tsup --watch",start:"node dist/index.js",inspect:"npx @modelcontextprotocol/inspector node dist/index.js","type-check":"tsc --noEmit",test:"vitest run",prepublishOnly:"npm run build"},dependencies:{"@modelcontextprotocol/sdk":"^1.29.0",zod:"^4.4.3"},devDependencies:{"@types/node":"^22.10.0",tsup:"^8.5.1",typescript:"^6.0.3",vitest:"^4.1.6"},keywords:["mcp","model-context-protocol","godxjp","ui","design-system","react","claude","cursor"],author:"GoDX (https://godx.jp)",bugs:{url:"https://github.com/godx-jp/godxjp-ui/issues"}};var O=[{name:"list_skills",description:"List every design/taste skill bundled by this MCP (id + name + whenToUse + section ids). Use FIRST to discover skills; then `get_skill_section` to drill in.",inputSchema:{type:"object",properties:{}}},{name:"list_primitives",description:'List every @godxjp/ui primitive/composite/shell (group + tagline per entry). Optionally filter by group. Then `get_component` for one\'s full API. Core only by default \u2014 pass tier="lab" for the opt-in @godxjp/ui/lab components.',inputSchema:{type:"object",properties:{tier:{type:"string",enum:["core","lab","all"],description:'Default "core". "lab" lists the opt-in `@godxjp/ui/lab` components (niche, kept and tested, not in the default context); "all" lists both.'},group:{type:"string",enum:["general","layout","data-display","data-entry","feedback","navigation","composites","shell","providers"]}}}},{name:"list_utilities",description:'List every NON-component public export of @godxjp/ui \u2014 hooks, helper functions and constants (cn, formatDate, formatCurrency, toast, useDebouncedValue, buttonVariants, CHART_COLORS, SHOW_PARENT \u2026). Reach for this before hand-writing a className merger, a date/money formatter, a debounce hook or a chart palette: two products in this org each re-implemented `cn` because it could not be found. Optionally filter by kind. Then `get_component name="<name>"` for its signature, usage and example.',inputSchema:{type:"object",properties:{kind:{type:"string",enum:["hook","function","value"],description:"hook = only legal inside a component body; function = callable anywhere; value = a constant to read."}}}},{name:"list_patterns",description:"List every canonical copy-paste code pattern (signup-form, settings-page, data-table-page, async-data-state, confirm-destructive, \u2026); common aliases resolve too. Use before `get_pattern`.",inputSchema:{type:"object",properties:{}}},{name:"list_anti_ai_tells",description:"List every AI-tell pattern to AVOID (optionally by category). Use to self-audit a design before shipping; then `get_anti_ai_tell` for the fix.",inputSchema:{type:"object",properties:{category:{type:"string",enum:["visual","layout","copy","interaction","imagery","structure"]}}}},{name:"list_redesign_checks",description:"List the redesign audit checklist (50+ checks; optionally by category). Use when auditing an existing project; then `get_redesign_check` for a symptom's fix.",inputSchema:{type:"object",properties:{category:{type:"string",enum:["typography","color-surface","layout","interactivity","content","components","iconography","code-quality","omissions"]}}}},{name:"list_audit_rules",description:"List the LOCAL static ui-audit rules (scripts/ui-audit.mjs) to run BEFORE any visual review \u2014 each cites the standard it enforces (WCAG/WAI-ARIA/Intl/ISO/IANA/CSS-Logical) + a fix + the run command. Optionally by category.",inputSchema:{type:"object",properties:{category:{type:"string",enum:["tokens","composition","api","a11y","i18n","rtl","copy"]}}}},{name:"list_visual_checks",description:"List the RUNTIME visual-audit checks (scripts/visual-audit.mjs \u2014 Playwright + axe-core) to run against the RUNNING app: contrast/ARIA (axe), target size, rendered-accent chroma, DOM emoji, banner layout. Needs a browser (vs list_audit_rules, static). Optionally by category.",inputSchema:{type:"object",properties:{category:{type:"string",enum:["a11y","color","i18n","layout"]}}}},{name:"get_anti_ai_tell",description:"Fetch ONE anti-AI-tell \u2014 full body + concrete fix. Use after `list_anti_ai_tells`.",inputSchema:{type:"object",properties:{name:{type:"string",description:"Exact tell name from list_anti_ai_tells."}},required:["name"]}},{name:"get_redesign_check",description:"Fetch redesign check(s) matching a symptom snippet. Returns full fix + UI note. Use after `list_redesign_checks`.",inputSchema:{type:"object",properties:{symptom:{type:"string",description:"Fragment of the symptom text (e.g. 'Inter everywhere' / '100vh')."}},required:["symptom"]}},{name:"get_skill_section",description:"Fetch ONE section of ONE skill \u2014 token-efficient. E.g. `skill='soft', section='double-bezel'`. Use after `list_skills` narrowed the relevant skill + section.",inputSchema:{type:"object",properties:{skill:{type:"string",description:"Skill id (e.g. 'soft', 'minimalist', 'taste')."},section:{type:"string",description:"Section id within that skill."}},required:["skill","section"]}},{name:"get_component",description:"Full guide for one @godxjp/ui component \u2014 import path, props/types/defaults, HOW to use it (DO/DON'T), WHEN to reach for it (use cases), related components (don't reinvent/confuse), a copy-paste example, story path, and cardinal rules. Use this before hand-rolling anything. Design-token knobs are listed compactly (name+default); pass `verbose:true` for what each token controls.",inputSchema:{type:"object",properties:{name:{type:"string",description:"Component name (e.g. 'Button', 'DataTable')."},verbose:{type:"boolean",description:"Include the full design-token table with a 'what it controls' description per token. Default false (compact token+default only) to save context."}},required:["name"]}},{name:"get_pattern",description:"Full code snippet for one canonical pattern \u2014 copy-paste-ready.",inputSchema:{type:"object",properties:{name:{type:"string",description:"Pattern slug (use list_patterns first)."}},required:["name"]}},{name:"get_rule",description:"Read one cardinal rule from CLAUDE.md (by number) OR all if no number.",inputSchema:{type:"object",properties:{number:{type:"number",description:"Rule number (1-N)."}}}},{name:"get_vocab",description:"Read shared prop-vocabulary type (`SizeProp`, `StatusProp`, `ColorProp`, `LoadingProp`, etc.) OR all if no name.",inputSchema:{type:"object",properties:{name:{type:"string",description:"Vocab type name."}}}},{name:"get_tokens",description:"Read design tokens, optionally filtered by tier category (primitive / semantic / component).",inputSchema:{type:"object",properties:{category:{type:"string",enum:["primitive","semantic","component"]}}}},{name:"list_consumer_skills",description:"List the design skills relevant to an app-dev BUILDING WITH @godxjp/ui (audience consumer/both). Hides core library-maintenance skills. START HERE if you import @godxjp/ui and want guidance (design-to-page, compose-a-screen, taste, \u2026). Returns id + name + whenToUse + section ids.",inputSchema:{type:"object",properties:{}}},{name:"get_consumer_skill",description:"Fetch ONE section of ONE consumer-facing skill. Same as get_skill_section but refuses core-only skills (steers app-devs away from library-maintenance material). Use after list_consumer_skills / route_consumer_task.",inputSchema:{type:"object",properties:{skill:{type:"string",description:"Consumer skill id (e.g. 'design-to-page', 'compose-a-screen')."},section:{type:"string",description:"Section id within that skill."}},required:["skill"]}},{name:"route_consumer_task",description:"Natural-language task \u2192 consumer skill+section pointer. Like route_task but only points to consumer-facing skills (never core library-maintenance). Use FIRST when you're building an app with @godxjp/ui.",inputSchema:{type:"object",properties:{task:{type:"string",description:"Describe what you want to build."}},required:["task"]}},{name:"draft_bug_report",description:"When @godxjp/ui ITSELF is at fault (missing token, a primitive lacking the controlled-vocabulary prop, a real a11y/behaviour bug, a wrong catalog example) and you cannot follow a rule \u2014 DON'T fake a workaround. This drafts a detailed GitHub issue body + a copy-paste `gh issue create` command so you can report it. Prints the command only; never runs gh.",inputSchema:{type:"object",properties:{summary:{type:"string",description:"One-line title of the bug / blocked rule."},repro:{type:"string",description:"Minimal steps or code to reproduce."},expected:{type:"string",description:"What SHOULD happen (per the rule/spec)."},actual:{type:"string",description:"What actually happens."},component:{type:"string",description:"Affected component name, if any (links to get_component)."},rule:{type:"number",description:"Cardinal rule number that can't be followed, if any."},version:{type:"string",description:"Installed @godxjp/ui version (e.g. '12.1.0')."},env:{type:"string",description:"Environment (browser/OS/framework), if relevant."}},required:["summary"]}},{name:"check_compatibility",description:"Report whether the @godxjp/ui version installed in the target project matches THIS catalog (which describes one release train). A mismatched minor means the props/tokens/patterns may describe a build they never installed (#140). Pass the installed version (`npm ls @godxjp/ui`); call it at the START of a consumer session.",inputSchema:{type:"object",properties:{version:{type:"string",description:"Installed @godxjp/ui version in the target project, e.g. '16.10.0'. Omit to just read the catalog's own version + compatible range."}}}},{name:"route_task",description:"Natural-language task \u2192 skill+section pointer (e.g. 'design a premium agency hero' \u2192 soft/vibe-archetypes). Use FIRST when you don't know which skill applies.",inputSchema:{type:"object",properties:{task:{type:"string",description:"Describe what you want to build."}},required:["task"]}},{name:"suggest_primitive",description:"Use case \u2192 primitive recommendation. E.g. 'confirm a destructive delete' \u2192 DangerZone pattern + Dialog suggestion.",inputSchema:{type:"object",properties:{use_case:{type:"string"}},required:["use_case"]}},{name:"search_components",description:'Fuzzy-search primitives by name / tagline / prop. Returns ranked matches. Core only by default; pass tier="lab" or "all" to include the opt-in @godxjp/ui/lab components.',inputSchema:{type:"object",properties:{query:{type:"string"},tier:{type:"string",enum:["core","lab","all"],description:'Default "core". "lab" lists the opt-in `@godxjp/ui/lab` components (niche, kept and tested, not in the default context); "all" lists both.'}},required:["query"]}},{name:"get_frame_coverage",description:"Verified preview-contract coverage for a component (issue #163). Answers 'is this state actually PROVEN?' \u2014 returns, per contract dimension (variants, tones, sizes, shapes, density, controlled/uncontrolled ownership, disabled/read-only/loading/empty/error/success, async retry/cancel/offline, responsive viewport matrix, RTL, long/localized content, keyboard/focus, accessible name/description/error, reduced motion / coarse touch), whether an EXECUTED case proves it (covered), whether nothing proves it (UNTESTED), or whether it cannot exist (not-applicable, with a reason). UNTESTED IS NOT A PASS: never infer that a component supports a state because an example renders. Call this before telling a user a component 'supports' anything. Omit `name` for the repo-wide summary and the tracked known gaps.",inputSchema:{type:"object",properties:{name:{type:"string",description:"Public export name (e.g. 'Button', 'DataTable', 'CardFooter'). Omit for the repo-wide coverage summary."}}}},{name:"get_design",description:"DESIGN.md \u2014 the visual spec for screens built with @godxjp/ui: real tokens (YAML front matter), colour scarcity rules, typography, layout & density, elevation, components, ADMIN SCREEN ANATOMY (list / detail / form / settings / dashboard / approval queue), do's and don'ts, responsive, iteration guide, known gaps. Read before composing a screen. Pass `section` for one section; omit it for the whole document (~12 KB).",inputSchema:{type:"object",properties:{section:{type:"string",description:"Section id or heading word, e.g. 'tokens', 'colors', 'admin-screen-anatomy', 'dos-and-donts', 'iteration-guide'. Unknown ids list the valid ones."}}}},{name:"get_exemplar",description:"A reference screen to match for an admin archetype: its anatomy notes from DESIGN.md, the full source of the showcase built from real @godxjp/ui primitives, and its live preview URL for screenshot comparison. Archetypes: "+E.map(e=>e.archetype).join(", ")+". Omit `archetype` to list them.",inputSchema:{type:"object",properties:{archetype:{type:"string",description:E.map(e=>e.archetype).join(" | ")+" (aliases: "+E.flatMap(e=>e.aliases??[]).join(", ")+")."}}}},{name:"lint_jsx",description:"Heuristic check of a JSX snippet for common violations \u2014 raw `<button>` / `<input>`, `color='error'` on Tag/Badge, missing aria-label, missing source.code override on stories with cell renderers (rule 34), etc.",inputSchema:{type:"object",properties:{jsx:{type:"string"}},required:["jsx"]}}],Ze=new Set(O.map(e=>e.name));function et(e=X()){let t=p.godxUiCompatibility??p.version,a=`@godxjp/ui-mcp ${p.version} (catalog for @godxjp/ui ${t})`;if(!e)return a;let n=e.source==="node_modules"?"read from node_modules at answer time":"from GODX_UI_VERSION at launch \u2014 node_modules/@godxjp/ui not resolved";return`${a} \u2014 installed @godxjp/ui ${e.version} (${n})`}function tt(e=X()){let t=e?V(e.version):null,a=V(p.version);return!e||!t||!a?null:dt(t,a)>0?`\u26A0\uFE0F SERVER OLDER THAN INSTALLED PACKAGE: this server is @godxjp/ui-mcp ${p.version}, the project has @godxjp/ui ${e.version} installed \u2014 this catalog is BEHIND the package and may be missing props and components that exist. Do not conclude from this answer that a prop is unavailable. Restart the session so the server relaunches on the installed version (run \`npx @godxjp/ui sync-rules\` first if the project's .mcp.json still pins an older @godxjp/ui-mcp).`:t.major===a.major?null:`\u26A0\uFE0F MAJOR MISMATCH: this server is @godxjp/ui-mcp ${p.version}, the project has @godxjp/ui ${e.version} installed \u2014 this catalog may describe components that do not exist in the installed package. Pin the MCP to @godxjp/ui-mcp@${e.version} (\`npx @godxjp/ui sync-rules\` updates the project's .mcp.json; a registration outside the project needs \`claude mcp remove <key>\`), then restart the agent.`}async function G(e,t){let a=await at(e,t);if(!Ze.has(e))return a;let n=X(),o=tt(n);return`${et(n)}
|
|
7980
|
+
`};var p={name:"@godxjp/ui-mcp",version:"33.12.8",godxUiCompatibility:"33.12.x",description:"Model Context Protocol server for @godxjp/ui \u2014 gives Claude Code / Codex CLI / Cursor / any MCP-aware agent live access to the component catalog, prop vocabulary, design tokens, 45 cardinal rules, copy-paste-ready patterns, 12 design / taste skills synthesised from Leonxlnx/taste-skill, 20+ anti-AI-tell patterns, and a 50-check redesign audit \u2014 token-efficient (list \u2192 drill-down).",type:"module",main:"./dist/index.js",module:"./dist/index.js",types:"./dist/index.d.ts",bin:{"godx-ui-mcp":"./dist/index.js"},files:["dist","README.md"],publishConfig:{registry:"https://registry.npmjs.org/",access:"public"},repository:{type:"git",url:"git+https://github.com/godx-jp/godxjp-ui.git",directory:"mcp"},homepage:"https://github.com/godx-jp/godxjp-ui/tree/main/mcp#readme",license:"Apache-2.0",scripts:{build:"tsup",dev:"tsup --watch",start:"node dist/index.js",inspect:"npx @modelcontextprotocol/inspector node dist/index.js","type-check":"tsc --noEmit",test:"vitest run",prepublishOnly:"npm run build"},dependencies:{"@modelcontextprotocol/sdk":"^1.29.0",zod:"^4.4.3"},devDependencies:{"@types/node":"^22.10.0",tsup:"^8.5.1",typescript:"^6.0.3",vitest:"^4.1.6"},keywords:["mcp","model-context-protocol","godxjp","ui","design-system","react","claude","cursor"],author:"GoDX (https://godx.jp)",bugs:{url:"https://github.com/godx-jp/godxjp-ui/issues"}};var O=[{name:"list_skills",description:"List every design/taste skill bundled by this MCP (id + name + whenToUse + section ids). Use FIRST to discover skills; then `get_skill_section` to drill in.",inputSchema:{type:"object",properties:{}}},{name:"list_primitives",description:'List every @godxjp/ui primitive/composite/shell (group + tagline per entry). Optionally filter by group. Then `get_component` for one\'s full API. Core only by default \u2014 pass tier="lab" for the opt-in @godxjp/ui/lab components.',inputSchema:{type:"object",properties:{tier:{type:"string",enum:["core","lab","all"],description:'Default "core". "lab" lists the opt-in `@godxjp/ui/lab` components (niche, kept and tested, not in the default context); "all" lists both.'},group:{type:"string",enum:["general","layout","data-display","data-entry","feedback","navigation","composites","shell","providers"]}}}},{name:"list_utilities",description:'List every NON-component public export of @godxjp/ui \u2014 hooks, helper functions and constants (cn, formatDate, formatCurrency, toast, useDebouncedValue, buttonVariants, CHART_COLORS, SHOW_PARENT \u2026). Reach for this before hand-writing a className merger, a date/money formatter, a debounce hook or a chart palette: two products in this org each re-implemented `cn` because it could not be found. Optionally filter by kind. Then `get_component name="<name>"` for its signature, usage and example.',inputSchema:{type:"object",properties:{kind:{type:"string",enum:["hook","function","value"],description:"hook = only legal inside a component body; function = callable anywhere; value = a constant to read."}}}},{name:"list_patterns",description:"List every canonical copy-paste code pattern (signup-form, settings-page, data-table-page, async-data-state, confirm-destructive, \u2026); common aliases resolve too. Use before `get_pattern`.",inputSchema:{type:"object",properties:{}}},{name:"list_anti_ai_tells",description:"List every AI-tell pattern to AVOID (optionally by category). Use to self-audit a design before shipping; then `get_anti_ai_tell` for the fix.",inputSchema:{type:"object",properties:{category:{type:"string",enum:["visual","layout","copy","interaction","imagery","structure"]}}}},{name:"list_redesign_checks",description:"List the redesign audit checklist (50+ checks; optionally by category). Use when auditing an existing project; then `get_redesign_check` for a symptom's fix.",inputSchema:{type:"object",properties:{category:{type:"string",enum:["typography","color-surface","layout","interactivity","content","components","iconography","code-quality","omissions"]}}}},{name:"list_audit_rules",description:"List the LOCAL static ui-audit rules (scripts/ui-audit.mjs) to run BEFORE any visual review \u2014 each cites the standard it enforces (WCAG/WAI-ARIA/Intl/ISO/IANA/CSS-Logical) + a fix + the run command. Optionally by category.",inputSchema:{type:"object",properties:{category:{type:"string",enum:["tokens","composition","api","a11y","i18n","rtl","copy"]}}}},{name:"list_visual_checks",description:"List the RUNTIME visual-audit checks (scripts/visual-audit.mjs \u2014 Playwright + axe-core) to run against the RUNNING app: contrast/ARIA (axe), target size, rendered-accent chroma, DOM emoji, banner layout. Needs a browser (vs list_audit_rules, static). Optionally by category.",inputSchema:{type:"object",properties:{category:{type:"string",enum:["a11y","color","i18n","layout"]}}}},{name:"get_anti_ai_tell",description:"Fetch ONE anti-AI-tell \u2014 full body + concrete fix. Use after `list_anti_ai_tells`.",inputSchema:{type:"object",properties:{name:{type:"string",description:"Exact tell name from list_anti_ai_tells."}},required:["name"]}},{name:"get_redesign_check",description:"Fetch redesign check(s) matching a symptom snippet. Returns full fix + UI note. Use after `list_redesign_checks`.",inputSchema:{type:"object",properties:{symptom:{type:"string",description:"Fragment of the symptom text (e.g. 'Inter everywhere' / '100vh')."}},required:["symptom"]}},{name:"get_skill_section",description:"Fetch ONE section of ONE skill \u2014 token-efficient. E.g. `skill='soft', section='double-bezel'`. Use after `list_skills` narrowed the relevant skill + section.",inputSchema:{type:"object",properties:{skill:{type:"string",description:"Skill id (e.g. 'soft', 'minimalist', 'taste')."},section:{type:"string",description:"Section id within that skill."}},required:["skill","section"]}},{name:"get_component",description:"Full guide for one @godxjp/ui component \u2014 import path, props/types/defaults, HOW to use it (DO/DON'T), WHEN to reach for it (use cases), related components (don't reinvent/confuse), a copy-paste example, story path, and cardinal rules. Use this before hand-rolling anything. Design-token knobs are listed compactly (name+default); pass `verbose:true` for what each token controls.",inputSchema:{type:"object",properties:{name:{type:"string",description:"Component name (e.g. 'Button', 'DataTable')."},verbose:{type:"boolean",description:"Include the full design-token table with a 'what it controls' description per token. Default false (compact token+default only) to save context."}},required:["name"]}},{name:"get_pattern",description:"Full code snippet for one canonical pattern \u2014 copy-paste-ready.",inputSchema:{type:"object",properties:{name:{type:"string",description:"Pattern slug (use list_patterns first)."}},required:["name"]}},{name:"get_rule",description:"Read one cardinal rule from CLAUDE.md (by number) OR all if no number.",inputSchema:{type:"object",properties:{number:{type:"number",description:"Rule number (1-N)."}}}},{name:"get_vocab",description:"Read shared prop-vocabulary type (`SizeProp`, `StatusProp`, `ColorProp`, `LoadingProp`, etc.) OR all if no name.",inputSchema:{type:"object",properties:{name:{type:"string",description:"Vocab type name."}}}},{name:"get_tokens",description:"Read design tokens, optionally filtered by tier category (primitive / semantic / component).",inputSchema:{type:"object",properties:{category:{type:"string",enum:["primitive","semantic","component"]}}}},{name:"list_consumer_skills",description:"List the design skills relevant to an app-dev BUILDING WITH @godxjp/ui (audience consumer/both). Hides core library-maintenance skills. START HERE if you import @godxjp/ui and want guidance (design-to-page, compose-a-screen, taste, \u2026). Returns id + name + whenToUse + section ids.",inputSchema:{type:"object",properties:{}}},{name:"get_consumer_skill",description:"Fetch ONE section of ONE consumer-facing skill. Same as get_skill_section but refuses core-only skills (steers app-devs away from library-maintenance material). Use after list_consumer_skills / route_consumer_task.",inputSchema:{type:"object",properties:{skill:{type:"string",description:"Consumer skill id (e.g. 'design-to-page', 'compose-a-screen')."},section:{type:"string",description:"Section id within that skill."}},required:["skill"]}},{name:"route_consumer_task",description:"Natural-language task \u2192 consumer skill+section pointer. Like route_task but only points to consumer-facing skills (never core library-maintenance). Use FIRST when you're building an app with @godxjp/ui.",inputSchema:{type:"object",properties:{task:{type:"string",description:"Describe what you want to build."}},required:["task"]}},{name:"draft_bug_report",description:"When @godxjp/ui ITSELF is at fault (missing token, a primitive lacking the controlled-vocabulary prop, a real a11y/behaviour bug, a wrong catalog example) and you cannot follow a rule \u2014 DON'T fake a workaround. This drafts a detailed GitHub issue body + a copy-paste `gh issue create` command so you can report it. Prints the command only; never runs gh.",inputSchema:{type:"object",properties:{summary:{type:"string",description:"One-line title of the bug / blocked rule."},repro:{type:"string",description:"Minimal steps or code to reproduce."},expected:{type:"string",description:"What SHOULD happen (per the rule/spec)."},actual:{type:"string",description:"What actually happens."},component:{type:"string",description:"Affected component name, if any (links to get_component)."},rule:{type:"number",description:"Cardinal rule number that can't be followed, if any."},version:{type:"string",description:"Installed @godxjp/ui version (e.g. '12.1.0')."},env:{type:"string",description:"Environment (browser/OS/framework), if relevant."}},required:["summary"]}},{name:"check_compatibility",description:"Report whether the @godxjp/ui version installed in the target project matches THIS catalog (which describes one release train). A mismatched minor means the props/tokens/patterns may describe a build they never installed (#140). Pass the installed version (`npm ls @godxjp/ui`); call it at the START of a consumer session.",inputSchema:{type:"object",properties:{version:{type:"string",description:"Installed @godxjp/ui version in the target project, e.g. '16.10.0'. Omit to just read the catalog's own version + compatible range."}}}},{name:"route_task",description:"Natural-language task \u2192 skill+section pointer (e.g. 'design a premium agency hero' \u2192 soft/vibe-archetypes). Use FIRST when you don't know which skill applies.",inputSchema:{type:"object",properties:{task:{type:"string",description:"Describe what you want to build."}},required:["task"]}},{name:"suggest_primitive",description:"Use case \u2192 primitive recommendation. E.g. 'confirm a destructive delete' \u2192 DangerZone pattern + Dialog suggestion.",inputSchema:{type:"object",properties:{use_case:{type:"string"}},required:["use_case"]}},{name:"search_components",description:'Fuzzy-search primitives by name / tagline / prop. Returns ranked matches. Core only by default; pass tier="lab" or "all" to include the opt-in @godxjp/ui/lab components.',inputSchema:{type:"object",properties:{query:{type:"string"},tier:{type:"string",enum:["core","lab","all"],description:'Default "core". "lab" lists the opt-in `@godxjp/ui/lab` components (niche, kept and tested, not in the default context); "all" lists both.'}},required:["query"]}},{name:"get_frame_coverage",description:"Verified preview-contract coverage for a component (issue #163). Answers 'is this state actually PROVEN?' \u2014 returns, per contract dimension (variants, tones, sizes, shapes, density, controlled/uncontrolled ownership, disabled/read-only/loading/empty/error/success, async retry/cancel/offline, responsive viewport matrix, RTL, long/localized content, keyboard/focus, accessible name/description/error, reduced motion / coarse touch), whether an EXECUTED case proves it (covered), whether nothing proves it (UNTESTED), or whether it cannot exist (not-applicable, with a reason). UNTESTED IS NOT A PASS: never infer that a component supports a state because an example renders. Call this before telling a user a component 'supports' anything. Omit `name` for the repo-wide summary and the tracked known gaps.",inputSchema:{type:"object",properties:{name:{type:"string",description:"Public export name (e.g. 'Button', 'DataTable', 'CardFooter'). Omit for the repo-wide coverage summary."}}}},{name:"get_design",description:"DESIGN.md \u2014 the visual spec for screens built with @godxjp/ui: real tokens (YAML front matter), colour scarcity rules, typography, layout & density, elevation, components, ADMIN SCREEN ANATOMY (list / detail / form / settings / dashboard / approval queue), do's and don'ts, responsive, iteration guide, known gaps. Read before composing a screen. Pass `section` for one section; omit it for the whole document (~12 KB).",inputSchema:{type:"object",properties:{section:{type:"string",description:"Section id or heading word, e.g. 'tokens', 'colors', 'admin-screen-anatomy', 'dos-and-donts', 'iteration-guide'. Unknown ids list the valid ones."}}}},{name:"get_exemplar",description:"A reference screen to match for an admin archetype: its anatomy notes from DESIGN.md, the full source of the showcase built from real @godxjp/ui primitives, and its live preview URL for screenshot comparison. Archetypes: "+E.map(e=>e.archetype).join(", ")+". Omit `archetype` to list them.",inputSchema:{type:"object",properties:{archetype:{type:"string",description:E.map(e=>e.archetype).join(" | ")+" (aliases: "+E.flatMap(e=>e.aliases??[]).join(", ")+")."}}}},{name:"lint_jsx",description:"Heuristic check of a JSX snippet for common violations \u2014 raw `<button>` / `<input>`, `color='error'` on Tag/Badge, missing aria-label, missing source.code override on stories with cell renderers (rule 34), etc.",inputSchema:{type:"object",properties:{jsx:{type:"string"}},required:["jsx"]}}],Ze=new Set(O.map(e=>e.name));function et(e=X()){let t=p.godxUiCompatibility??p.version,a=`@godxjp/ui-mcp ${p.version} (catalog for @godxjp/ui ${t})`;if(!e)return a;let n=e.source==="node_modules"?"read from node_modules at answer time":"from GODX_UI_VERSION at launch \u2014 node_modules/@godxjp/ui not resolved";return`${a} \u2014 installed @godxjp/ui ${e.version} (${n})`}function tt(e=X()){let t=e?V(e.version):null,a=V(p.version);return!e||!t||!a?null:dt(t,a)>0?`\u26A0\uFE0F SERVER OLDER THAN INSTALLED PACKAGE: this server is @godxjp/ui-mcp ${p.version}, the project has @godxjp/ui ${e.version} installed \u2014 this catalog is BEHIND the package and may be missing props and components that exist. Do not conclude from this answer that a prop is unavailable. Restart the session so the server relaunches on the installed version (run \`npx @godxjp/ui sync-rules\` first if the project's .mcp.json still pins an older @godxjp/ui-mcp).`:t.major===a.major?null:`\u26A0\uFE0F MAJOR MISMATCH: this server is @godxjp/ui-mcp ${p.version}, the project has @godxjp/ui ${e.version} installed \u2014 this catalog may describe components that do not exist in the installed package. Pin the MCP to @godxjp/ui-mcp@${e.version} (\`npx @godxjp/ui sync-rules\` updates the project's .mcp.json; a registration outside the project needs \`claude mcp remove <key>\`), then restart the agent.`}async function G(e,t){let a=await at(e,t);if(!Ze.has(e))return a;let n=X(),o=tt(n);return`${et(n)}
|
|
7981
7981
|
${o?`${o}
|
|
7982
7982
|
`:""}
|
|
7983
7983
|
${a}`}async function at(e,t){switch(e){case"list_skills":return it();case"list_primitives":return Pe(t.group,t.tier);case"list_utilities":return Tt(t.kind);case"list_patterns":return ut();case"list_anti_ai_tells":return bt(t.category);case"list_redesign_checks":return vt(t.category);case"list_audit_rules":return gt(t.category);case"list_visual_checks":return mt(t.category);case"get_anti_ai_tell":return ft(String(t.name??""));case"get_redesign_check":return yt(String(t.symptom??""));case"get_skill_section":return Le(String(t.skill??""),String(t.section??""));case"get_component":return St(String(t.name??""),t.verbose===!0);case"get_pattern":return Dt(String(t.name??""));case"get_rule":return Et(typeof t.number=="number"?t.number:void 0);case"get_vocab":return Ot(t.name==null?void 0:String(t.name));case"get_tokens":return Nt(t.category);case"list_consumer_skills":return rt();case"get_consumer_skill":return st(String(t.skill??""),String(t.section??""));case"route_consumer_task":return Oe(String(t.task??""),{consumerOnly:!0});case"draft_bug_report":return lt(t);case"check_compatibility":return ze(t.version==null?void 0:String(t.version));case"route_task":return Oe(String(t.task??""));case"suggest_primitive":return Rt(String(t.use_case??""));case"search_components":return It(String(t.query??""),t.tier);case"get_frame_coverage":return At(t.name===void 0?void 0:String(t.name));case"get_design":return nt(t.section==null?void 0:String(t.section));case"get_exemplar":return ot(t.archetype==null?"":String(t.archetype));case"lint_jsx":return zt(String(t.jsx??""));default:return`Unknown tool: ${e}`}}function nt(e){if(e===void 0||e.trim()==="")return U;let t=ke(e);if(t)return t.body;let a=j().map(n=>`- \`${n.id}\` \u2014 ${n.title}`).join(`
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@godxjp/ui-mcp",
|
|
3
|
-
"version": "33.12.
|
|
3
|
+
"version": "33.12.8",
|
|
4
4
|
"godxUiCompatibility": "33.12.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",
|