@nexus-cross/design-system 1.0.13 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/claude-rules/nexus/CLAUDE.md +85 -0
- package/claude-rules/nexus/commands/nexus-audit.md +79 -0
- package/claude-rules/nexus/commands/nexus-component-map.md +85 -0
- package/claude-rules/nexus/commands/nexus-token-check.md +68 -0
- package/claude-rules/nexus/skills/nexus-design-system/SKILL.md +92 -0
- package/cursor-rules/nexus-ui-api.mdc +824 -41
- package/cursor-rules/nexus-ui-decisions.mdc +259 -0
- package/dist/accordion.js +0 -1
- package/dist/accordion.mjs +0 -1
- package/dist/alert.js +0 -1
- package/dist/alert.mjs +0 -1
- package/dist/avatar.js +0 -1
- package/dist/avatar.mjs +0 -1
- package/dist/badge.js +0 -1
- package/dist/badge.mjs +0 -1
- package/dist/breadcrumb.js +0 -1
- package/dist/breadcrumb.mjs +0 -1
- package/dist/button.js +0 -1
- package/dist/button.mjs +0 -1
- package/dist/carousel.js +0 -1
- package/dist/carousel.mjs +0 -1
- package/dist/checkbox.js +0 -1
- package/dist/checkbox.mjs +0 -1
- package/dist/chip.js +0 -1
- package/dist/chip.mjs +0 -1
- package/dist/chunks/chunk-2Z52NPWB.js +78 -0
- package/dist/chunks/chunk-46P52MFM.mjs +56 -0
- package/dist/chunks/{chunk-X3CTJ7TD.js → chunk-4KBFVIKX.js} +41 -11
- package/dist/chunks/chunk-56ZOOQFE.mjs +514 -0
- package/dist/chunks/chunk-5ASTWFJW.js +538 -0
- package/dist/chunks/{chunk-33UFQJIO.mjs → chunk-BJMXZJWO.mjs} +16 -5
- package/dist/chunks/chunk-EILXBLEV.mjs +5 -0
- package/dist/chunks/chunk-G3RLK2HS.js +7 -0
- package/dist/chunks/{chunk-YZV6FWE7.js → chunk-JLDQNDFT.js} +16 -5
- package/dist/chunks/{chunk-K574BYHQ.js → chunk-K3CK7NTP.js} +22 -4
- package/dist/chunks/{chunk-Z4YM7LU3.mjs → chunk-PIGHBDK5.mjs} +22 -4
- package/dist/chunks/{chunk-PEIEVKD5.js → chunk-RCIBLLSF.js} +11 -12
- package/dist/chunks/{chunk-MMCA33FW.mjs → chunk-RSFLNWOM.mjs} +41 -11
- package/dist/chunks/{chunk-K2TBLM3F.mjs → chunk-THBE27U3.mjs} +11 -12
- package/dist/client-only.js +0 -1
- package/dist/client-only.mjs +0 -1
- package/dist/combobox.js +16 -0
- package/dist/combobox.mjs +3 -0
- package/dist/components/Combobox.d.ts +48 -0
- package/dist/components/Combobox.d.ts.map +1 -0
- package/dist/components/DataGrid.d.ts +44 -0
- package/dist/components/DataGrid.d.ts.map +1 -0
- package/dist/components/DataList.d.ts +3 -1
- package/dist/components/DataList.d.ts.map +1 -1
- package/dist/components/RadioGroup.d.ts +4 -0
- package/dist/components/RadioGroup.d.ts.map +1 -1
- package/dist/components/Stepper.d.ts.map +1 -1
- package/dist/components/ToggleGroup.d.ts +2 -1
- package/dist/components/ToggleGroup.d.ts.map +1 -1
- package/dist/countdown.js +0 -1
- package/dist/countdown.mjs +0 -1
- package/dist/counter.js +0 -1
- package/dist/counter.mjs +0 -1
- package/dist/data-grid.js +14 -0
- package/dist/data-grid.mjs +5 -0
- package/dist/data-list.js +2 -3
- package/dist/data-list.mjs +1 -2
- package/dist/date-picker.js +0 -1
- package/dist/date-picker.mjs +0 -1
- package/dist/divider.js +0 -1
- package/dist/divider.mjs +0 -1
- package/dist/drawer.js +0 -1
- package/dist/drawer.mjs +0 -1
- package/dist/dropdown-menu.js +0 -1
- package/dist/dropdown-menu.mjs +0 -1
- package/dist/ellipsis.js +0 -1
- package/dist/ellipsis.mjs +0 -1
- package/dist/empty-state.js +0 -1
- package/dist/empty-state.mjs +0 -1
- package/dist/error-boundary.js +0 -1
- package/dist/error-boundary.mjs +0 -1
- package/dist/hooks/useCheckDevice.js +0 -1
- package/dist/hooks/useCheckDevice.mjs +0 -1
- package/dist/hooks/useClickOutside.js +0 -1
- package/dist/hooks/useClickOutside.mjs +0 -1
- package/dist/hooks/useDraggableBottomSheet.js +0 -1
- package/dist/hooks/useDraggableBottomSheet.mjs +0 -1
- package/dist/hooks/useDraggableWindow.js +0 -1
- package/dist/hooks/useDraggableWindow.mjs +0 -1
- package/dist/hooks/useInView.js +0 -1
- package/dist/hooks/useInView.mjs +0 -1
- package/dist/hooks/useModal.js +0 -1
- package/dist/hooks/useModal.mjs +0 -1
- package/dist/image-upload.js +0 -1
- package/dist/image-upload.mjs +0 -1
- package/dist/index.d.ts +4 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +92 -88
- package/dist/index.mjs +12 -12
- package/dist/infinite-scroll.js +0 -1
- package/dist/infinite-scroll.mjs +0 -1
- package/dist/marquee.js +0 -1
- package/dist/marquee.mjs +0 -1
- package/dist/modal/index.js +11 -12
- package/dist/modal/index.mjs +2 -3
- package/dist/number-input.js +0 -1
- package/dist/number-input.mjs +0 -1
- package/dist/nx-image.js +0 -1
- package/dist/nx-image.mjs +0 -1
- package/dist/pagination.js +0 -1
- package/dist/pagination.mjs +0 -1
- package/dist/popover.js +0 -1
- package/dist/popover.mjs +0 -1
- package/dist/price-input.js +0 -1
- package/dist/price-input.mjs +0 -1
- package/dist/progress.js +0 -1
- package/dist/progress.mjs +0 -1
- package/dist/radio-group.js +5 -6
- package/dist/radio-group.mjs +1 -2
- package/dist/schemas/_all.json +308 -117
- package/dist/schemas/accordion.d.ts.map +1 -1
- package/dist/schemas/accordion.json +1 -1
- package/dist/schemas/alert.d.ts.map +1 -1
- package/dist/schemas/alert.json +1 -1
- package/dist/schemas/avatar.d.ts.map +1 -1
- package/dist/schemas/avatar.json +1 -1
- package/dist/schemas/badge.d.ts.map +1 -1
- package/dist/schemas/badge.json +1 -1
- package/dist/schemas/breadcrumb.d.ts.map +1 -1
- package/dist/schemas/breadcrumb.json +1 -1
- package/dist/schemas/button.d.ts.map +1 -1
- package/dist/schemas/button.json +1 -1
- package/dist/schemas/carousel.d.ts.map +1 -1
- package/dist/schemas/carousel.json +1 -1
- package/dist/schemas/checkBox.json +1 -1
- package/dist/schemas/checkbox.d.ts.map +1 -1
- package/dist/schemas/chip.d.ts.map +1 -1
- package/dist/schemas/chip.json +1 -1
- package/dist/schemas/client-only.d.ts.map +1 -1
- package/dist/schemas/clientOnly.json +1 -1
- package/dist/schemas/combobox.d.ts +85 -0
- package/dist/schemas/combobox.d.ts.map +1 -0
- package/dist/schemas/combobox.json +98 -0
- package/dist/schemas/comboboxOption.json +30 -0
- package/dist/schemas/countdown.d.ts.map +1 -1
- package/dist/schemas/countdown.json +1 -1
- package/dist/schemas/counter.d.ts.map +1 -1
- package/dist/schemas/counter.json +1 -1
- package/dist/schemas/data-grid.d.ts +74 -0
- package/dist/schemas/data-grid.d.ts.map +1 -0
- package/dist/schemas/data-list.d.ts.map +1 -1
- package/dist/schemas/dataGrid.json +102 -0
- package/dist/schemas/dataList.json +1 -1
- package/dist/schemas/date-picker.d.ts.map +1 -1
- package/dist/schemas/datePicker.json +1 -1
- package/dist/schemas/divider.d.ts.map +1 -1
- package/dist/schemas/divider.json +1 -1
- package/dist/schemas/drawer.d.ts.map +1 -1
- package/dist/schemas/drawer.json +1 -1
- package/dist/schemas/dropdown-menu.d.ts.map +1 -1
- package/dist/schemas/dropdownMenu.json +1 -1
- package/dist/schemas/ellipsis.d.ts.map +1 -1
- package/dist/schemas/ellipsis.json +1 -1
- package/dist/schemas/empty-state.d.ts.map +1 -1
- package/dist/schemas/emptyState.json +1 -1
- package/dist/schemas/error-boundary.d.ts.map +1 -1
- package/dist/schemas/errorBoundary.json +1 -1
- package/dist/schemas/image-upload.d.ts.map +1 -1
- package/dist/schemas/imageUpload.json +1 -1
- package/dist/schemas/index.d.ts +2 -1
- package/dist/schemas/index.d.ts.map +1 -1
- package/dist/schemas/infinite-scroll.d.ts.map +1 -1
- package/dist/schemas/infiniteScroll.json +1 -1
- package/dist/schemas/marquee.d.ts.map +1 -1
- package/dist/schemas/marquee.json +1 -1
- package/dist/schemas/modal.d.ts.map +1 -1
- package/dist/schemas/modalTemplate.json +1 -1
- package/dist/schemas/number-input.d.ts.map +1 -1
- package/dist/schemas/numberInput.json +1 -1
- package/dist/schemas/nx-image.d.ts.map +1 -1
- package/dist/schemas/nxImage.json +1 -1
- package/dist/schemas/pagination.d.ts.map +1 -1
- package/dist/schemas/pagination.json +1 -1
- package/dist/schemas/popover.d.ts.map +1 -1
- package/dist/schemas/popover.json +1 -1
- package/dist/schemas/price-input.d.ts.map +1 -1
- package/dist/schemas/priceInput.json +1 -1
- package/dist/schemas/progress.d.ts.map +1 -1
- package/dist/schemas/progress.json +1 -1
- package/dist/schemas/radio-group.d.ts +9 -0
- package/dist/schemas/radio-group.d.ts.map +1 -1
- package/dist/schemas/radioGroup.json +10 -1
- package/dist/schemas/radioItem.json +11 -0
- package/dist/schemas/select.d.ts.map +1 -1
- package/dist/schemas/select.json +1 -1
- package/dist/schemas/skeleton.d.ts.map +1 -1
- package/dist/schemas/skeleton.json +1 -1
- package/dist/schemas/slider.d.ts.map +1 -1
- package/dist/schemas/slider.json +1 -1
- package/dist/schemas/spinner.d.ts.map +1 -1
- package/dist/schemas/spinner.json +1 -1
- package/dist/schemas/stepper.d.ts.map +1 -1
- package/dist/schemas/stepper.json +1 -1
- package/dist/schemas/switch.d.ts.map +1 -1
- package/dist/schemas/switch.json +1 -1
- package/dist/schemas/tab.d.ts.map +1 -1
- package/dist/schemas/tab.json +1 -1
- package/dist/schemas/table.d.ts.map +1 -1
- package/dist/schemas/table.json +1 -1
- package/dist/schemas/tableRow.json +1 -1
- package/dist/schemas/tag-input.d.ts.map +1 -1
- package/dist/schemas/tagInput.json +1 -1
- package/dist/schemas/tdColumn.json +1 -1
- package/dist/schemas/text-area.d.ts.map +1 -1
- package/dist/schemas/text-input.d.ts +2 -2
- package/dist/schemas/text-input.d.ts.map +1 -1
- package/dist/schemas/textArea.json +1 -1
- package/dist/schemas/textInput.json +1 -1
- package/dist/schemas/toast.d.ts.map +1 -1
- package/dist/schemas/toastOptions.json +1 -1
- package/dist/schemas/toaster.json +1 -1
- package/dist/schemas/toggle-group.d.ts +6 -3
- package/dist/schemas/toggle-group.d.ts.map +1 -1
- package/dist/schemas/toggleGroup.json +9 -3
- package/dist/schemas/tooltip.d.ts.map +1 -1
- package/dist/schemas/tooltip.json +1 -1
- package/dist/schemas/virtual-scroll.d.ts.map +1 -1
- package/dist/schemas/virtualGrid.json +1 -1
- package/dist/schemas/virtualList.json +1 -1
- package/dist/schemas.js +867 -66
- package/dist/schemas.mjs +865 -66
- package/dist/select.js +0 -1
- package/dist/select.mjs +0 -1
- package/dist/skeleton.js +0 -1
- package/dist/skeleton.mjs +0 -1
- package/dist/slider.js +0 -1
- package/dist/slider.mjs +0 -1
- package/dist/spinner.js +0 -1
- package/dist/spinner.mjs +0 -1
- package/dist/stepper.js +3 -4
- package/dist/stepper.mjs +1 -2
- package/dist/styles/.generated/built.d.ts +1 -1
- package/dist/styles/.generated/built.d.ts.map +1 -1
- package/dist/styles/layer.js +2 -3
- package/dist/styles/layer.mjs +1 -2
- package/dist/styles.css +554 -51
- package/dist/styles.js +2 -3
- package/dist/styles.layered.css +554 -51
- package/dist/styles.mjs +1 -2
- package/dist/switch.js +0 -1
- package/dist/switch.mjs +0 -1
- package/dist/tab.js +0 -1
- package/dist/tab.mjs +0 -1
- package/dist/table.js +0 -1
- package/dist/table.mjs +0 -1
- package/dist/tag-input.js +0 -1
- package/dist/tag-input.mjs +0 -1
- package/dist/text-area.js +0 -1
- package/dist/text-area.mjs +0 -1
- package/dist/text-input.js +0 -1
- package/dist/text-input.mjs +0 -1
- package/dist/toast.js +0 -1
- package/dist/toast.mjs +0 -1
- package/dist/toggle-group.js +3 -4
- package/dist/toggle-group.mjs +1 -2
- package/dist/tooltip.js +0 -1
- package/dist/tooltip.mjs +0 -1
- package/dist/utils/cn.js +0 -1
- package/dist/utils/cn.mjs +0 -1
- package/dist/utils/scroll.js +0 -1
- package/dist/utils/scroll.mjs +0 -1
- package/dist/virtual-scroll.js +0 -1
- package/dist/virtual-scroll.mjs +0 -1
- package/package.json +14 -8
- package/scripts/setup-cursor-rules.cjs +164 -27
- package/dist/chunks/chunk-22ULI3BF.js +0 -21
- package/dist/chunks/chunk-6ECGMUT6.mjs +0 -5
- package/dist/chunks/chunk-CVYXRSXT.mjs +0 -8
- package/dist/chunks/chunk-I252NERB.mjs +0 -21
- package/dist/chunks/chunk-JNMCYWGY.js +0 -10
- package/dist/chunks/chunk-V35IEPRL.js +0 -7
- package/dist/components/ThemeProvider.d.ts +0 -25
- package/dist/components/ThemeProvider.d.ts.map +0 -1
- package/dist/schemas/theme-provider.d.ts +0 -36
- package/dist/schemas/theme-provider.d.ts.map +0 -1
- package/dist/schemas/themeProvider.json +0 -65
- package/dist/theme-provider.js +0 -15
- package/dist/theme-provider.mjs +0 -2
- package/dist/chunks/{chunk-CWMLTXOH.mjs → chunk-5ZVPTIL3.mjs} +1 -1
- package/dist/chunks/{chunk-HFBTS42N.js → chunk-7F4SOLAC.js} +1 -1
package/dist/schemas.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
require('./chunks/chunk-JNMCYWGY.js');
|
|
4
3
|
var zod = require('zod');
|
|
5
4
|
|
|
5
|
+
// src/schemas/breadcrumb.ts
|
|
6
6
|
zod.z.object({
|
|
7
7
|
children: zod.z.any().describe("Content to render inside the breadcrumb item (ReactNode). Can be plain text, Link, Select, or any ReactElement."),
|
|
8
8
|
className: zod.z.string().optional().describe("Additional CSS class")
|
|
@@ -13,7 +13,21 @@ var breadcrumbPropsSchema = zod.z.object({
|
|
|
13
13
|
maxItems: zod.z.number().optional().describe('Max visible items. When exceeded, middle items collapse with "\u2026"'),
|
|
14
14
|
className: zod.z.string().optional().describe("Style override for the root nav element")
|
|
15
15
|
}).describe(
|
|
16
|
-
|
|
16
|
+
`Breadcrumb \u2014 hierarchical location navigation (Home > Settings > Profile).
|
|
17
|
+
|
|
18
|
+
WHEN TO USE:
|
|
19
|
+
\u2022 Multi-level information architecture (>=3 levels deep)
|
|
20
|
+
\u2022 Hierarchical category drill-down (file system, taxonomy)
|
|
21
|
+
\u2022 Step-based linear flow \u2192 Stepper (not Breadcrumb)
|
|
22
|
+
\u2022 Tab switching \u2192 Tab
|
|
23
|
+
\u2022 Single-level navigation \u2192 page title alone
|
|
24
|
+
|
|
25
|
+
Compound pattern: use <Breadcrumb.Item> children. Each Item wraps any ReactNode (Link, Select, plain text). Use maxItems for long paths (auto-collapse with "\u2026").
|
|
26
|
+
|
|
27
|
+
ANTI-PATTERNS:
|
|
28
|
+
\u2717 Breadcrumb with 1 level \u2014 just show page title
|
|
29
|
+
\u2717 Breadcrumb with > 6 visible items \u2192 set maxItems
|
|
30
|
+
\u2717 Last item as a link (it's the current page; should be plain text)`
|
|
17
31
|
);
|
|
18
32
|
var buttonPropsSchema = zod.z.object({
|
|
19
33
|
semantic: zod.z.enum(["primary", "secondary", "normal", "danger"]).default("primary").describe(
|
|
@@ -33,7 +47,17 @@ var buttonPropsSchema = zod.z.object({
|
|
|
33
47
|
style: zod.z.any().optional().describe("Inline style (CSSProperties)"),
|
|
34
48
|
className: zod.z.string().optional().describe("Style override")
|
|
35
49
|
}).describe(
|
|
36
|
-
|
|
50
|
+
`Interactive button (always prefer over native <button>).
|
|
51
|
+
|
|
52
|
+
WHEN TO USE: any clickable action \u2014 submit, navigate (with asChild), open modal, trigger menu.
|
|
53
|
+
2-axis: semantic (color intent) \xD7 variant (visual weight). Use semantic="primary" for the page's main CTA, "danger" for destructive actions, "secondary" for sub actions, "normal" for neutral.
|
|
54
|
+
|
|
55
|
+
ANTI-PATTERNS:
|
|
56
|
+
\u2717 <button className="bg-blue-500"> \u2192 <Button semantic="primary">
|
|
57
|
+
\u2717 <a className="..."> styled as button \u2192 <Button asChild><a href="..."/></Button>
|
|
58
|
+
\u2717 Mixing variants randomly within one row \u2014 pick one per visual hierarchy level
|
|
59
|
+
\u2717 Using primary + contained for every button \u2192 only ONE primary CTA per view
|
|
60
|
+
\u2717 <Button className="!bg-red-500"> \u2192 <Button semantic="danger"> (no !important)`
|
|
37
61
|
);
|
|
38
62
|
var textInputPropsSchema = zod.z.object({
|
|
39
63
|
size: zod.z.enum(["md", "lg", "xl"]).default("md").describe("Size"),
|
|
@@ -60,7 +84,20 @@ var textInputPropsSchema = zod.z.object({
|
|
|
60
84
|
onBlur: zod.z.any().optional().describe("Blur callback"),
|
|
61
85
|
onFocus: zod.z.any().optional().describe("Focus callback"),
|
|
62
86
|
className: zod.z.string().optional().describe("Style override")
|
|
63
|
-
}).describe(
|
|
87
|
+
}).describe(
|
|
88
|
+
`Single-line text input (always prefer over native <input type="text">).
|
|
89
|
+
|
|
90
|
+
WHEN TO USE: any short text \u2014 name, email, search, URL, password.
|
|
91
|
+
Use the built-in label/description props instead of wrapping with your own <label>/<p> tags (auto-binds htmlFor/aria-describedby for accessibility).
|
|
92
|
+
For numeric input use NumberInput; for currency PriceInput; for long text TextArea; for date DatePicker.
|
|
93
|
+
|
|
94
|
+
ANTI-PATTERNS:
|
|
95
|
+
\u2717 <TextInput type="number"> \u2192 <NumberInput> (gives unit, step, \u2191\u2193 keys)
|
|
96
|
+
\u2717 <label>Email <input ...></label> + <p>helper</p> \u2192 <TextInput label="Email" description="helper">
|
|
97
|
+
\u2717 Custom red border for error \u2192 use error prop (auto aria-invalid + token color)
|
|
98
|
+
\u2717 Manual character counter \u2192 use showCount + maxLength
|
|
99
|
+
\u2717 Manual clear X button \u2192 use clearable prop`
|
|
100
|
+
);
|
|
64
101
|
var textAreaPropsSchema = zod.z.object({
|
|
65
102
|
label: zod.z.string().optional().describe("Label text above the textarea"),
|
|
66
103
|
description: zod.z.string().optional().describe("Helper/error description below the textarea"),
|
|
@@ -83,7 +120,21 @@ var textAreaPropsSchema = zod.z.object({
|
|
|
83
120
|
onBlur: zod.z.any().optional().describe("Blur callback"),
|
|
84
121
|
onFocus: zod.z.any().optional().describe("Focus callback"),
|
|
85
122
|
className: zod.z.string().optional().describe("Style override")
|
|
86
|
-
}).describe(
|
|
123
|
+
}).describe(
|
|
124
|
+
`Multi-line text input. Always prefer over native <textarea>.
|
|
125
|
+
|
|
126
|
+
WHEN TO USE:
|
|
127
|
+
\u2022 Long-form text \u2014 comments, descriptions, memos, bios
|
|
128
|
+
\u2022 Single-line input \u2192 TextInput
|
|
129
|
+
\u2022 Numeric \u2192 NumberInput
|
|
130
|
+
|
|
131
|
+
resize="auto" auto-grows with content (great for chat input). resize="none" locks size for fixed UI.
|
|
132
|
+
|
|
133
|
+
ANTI-PATTERNS:
|
|
134
|
+
\u2717 Native <textarea> + custom counter \u2192 showCount + maxLength
|
|
135
|
+
\u2717 <TextArea> for short labels \u2014 use TextInput (smaller affordance)
|
|
136
|
+
\u2717 Wrapping with custom <label>/<p> \u2192 use built-in label/description props (auto a11y binding)`
|
|
137
|
+
);
|
|
87
138
|
var selectPropsSchema = zod.z.object({
|
|
88
139
|
value: zod.z.string().optional().describe("Selected value"),
|
|
89
140
|
placeholder: zod.z.string().optional().describe("Placeholder"),
|
|
@@ -95,13 +146,75 @@ var selectPropsSchema = zod.z.object({
|
|
|
95
146
|
children: zod.z.any().describe("SelectItem list (ReactNode, required)"),
|
|
96
147
|
className: zod.z.string().optional().describe("Wrapper style"),
|
|
97
148
|
triggerClassName: zod.z.string().optional().describe("Trigger style override")
|
|
98
|
-
}).describe(
|
|
149
|
+
}).describe(
|
|
150
|
+
`Dropdown select for short option lists. Based on Radix Select. Used with SelectItem.
|
|
151
|
+
|
|
152
|
+
WHEN TO USE:
|
|
153
|
+
\u2022 Options \u2264 7, no search needed \u2192 Select
|
|
154
|
+
\u2022 Options \u2265 7 OR search needed OR async \u2192 Combobox instead
|
|
155
|
+
\u2022 Need multi-select \u2192 Combobox (multiple)
|
|
156
|
+
\u2022 Action menu (save/delete/share) \u2192 DropdownMenu (not Select; values vs actions)
|
|
157
|
+
|
|
158
|
+
ANTI-PATTERNS:
|
|
159
|
+
\u2717 Select with 20+ options \u2192 Combobox
|
|
160
|
+
\u2717 Using Select for menu items that trigger functions \u2192 DropdownMenu
|
|
161
|
+
\u2717 Manual <select> styling \u2192 Select gives consistent token styling
|
|
162
|
+
\u2717 Wrapping each SelectItem with Tooltip \u2014 instead put hint in item label`
|
|
163
|
+
);
|
|
99
164
|
var selectItemPropsSchema = zod.z.object({
|
|
100
165
|
value: zod.z.string().describe("Item value"),
|
|
101
166
|
children: zod.z.any().describe("Item content (ReactNode, required)"),
|
|
102
167
|
disabled: zod.z.boolean().optional().describe("Disabled"),
|
|
103
168
|
className: zod.z.string().optional().describe("Style override")
|
|
104
169
|
}).describe("Individual option within Select.");
|
|
170
|
+
var comboboxOptionSchema = zod.z.object({
|
|
171
|
+
value: zod.z.string().describe("Option value (unique key)"),
|
|
172
|
+
label: zod.z.any().describe("Display label (string | ReactNode)"),
|
|
173
|
+
description: zod.z.any().optional().describe("Secondary text below label (ReactNode)"),
|
|
174
|
+
disabled: zod.z.boolean().optional().describe("Disabled option")
|
|
175
|
+
}).describe("Single Combobox option.");
|
|
176
|
+
var comboboxPropsSchema = zod.z.object({
|
|
177
|
+
options: zod.z.any().describe("Available options array (ComboboxOption[], required)"),
|
|
178
|
+
value: zod.z.any().optional().describe("Selected value. string for single, string[] for multiple"),
|
|
179
|
+
defaultValue: zod.z.any().optional().describe("Initial value (uncontrolled)"),
|
|
180
|
+
onValueChange: zod.z.any().optional().describe("Value change callback. (value: string | string[]) => void"),
|
|
181
|
+
multiple: zod.z.boolean().default(false).describe("Multi-select mode. Selected values shown as chips inside input"),
|
|
182
|
+
onSearch: zod.z.any().optional().describe("Async search callback. (query: string) => void. Triggers external data fetching with debounce"),
|
|
183
|
+
searchDebounce: zod.z.number().default(250).describe("Debounce delay (ms) before onSearch fires"),
|
|
184
|
+
loading: zod.z.boolean().default(false).describe("Externally-controlled loading state. Shows spinner in input suffix"),
|
|
185
|
+
filter: zod.z.any().optional().describe("Custom client-side filter. (option, query) => boolean. Default: case-insensitive label includes match"),
|
|
186
|
+
placeholder: zod.z.string().optional().describe("Input placeholder"),
|
|
187
|
+
emptyMessage: zod.z.any().optional().describe('Message when no options match (string | ReactNode). Default: "\uAC80\uC0C9 \uACB0\uACFC \uC5C6\uC74C"'),
|
|
188
|
+
loadingMessage: zod.z.any().optional().describe('Message during loading state inside popover (string | ReactNode). Default: "\uAC80\uC0C9 \uC911\u2026"'),
|
|
189
|
+
size: zod.z.enum(["md", "lg", "xl"]).default("md").describe("Input size (matches TextInput tokens)"),
|
|
190
|
+
disabled: zod.z.boolean().optional().describe("Disabled"),
|
|
191
|
+
error: zod.z.boolean().optional().describe("Error state"),
|
|
192
|
+
clearable: zod.z.boolean().default(true).describe("Show clear button when value(s) exist"),
|
|
193
|
+
autoOpenOnFocus: zod.z.boolean().default(true).describe("Open popover automatically when input gains focus"),
|
|
194
|
+
label: zod.z.any().optional().describe("Field label (ReactNode)"),
|
|
195
|
+
description: zod.z.any().optional().describe("Helper text below input (ReactNode)"),
|
|
196
|
+
className: zod.z.string().optional().describe("Wrapper className"),
|
|
197
|
+
popoverClassName: zod.z.string().optional().describe("Popover content className")
|
|
198
|
+
}).describe(
|
|
199
|
+
`Searchable select. Text input + popover listbox. Single/multi-select. Sync (auto-filter) or async (onSearch + loading) modes.
|
|
200
|
+
|
|
201
|
+
WHEN TO USE:
|
|
202
|
+
\u2022 Options \u2265 7, OR labels are long, OR search/filter is needed \u2192 Combobox (not Select)
|
|
203
|
+
\u2022 Multi-select form field \u2192 Combobox with multiple (chips render inside input)
|
|
204
|
+
\u2022 Async data from server \u2192 set onSearch + loading
|
|
205
|
+
For \u22647 simple options use Select. For free-text tags use TagInput.
|
|
206
|
+
|
|
207
|
+
ASYNC PATTERN:
|
|
208
|
+
<Combobox options={results} loading={isFetching} onSearch={(q) => mutate(q)} />
|
|
209
|
+
\u2014 onSearch fires after searchDebounce (default 250ms). Do NOT clear input on result update; component preserves user's typing.
|
|
210
|
+
|
|
211
|
+
IME (Korean/Japanese/Chinese): Enter during composition is ignored automatically \u2014 do not add custom keydown handlers.
|
|
212
|
+
|
|
213
|
+
ANTI-PATTERNS:
|
|
214
|
+
\u2717 <Select> with 20 options \u2192 <Combobox>
|
|
215
|
+
\u2717 Manual <input> + dropdown div + filter logic \u2192 <Combobox>
|
|
216
|
+
\u2717 Setting value externally to clear input mid-typing \u2192 use onValueChange instead`
|
|
217
|
+
);
|
|
105
218
|
var dropdownMenuItemSchema = zod.z.object({
|
|
106
219
|
label: zod.z.any().describe("Menu item text (ReactNode)"),
|
|
107
220
|
value: zod.z.string().optional().describe("Item identifier"),
|
|
@@ -118,7 +231,24 @@ var dropdownMenuPropsSchema = zod.z.object({
|
|
|
118
231
|
side: zod.z.enum(["top", "right", "bottom", "left"]).default("bottom").describe("Position"),
|
|
119
232
|
className: zod.z.string().optional().describe("Trigger wrapper style"),
|
|
120
233
|
contentClassName: zod.z.string().optional().describe("Content panel style")
|
|
121
|
-
}).describe(
|
|
234
|
+
}).describe(
|
|
235
|
+
`Dropdown menu \u2014 list of actions/commands triggered by a button. Based on Radix DropdownMenu (role="menu" + keyboard nav).
|
|
236
|
+
|
|
237
|
+
WHEN TO USE:
|
|
238
|
+
\u2022 "More" / context menu (\u2022\u2022\u2022, \u22EE)
|
|
239
|
+
\u2022 Action lists where each item triggers a function (save, share, delete)
|
|
240
|
+
\u2022 Selecting a value (form field) \u2192 Select / Combobox (not DropdownMenu)
|
|
241
|
+
\u2022 Multi-select toggles \u2192 ToggleGroup or CheckBox group
|
|
242
|
+
\u2022 Anchored info panel \u2192 Popover
|
|
243
|
+
|
|
244
|
+
Use danger=true on destructive items (Delete) for visual + semantic emphasis.
|
|
245
|
+
Use separator=true to group related actions.
|
|
246
|
+
|
|
247
|
+
ANTI-PATTERNS:
|
|
248
|
+
\u2717 DropdownMenu for value selection submitted later \u2192 Select / Combobox
|
|
249
|
+
\u2717 Custom <div onClick> with isOpen state \u2192 DropdownMenu
|
|
250
|
+
\u2717 Long form inputs inside menu items \u2192 Popover instead`
|
|
251
|
+
);
|
|
122
252
|
var toggleGroupItemSchema = zod.z.object({
|
|
123
253
|
value: zod.z.string().describe("Item value"),
|
|
124
254
|
label: zod.z.any().describe("Display label (ReactNode)"),
|
|
@@ -132,12 +262,37 @@ var toggleGroupPropsSchema = zod.z.object({
|
|
|
132
262
|
value: zod.z.any().optional().describe("Controlled value (string | string[])"),
|
|
133
263
|
defaultValue: zod.z.any().optional().describe("Default value"),
|
|
134
264
|
onValueChange: zod.z.any().optional().describe("Value change callback"),
|
|
135
|
-
variant: zod.z.enum(["default", "primary", "secondary"]).default("default").describe(
|
|
265
|
+
variant: zod.z.enum(["default", "primary", "secondary", "outline"]).default("default").describe(
|
|
266
|
+
"Style variant (default=slider, primary/secondary=accent filled, outline=bordered buttons with no background)"
|
|
267
|
+
),
|
|
136
268
|
size: zod.z.enum(["sm", "md", "lg"]).default("md").describe("Size"),
|
|
269
|
+
fullWidth: zod.z.boolean().default(false).describe("Stretch the group to parent width and split items equally"),
|
|
137
270
|
disabled: zod.z.boolean().optional().describe("Disable all items"),
|
|
138
271
|
required: zod.z.boolean().default(true).describe("Prevent deselection (at least one must be selected)"),
|
|
139
272
|
className: zod.z.string().optional().describe("Style override")
|
|
140
|
-
}).describe(
|
|
273
|
+
}).describe(
|
|
274
|
+
`Toggle group / Segment control for immediate-effect option selection. Based on Radix ToggleGroup.
|
|
275
|
+
|
|
276
|
+
WHEN TO USE:
|
|
277
|
+
\u2022 Sort order, view mode (grid/list), filter chips \u2014 selection takes effect immediately
|
|
278
|
+
\u2022 Visual comparison important (icons or short labels)
|
|
279
|
+
\u2022 Form field that submits later \u2192 RadioGroup or CheckBox instead
|
|
280
|
+
\u2022 Page area switching (settings tabs) \u2192 Tab instead
|
|
281
|
+
|
|
282
|
+
VARIANTS:
|
|
283
|
+
\u2022 default \u2014 slider-style background (sleek)
|
|
284
|
+
\u2022 primary / secondary \u2014 accent-filled selected state
|
|
285
|
+
\u2022 outline \u2014 bordered buttons with no background (button-style toolbar)
|
|
286
|
+
|
|
287
|
+
fullWidth=true distributes items equally across parent width (use with outline variant for button-row look).
|
|
288
|
+
|
|
289
|
+
type="single" requires at least one selection by default (required=true). Set required=false to allow deselection.
|
|
290
|
+
|
|
291
|
+
ANTI-PATTERNS:
|
|
292
|
+
\u2717 Using ToggleGroup for content tabs \u2192 Tab
|
|
293
|
+
\u2717 Using ToggleGroup as form field submitted later \u2192 RadioGroup (semantics + a11y)
|
|
294
|
+
\u2717 Mixing icons and text labels of different sizes \u2014 keep visual rhythm consistent`
|
|
295
|
+
);
|
|
141
296
|
var sliderPropsSchema = zod.z.object({
|
|
142
297
|
value: zod.z.array(zod.z.number()).optional().describe("Controlled value (number[]). Use [50] for single, [20, 80] for range"),
|
|
143
298
|
defaultValue: zod.z.array(zod.z.number()).optional().describe("Default value"),
|
|
@@ -152,7 +307,23 @@ var sliderPropsSchema = zod.z.object({
|
|
|
152
307
|
onValueChange: zod.z.any().optional().describe("Value change callback (value: number[]) => void"),
|
|
153
308
|
onValueCommit: zod.z.any().optional().describe("Committed value callback (on pointer up)"),
|
|
154
309
|
className: zod.z.string().optional().describe("Style override")
|
|
155
|
-
}).describe(
|
|
310
|
+
}).describe(
|
|
311
|
+
`Slider \u2014 numeric range selector. Based on Radix Slider. Single thumb or range (two thumbs).
|
|
312
|
+
|
|
313
|
+
WHEN TO USE:
|
|
314
|
+
\u2022 Continuous range with visual feedback: volume, brightness, price filter
|
|
315
|
+
\u2022 Range filter (min-max) \u2192 defaultValue=[20, 80]
|
|
316
|
+
\u2022 Precise number entry \u2192 NumberInput
|
|
317
|
+
\u2022 Discrete few options \u2192 ToggleGroup or RadioGroup
|
|
318
|
+
\u2022 Boolean \u2192 Switch
|
|
319
|
+
|
|
320
|
+
step controls increments. onValueCommit fires only after pointer release (good for expensive recomputations).
|
|
321
|
+
|
|
322
|
+
ANTI-PATTERNS:
|
|
323
|
+
\u2717 Slider for required precise input (typing 47 is faster than dragging)
|
|
324
|
+
\u2717 Long step count without showValue / labels (users have no reference)
|
|
325
|
+
\u2717 Calling expensive API on every onValueChange tick \u2192 use onValueCommit`
|
|
326
|
+
);
|
|
156
327
|
var checkBoxPropsSchema = zod.z.object({
|
|
157
328
|
size: zod.z.enum(["sm", "md"]).default("md").describe("Size"),
|
|
158
329
|
shape: zod.z.enum(["square", "round"]).default("square").describe("Shape"),
|
|
@@ -168,12 +339,30 @@ var checkBoxPropsSchema = zod.z.object({
|
|
|
168
339
|
onCheckedChange: zod.z.any().optional().describe("Checked state change callback (checked: boolean) => void"),
|
|
169
340
|
onChange: zod.z.any().optional().describe("Native change event handler"),
|
|
170
341
|
className: zod.z.string().optional().describe("Style override")
|
|
171
|
-
}).describe(
|
|
342
|
+
}).describe(
|
|
343
|
+
`Checkbox for multi-select form fields. Native input-based, supports square/round shapes.
|
|
344
|
+
|
|
345
|
+
WHEN TO USE:
|
|
346
|
+
\u2022 Form field with multiple independent options (T&C agreements, multi-select filters submitted later)
|
|
347
|
+
\u2022 Tri-state (parent-child selection) \u2014 use indeterminate prop
|
|
348
|
+
\u2022 Single binary that takes effect immediately \u2192 Switch instead
|
|
349
|
+
\u2022 Many options with search \u2192 Combobox (multiple)
|
|
350
|
+
|
|
351
|
+
INDETERMINATE: set indeterminate=true when some children are checked, others not. aria-checked becomes "mixed" automatically.
|
|
352
|
+
|
|
353
|
+
ANTI-PATTERNS:
|
|
354
|
+
\u2717 <CheckBox> for "Enable dark mode" toggle \u2192 <Switch>
|
|
355
|
+
\u2717 Native <input type="checkbox"> + manual styling \u2192 <CheckBox>
|
|
356
|
+
\u2717 Forgetting indeterminate for "select all" parent`
|
|
357
|
+
);
|
|
172
358
|
var radioGroupPropsSchema = zod.z.object({
|
|
173
359
|
name: zod.z.string().describe("Form name (required)"),
|
|
174
360
|
value: zod.z.string().optional().describe("Selected value (controlled)"),
|
|
175
361
|
defaultValue: zod.z.string().optional().describe("Initial value (uncontrolled)"),
|
|
176
362
|
size: zod.z.enum(["sm", "md"]).default("md").describe("Size"),
|
|
363
|
+
variant: zod.z.enum(["default", "ring"]).default("default").describe(
|
|
364
|
+
"Visual style. default=outline circle with inner dot, ring=thick border replaces dot when checked"
|
|
365
|
+
),
|
|
177
366
|
orientation: zod.z.enum(["horizontal", "vertical"]).default("vertical").describe("Layout direction"),
|
|
178
367
|
disabled: zod.z.boolean().optional().describe("Disabled"),
|
|
179
368
|
children: zod.z.any().describe("RadioItem list (ReactNode, required)"),
|
|
@@ -181,11 +370,32 @@ var radioGroupPropsSchema = zod.z.object({
|
|
|
181
370
|
"aria-labelledby": zod.z.string().optional().describe("Accessibility label reference ID"),
|
|
182
371
|
onValueChange: zod.z.any().optional().describe("Value change callback (value: string) => void"),
|
|
183
372
|
className: zod.z.string().optional().describe("Style override")
|
|
184
|
-
}).describe(
|
|
373
|
+
}).describe(
|
|
374
|
+
`Radio group for single-choice form fields. Used with RadioItem.
|
|
375
|
+
|
|
376
|
+
WHEN TO USE:
|
|
377
|
+
\u2022 Form field where user picks ONE of small set (\u22644-7) and submits later \u2192 RadioGroup
|
|
378
|
+
\u2022 All options should be visible at once for comparison \u2192 RadioGroup (not Select)
|
|
379
|
+
\u2022 Immediate effect on selection (no submit) \u2192 ToggleGroup instead
|
|
380
|
+
\u2022 Page area switching (tabs) \u2192 Tab (not RadioGroup)
|
|
381
|
+
\u2022 Many options \u2192 Select / Combobox
|
|
382
|
+
|
|
383
|
+
VARIANTS:
|
|
384
|
+
\u2022 variant="default" \u2014 outline circle with inner dot when checked (classic)
|
|
385
|
+
\u2022 variant="ring" \u2014 thick border replaces inner dot when checked (modern, Figma "ring" style)
|
|
386
|
+
|
|
387
|
+
ANTI-PATTERNS:
|
|
388
|
+
\u2717 Using RadioGroup for tab-like content switching \u2192 Tab
|
|
389
|
+
\u2717 Using RadioGroup for immediate filters \u2192 ToggleGroup
|
|
390
|
+
\u2717 Mixing RadioGroup and ToggleGroup in same form \u2192 pick one pattern
|
|
391
|
+
\u2717 Native <input type="radio"> \u2192 RadioItem (gets a11y, focus ring, tokens)`
|
|
392
|
+
);
|
|
185
393
|
var radioItemPropsSchema = zod.z.object({
|
|
186
394
|
value: zod.z.string().describe("Item value (required)"),
|
|
187
395
|
size: zod.z.enum(["sm", "md"]).optional().describe("Size (overrides group)"),
|
|
396
|
+
variant: zod.z.enum(["default", "ring"]).optional().describe("Visual style (overrides group)"),
|
|
188
397
|
label: zod.z.any().optional().describe("Label text (ReactNode)"),
|
|
398
|
+
description: zod.z.any().optional().describe("Help text shown beneath the label (ReactNode)"),
|
|
189
399
|
children: zod.z.any().optional().describe("Label alternative content (ReactNode)"),
|
|
190
400
|
disabled: zod.z.boolean().optional().describe("Disabled"),
|
|
191
401
|
className: zod.z.string().optional().describe("Style override")
|
|
@@ -200,7 +410,20 @@ var switchPropsSchema = zod.z.object({
|
|
|
200
410
|
onCheckedChange: zod.z.any().optional().describe("Toggle state change callback (checked: boolean) => void"),
|
|
201
411
|
onChange: zod.z.any().optional().describe("Native change event handler (ChangeEvent)"),
|
|
202
412
|
className: zod.z.string().optional().describe("Style override")
|
|
203
|
-
}).describe(
|
|
413
|
+
}).describe(
|
|
414
|
+
`Toggle switch for immediate on/off binary state. Native checkbox-based, role="switch".
|
|
415
|
+
|
|
416
|
+
WHEN TO USE:
|
|
417
|
+
\u2022 Setting that takes effect immediately (notifications on/off, dark mode)
|
|
418
|
+
\u2022 Binary state with no submit step
|
|
419
|
+
\u2022 Form field submitted later \u2192 CheckBox instead (semantics: checkbox is form data)
|
|
420
|
+
\u2022 Multiple related options \u2192 CheckBox group or ToggleGroup (multiple)
|
|
421
|
+
|
|
422
|
+
ANTI-PATTERNS:
|
|
423
|
+
\u2717 <CheckBox> for "Enable notifications" toggle \u2192 <Switch>
|
|
424
|
+
\u2717 <Switch> inside form requiring submit \u2192 <CheckBox>
|
|
425
|
+
\u2717 Wrapping Switch in <label onClick> manually \u2192 use label prop or htmlFor pattern`
|
|
426
|
+
);
|
|
204
427
|
var chipPropsSchema = zod.z.object({
|
|
205
428
|
variant: zod.z.enum(["default", "filled", "outline", "accent"]).default("default").describe("Style"),
|
|
206
429
|
size: zod.z.enum(["sm", "md", "lg"]).default("md").describe("Size"),
|
|
@@ -210,7 +433,21 @@ var chipPropsSchema = zod.z.object({
|
|
|
210
433
|
onClose: zod.z.any().optional().describe("Close button click callback (e: MouseEvent) => void. Shows X button when provided"),
|
|
211
434
|
onClick: zod.z.any().optional().describe("Click event handler"),
|
|
212
435
|
className: zod.z.string().optional().describe("Style override")
|
|
213
|
-
}).describe(
|
|
436
|
+
}).describe(
|
|
437
|
+
`Chip \u2014 small interactive token for filters, tags, removable selections, status labels.
|
|
438
|
+
|
|
439
|
+
WHEN TO USE:
|
|
440
|
+
\u2022 Filter token / removable selection (set onClose for X button)
|
|
441
|
+
\u2022 Tag/category indicator
|
|
442
|
+
\u2022 Status indicator with color (variant="accent")
|
|
443
|
+
\u2022 Pure count badge \u2192 Badge instead
|
|
444
|
+
\u2022 Toggleable filter \u2192 ToggleGroup or Chip with onClick + active state
|
|
445
|
+
|
|
446
|
+
ANTI-PATTERNS:
|
|
447
|
+
\u2717 Building dismiss UI manually with custom div + X icon \u2192 use onClose prop
|
|
448
|
+
\u2717 Using Chip as a primary CTA \u2192 Button
|
|
449
|
+
\u2717 Using Chip for hover-only labels \u2192 Tooltip`
|
|
450
|
+
);
|
|
214
451
|
var badgePropsSchema = zod.z.object({
|
|
215
452
|
count: zod.z.number().optional().describe("Badge count number"),
|
|
216
453
|
max: zod.z.number().default(99).describe('Max count (shows "99+" when exceeded)'),
|
|
@@ -221,7 +458,23 @@ var badgePropsSchema = zod.z.object({
|
|
|
221
458
|
offset: zod.z.tuple([zod.z.number(), zod.z.number()]).optional().describe("Position offset [x, y] in px"),
|
|
222
459
|
children: zod.z.any().optional().describe("Anchor element to attach badge to (ReactNode)"),
|
|
223
460
|
className: zod.z.string().optional().describe("Style override")
|
|
224
|
-
}).describe(
|
|
461
|
+
}).describe(
|
|
462
|
+
`Badge \u2014 small status / count indicator overlaid on an anchor (icon, avatar, button).
|
|
463
|
+
|
|
464
|
+
WHEN TO USE:
|
|
465
|
+
\u2022 Notification count on bell icon
|
|
466
|
+
\u2022 Unread message count on inbox tab
|
|
467
|
+
\u2022 Status dot (online/offline) \u2192 dot=true
|
|
468
|
+
\u2022 Status label with text (e.g. "PRO", "NEW") \u2192 Chip variant="accent"
|
|
469
|
+
\u2022 Removable filter token \u2192 Chip with onClose
|
|
470
|
+
|
|
471
|
+
count={0} hides badge by default; pass showZero=true to keep visible.
|
|
472
|
+
|
|
473
|
+
ANTI-PATTERNS:
|
|
474
|
+
\u2717 Using Badge as standalone label without anchor \u2192 Chip
|
|
475
|
+
\u2717 count > 999 without max \u2192 ugly layout; default max=99 ("99+")
|
|
476
|
+
\u2717 Multiple badges on same anchor (visual noise)`
|
|
477
|
+
);
|
|
225
478
|
var progressPropsSchema = zod.z.object({
|
|
226
479
|
value: zod.z.number().default(0).describe("Current progress value"),
|
|
227
480
|
max: zod.z.number().default(100).describe("Maximum value"),
|
|
@@ -231,7 +484,23 @@ var progressPropsSchema = zod.z.object({
|
|
|
231
484
|
indeterminate: zod.z.boolean().default(false).describe("Indeterminate loading animation"),
|
|
232
485
|
label: zod.z.string().optional().describe("Label text above the bar"),
|
|
233
486
|
className: zod.z.string().optional().describe("Style override")
|
|
234
|
-
}).describe(
|
|
487
|
+
}).describe(
|
|
488
|
+
`Progress \u2014 linear progress bar (file upload, multi-step form, loading with known %).
|
|
489
|
+
|
|
490
|
+
WHEN TO USE:
|
|
491
|
+
\u2022 Quantifiable progress (% complete, X of Y)
|
|
492
|
+
\u2022 Unknown duration spinner \u2192 Spinner
|
|
493
|
+
\u2022 Stable component shape during load \u2192 Skeleton
|
|
494
|
+
\u2022 Step-based navigation \u2192 Stepper
|
|
495
|
+
\u2022 Indeterminate (loading without %) \u2192 set indeterminate=true
|
|
496
|
+
|
|
497
|
+
variant follows semantic colors (success when complete, danger on error).
|
|
498
|
+
|
|
499
|
+
ANTI-PATTERNS:
|
|
500
|
+
\u2717 Indeterminate Progress for short loads (<1s) \u2014 Spinner is lighter
|
|
501
|
+
\u2717 Custom <div style={{ width: x% }}> \u2192 Progress (a11y, tokens)
|
|
502
|
+
\u2717 Progress without label/showValue when % is critical info`
|
|
503
|
+
);
|
|
235
504
|
var alertPropsSchema = zod.z.object({
|
|
236
505
|
variant: zod.z.enum(["info", "success", "warning", "danger"]).default("info").describe("Alert type / color"),
|
|
237
506
|
title: zod.z.string().optional().describe("Alert title (bold)"),
|
|
@@ -241,14 +510,42 @@ var alertPropsSchema = zod.z.object({
|
|
|
241
510
|
onClose: zod.z.any().optional().describe("Close callback () => void"),
|
|
242
511
|
action: zod.z.any().optional().describe("Action area (ReactNode, e.g. Button)"),
|
|
243
512
|
className: zod.z.string().optional().describe("Style override")
|
|
244
|
-
}).describe(
|
|
513
|
+
}).describe(
|
|
514
|
+
`Alert \u2014 persistent inline notification (banner). Auto icon by variant.
|
|
515
|
+
|
|
516
|
+
WHEN TO USE:
|
|
517
|
+
\u2022 In-page status: form errors, server warnings, info banners, success confirmation
|
|
518
|
+
\u2022 Transient toast/snackbar \u2192 use a toast library, NOT Alert
|
|
519
|
+
\u2022 Modal-blocking error \u2192 Modal with semantic="danger"
|
|
520
|
+
\u2022 Inline form field error \u2192 use error/description prop on TextInput / Select / etc.
|
|
521
|
+
|
|
522
|
+
variant maps to semantic colors. closable=true gives users dismiss control. action prop reserved for inline buttons (e.g. "Retry").
|
|
523
|
+
|
|
524
|
+
ANTI-PATTERNS:
|
|
525
|
+
\u2717 Stacking 5 alerts at top of page (use one with summary)
|
|
526
|
+
\u2717 Critical destructive action confirmation in Alert \u2192 Modal
|
|
527
|
+
\u2717 Wrapping <div className="bg-red-100"> manually \u2192 Alert (a11y role + tokens)`
|
|
528
|
+
);
|
|
245
529
|
var spinnerPropsSchema = zod.z.object({
|
|
246
530
|
size: zod.z.number().default(20).describe("Size in px"),
|
|
247
531
|
color: zod.z.string().optional().describe("Color (CSS color value, default currentColor)"),
|
|
248
532
|
"aria-label": zod.z.string().default("Loading").describe("Accessibility label"),
|
|
249
533
|
style: zod.z.any().optional().describe("Inline style (CSSProperties)"),
|
|
250
534
|
className: zod.z.string().optional().describe("Color override etc.")
|
|
251
|
-
}).describe(
|
|
535
|
+
}).describe(
|
|
536
|
+
`Loading indicator (spinner). SVG-based. role="status" + aria-label built-in.
|
|
537
|
+
|
|
538
|
+
WHEN TO USE:
|
|
539
|
+
\u2022 Short loads (<1s), inline indicator (button content while submitting)
|
|
540
|
+
\u2022 Long loads with known structure \u2192 Skeleton (better perceived performance)
|
|
541
|
+
\u2022 Quantifiable progress \u2192 Progress
|
|
542
|
+
\u2022 Page-level loading boundary inside DataList/DataGrid \u2192 use their loading prop instead
|
|
543
|
+
|
|
544
|
+
ANTI-PATTERNS:
|
|
545
|
+
\u2717 Custom CSS spinning div \u2192 Spinner (a11y + tokens)
|
|
546
|
+
\u2717 Using Spinner where Skeleton fits (long loads with stable layout)
|
|
547
|
+
\u2717 Forgetting aria-label override when meaning differs from "Loading"`
|
|
548
|
+
);
|
|
252
549
|
var stepItemSchema = zod.z.object({
|
|
253
550
|
label: zod.z.string().describe("Step title"),
|
|
254
551
|
description: zod.z.string().optional().describe("Step description")
|
|
@@ -260,7 +557,23 @@ var stepperPropsSchema = zod.z.object({
|
|
|
260
557
|
orientation: zod.z.enum(["horizontal", "vertical"]).default("horizontal").describe("Layout direction"),
|
|
261
558
|
size: zod.z.enum(["sm", "md"]).default("md").describe("Size"),
|
|
262
559
|
className: zod.z.string().optional().describe("Style override")
|
|
263
|
-
}).describe(
|
|
560
|
+
}).describe(
|
|
561
|
+
`Stepper \u2014 multi-step linear flow indicator (checkout, onboarding, wizard).
|
|
562
|
+
|
|
563
|
+
WHEN TO USE:
|
|
564
|
+
\u2022 Sequential workflow with finite steps (3-7)
|
|
565
|
+
\u2022 Show user's current position in flow + completed/upcoming steps
|
|
566
|
+
\u2022 Independent navigation between unrelated sections \u2192 Tab
|
|
567
|
+
\u2022 Continuous % progress \u2192 Progress
|
|
568
|
+
\u2022 Hierarchy / location \u2192 Breadcrumb
|
|
569
|
+
|
|
570
|
+
status="error" highlights the current step with danger color when validation fails.
|
|
571
|
+
|
|
572
|
+
ANTI-PATTERNS:
|
|
573
|
+
\u2717 Stepper with 2 steps (use Progress or just navigation)
|
|
574
|
+
\u2717 Stepper with 10+ steps (overwhelming) \u2014 chunk into sub-flows
|
|
575
|
+
\u2717 Letting users skip ahead by clicking future steps (only mark completed \u2192 current is allowed)`
|
|
576
|
+
);
|
|
264
577
|
var skeletonPropsSchema = zod.z.object({
|
|
265
578
|
as: zod.z.enum(["div", "span"]).default("div").describe("Rendered tag"),
|
|
266
579
|
circle: zod.z.boolean().default(false).describe("Circle skeleton (rounded-full)"),
|
|
@@ -270,7 +583,21 @@ var skeletonPropsSchema = zod.z.object({
|
|
|
270
583
|
style: zod.z.any().optional().describe("Inline style (CSSProperties)"),
|
|
271
584
|
className: zod.z.string().optional().describe("Style override")
|
|
272
585
|
}).describe(
|
|
273
|
-
|
|
586
|
+
`Skeleton loading placeholder. Size/shape via className. With children, wraps transparently to maintain actual size.
|
|
587
|
+
|
|
588
|
+
WHEN TO USE:
|
|
589
|
+
\u2022 Long load with known component shape (cards, lists, profile headers)
|
|
590
|
+
\u2022 Reduces perceived wait time when layout is predictable
|
|
591
|
+
\u2022 Short loads (<1s) \u2192 Spinner
|
|
592
|
+
\u2022 Quantifiable progress \u2192 Progress
|
|
593
|
+
\u2022 DataList/DataGrid loading \u2192 set list={null} (uses skeletonElement prop automatically)
|
|
594
|
+
|
|
595
|
+
GOLDEN RULE: Skeleton must match the real component's shape and size. Mismatch causes layout shift.
|
|
596
|
+
|
|
597
|
+
ANTI-PATTERNS:
|
|
598
|
+
\u2717 Generic gray rectangle for everything \u2192 match real component shape
|
|
599
|
+
\u2717 Skeleton for instant loads (causes flash)
|
|
600
|
+
\u2717 Many skeletons of different shapes when component is uniform \u2192 use a single skeleton in DataList`
|
|
274
601
|
);
|
|
275
602
|
var dividerPropsSchema = zod.z.object({
|
|
276
603
|
orientation: zod.z.enum(["horizontal", "vertical"]).default("horizontal").describe("Direction"),
|
|
@@ -278,7 +605,21 @@ var dividerPropsSchema = zod.z.object({
|
|
|
278
605
|
color: zod.z.string().optional().describe("Custom color (CSS value)"),
|
|
279
606
|
style: zod.z.any().optional().describe("Inline style (CSSProperties)"),
|
|
280
607
|
className: zod.z.string().optional().describe("Style override")
|
|
281
|
-
}).describe(
|
|
608
|
+
}).describe(
|
|
609
|
+
`Divider \u2014 visual separator (horizontal/vertical line).
|
|
610
|
+
|
|
611
|
+
WHEN TO USE:
|
|
612
|
+
\u2022 Separating sections within a card / list
|
|
613
|
+
\u2022 Vertical separator between inline items (orientation="vertical")
|
|
614
|
+
\u2022 Use color prop sparingly \u2014 defaults to border-default token
|
|
615
|
+
\u2022 For grouping form sections, prefer larger spacing over Divider
|
|
616
|
+
\u2022 Tab/Accordion already provide visual separation \u2014 don't add Divider
|
|
617
|
+
|
|
618
|
+
ANTI-PATTERNS:
|
|
619
|
+
\u2717 Stacking many Dividers \u2014 increase spacing instead
|
|
620
|
+
\u2717 Using Divider as decorative line with bright color \u2192 use Tailwind border utility on container
|
|
621
|
+
\u2717 Inline <hr> with custom CSS \u2192 Divider (consistent token)`
|
|
622
|
+
);
|
|
282
623
|
var tooltipPropsSchema = zod.z.object({
|
|
283
624
|
children: zod.z.any().describe("Trigger element (ReactNode, required)"),
|
|
284
625
|
content: zod.z.any().describe("Tooltip content (ReactNode, required)"),
|
|
@@ -289,7 +630,22 @@ var tooltipPropsSchema = zod.z.object({
|
|
|
289
630
|
disabled: zod.z.boolean().default(false).describe("Disabled"),
|
|
290
631
|
className: zod.z.string().optional().describe("Content style"),
|
|
291
632
|
triggerClassName: zod.z.string().optional().describe("Trigger style")
|
|
292
|
-
}).describe(
|
|
633
|
+
}).describe(
|
|
634
|
+
`Tooltip \u2014 short text hint shown on hover/focus. Based on Radix Tooltip. Provider built-in.
|
|
635
|
+
|
|
636
|
+
WHEN TO USE:
|
|
637
|
+
\u2022 Brief explanation of an icon button or truncated label
|
|
638
|
+
\u2022 Hover-only, non-interactive content (text only)
|
|
639
|
+
\u2022 Need clickable content inside \u2192 Popover (not Tooltip)
|
|
640
|
+
\u2022 Action menu \u2192 DropdownMenu
|
|
641
|
+
\u2022 Force user attention \u2192 Modal
|
|
642
|
+
|
|
643
|
+
ANTI-PATTERNS:
|
|
644
|
+
\u2717 Buttons/links inside content \u2192 use Popover (Tooltip not focusable)
|
|
645
|
+
\u2717 Long paragraphs in tooltip \u2192 consider Popover or Drawer
|
|
646
|
+
\u2717 Tooltip on disabled buttons (won't show in some browsers) \u2014 wrap in span instead
|
|
647
|
+
\u2717 Critical info only in tooltip \u2014 duplicate visible elsewhere for mobile/touch`
|
|
648
|
+
);
|
|
293
649
|
var popoverPropsSchema = zod.z.object({
|
|
294
650
|
trigger: zod.z.any().describe("Trigger element (ReactNode, required)"),
|
|
295
651
|
side: zod.z.enum(["top", "right", "bottom", "left"]).default("bottom").describe("Position"),
|
|
@@ -302,7 +658,21 @@ var popoverPropsSchema = zod.z.object({
|
|
|
302
658
|
children: zod.z.any().optional().describe("Popover body (ReactNode)"),
|
|
303
659
|
className: zod.z.string().optional().describe("Content style"),
|
|
304
660
|
arrowClassName: zod.z.string().optional().describe("Arrow style")
|
|
305
|
-
}).describe(
|
|
661
|
+
}).describe(
|
|
662
|
+
`Popover \u2014 anchor-positioned panel with interactive content. Based on Radix Popover.
|
|
663
|
+
|
|
664
|
+
WHEN TO USE:
|
|
665
|
+
\u2022 Trigger-anchored UI with buttons, inputs, or rich content
|
|
666
|
+
\u2022 Filter/option panel near a button (not a full sidebar)
|
|
667
|
+
\u2022 Hover-only text hint \u2192 Tooltip (lighter)
|
|
668
|
+
\u2022 Action menu list \u2192 DropdownMenu (gives role=menu, keyboard nav)
|
|
669
|
+
\u2022 Decision dialog \u2192 Modal
|
|
670
|
+
|
|
671
|
+
ANTI-PATTERNS:
|
|
672
|
+
\u2717 Action lists with onClick handlers \u2192 DropdownMenu (a11y semantics)
|
|
673
|
+
\u2717 Implementing dropdown manually with Popover + custom buttons \u2192 DropdownMenu
|
|
674
|
+
\u2717 Long forms inside Popover \u2192 Drawer or Modal`
|
|
675
|
+
);
|
|
306
676
|
var accordionItemData = zod.z.object({
|
|
307
677
|
id: zod.z.string().describe("Unique ID"),
|
|
308
678
|
trigger: zod.z.any().describe("Trigger content (ReactNode)"),
|
|
@@ -320,7 +690,23 @@ var accordionPropsSchema = zod.z.object({
|
|
|
320
690
|
defaultValue: zod.z.union([zod.z.string(), zod.z.array(zod.z.string())]).optional().describe("Uncontrolled initial value"),
|
|
321
691
|
onValueChange: zod.z.any().optional().describe("Open item change callback (value: string | string[]) => void"),
|
|
322
692
|
className: zod.z.string().optional().describe("Root style")
|
|
323
|
-
}).describe(
|
|
693
|
+
}).describe(
|
|
694
|
+
`Accordion \u2014 collapsible content sections (FAQ, settings groups).
|
|
695
|
+
|
|
696
|
+
WHEN TO USE:
|
|
697
|
+
\u2022 FAQ, help docs, settings groups
|
|
698
|
+
\u2022 Long page where each section is independently scannable
|
|
699
|
+
\u2022 Hidden critical info \u2014 DO NOT bury what users always need
|
|
700
|
+
\u2022 Tab-like content switching \u2192 Tab (Accordion is for stacked, not exclusive)
|
|
701
|
+
|
|
702
|
+
type="single" + collapsible=true \u2192 all-closed allowed (recommended for FAQ).
|
|
703
|
+
type="multiple" \u2192 multiple sections open at once.
|
|
704
|
+
|
|
705
|
+
ANTI-PATTERNS:
|
|
706
|
+
\u2717 Hiding the page's primary content inside collapsed Accordion
|
|
707
|
+
\u2717 Single-section Accordion (just show the content)
|
|
708
|
+
\u2717 Custom toggle div + state \u2014 use Accordion (gets a11y, keyboard nav)`
|
|
709
|
+
);
|
|
324
710
|
var drawerDirection = zod.z.enum(["bottom", "top", "left", "right"]).default("bottom");
|
|
325
711
|
var drawerPropsSchema = zod.z.object({
|
|
326
712
|
direction: drawerDirection.describe("Direction"),
|
|
@@ -330,7 +716,23 @@ var drawerPropsSchema = zod.z.object({
|
|
|
330
716
|
modal: zod.z.boolean().optional().describe("Modal mode (default true). If false, background is interactive"),
|
|
331
717
|
shouldScaleBackground: zod.z.boolean().optional().describe("Background scale effect (default false)"),
|
|
332
718
|
children: zod.z.any().describe("Drawer sub-components (ReactNode, required)")
|
|
333
|
-
}).describe(
|
|
719
|
+
}).describe(
|
|
720
|
+
`Drawer / bottom sheet. Based on Vaul. Compound component pattern.
|
|
721
|
+
|
|
722
|
+
WHEN TO USE:
|
|
723
|
+
\u2022 Side panel for secondary action while user can still see main content (filter panel, item details)
|
|
724
|
+
\u2022 Mobile bottom sheet (direction="bottom")
|
|
725
|
+
\u2022 Force decision blocking main flow \u2192 Modal instead
|
|
726
|
+
\u2022 Inline anchor-positioned UI \u2192 Popover instead
|
|
727
|
+
|
|
728
|
+
DIRECTION: bottom (default, mobile-friendly), top, left, right.
|
|
729
|
+
dismissible=true (default) allows swipe/outside-click close. Set false for blocking flows.
|
|
730
|
+
|
|
731
|
+
ANTI-PATTERNS:
|
|
732
|
+
\u2717 Drawer for confirmation dialogs \u2192 Modal (decision-forcing)
|
|
733
|
+
\u2717 Always shouldScaleBackground \u2192 only enable for true mobile bottom-sheets
|
|
734
|
+
\u2717 Forgetting Drawer.Title \u2192 required for screen readers (a11y)`
|
|
735
|
+
);
|
|
334
736
|
var drawerContentPropsSchema = zod.z.object({
|
|
335
737
|
direction: drawerDirection.optional().describe("Direction (Context takes priority)"),
|
|
336
738
|
blur: zod.z.enum(["none", "sm", "md"]).default("none").describe("Overlay blur"),
|
|
@@ -374,7 +776,24 @@ var tabPropsSchema = zod.z.object({
|
|
|
374
776
|
className: zod.z.string().optional().describe("Root style"),
|
|
375
777
|
tabListClassName: zod.z.string().optional().describe("Tab list style"),
|
|
376
778
|
tabPanelClassName: zod.z.string().optional().describe("Tab panel style")
|
|
377
|
-
}).describe(
|
|
779
|
+
}).describe(
|
|
780
|
+
`Tab navigation \u2014 switch between content panels (settings sections, profile views).
|
|
781
|
+
|
|
782
|
+
WHEN TO USE:
|
|
783
|
+
\u2022 Page area swap where only one panel is visible at a time
|
|
784
|
+
\u2022 Mutually exclusive content with stable section labels
|
|
785
|
+
\u2022 Form field selection \u2192 RadioGroup (semantics: not navigation)
|
|
786
|
+
\u2022 Immediate filter/option toggle \u2192 ToggleGroup
|
|
787
|
+
\u2022 Stacked collapsible sections \u2192 Accordion
|
|
788
|
+
|
|
789
|
+
destroyInactive=true unmounts hidden panels (saves memory but loses state).
|
|
790
|
+
|
|
791
|
+
ANTI-PATTERNS:
|
|
792
|
+
\u2717 Tab with 1 item \u2014 just render the panel
|
|
793
|
+
\u2717 Tab with 8+ items \u2014 consider sub-routing or DropdownMenu
|
|
794
|
+
\u2717 Using Tab for form value selection \u2192 RadioGroup
|
|
795
|
+
\u2717 Custom <button> + onClick + state \u2192 Tab (a11y, keyboard, focus management)`
|
|
796
|
+
);
|
|
378
797
|
var carouselPropsSchema = zod.z.object({
|
|
379
798
|
opts: zod.z.record(zod.z.any()).optional().describe("Embla options (loop, align, etc.)"),
|
|
380
799
|
plugins: zod.z.array(zod.z.any()).optional().describe("Embla plugins"),
|
|
@@ -382,7 +801,20 @@ var carouselPropsSchema = zod.z.object({
|
|
|
382
801
|
children: zod.z.any().optional().describe("Carousel slides and sub-components (ReactNode)"),
|
|
383
802
|
className: zod.z.string().optional().describe("Style override")
|
|
384
803
|
}).describe(
|
|
385
|
-
|
|
804
|
+
`Carousel \u2014 horizontal slide gallery. Based on Embla Carousel. Compound: CarouselSlide, CarouselPrev/Next, CarouselDots.
|
|
805
|
+
|
|
806
|
+
WHEN TO USE:
|
|
807
|
+
\u2022 Hero banners, image gallery, product showcase
|
|
808
|
+
\u2022 Multi-card horizontal scroll with snap behavior
|
|
809
|
+
\u2022 Vertical scrolling list \u2192 Marquee or VirtualList (not Carousel)
|
|
810
|
+
\u2022 Critical content that must always be visible \u2014 Carousel hides slides
|
|
811
|
+
|
|
812
|
+
opts={{ loop: true, align: 'start' }} for endless loop. Add Embla autoplay plugin for auto-advance.
|
|
813
|
+
|
|
814
|
+
ANTI-PATTERNS:
|
|
815
|
+
\u2717 Critical CTA inside non-first slide (users might never scroll)
|
|
816
|
+
\u2717 Auto-advance without pause-on-hover (a11y)
|
|
817
|
+
\u2717 Manual scroll-snap div \u2192 Carousel (gets keyboard nav, indicators)`
|
|
386
818
|
);
|
|
387
819
|
var carouselSlidePropsSchema = zod.z.object({
|
|
388
820
|
className: zod.z.string().optional().describe("Slide style (use basis-1/3 etc. for multi-slide view)"),
|
|
@@ -403,7 +835,21 @@ var paginationPropsSchema = zod.z.object({
|
|
|
403
835
|
size: zod.z.enum(["sm", "md"]).default("md").describe("Size"),
|
|
404
836
|
onPageChange: zod.z.any().describe("Page change callback (page: number) => void, required"),
|
|
405
837
|
className: zod.z.string().optional().describe("<nav> style")
|
|
406
|
-
}).describe(
|
|
838
|
+
}).describe(
|
|
839
|
+
`Pagination \u2014 page-by-page navigation for long datasets.
|
|
840
|
+
|
|
841
|
+
WHEN TO USE:
|
|
842
|
+
\u2022 User needs to jump to specific pages (search results, blog archives)
|
|
843
|
+
\u2022 Total count is known and stable
|
|
844
|
+
\u2022 Continuous browsing \u2192 InfiniteScroll instead
|
|
845
|
+
\u2022 Real-time stream \u2192 InfiniteScroll
|
|
846
|
+
\u2022 Both fit \u2192 Pagination is more accessible (keyboard, deep-linkable URL)
|
|
847
|
+
|
|
848
|
+
ANTI-PATTERNS:
|
|
849
|
+
\u2717 Pagination with totalPages=1 \u2014 hide it
|
|
850
|
+
\u2717 Mixing Pagination + InfiniteScroll on same list (confusing)
|
|
851
|
+
\u2717 Custom page button divs \u2192 Pagination (a11y, edge cases like ellipsis)`
|
|
852
|
+
);
|
|
407
853
|
var avatarPropsSchema = zod.z.object({
|
|
408
854
|
src: zod.z.string().optional().describe("Image URL"),
|
|
409
855
|
alt: zod.z.string().optional().describe("Alt text"),
|
|
@@ -413,7 +859,22 @@ var avatarPropsSchema = zod.z.object({
|
|
|
413
859
|
children: zod.z.any().optional().describe("Custom image element (e.g. Next.js Image)"),
|
|
414
860
|
onImageError: zod.z.any().optional().describe("Image load error callback () => void"),
|
|
415
861
|
className: zod.z.string().optional().describe("Style override")
|
|
416
|
-
}).describe(
|
|
862
|
+
}).describe(
|
|
863
|
+
`Avatar \u2014 user/entity profile image with text fallback.
|
|
864
|
+
|
|
865
|
+
WHEN TO USE:
|
|
866
|
+
\u2022 User profiles, comment authors, team member lists, message sender icons
|
|
867
|
+
\u2022 Image fails / not provided \u2192 fallback (initials or icon) shown automatically
|
|
868
|
+
\u2022 Need optimized image (Next.js) \u2192 pass <Image> via children, omit src
|
|
869
|
+
\u2022 Larger illustration / logo \u2192 use NxImage instead
|
|
870
|
+
|
|
871
|
+
shape="square" for organization/team logos; "circle" for people (default).
|
|
872
|
+
|
|
873
|
+
ANTI-PATTERNS:
|
|
874
|
+
\u2717 <img> + manual fallback handling \u2192 Avatar (handles error)
|
|
875
|
+
\u2717 Avatar without alt for screen readers (always set alt or aria-label)
|
|
876
|
+
\u2717 Mixing avatar sizes inconsistently in a list \u2014 pick one size`
|
|
877
|
+
);
|
|
417
878
|
var counterPropsSchema = zod.z.object({
|
|
418
879
|
endValue: zod.z.number().describe("Target value (required)"),
|
|
419
880
|
startValue: zod.z.number().default(0).describe("Start value"),
|
|
@@ -425,7 +886,22 @@ var counterPropsSchema = zod.z.object({
|
|
|
425
886
|
onEnd: zod.z.any().optional().describe("Count complete callback () => void"),
|
|
426
887
|
style: zod.z.any().optional().describe("Inline style (CSSProperties)"),
|
|
427
888
|
className: zod.z.string().optional().describe("Style override")
|
|
428
|
-
}).describe(
|
|
889
|
+
}).describe(
|
|
890
|
+
`Counter \u2014 animated number tick from startValue to endValue.
|
|
891
|
+
|
|
892
|
+
WHEN TO USE:
|
|
893
|
+
\u2022 Marketing landing \u2014 "10,000+ users" KPI displays
|
|
894
|
+
\u2022 Stat dashboards (animate when value changes)
|
|
895
|
+
\u2022 Live tickers / real-time data \u2014 re-render plain text instead (Counter is one-shot animation)
|
|
896
|
+
\u2022 Currency input / editable number \u2192 NumberInput / PriceInput
|
|
897
|
+
|
|
898
|
+
triggerOnView=true delays animation until element scrolls into view (good for landing pages).
|
|
899
|
+
|
|
900
|
+
ANTI-PATTERNS:
|
|
901
|
+
\u2717 Counter for values that update frequently \u2014 animation queue conflicts
|
|
902
|
+
\u2717 Long duration on critical numbers (users wait to read)
|
|
903
|
+
\u2717 Counter without separator for large numbers (hard to read)`
|
|
904
|
+
);
|
|
429
905
|
var countdownPropsSchema = zod.z.object({
|
|
430
906
|
endTimestamp: zod.z.number().describe("End time (Unix ms, required)"),
|
|
431
907
|
separator: zod.z.any().default(":").describe("Separator (ReactNode)"),
|
|
@@ -439,7 +915,22 @@ var countdownPropsSchema = zod.z.object({
|
|
|
439
915
|
render: zod.z.any().optional().describe("Custom render function"),
|
|
440
916
|
onEnd: zod.z.any().optional().describe("Countdown end callback () => void"),
|
|
441
917
|
className: zod.z.string().optional().describe("Style override")
|
|
442
|
-
}).describe(
|
|
918
|
+
}).describe(
|
|
919
|
+
`Countdown \u2014 live timer counting down to endTimestamp (Unix ms).
|
|
920
|
+
|
|
921
|
+
WHEN TO USE:
|
|
922
|
+
\u2022 Sale ends in / event starts in / token claim window
|
|
923
|
+
\u2022 OTP / verification code expiry
|
|
924
|
+
\u2022 Counting up (since X) \u2192 not Countdown; use Counter or custom interval
|
|
925
|
+
\u2022 Persistent server time \u2192 pass server-synced endTimestamp (not Date.now offset)
|
|
926
|
+
|
|
927
|
+
showDays=false for short timers (<24h) to declutter. Use render prop for fully custom layouts.
|
|
928
|
+
|
|
929
|
+
ANTI-PATTERNS:
|
|
930
|
+
\u2717 Countdown without onEnd handler \u2014 UI stuck at 0
|
|
931
|
+
\u2717 Countdown across SSR without hydration safety \u2014 pass endTimestamp from server
|
|
932
|
+
\u2717 Updating endTimestamp every render \u2014 causes jitter`
|
|
933
|
+
);
|
|
443
934
|
var marqueePropsSchema = zod.z.object({
|
|
444
935
|
direction: zod.z.enum(["left", "right", "up", "down"]).default("left").describe("Direction"),
|
|
445
936
|
speed: zod.z.number().default(40).describe("Animation speed (seconds)"),
|
|
@@ -448,7 +939,22 @@ var marqueePropsSchema = zod.z.object({
|
|
|
448
939
|
children: zod.z.any().describe("Content to repeat (ReactNode, required)"),
|
|
449
940
|
style: zod.z.any().optional().describe("Inline style (CSSProperties)"),
|
|
450
941
|
className: zod.z.string().optional().describe("Style override")
|
|
451
|
-
}).describe(
|
|
942
|
+
}).describe(
|
|
943
|
+
`Marquee \u2014 endless scrolling content (logo strip, promo banner, news ticker).
|
|
944
|
+
|
|
945
|
+
WHEN TO USE:
|
|
946
|
+
\u2022 Logo cloud, partner brands strip, social proof
|
|
947
|
+
\u2022 Critical info that must be read \u2192 not Marquee (auto-scroll hurts a11y)
|
|
948
|
+
\u2022 Long static list \u2192 VirtualList
|
|
949
|
+
\u2022 User-paced gallery \u2192 Carousel
|
|
950
|
+
|
|
951
|
+
pauseOnHover=true is recommended whenever content is readable text.
|
|
952
|
+
|
|
953
|
+
ANTI-PATTERNS:
|
|
954
|
+
\u2717 Marquee with action buttons inside (hard to click)
|
|
955
|
+
\u2717 Fast-speed marquee on important text (unreadable, a11y violation)
|
|
956
|
+
\u2717 Multiple Marquees on same page in different directions (visual chaos)`
|
|
957
|
+
);
|
|
452
958
|
var virtualListPropsSchema = zod.z.object({
|
|
453
959
|
items: zod.z.array(zod.z.any()).describe("Data array (required)"),
|
|
454
960
|
estimateSize: zod.z.union([zod.z.number(), zod.z.any()]).describe("Estimated item height (number or (index) => number, required)"),
|
|
@@ -459,7 +965,23 @@ var virtualListPropsSchema = zod.z.object({
|
|
|
459
965
|
style: zod.z.any().optional().describe("Inline style (CSSProperties)"),
|
|
460
966
|
endReachedThreshold: zod.z.number().default(200).describe("End detection threshold (px)"),
|
|
461
967
|
onEndReached: zod.z.any().optional().describe("End reached callback () => void")
|
|
462
|
-
}).describe(
|
|
968
|
+
}).describe(
|
|
969
|
+
`VirtualList \u2014 performant rendering of huge lists (1000+ items). Based on @tanstack/react-virtual.
|
|
970
|
+
|
|
971
|
+
WHEN TO USE:
|
|
972
|
+
\u2022 Large datasets (>200 rows): chat history, transactions, logs, leaderboard
|
|
973
|
+
\u2022 Stable item height (or measurable per-item via estimateSize fn)
|
|
974
|
+
\u2022 Small list (<100 items) \u2192 DataList (much simpler API)
|
|
975
|
+
\u2022 Grid layout \u2192 VirtualGrid
|
|
976
|
+
\u2022 Server-side pagination \u2192 InfiniteScroll wrapping plain list
|
|
977
|
+
|
|
978
|
+
estimateSize is critical \u2014 wrong values cause scroll jumps. Pair with onEndReached for server pagination.
|
|
979
|
+
|
|
980
|
+
ANTI-PATTERNS:
|
|
981
|
+
\u2717 VirtualList for short lists (DataList is simpler and renders faster)
|
|
982
|
+
\u2717 Variable estimateSize for uniform items \u2014 use a single number
|
|
983
|
+
\u2717 Putting interactive overlays inside virtual rows (mounted/unmounted on scroll)`
|
|
984
|
+
);
|
|
463
985
|
var virtualGridPropsSchema = zod.z.object({
|
|
464
986
|
items: zod.z.array(zod.z.any()).describe("Data array (required)"),
|
|
465
987
|
columns: zod.z.number().describe("Column count (required)"),
|
|
@@ -471,7 +993,20 @@ var virtualGridPropsSchema = zod.z.object({
|
|
|
471
993
|
style: zod.z.any().optional().describe("Inline style (CSSProperties)"),
|
|
472
994
|
endReachedThreshold: zod.z.number().default(200).describe("End detection threshold (px)"),
|
|
473
995
|
onEndReached: zod.z.any().optional().describe("End reached callback () => void")
|
|
474
|
-
}).describe(
|
|
996
|
+
}).describe(
|
|
997
|
+
`VirtualGrid \u2014 performant grid for huge lists. Based on @tanstack/react-virtual.
|
|
998
|
+
|
|
999
|
+
WHEN TO USE:
|
|
1000
|
+
\u2022 Image gallery / card grid with 200+ items
|
|
1001
|
+
\u2022 Fixed column count (responsive via JS \u2014 recompute columns on breakpoint)
|
|
1002
|
+
\u2022 Small grid \u2192 DataGrid (no virtualization, simpler API)
|
|
1003
|
+
\u2022 Single-column list \u2192 VirtualList
|
|
1004
|
+
|
|
1005
|
+
ANTI-PATTERNS:
|
|
1006
|
+
\u2717 VirtualGrid with <50 items \u2014 DataGrid is simpler
|
|
1007
|
+
\u2717 Cards with hover-expanding height (breaks virtualization)
|
|
1008
|
+
\u2717 Forgetting to recompute columns on resize \u2192 visible empty space`
|
|
1009
|
+
);
|
|
475
1010
|
var infiniteScrollPropsSchema = zod.z.object({
|
|
476
1011
|
list: zod.z.array(zod.z.any()).nullable().describe("Current data array (required)"),
|
|
477
1012
|
totalCount: zod.z.number().optional().describe("Total count (mutually exclusive with hasMore)"),
|
|
@@ -484,7 +1019,23 @@ var infiniteScrollPropsSchema = zod.z.object({
|
|
|
484
1019
|
scrollTarget: zod.z.any().optional().describe("Scroll target element (HTMLElement | Document | MutableRefObject)"),
|
|
485
1020
|
children: zod.z.any().describe("List item rendering (ReactNode, required)"),
|
|
486
1021
|
className: zod.z.string().optional().describe("Style override")
|
|
487
|
-
}).describe(
|
|
1022
|
+
}).describe(
|
|
1023
|
+
`InfiniteScroll \u2014 auto-load more when sentinel enters viewport. Based on IntersectionObserver.
|
|
1024
|
+
|
|
1025
|
+
WHEN TO USE:
|
|
1026
|
+
\u2022 Feeds, social timelines, search-as-you-scroll
|
|
1027
|
+
\u2022 Continuous browsing where total isn't critical
|
|
1028
|
+
\u2022 Need jump-to-page \u2192 Pagination (not InfiniteScroll)
|
|
1029
|
+
\u2022 Need to render 1000s of already-loaded items efficiently \u2192 VirtualList
|
|
1030
|
+
\u2022 Combine with VirtualList for huge + paginated data
|
|
1031
|
+
|
|
1032
|
+
Pass either totalCount or hasMore (not both). handleLoadMore is required.
|
|
1033
|
+
|
|
1034
|
+
ANTI-PATTERNS:
|
|
1035
|
+
\u2717 InfiniteScroll without footer/loading element (looks broken at the bottom)
|
|
1036
|
+
\u2717 InfiniteScroll without debouncing handleLoadMore \u2014 duplicate fetches
|
|
1037
|
+
\u2717 Auto-loading critical actions in footer (links, contact) \u2014 they become unreachable`
|
|
1038
|
+
);
|
|
488
1039
|
var ellipsisPropsSchema = zod.z.object({
|
|
489
1040
|
content: zod.z.any().default("").describe("Body text (ReactNode)"),
|
|
490
1041
|
lineClamp: zod.z.number().default(2).describe("Line clamp limit"),
|
|
@@ -494,7 +1045,22 @@ var ellipsisPropsSchema = zod.z.object({
|
|
|
494
1045
|
observingEnvs: zod.z.array(zod.z.boolean()).optional().describe("Re-measure on external condition change"),
|
|
495
1046
|
onShowMoreLessClick: zod.z.any().optional().describe("Show more/less click callback () => void"),
|
|
496
1047
|
className: zod.z.string().optional().describe("Style override")
|
|
497
|
-
}).describe(
|
|
1048
|
+
}).describe(
|
|
1049
|
+
`Ellipsis \u2014 clamp long text to N lines with "show more / less" toggle.
|
|
1050
|
+
|
|
1051
|
+
WHEN TO USE:
|
|
1052
|
+
\u2022 Long descriptions in cards, comments, post previews
|
|
1053
|
+
\u2022 Single-line truncation only \u2192 CSS line-clamp utility (lighter)
|
|
1054
|
+
\u2022 Tooltip on hover for full text \u2192 Tooltip + truncate utility
|
|
1055
|
+
\u2022 Critical content that must be fully readable \u2014 don't truncate
|
|
1056
|
+
|
|
1057
|
+
triggerMore/triggerLess accept ReactNode for icons or styled buttons.
|
|
1058
|
+
|
|
1059
|
+
ANTI-PATTERNS:
|
|
1060
|
+
\u2717 Ellipsis on titles / labels \u2014 confusing UX
|
|
1061
|
+
\u2717 Always-collapsed (defaultShortened=true) for short text \u2014 measurement waste
|
|
1062
|
+
\u2717 Overriding triggerMore/Less with HTML that breaks accessibility (use button-like)`
|
|
1063
|
+
);
|
|
498
1064
|
var emptyStatePropsSchema = zod.z.object({
|
|
499
1065
|
icon: zod.z.any().optional().describe("Custom icon (ReactNode). Default inbox icon"),
|
|
500
1066
|
title: zod.z.string().optional().describe("Title text"),
|
|
@@ -503,7 +1069,22 @@ var emptyStatePropsSchema = zod.z.object({
|
|
|
503
1069
|
size: zod.z.enum(["sm", "md", "lg"]).default("md").describe("Overall size"),
|
|
504
1070
|
children: zod.z.any().optional().describe("Additional content (ReactNode)"),
|
|
505
1071
|
className: zod.z.string().optional().describe("Style override")
|
|
506
|
-
}).describe(
|
|
1072
|
+
}).describe(
|
|
1073
|
+
`EmptyState \u2014 friendly placeholder for empty lists, no search results, first-time setup.
|
|
1074
|
+
|
|
1075
|
+
WHEN TO USE:
|
|
1076
|
+
\u2022 Empty inbox / list / search results
|
|
1077
|
+
\u2022 First-time use (onboarding nudge with action button)
|
|
1078
|
+
\u2022 Loading \u2192 Skeleton/Spinner (NOT EmptyState)
|
|
1079
|
+
\u2022 Error \u2192 Alert (or pass icon + title to EmptyState only when conceptually "nothing here")
|
|
1080
|
+
|
|
1081
|
+
DataList/DataGrid have built-in noDataMessage that wraps EmptyState \u2014 use that prop instead of conditional rendering.
|
|
1082
|
+
|
|
1083
|
+
ANTI-PATTERNS:
|
|
1084
|
+
\u2717 Showing EmptyState during loading (confuses users into thinking data is missing)
|
|
1085
|
+
\u2717 EmptyState without action when user can fix it ("Create your first X" button)
|
|
1086
|
+
\u2717 Cluttered EmptyState (too much text/multiple CTAs) \u2014 keep one primary action`
|
|
1087
|
+
);
|
|
507
1088
|
var numberInputPropsSchema = zod.z.object({
|
|
508
1089
|
variant: zod.z.enum(["basic", "bind"]).default("basic").describe("Variant: basic (right chevron arrows) or bind (left/right +/- buttons)"),
|
|
509
1090
|
value: zod.z.union([zod.z.number(), zod.z.string()]).optional().describe("Current value"),
|
|
@@ -530,7 +1111,17 @@ var numberInputPropsSchema = zod.z.object({
|
|
|
530
1111
|
onFocus: zod.z.any().optional().describe("Focus callback"),
|
|
531
1112
|
className: zod.z.string().optional().describe("Style override")
|
|
532
1113
|
}).describe(
|
|
533
|
-
|
|
1114
|
+
`Number input with two variants: basic (chevron arrows) and bind (+/- buttons). Supports label, description, max display (click to fill), accelerated increment on long press. numberInputBind(ref, direction) binds acceleration to external buttons.
|
|
1115
|
+
|
|
1116
|
+
WHEN TO USE:
|
|
1117
|
+
\u2022 Any numeric field \u2014 quantity, score, age, count
|
|
1118
|
+
\u2022 Currency with thousand separators \u2192 PriceInput instead
|
|
1119
|
+
\u2022 Date / time \u2192 DatePicker instead
|
|
1120
|
+
|
|
1121
|
+
ANTI-PATTERNS:
|
|
1122
|
+
\u2717 <TextInput type="number"> \u2192 <NumberInput> (loses keyboard \u2191\u2193, step, accelerated long-press, max click)
|
|
1123
|
+
\u2717 Custom +/- buttons + <input> \u2192 variant="bind" (or numberInputBind for external)
|
|
1124
|
+
\u2717 Manual thousand separators for currency \u2192 PriceInput`
|
|
534
1125
|
);
|
|
535
1126
|
var priceInputPropsSchema = zod.z.object({
|
|
536
1127
|
size: zod.z.enum(["md", "lg", "xl"]).default("md").describe("Size"),
|
|
@@ -553,7 +1144,20 @@ var priceInputPropsSchema = zod.z.object({
|
|
|
553
1144
|
onBalanceClick: zod.z.any().optional().describe("Balance click callback (balance: string | number) => void"),
|
|
554
1145
|
className: zod.z.string().optional().describe("Style override")
|
|
555
1146
|
}).describe(
|
|
556
|
-
|
|
1147
|
+
`PriceInput \u2014 currency / amount input with prefix, suffix, balance display, click-to-fill.
|
|
1148
|
+
|
|
1149
|
+
WHEN TO USE:
|
|
1150
|
+
\u2022 Money / token amounts: payment, transfer, swap, withdraw
|
|
1151
|
+
\u2022 Need balance hint with auto-fill UX (set balance + onBalanceClick)
|
|
1152
|
+
\u2022 Pure number (count, age, score) \u2192 NumberInput
|
|
1153
|
+
\u2022 Generic text \u2192 TextInput
|
|
1154
|
+
|
|
1155
|
+
separator=true displays commas; onValueChange always returns raw value (no commas). maxBalance auto-applies error styling on overflow.
|
|
1156
|
+
|
|
1157
|
+
ANTI-PATTERNS:
|
|
1158
|
+
\u2717 <TextInput type="number"> + manual currency formatting \u2192 PriceInput
|
|
1159
|
+
\u2717 NumberInput for currency (loses prefix/suffix/balance UX)
|
|
1160
|
+
\u2717 Using string input for amounts then parseFloat \u2014 lose precision; use this component`
|
|
557
1161
|
);
|
|
558
1162
|
var dataListPropsSchema = zod.z.object({
|
|
559
1163
|
list: zod.z.array(zod.z.any()).nullable().describe("Data array to render. null = loading state (required)"),
|
|
@@ -566,7 +1170,58 @@ var dataListPropsSchema = zod.z.object({
|
|
|
566
1170
|
children: zod.z.any().describe("Item render function: ({ item, index }) => ReactNode (required)"),
|
|
567
1171
|
className: zod.z.string().optional().describe("Root element style")
|
|
568
1172
|
}).describe(
|
|
569
|
-
|
|
1173
|
+
`DataList \u2014 render-prop list that handles loading / skeleton / empty / error / data in one component. Built-in ErrorBoundary.
|
|
1174
|
+
|
|
1175
|
+
WHEN TO USE:
|
|
1176
|
+
\u2022 Any async list (<200 items) \u2014 feed, comments, dashboard rows
|
|
1177
|
+
\u2022 Pass list={null} during loading (auto-shows skeleton/spinner)
|
|
1178
|
+
\u2022 Pass list=[] for empty state (auto-shows noDataMessage)
|
|
1179
|
+
\u2022 Card grid \u2192 DataGrid (same API + columns prop)
|
|
1180
|
+
\u2022 Huge dataset \u2192 VirtualList
|
|
1181
|
+
|
|
1182
|
+
children is render fn: ({ item, index }) => ReactNode.
|
|
1183
|
+
|
|
1184
|
+
ANTI-PATTERNS:
|
|
1185
|
+
\u2717 Manual if (loading) {...} else if (!data.length) {...} chains \u2192 DataList handles all
|
|
1186
|
+
\u2717 DataList without skeletonElement when component shape is known (use Skeleton)
|
|
1187
|
+
\u2717 list=undefined (treated as data, not loading) \u2014 use null for loading`
|
|
1188
|
+
);
|
|
1189
|
+
var responsiveColumnsSchema = zod.z.object({
|
|
1190
|
+
base: zod.z.number().optional().describe("Default column count (mobile-first)"),
|
|
1191
|
+
sm: zod.z.number().optional().describe(">= 640px"),
|
|
1192
|
+
md: zod.z.number().optional().describe(">= 768px"),
|
|
1193
|
+
lg: zod.z.number().optional().describe(">= 1024px"),
|
|
1194
|
+
xl: zod.z.number().optional().describe(">= 1280px"),
|
|
1195
|
+
"2xl": zod.z.number().optional().describe(">= 1536px")
|
|
1196
|
+
});
|
|
1197
|
+
var dataGridPropsSchema = zod.z.object({
|
|
1198
|
+
list: zod.z.array(zod.z.any()).nullable().describe("Data array to render. null = loading state (required)"),
|
|
1199
|
+
columns: zod.z.union([zod.z.number(), responsiveColumnsSchema]).describe(
|
|
1200
|
+
"Column count. number = fixed | { base, sm, md, lg, xl, 2xl } = responsive (required)"
|
|
1201
|
+
),
|
|
1202
|
+
gap: zod.z.union([zod.z.number(), zod.z.string()]).optional().describe("Item gap. number = px | string = CSS value"),
|
|
1203
|
+
noDataMessage: zod.z.any().optional().describe("Message for empty array (string | ReactElement)"),
|
|
1204
|
+
errorFallback: zod.z.any().optional().describe("Fallback on error (ReactNode)"),
|
|
1205
|
+
loadingElement: zod.z.any().optional().describe("Custom loading element (default: Spinner)"),
|
|
1206
|
+
skeletonElement: zod.z.any().optional().describe("Skeleton element during loading (ReactElement)"),
|
|
1207
|
+
skeletonCount: zod.z.number().default(3).describe("Skeleton repeat count"),
|
|
1208
|
+
loading: zod.z.boolean().default(false).describe("Force loading state"),
|
|
1209
|
+
children: zod.z.any().describe("Item render function: ({ item, index }) => ReactNode (required)"),
|
|
1210
|
+
className: zod.z.string().optional().describe("Root element style")
|
|
1211
|
+
}).describe(
|
|
1212
|
+
`DataGrid \u2014 card grid version of DataList with responsive columns. Built-in ErrorBoundary, loading/skeleton/empty/error states.
|
|
1213
|
+
|
|
1214
|
+
WHEN TO USE:
|
|
1215
|
+
\u2022 Card grids: products, gallery, team members, posts
|
|
1216
|
+
\u2022 Need responsive column count \u2192 pass { base: 1, sm: 2, lg: 3, xl: 4 }
|
|
1217
|
+
\u2022 Single column / row layout \u2192 DataList
|
|
1218
|
+
\u2022 Tabular data \u2192 table component (not DataGrid)
|
|
1219
|
+
\u2022 Huge dataset \u2192 VirtualGrid
|
|
1220
|
+
|
|
1221
|
+
ANTI-PATTERNS:
|
|
1222
|
+
\u2717 Tabular data forced into card grid (use a table)
|
|
1223
|
+
\u2717 Hardcoded column count for responsive layouts \u2192 use responsive object
|
|
1224
|
+
\u2717 Manual loading/empty handling \u2192 DataGrid does it`
|
|
570
1225
|
);
|
|
571
1226
|
var animationOptionsSchema = zod.z.object({
|
|
572
1227
|
name: zod.z.string().optional().describe("Animation name"),
|
|
@@ -605,7 +1260,22 @@ var modalTemplatePropsSchema = zod.z.object({
|
|
|
605
1260
|
dimClassName: zod.z.string().optional().describe("Dim overlay style"),
|
|
606
1261
|
headerClassName: zod.z.string().optional().describe("Header area style")
|
|
607
1262
|
}).describe(
|
|
608
|
-
|
|
1263
|
+
`Modal template. All modal components must be wrapped with ModalTemplate.
|
|
1264
|
+
|
|
1265
|
+
WHEN TO USE:
|
|
1266
|
+
\u2022 Force user decision (delete confirm, submit confirm, blocking dialog)
|
|
1267
|
+
\u2022 Long form/flow that needs full attention
|
|
1268
|
+
\u2022 Side panel that doesn't block main flow \u2192 Drawer instead
|
|
1269
|
+
\u2022 Inline contextual UI \u2192 Popover instead
|
|
1270
|
+
\u2022 Short hint \u2192 Tooltip instead
|
|
1271
|
+
|
|
1272
|
+
PREFERRED API: use modal() / useModal() imperative API rather than mounting <ModalTemplate> directly. modal() handles stacking, focus return, ESC, and background scroll automatically.
|
|
1273
|
+
|
|
1274
|
+
ANTI-PATTERNS:
|
|
1275
|
+
\u2717 Custom <div className="fixed inset-0"> \u2192 modal() (loses focus trap, a11y)
|
|
1276
|
+
\u2717 Direct <ModalTemplate> mount in render tree \u2192 wrap with modal()
|
|
1277
|
+
\u2717 Modal with no title for screen readers \u2192 always pass title prop
|
|
1278
|
+
\u2717 Multiple modals stacking confusingly \u2192 use isAlone:true to close prior modals`
|
|
609
1279
|
);
|
|
610
1280
|
var modalCallSchema = zod.z.object({
|
|
611
1281
|
component: zod.z.any().describe("Modal component (required). Automatically receives close/resolve as props"),
|
|
@@ -636,24 +1306,39 @@ var errorBoundaryPropsSchema = zod.z.object({
|
|
|
636
1306
|
children: zod.z.any().describe("Child elements to wrap (ReactNode, required)"),
|
|
637
1307
|
fallback: zod.z.any().optional().describe("Fallback UI on error (ReactNode)"),
|
|
638
1308
|
onError: zod.z.any().optional().describe("Error callback (error: Error, errorInfo: ErrorInfo) => void")
|
|
639
|
-
}).describe(
|
|
1309
|
+
}).describe(
|
|
1310
|
+
`ErrorBoundary \u2014 catches render-time errors in subtree and shows fallback UI.
|
|
1311
|
+
|
|
1312
|
+
WHEN TO USE:
|
|
1313
|
+
\u2022 Wrap risky areas: third-party widgets, dynamic imports, untrusted content rendering
|
|
1314
|
+
\u2022 Async errors / promise rejections \u2192 NOT caught (use try/catch in handlers)
|
|
1315
|
+
\u2022 Per-route error wrapping \u2192 use framework's error.tsx (Next.js) where possible
|
|
1316
|
+
|
|
1317
|
+
DataList / DataGrid have ErrorBoundary built-in \u2014 don't double-wrap.
|
|
1318
|
+
|
|
1319
|
+
ANTI-PATTERNS:
|
|
1320
|
+
\u2717 ErrorBoundary at app root only \u2014 granular boundaries give better UX (one widget fails, page survives)
|
|
1321
|
+
\u2717 Showing raw Error.message in production (leak risk) \u2014 use friendly fallback
|
|
1322
|
+
\u2717 Forgetting onError logging \u2192 silent failures in production`
|
|
1323
|
+
);
|
|
640
1324
|
var clientOnlyPropsSchema = zod.z.object({
|
|
641
1325
|
children: zod.z.any().describe("Element to render only on client (ReactNode, required)"),
|
|
642
1326
|
fallback: zod.z.any().optional().describe("Fallback UI during SSR (ReactNode, default: null)")
|
|
643
|
-
}).describe(
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
1327
|
+
}).describe(
|
|
1328
|
+
`ClientOnly \u2014 defers children to client-side render, preventing SSR hydration mismatch.
|
|
1329
|
+
|
|
1330
|
+
WHEN TO USE:
|
|
1331
|
+
\u2022 Wrap components that read window/document/localStorage at render time
|
|
1332
|
+
\u2022 Components depending on browser-only APIs (IntersectionObserver eager init, geolocation)
|
|
1333
|
+
\u2022 Server-renderable content \u2192 DON'T wrap (loses SEO/SSR perf benefits)
|
|
1334
|
+
\u2022 Conditional based on data \u2192 use proper SSR-safe state instead
|
|
1335
|
+
|
|
1336
|
+
Pass fallback to avoid layout shift during hydration.
|
|
1337
|
+
|
|
1338
|
+
ANTI-PATTERNS:
|
|
1339
|
+
\u2717 Wrapping the entire page in ClientOnly (defeats SSR)
|
|
1340
|
+
\u2717 ClientOnly without fallback for above-the-fold UI (CLS)
|
|
1341
|
+
\u2717 Using ClientOnly to "fix" any hydration warning \u2014 root-cause the mismatch first`
|
|
657
1342
|
);
|
|
658
1343
|
var tablePropsSchema = zod.z.object({
|
|
659
1344
|
list: zod.z.array(zod.z.any()).nullable().describe("Data array. null/undefined = loading state (required)"),
|
|
@@ -670,14 +1355,35 @@ var tablePropsSchema = zod.z.object({
|
|
|
670
1355
|
className: zod.z.string().optional().describe("Table wrapper style"),
|
|
671
1356
|
theadClassName: zod.z.string().optional().describe("Header row style")
|
|
672
1357
|
}).describe(
|
|
673
|
-
|
|
1358
|
+
`Table \u2014 tabular data with sortable columns, skeleton/loading/empty states. Compound: TableRow + TdColumn.
|
|
1359
|
+
|
|
1360
|
+
WHEN TO USE:
|
|
1361
|
+
\u2022 Comparable structured data (financial reports, transaction history, leaderboard)
|
|
1362
|
+
\u2022 Sortable per-column \u2192 enableSorting on TdColumn
|
|
1363
|
+
\u2022 Card-style entities \u2192 DataGrid
|
|
1364
|
+
\u2022 Single-column read-only list \u2192 DataList
|
|
1365
|
+
\u2022 Huge dataset (>500 rows) \u2192 wrap with VirtualList logic or paginate
|
|
1366
|
+
|
|
1367
|
+
list={null} \u2192 loading state. list=[] \u2192 noDataMsg. children: ({ item, index }) => <TableRow>...</TableRow>.
|
|
1368
|
+
|
|
1369
|
+
ANTI-PATTERNS:
|
|
1370
|
+
\u2717 Native <table> + manual loading/empty handling \u2192 Table component
|
|
1371
|
+
\u2717 Forcing card-style data into Table (use DataGrid)
|
|
1372
|
+
\u2717 Sorting in client when server pagination is in use \u2192 server-side sort`
|
|
674
1373
|
);
|
|
675
1374
|
var tableRowPropsSchema = zod.z.object({
|
|
676
1375
|
variant: zod.z.enum(["default", "accent"]).default("default").describe("Row style"),
|
|
677
1376
|
className: zod.z.string().optional().describe("Style override"),
|
|
678
1377
|
children: zod.z.any().describe("TdColumn list (ReactNode, required)"),
|
|
679
1378
|
onClick: zod.z.any().optional().describe("Row click callback (e: MouseEvent) => void")
|
|
680
|
-
}).describe(
|
|
1379
|
+
}).describe(
|
|
1380
|
+
`TableRow \u2014 a single row inside Table. Wraps TdColumn cells.
|
|
1381
|
+
|
|
1382
|
+
WHEN TO USE:
|
|
1383
|
+
\u2022 variant="accent" highlights selected/current row
|
|
1384
|
+
\u2022 onClick for row-level navigation (e.g. open detail page)
|
|
1385
|
+
\u2022 Per-row checkbox/action \u2192 place inside a TdColumn child`
|
|
1386
|
+
);
|
|
681
1387
|
var tdColumnPropsSchema = zod.z.object({
|
|
682
1388
|
label: zod.z.any().optional().describe("Header label (ReactElement | string)"),
|
|
683
1389
|
fieldId: zod.z.string().nullable().describe("Column identifier (sort key, required)"),
|
|
@@ -695,7 +1401,20 @@ var tdColumnPropsSchema = zod.z.object({
|
|
|
695
1401
|
handleClickSort: zod.z.any().optional().describe("Sort click callback ({ index, fieldId, order }) => void"),
|
|
696
1402
|
children: zod.z.any().describe("Cell content (ReactNode, required)"),
|
|
697
1403
|
className: zod.z.string().optional().describe("Style override")
|
|
698
|
-
}).describe(
|
|
1404
|
+
}).describe(
|
|
1405
|
+
`TdColumn \u2014 table cell. Drives both <th> and <td> for the column. Provides sorting, alignment, overflow handling.
|
|
1406
|
+
|
|
1407
|
+
WHEN TO USE:
|
|
1408
|
+
\u2022 textOverflow="truncate" (default) for fixed-width columns; "wrap" for narrative
|
|
1409
|
+
\u2022 align="right" for numeric/currency columns (a11y readability)
|
|
1410
|
+
\u2022 enableSorting=true when column is sortable; supply order + handleClickSort for controlled sort
|
|
1411
|
+
\u2022 highlightKey to group columns that highlight together on hover
|
|
1412
|
+
|
|
1413
|
+
ANTI-PATTERNS:
|
|
1414
|
+
\u2717 enableSorting without handleClickSort \u2192 sort indicator is dead
|
|
1415
|
+
\u2717 align="left" for currency/number columns
|
|
1416
|
+
\u2717 Mixing text and numeric in one column without consistent align`
|
|
1417
|
+
);
|
|
699
1418
|
var toastOptionsSchema = zod.z.object({
|
|
700
1419
|
description: zod.z.any().optional().describe("Toast subtitle (ReactNode)"),
|
|
701
1420
|
duration: zod.z.number().optional().describe("Auto-dismiss duration (ms). Default 4000"),
|
|
@@ -721,7 +1440,20 @@ var toastOptionsSchema = zod.z.object({
|
|
|
721
1440
|
unstyled: zod.z.boolean().optional().describe("Remove default styles (for custom styling)"),
|
|
722
1441
|
id: zod.z.union([zod.z.string(), zod.z.number()]).optional().describe("Toast ID (for deduplication or updates)")
|
|
723
1442
|
}).describe(
|
|
724
|
-
|
|
1443
|
+
`toast() options. Used as toast(message, options) / toast.success / .error / .warning / .info / .promise / .custom(jsx).
|
|
1444
|
+
|
|
1445
|
+
WHEN TO USE TOAST:
|
|
1446
|
+
\u2022 Transient feedback after user action: "Saved", "Copied", "Network error"
|
|
1447
|
+
\u2022 Persistent in-page banner \u2192 Alert
|
|
1448
|
+
\u2022 Critical destructive confirmation \u2192 Modal (toast can be missed)
|
|
1449
|
+
\u2022 Form field error \u2192 use error/description prop on the input
|
|
1450
|
+
|
|
1451
|
+
richColors=true gives strong success/error/warning/info colors. Use action for "Undo" patterns.
|
|
1452
|
+
|
|
1453
|
+
ANTI-PATTERNS:
|
|
1454
|
+
\u2717 Toast for confirmation that user MUST acknowledge \u2192 Modal
|
|
1455
|
+
\u2717 Stacking many toasts \u2192 set visibleToasts on Toaster
|
|
1456
|
+
\u2717 Long-form content in toast (toast is for short messages)`
|
|
725
1457
|
);
|
|
726
1458
|
var toasterPropsSchema = zod.z.object({
|
|
727
1459
|
position: zod.z.enum([
|
|
@@ -743,7 +1475,17 @@ var toasterPropsSchema = zod.z.object({
|
|
|
743
1475
|
offset: zod.z.any().optional().describe("Offset from screen edge. string | number | { top, right, bottom, left }"),
|
|
744
1476
|
dir: zod.z.enum(["ltr", "rtl", "auto"]).optional().describe("Text direction")
|
|
745
1477
|
}).describe(
|
|
746
|
-
|
|
1478
|
+
`Toaster \u2014 toast container. Mount ONCE at app root. Then call toast() anywhere. Based on sonner.
|
|
1479
|
+
|
|
1480
|
+
WHEN TO USE:
|
|
1481
|
+
\u2022 Mount in app shell (layout.tsx / _app.tsx) \u2014 exactly one instance globally
|
|
1482
|
+
\u2022 Set position once here; per-toast position only when needed
|
|
1483
|
+
\u2022 Provide visibleToasts cap to avoid stacking
|
|
1484
|
+
|
|
1485
|
+
ANTI-PATTERNS:
|
|
1486
|
+
\u2717 Multiple Toasters across pages \u2014 only one global Toaster
|
|
1487
|
+
\u2717 Mounting Toaster inside conditional render \u2014 toasts vanish on remount
|
|
1488
|
+
\u2717 Forgetting Toaster mount \u2014 toast() calls do nothing`
|
|
747
1489
|
);
|
|
748
1490
|
var tagInputPropsSchema = zod.z.object({
|
|
749
1491
|
value: zod.z.array(zod.z.string()).optional().describe("Controlled tags array"),
|
|
@@ -757,7 +1499,22 @@ var tagInputPropsSchema = zod.z.object({
|
|
|
757
1499
|
description: zod.z.string().optional().describe("Helper text below input"),
|
|
758
1500
|
size: zod.z.enum(["sm", "md", "lg"]).default("md").describe("Size"),
|
|
759
1501
|
className: zod.z.string().optional().describe("Style override")
|
|
760
|
-
}).describe(
|
|
1502
|
+
}).describe(
|
|
1503
|
+
`TagInput \u2014 free-form multi-value entry (Enter to add, Backspace to remove last).
|
|
1504
|
+
|
|
1505
|
+
WHEN TO USE:
|
|
1506
|
+
\u2022 Free-form labels: skills, hashtags, email recipients, keywords
|
|
1507
|
+
\u2022 Predefined options \u2192 Combobox with multi-select (NOT TagInput)
|
|
1508
|
+
\u2022 Single value \u2192 TextInput
|
|
1509
|
+
\u2022 Limited options \u2192 Select / RadioGroup / Checkbox
|
|
1510
|
+
|
|
1511
|
+
allowDuplicates=false (default) prevents repeats. Use max to cap count.
|
|
1512
|
+
|
|
1513
|
+
ANTI-PATTERNS:
|
|
1514
|
+
\u2717 TagInput for predefined taxonomy \u2192 Combobox (controlled options)
|
|
1515
|
+
\u2717 TagInput without max for spam-prone fields
|
|
1516
|
+
\u2717 Custom comma-split string field \u2192 TagInput (proper UX + a11y)`
|
|
1517
|
+
);
|
|
761
1518
|
var nxImagePropsSchema = zod.z.object({
|
|
762
1519
|
src: zod.z.string().optional().describe("Image source URL"),
|
|
763
1520
|
alt: zod.z.string().optional().describe("Alt text"),
|
|
@@ -768,7 +1525,22 @@ var nxImagePropsSchema = zod.z.object({
|
|
|
768
1525
|
lazy: zod.z.boolean().default(true).describe('Enable lazy loading (loading="lazy")'),
|
|
769
1526
|
wrapperClassName: zod.z.string().optional().describe("Wrapper div style"),
|
|
770
1527
|
className: zod.z.string().optional().describe("Image element style")
|
|
771
|
-
}).describe(
|
|
1528
|
+
}).describe(
|
|
1529
|
+
`NxImage \u2014 lazy-loaded <img> with fallback, fixed aspect-ratio, object-fit. Always prefer over native <img>.
|
|
1530
|
+
|
|
1531
|
+
WHEN TO USE:
|
|
1532
|
+
\u2022 Content images: covers, banners, illustrations, hero images
|
|
1533
|
+
\u2022 Profile/user avatar (with text fallback) \u2192 Avatar
|
|
1534
|
+
\u2022 Background image / decorative \u2192 CSS bg-image
|
|
1535
|
+
\u2022 Need Next.js optimization \u2192 use next/image directly (NxImage doesn't optimize)
|
|
1536
|
+
|
|
1537
|
+
aspectRatio reserves space, preventing CLS (layout shift).
|
|
1538
|
+
|
|
1539
|
+
ANTI-PATTERNS:
|
|
1540
|
+
\u2717 <img> with manual onError handling \u2192 NxImage (built-in fallback)
|
|
1541
|
+
\u2717 NxImage without alt for content images (a11y violation)
|
|
1542
|
+
\u2717 NxImage without aspectRatio in fluid layouts \u2192 CLS jank`
|
|
1543
|
+
);
|
|
772
1544
|
var datePickerPropsSchema = zod.z.object({
|
|
773
1545
|
value: zod.z.any().optional().describe("Controlled date value (Date)"),
|
|
774
1546
|
defaultValue: zod.z.any().optional().describe("Default date (Date)"),
|
|
@@ -780,7 +1552,22 @@ var datePickerPropsSchema = zod.z.object({
|
|
|
780
1552
|
locale: zod.z.enum(["ko", "en"]).default("ko").describe("Calendar locale"),
|
|
781
1553
|
formatStr: zod.z.string().default("yyyy-MM-dd").describe("Date format string (date-fns format)"),
|
|
782
1554
|
className: zod.z.string().optional().describe("Style override")
|
|
783
|
-
}).describe(
|
|
1555
|
+
}).describe(
|
|
1556
|
+
`DatePicker \u2014 calendar popup for date selection. Based on react-day-picker.
|
|
1557
|
+
|
|
1558
|
+
WHEN TO USE:
|
|
1559
|
+
\u2022 Single date selection: birthday, due date, appointment
|
|
1560
|
+
\u2022 Date range \u2192 use two DatePickers with minDate/maxDate cross-bound
|
|
1561
|
+
\u2022 Time selection \u2192 not yet supported; use TextInput with type="time" + DatePicker combo
|
|
1562
|
+
\u2022 Quick relative ranges (Today/Last 7 days) \u2192 DropdownMenu of preset Buttons + DatePicker for "Custom"
|
|
1563
|
+
|
|
1564
|
+
minDate/maxDate disable out-of-range dates. locale="ko" for Korean labels.
|
|
1565
|
+
|
|
1566
|
+
ANTI-PATTERNS:
|
|
1567
|
+
\u2717 Native <input type="date"> for branded UI (inconsistent across browsers) \u2192 DatePicker
|
|
1568
|
+
\u2717 Free-text date with parsing \u2192 DatePicker (consistent UX)
|
|
1569
|
+
\u2717 DatePicker without minDate for past-date-invalid fields (e.g. booking)`
|
|
1570
|
+
);
|
|
784
1571
|
var imageUploadPropsSchema = zod.z.object({
|
|
785
1572
|
value: zod.z.string().nullable().optional().describe("Controlled image URL (string | null)"),
|
|
786
1573
|
defaultValue: zod.z.string().optional().describe("Default image URL"),
|
|
@@ -796,7 +1583,19 @@ var imageUploadPropsSchema = zod.z.object({
|
|
|
796
1583
|
size: zod.z.enum(["sm", "md", "lg"]).default("md").describe("Upload area size"),
|
|
797
1584
|
className: zod.z.string().optional().describe("Style override")
|
|
798
1585
|
}).describe(
|
|
799
|
-
|
|
1586
|
+
`ImageUpload \u2014 drag-and-drop image upload with preview, file-type/size validation, label/description.
|
|
1587
|
+
|
|
1588
|
+
WHEN TO USE:
|
|
1589
|
+
\u2022 Single image upload: avatar, cover, KYC document, post thumbnail
|
|
1590
|
+
\u2022 Multiple files / non-image \u2192 not yet supported; build custom or use a file dropzone
|
|
1591
|
+
\u2022 Inline image picker without preview \u2192 custom <input type="file">
|
|
1592
|
+
|
|
1593
|
+
accept whitelist + maxSize together cover validation. onError fires with i18n-ready string.
|
|
1594
|
+
|
|
1595
|
+
ANTI-PATTERNS:
|
|
1596
|
+
\u2717 <input type="file"> + manual preview \u2192 ImageUpload (handles drag, validation, preview)
|
|
1597
|
+
\u2717 ImageUpload without onError handler \u2192 silent failure on validation reject
|
|
1598
|
+
\u2717 Storing image as data-URL value (use File via onChange and upload to server)`
|
|
800
1599
|
);
|
|
801
1600
|
|
|
802
1601
|
exports.accordionPropsSchema = accordionPropsSchema;
|
|
@@ -812,8 +1611,11 @@ exports.carouselSlidePropsSchema = carouselSlidePropsSchema;
|
|
|
812
1611
|
exports.checkBoxPropsSchema = checkBoxPropsSchema;
|
|
813
1612
|
exports.chipPropsSchema = chipPropsSchema;
|
|
814
1613
|
exports.clientOnlyPropsSchema = clientOnlyPropsSchema;
|
|
1614
|
+
exports.comboboxOptionSchema = comboboxOptionSchema;
|
|
1615
|
+
exports.comboboxPropsSchema = comboboxPropsSchema;
|
|
815
1616
|
exports.countdownPropsSchema = countdownPropsSchema;
|
|
816
1617
|
exports.counterPropsSchema = counterPropsSchema;
|
|
1618
|
+
exports.dataGridPropsSchema = dataGridPropsSchema;
|
|
817
1619
|
exports.dataListPropsSchema = dataListPropsSchema;
|
|
818
1620
|
exports.datePickerPropsSchema = datePickerPropsSchema;
|
|
819
1621
|
exports.dividerPropsSchema = dividerPropsSchema;
|
|
@@ -854,7 +1656,6 @@ exports.tagInputPropsSchema = tagInputPropsSchema;
|
|
|
854
1656
|
exports.tdColumnPropsSchema = tdColumnPropsSchema;
|
|
855
1657
|
exports.textAreaPropsSchema = textAreaPropsSchema;
|
|
856
1658
|
exports.textInputPropsSchema = textInputPropsSchema;
|
|
857
|
-
exports.themeProviderPropsSchema = themeProviderPropsSchema;
|
|
858
1659
|
exports.toastOptionsSchema = toastOptionsSchema;
|
|
859
1660
|
exports.toasterPropsSchema = toasterPropsSchema;
|
|
860
1661
|
exports.toggleGroupPropsSchema = toggleGroupPropsSchema;
|