@godxjp/ui 28.9.0 → 28.10.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/agent/START-HERE.md +193 -0
- package/agent/anti-ai-tells.json +158 -0
- package/agent/components/Accordion.json +60 -0
- package/agent/components/AccountChip.json +59 -0
- package/agent/components/Actions.json +78 -0
- package/agent/components/Activity.json +80 -0
- package/agent/components/Affix.json +78 -0
- package/agent/components/Alert.json +65 -0
- package/agent/components/AlertDialog.json +109 -0
- package/agent/components/AlertDialogRoot.json +52 -0
- package/agent/components/Anchor.json +119 -0
- package/agent/components/AppLauncher.json +95 -0
- package/agent/components/AppProvider.json +105 -0
- package/agent/components/AppSettingPicker.json +88 -0
- package/agent/components/AppSettingToggle.json +70 -0
- package/agent/components/AppShell.json +159 -0
- package/agent/components/AreaChart.json +105 -0
- package/agent/components/AspectRatio.json +38 -0
- package/agent/components/Attachments.json +76 -0
- package/agent/components/AuthAccountSummary.json +64 -0
- package/agent/components/AuthDivider.json +35 -0
- package/agent/components/AuthFooter.json +48 -0
- package/agent/components/AuthIdentity.json +42 -0
- package/agent/components/AuthShell.json +108 -0
- package/agent/components/AuthStack.json +21 -0
- package/agent/components/Avatar.json +89 -0
- package/agent/components/Badge.json +96 -0
- package/agent/components/Banner.json +48 -0
- package/agent/components/BarChart.json +108 -0
- package/agent/components/BranchScopePicker.json +89 -0
- package/agent/components/Breadcrumb.json +54 -0
- package/agent/components/Button.json +133 -0
- package/agent/components/Calendar.json +259 -0
- package/agent/components/Callout.json +46 -0
- package/agent/components/Card.json +112 -0
- package/agent/components/CardBar.json +49 -0
- package/agent/components/CardContent.json +51 -0
- package/agent/components/Carousel.json +50 -0
- package/agent/components/Cascader.json +209 -0
- package/agent/components/CenteredShell.json +66 -0
- package/agent/components/ChatBubble.json +100 -0
- package/agent/components/ChatBubbleList.json +64 -0
- package/agent/components/ChatComposer.json +160 -0
- package/agent/components/ChatSuggestion.json +86 -0
- package/agent/components/Checkbox.json +68 -0
- package/agent/components/CheckboxGroup.json +96 -0
- package/agent/components/CodeBlock.json +64 -0
- package/agent/components/Collapsible.json +74 -0
- package/agent/components/ColorPicker.json +87 -0
- package/agent/components/Command.json +168 -0
- package/agent/components/CommandPalette.json +84 -0
- package/agent/components/CompactBarTrend.json +101 -0
- package/agent/components/Conversations.json +82 -0
- package/agent/components/CredentialReveal.json +93 -0
- package/agent/components/DataState.json +79 -0
- package/agent/components/DataTable.json +268 -0
- package/agent/components/DatePicker.json +275 -0
- package/agent/components/Descriptions.json +67 -0
- package/agent/components/Dialog.json +78 -0
- package/agent/components/DraggablePanel.json +106 -0
- package/agent/components/DropdownMenu.json +102 -0
- package/agent/components/EmptyState.json +83 -0
- package/agent/components/ErrorSurface.json +128 -0
- package/agent/components/FeatureList.json +43 -0
- package/agent/components/Field.json +64 -0
- package/agent/components/FilterBar.json +99 -0
- package/agent/components/Flex.json +153 -0
- package/agent/components/FloatButton.json +91 -0
- package/agent/components/Form.json +87 -0
- package/agent/components/FormErrors.json +51 -0
- package/agent/components/FormField.json +137 -0
- package/agent/components/FormFieldArray.json +39 -0
- package/agent/components/FormFieldControl.json +129 -0
- package/agent/components/FormRoot.json +122 -0
- package/agent/components/Heading.json +61 -0
- package/agent/components/HoverCard.json +55 -0
- package/agent/components/Icon.json +60 -0
- package/agent/components/InfiniteQueryState.json +58 -0
- package/agent/components/Input.json +122 -0
- package/agent/components/InputOTP.json +106 -0
- package/agent/components/Label.json +43 -0
- package/agent/components/LegalDocumentShell.json +102 -0
- package/agent/components/Legend.json +42 -0
- package/agent/components/LineChart.json +103 -0
- package/agent/components/Link.json +41 -0
- package/agent/components/ListRow.json +92 -0
- package/agent/components/Logo.json +85 -0
- package/agent/components/Marquee.json +91 -0
- package/agent/components/Masonry.json +82 -0
- package/agent/components/MasterDetail.json +95 -0
- package/agent/components/MegaMenu.json +120 -0
- package/agent/components/MobileShell.json +73 -0
- package/agent/components/NavList.json +63 -0
- package/agent/components/NumberInput.json +158 -0
- package/agent/components/OrgSwitcher.json +89 -0
- package/agent/components/OverlayPortalProvider.json +42 -0
- package/agent/components/PageContainer.json +181 -0
- package/agent/components/Pagination.json +132 -0
- package/agent/components/Paragraph.json +40 -0
- package/agent/components/PasswordInput.json +79 -0
- package/agent/components/PasswordStrength.json +51 -0
- package/agent/components/PermissionMatrix.json +81 -0
- package/agent/components/PieChart.json +99 -0
- package/agent/components/Popover.json +110 -0
- package/agent/components/PrefetchLink.json +65 -0
- package/agent/components/Progress.json +79 -0
- package/agent/components/Prose.json +57 -0
- package/agent/components/QrCode.json +62 -0
- package/agent/components/Radio.json +98 -0
- package/agent/components/RadioGroup.json +91 -0
- package/agent/components/RangeTimeline.json +80 -0
- package/agent/components/Rating.json +92 -0
- package/agent/components/ResizablePanel.json +69 -0
- package/agent/components/ResponsiveGrid.json +77 -0
- package/agent/components/Reveal.json +70 -0
- package/agent/components/ScrollArea.json +104 -0
- package/agent/components/SearchInput.json +98 -0
- package/agent/components/Segmented.json +96 -0
- package/agent/components/Select.json +397 -0
- package/agent/components/Separator.json +86 -0
- package/agent/components/ServiceCatalogCta.json +46 -0
- package/agent/components/ServiceLauncherCard.json +86 -0
- package/agent/components/ServiceRolePanel.json +83 -0
- package/agent/components/Sheet.json +85 -0
- package/agent/components/Sidebar.json +118 -0
- package/agent/components/Skeleton.json +57 -0
- package/agent/components/SkeletonArticle.json +71 -0
- package/agent/components/SkeletonAvatar.json +50 -0
- package/agent/components/SkeletonButton.json +57 -0
- package/agent/components/SkeletonForm.json +52 -0
- package/agent/components/SkeletonImage.json +37 -0
- package/agent/components/SkeletonInput.json +51 -0
- package/agent/components/SkeletonNode.json +42 -0
- package/agent/components/SkeletonRows.json +49 -0
- package/agent/components/SkeletonTable.json +45 -0
- package/agent/components/Slider.json +160 -0
- package/agent/components/SplitPane.json +66 -0
- package/agent/components/StatCard.json +83 -0
- package/agent/components/Steps.json +95 -0
- package/agent/components/Swatch.json +41 -0
- package/agent/components/Switch.json +81 -0
- package/agent/components/Table.json +112 -0
- package/agent/components/Tabs.json +158 -0
- package/agent/components/TagInput.json +105 -0
- package/agent/components/Text.json +201 -0
- package/agent/components/Textarea.json +126 -0
- package/agent/components/ThoughtChain.json +76 -0
- package/agent/components/Thumbnail.json +70 -0
- package/agent/components/TimePicker.json +200 -0
- package/agent/components/TimeRangePicker.json +90 -0
- package/agent/components/Timeline.json +47 -0
- package/agent/components/TimelineGrid.json +92 -0
- package/agent/components/Title.json +67 -0
- package/agent/components/Toaster.json +42 -0
- package/agent/components/Toggle.json +90 -0
- package/agent/components/ToggleGroup.json +102 -0
- package/agent/components/Toolbar.json +120 -0
- package/agent/components/Tooltip.json +110 -0
- package/agent/components/Topbar.json +83 -0
- package/agent/components/TopbarItem.json +79 -0
- package/agent/components/Transfer.json +141 -0
- package/agent/components/Tree.json +185 -0
- package/agent/components/TreeSelect.json +232 -0
- package/agent/components/TwoFactorSetup.json +79 -0
- package/agent/components/Typography.json +42 -0
- package/agent/components/Upload.json +221 -0
- package/agent/components/UploadCropDialog.json +60 -0
- package/agent/components/VisuallyHidden.json +20 -0
- package/agent/components/Welcome.json +65 -0
- package/agent/components/formatDate.json +46 -0
- package/agent/components/inertiaUpload.json +32 -0
- package/agent/components/useZodForm.json +39 -0
- package/agent/components-index.json +884 -0
- package/agent/components.json +15507 -0
- package/agent/index.json +56 -0
- package/agent/llms.txt +32 -0
- package/agent/patterns/account-recovery-settings.json +19 -0
- package/agent/patterns/async-data-state.json +20 -0
- package/agent/patterns/auth-recovery-panels.json +29 -0
- package/agent/patterns/badge-coloring.json +14 -0
- package/agent/patterns/common-fixes.json +16 -0
- package/agent/patterns/confirm-destructive.json +11 -0
- package/agent/patterns/data-table-page.json +18 -0
- package/agent/patterns/deferred-loading.json +12 -0
- package/agent/patterns/error-pages.json +28 -0
- package/agent/patterns/inertia-detail-page.json +13 -0
- package/agent/patterns/inertia-list-page.json +15 -0
- package/agent/patterns/inertia-persistent-layout.json +14 -0
- package/agent/patterns/organization-memberships.json +19 -0
- package/agent/patterns/page-sections.json +18 -0
- package/agent/patterns/settings-page-responsive.json +18 -0
- package/agent/patterns/settings-section-rows.json +23 -0
- package/agent/patterns/signup-form.json +13 -0
- package/agent/patterns/topbar-account-chip.json +18 -0
- package/agent/patterns/transactional-email.json +22 -0
- package/agent/patterns-index.json +323 -0
- package/agent/patterns.json +342 -0
- package/agent/rules.json +237 -0
- package/agent/tokens.json +8422 -0
- package/agent/vocabulary.json +198 -0
- package/dist/components/data-entry/input.js +8 -1
- package/dist/components/layout/flex.d.ts +2 -2
- package/dist/components/layout/flex.js +2 -0
- package/dist/components/ui/tag-input.d.ts +10 -0
- package/dist/components/ui/tag-input.js +35 -2
- package/dist/contracts/measurement.json +1 -1
- package/dist/i18n/messages/en.json +23 -1
- package/dist/i18n/messages/ja.json +21 -1
- package/dist/i18n/messages/vi.json +21 -1
- package/dist/props/components/data-entry.prop.d.ts +21 -2
- package/dist/props/components/layout.prop.d.ts +42 -0
- package/dist/props/registry.d.ts +9 -0
- package/dist/props/registry.js +6 -0
- package/dist/styles/card-layout.css +4 -4
- package/dist/styles/control.css +31 -2
- package/dist/styles/data-display-layout.css +1 -1
- package/dist/styles/layout.css +17 -0
- package/dist/styles/navigation-layout.css +3 -1
- package/dist/styles/shell-layout.css +2 -0
- package/dist/styles/table-layout.css +50 -9
- package/dist/tokens/components/segmented.css +5 -1
- package/dist/tokens/components/table.css +2 -1
- package/docs/COMPOSITION-VS-COMPONENT.md +41 -0
- package/docs/DESIGN-AUTHORITY.md +14 -0
- package/docs/DEVELOPMENT.md +81 -6
- package/docs/data-entry/tag-input.tsx +37 -0
- package/docs/layout/flex.tsx +40 -0
- package/docs/roadmap/website-components.md +34 -0
- package/docs/showcase/marketing-page.tsx +54 -45
- package/docs/showcase/table-pagination.tsx +88 -18
- package/docs/showcase/theme-customization.tsx +25 -2
- package/package.json +6 -4
|
@@ -0,0 +1,259 @@
|
|
|
1
|
+
{
|
|
2
|
+
"example": "import { useState } from \"react\";\nimport { Calendar } from \"@godxjp/ui/data-entry\";\nimport { ja } from \"react-day-picker/locale\";\n\n// --- Single-date example (controlled) ---\nexport function InvoiceDateCalendar() {\n const [date, setDate] = useState<Date | undefined>(new Date());\n\n return (\n <Calendar\n mode=\"single\"\n selected={date}\n onSelect={setDate}\n locale={ja}\n disabled={{ before: new Date(2024, 0, 1) }}\n footer={date ? `選択日: ${date.toLocaleDateString(\"ja-JP\")}` : \"日付を選択してください\"}\n aria-label=\"発行日カレンダー\"\n />\n );\n}\n\n// --- Range example inside a Popover (mirrors DatePicker range internals) ---\nimport { Popover, PopoverContent, PopoverTrigger } from \"@godxjp/ui/data-display\";\nimport { Button } from \"@godxjp/ui/general\";\nimport type { DateRange } from \"react-day-picker\";\n\nexport function ReportRangeFilter() {\n const [range, setRange] = useState<DateRange | undefined>();\n\n return (\n <Popover>\n <PopoverTrigger asChild>\n <Button variant=\"outline\">期間を選択</Button>\n </PopoverTrigger>\n {/* flush drops the panel's padding and width=\"auto\" lets the calendar set the measure —\n the panel's own 18rem would clip two months. Never a w-auto/p-0 utility on className:\n those are per-call-site constants no service theme can retune. */}\n <PopoverContent flush width=\"auto\" align=\"end\">\n <Calendar\n mode=\"range\"\n selected={range}\n onSelect={setRange}\n locale={ja}\n numberOfMonths={2}\n disabled={{ after: new Date() }}\n autoFocus\n />\n </PopoverContent>\n </Popover>\n );\n}",
|
|
3
|
+
"group": "data-entry",
|
|
4
|
+
"importPath": "@godxjp/ui/data-entry",
|
|
5
|
+
"name": "Calendar",
|
|
6
|
+
"props": [
|
|
7
|
+
{
|
|
8
|
+
"description": "OVERRIDE only — omit it and the calendar follows AppProvider, like every other component here. It did not always: `locale` used to arrive solely through the react-day-picker spread, so with nothing passed the library's own en-US default won and a Japanese page rendered Su Mo Tu We Th Fr Sa inside an otherwise Japanese card, with no error and no warning. Pass it to PIN one market (a booking screen that must stay Japanese wherever it is opened); the locale also decides which weekday the grid starts on, not only the labels.",
|
|
9
|
+
"name": "locale",
|
|
10
|
+
"type": "DayPickerLocale"
|
|
11
|
+
},
|
|
12
|
+
{
|
|
13
|
+
"description": "Decorate a day cell — 祝日, a booked day, a deadline. It WRAPS the library's own day button rather than replacing it: `originNode` already carries the selection state, `aria-selected`, the disabled handling and its place in the grid's roving tabindex. Write `<>{originNode}<Badge …/></>` — decorate, never rebuild, or every marker re-derives all of that and most get it wrong.",
|
|
14
|
+
"name": "cellRender",
|
|
15
|
+
"type": "(date: Date, info: { originNode: ReactNode }) => ReactNode"
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
"defaultValue": "true",
|
|
19
|
+
"description": "Rule the grid: one line between every pair of days, weekday header included (the header row is also tinted --muted). ON BY DEFAULT — with no ruling the month read as a cloud of numbers and was reported as very hard to read. Pass `bordered={false}` for floating day buttons. It is NOT a box around the calendar — that is Card's job, and the Card/popover edge is the OUTER FRAME tier. The INSIDE grid is the `--calendar-grid-border-color` knob, default `hsl(var(--border))` (L* 93.80 / 1.149:1 on the popover in light, L* 20.76 / 1.270:1 in dark) — the same tier as the frame around it, as a DataTable row rule and as the RangeTimeline grid, so the ruling can never out-weigh the surface it is drawn on. It was `hsl(var(--input) / 0.5)` (L* 78.67 / 1.738:1) through 27.6.0 and gh#730 reported that still darker than the --border every card and table uses. Retint with `--calendar-grid-border-color: hsl(var(--input) / 0.5)` for the 27.6.0 weight or `hsl(var(--input))` for the heavy line. DatePicker forwards the same prop to its popup calendar.",
|
|
20
|
+
"name": "bordered",
|
|
21
|
+
"type": "boolean"
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
"defaultValue": "\"auto\"",
|
|
25
|
+
"description": "How the grid claims horizontal space. `auto` (default) shrink-wraps to seven fixed day columns — the shape a picker popover needs, because the panel is shrink-to-fit and takes ITS width from the calendar inside it. Use `full` for an EMBEDDED calendar (a shift board, a booking month) that is the content of a Card rather than a dropdown: it stacks the months and lets the day cells share the row. Measured at a 1200px container: auto → root 248px / cells 32px; full → root 1200px / cells 168px; the DatePicker popover stays 250px either way. Do NOT reach for `className=\"w-full\"` instead — it widens the root and leaves the grid at 224px pinned left.",
|
|
26
|
+
"name": "width",
|
|
27
|
+
"type": "\"auto\" | \"full\""
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
"defaultValue": "false",
|
|
31
|
+
"description": "Footer action that jumps to the current month and selects today (single), fills the open end of the range (range) or adds today (multiple). Disabled when today is outside startMonth / endMonth or matches `disabled`.",
|
|
32
|
+
"name": "showToday",
|
|
33
|
+
"type": "boolean"
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
"defaultValue": "false",
|
|
37
|
+
"description": "Footer action that calls `onClose`.",
|
|
38
|
+
"name": "showClose",
|
|
39
|
+
"type": "boolean"
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
"description": "Called by the Close footer action.",
|
|
43
|
+
"name": "onClose",
|
|
44
|
+
"type": "() => void"
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
"description": "Selection mode. 'single' picks one day, 'multiple' picks several, 'range' picks a from/to span. Omit or set undefined for a display-only calendar with no selection.",
|
|
48
|
+
"name": "mode",
|
|
49
|
+
"type": "'single' | 'multiple' | 'range' | undefined"
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
"description": "Controlled selected value. Shape depends on mode: Date for 'single', Date[] for 'multiple', { from?: Date; to?: Date } for 'range'.",
|
|
53
|
+
"name": "selected",
|
|
54
|
+
"type": "Date | Date[] | DateRange | undefined"
|
|
55
|
+
},
|
|
56
|
+
{
|
|
57
|
+
"description": "Callback fired when the user clicks a day. Receives the new selection, the clicked date, active modifiers, and the event.",
|
|
58
|
+
"name": "onSelect",
|
|
59
|
+
"type": "(date: Date | Date[] | DateRange | undefined, triggerDate: Date, modifiers: Modifiers, e: MouseEvent) => void"
|
|
60
|
+
},
|
|
61
|
+
{
|
|
62
|
+
"description": "Uncontrolled initial month shown. For controlled month navigation use month + onMonthChange.",
|
|
63
|
+
"name": "defaultMonth",
|
|
64
|
+
"type": "Date"
|
|
65
|
+
},
|
|
66
|
+
{
|
|
67
|
+
"description": "Controlled currently-displayed month. Pair with onMonthChange to drive navigation programmatically.",
|
|
68
|
+
"name": "month",
|
|
69
|
+
"type": "Date"
|
|
70
|
+
},
|
|
71
|
+
{
|
|
72
|
+
"description": "Fired when the user navigates to a different month.",
|
|
73
|
+
"name": "onMonthChange",
|
|
74
|
+
"type": "(month: Date) => void"
|
|
75
|
+
},
|
|
76
|
+
{
|
|
77
|
+
"defaultValue": "1",
|
|
78
|
+
"description": "Number of month grids to show side-by-side.",
|
|
79
|
+
"name": "numberOfMonths",
|
|
80
|
+
"type": "number"
|
|
81
|
+
},
|
|
82
|
+
{
|
|
83
|
+
"description": "Earliest month reachable via navigation. Also constrains the dropdown range when captionLayout includes 'dropdown'.",
|
|
84
|
+
"name": "startMonth",
|
|
85
|
+
"type": "Date | undefined"
|
|
86
|
+
},
|
|
87
|
+
{
|
|
88
|
+
"description": "Latest month reachable via navigation.",
|
|
89
|
+
"name": "endMonth",
|
|
90
|
+
"type": "Date | undefined"
|
|
91
|
+
},
|
|
92
|
+
{
|
|
93
|
+
"description": "Days to disable. Accepts a Date, Date[], { before: Date }, { after: Date }, { from: Date; to: Date }, { dayOfWeek: number[] }, or an array of any of these.",
|
|
94
|
+
"name": "disabled",
|
|
95
|
+
"type": "Matcher | Matcher[] | undefined"
|
|
96
|
+
},
|
|
97
|
+
{
|
|
98
|
+
"description": "Days to hide entirely from the grid.",
|
|
99
|
+
"name": "hidden",
|
|
100
|
+
"type": "Matcher | Matcher[] | undefined"
|
|
101
|
+
},
|
|
102
|
+
{
|
|
103
|
+
"defaultValue": "true",
|
|
104
|
+
"description": "Show greyed-out days from adjacent months. godx-ui defaults this to true (overrides react-day-picker's false default).",
|
|
105
|
+
"name": "showOutsideDays",
|
|
106
|
+
"type": "boolean"
|
|
107
|
+
},
|
|
108
|
+
{
|
|
109
|
+
"defaultValue": "false",
|
|
110
|
+
"description": "Show ISO/locale week-number column on the left.",
|
|
111
|
+
"name": "showWeekNumber",
|
|
112
|
+
"type": "boolean"
|
|
113
|
+
},
|
|
114
|
+
{
|
|
115
|
+
"description": "Always render 6 weeks per month, padding with days from the next month.",
|
|
116
|
+
"name": "fixedWeeks",
|
|
117
|
+
"type": "boolean"
|
|
118
|
+
},
|
|
119
|
+
{
|
|
120
|
+
"defaultValue": "'label'",
|
|
121
|
+
"description": "Caption area layout. 'dropdown' shows month/year select dropdowns for faster large-range navigation.",
|
|
122
|
+
"name": "captionLayout",
|
|
123
|
+
"type": "'label' | 'dropdown' | 'dropdown-months' | 'dropdown-years'"
|
|
124
|
+
},
|
|
125
|
+
{
|
|
126
|
+
"description": "Day index (0=Sun) for the first column of the week grid. Overrides locale default.",
|
|
127
|
+
"name": "weekStartsOn",
|
|
128
|
+
"type": "0 | 1 | 2 | 3 | 4 | 5 | 6 | undefined"
|
|
129
|
+
},
|
|
130
|
+
{
|
|
131
|
+
"description": "Custom named modifiers applied to matched days. Pair with modifiersClassNames or modifiersStyles to style them.",
|
|
132
|
+
"name": "modifiers",
|
|
133
|
+
"type": "Record<string, Matcher | Matcher[] | undefined>"
|
|
134
|
+
},
|
|
135
|
+
{
|
|
136
|
+
"description": "CSS class names keyed by modifier name.",
|
|
137
|
+
"name": "modifiersClassNames",
|
|
138
|
+
"type": "ModifiersClassNames"
|
|
139
|
+
},
|
|
140
|
+
{
|
|
141
|
+
"description": "Content rendered below the grid as a live ARIA region. Use a string to communicate selection status to screen readers. Set it to replace the built-in showToday / showClose actions.",
|
|
142
|
+
"name": "footer",
|
|
143
|
+
"type": "React.ReactNode | string"
|
|
144
|
+
},
|
|
145
|
+
{
|
|
146
|
+
"description": "Focus the first selected day (or today) when the calendar mounts — recommended when opening inside a Popover.",
|
|
147
|
+
"name": "autoFocus",
|
|
148
|
+
"type": "boolean"
|
|
149
|
+
},
|
|
150
|
+
{
|
|
151
|
+
"description": "Override the 'today' date used for the today modifier and default navigation. Defaults to new Date().",
|
|
152
|
+
"name": "today",
|
|
153
|
+
"type": "Date"
|
|
154
|
+
},
|
|
155
|
+
{
|
|
156
|
+
"description": "Extra class added to the root wrapper element (adds to the built-in p-3 padding).",
|
|
157
|
+
"name": "className",
|
|
158
|
+
"type": "string"
|
|
159
|
+
},
|
|
160
|
+
{
|
|
161
|
+
"description": "Override individual part class names (months, weekday, day, selected, today, range_start, range_end, range_middle, disabled, outside, etc.). Merged with godx-ui defaults.",
|
|
162
|
+
"name": "classNames",
|
|
163
|
+
"type": "Partial<ClassNames>"
|
|
164
|
+
},
|
|
165
|
+
{
|
|
166
|
+
"description": "Swap out internal sub-components (Chevron is already replaced by lucide icons). Use for advanced custom rendering.",
|
|
167
|
+
"name": "components",
|
|
168
|
+
"type": "Partial<CustomComponents>"
|
|
169
|
+
},
|
|
170
|
+
{
|
|
171
|
+
"description": "Animate month-to-month navigation transitions (react-day-picker >=9.6).",
|
|
172
|
+
"name": "animate",
|
|
173
|
+
"type": "boolean"
|
|
174
|
+
},
|
|
175
|
+
{
|
|
176
|
+
"description": "'ltr' (default) or 'rtl' for right-to-left layouts.",
|
|
177
|
+
"name": "dir",
|
|
178
|
+
"type": "string"
|
|
179
|
+
},
|
|
180
|
+
{
|
|
181
|
+
"description": "aria-label on the container. Provide a meaningful label when the calendar is not described by a visible heading.",
|
|
182
|
+
"name": "aria-label",
|
|
183
|
+
"type": "string"
|
|
184
|
+
},
|
|
185
|
+
{
|
|
186
|
+
"description": "ARIA role for the container element. Use 'dialog' when rendering inside a modal Popover.",
|
|
187
|
+
"name": "role",
|
|
188
|
+
"type": "'application' | 'dialog' | undefined"
|
|
189
|
+
},
|
|
190
|
+
{
|
|
191
|
+
"description": "When true the user cannot deselect the currently selected day (mode must also be set).",
|
|
192
|
+
"name": "required",
|
|
193
|
+
"type": "boolean | undefined"
|
|
194
|
+
},
|
|
195
|
+
{
|
|
196
|
+
"description": "When numberOfMonths > 1, advance all visible months at once instead of one at a time.",
|
|
197
|
+
"name": "pagedNavigation",
|
|
198
|
+
"type": "boolean"
|
|
199
|
+
},
|
|
200
|
+
{
|
|
201
|
+
"description": "Render months newest-first (right-to-left reading order) when numberOfMonths > 1.",
|
|
202
|
+
"name": "reverseMonths",
|
|
203
|
+
"type": "boolean"
|
|
204
|
+
},
|
|
205
|
+
{
|
|
206
|
+
"description": "Hide the prev/next navigation buttons without disabling keyboard navigation.",
|
|
207
|
+
"name": "hideNavigation",
|
|
208
|
+
"type": "boolean"
|
|
209
|
+
},
|
|
210
|
+
{
|
|
211
|
+
"description": "Disable month navigation entirely (buttons hidden and keyboard navigation locked).",
|
|
212
|
+
"name": "disableNavigation",
|
|
213
|
+
"type": "boolean"
|
|
214
|
+
},
|
|
215
|
+
{
|
|
216
|
+
"description": "Hide the row of weekday abbreviation headers (Mon, Tue, ...).",
|
|
217
|
+
"name": "hideWeekdays",
|
|
218
|
+
"type": "boolean"
|
|
219
|
+
},
|
|
220
|
+
{
|
|
221
|
+
"description": "Use ISO week numbering (Monday first week, ignores weekStartsOn and firstWeekContainsDate).",
|
|
222
|
+
"name": "ISOWeek",
|
|
223
|
+
"type": "boolean"
|
|
224
|
+
}
|
|
225
|
+
],
|
|
226
|
+
"related": [
|
|
227
|
+
"DatePicker — the complete single-date form control (typeable ISO input + calendar icon + Popover). Use DatePicker instead of Calendar when you need a form-submittable field with an input box.",
|
|
228
|
+
"DatePicker — the complete date form control (typeable ISO input + calendar icon + Popover); add `range` for the two-input from/to pair. Use it instead of Calendar when you need form fields.",
|
|
229
|
+
"Popover / PopoverContent — the shell you must provide when you want Calendar inside a trigger. Pass `flush` and `width=\"auto\"` so the panel neither double-pads nor clips the grid."
|
|
230
|
+
],
|
|
231
|
+
"rules": [
|
|
232
|
+
3,
|
|
233
|
+
5,
|
|
234
|
+
6,
|
|
235
|
+
23
|
|
236
|
+
],
|
|
237
|
+
"storyPath": "data-entry/Calendar.stories.tsx",
|
|
238
|
+
"subParts": [
|
|
239
|
+
"DayButton"
|
|
240
|
+
],
|
|
241
|
+
"tagline": "A styled react-day-picker grid for picking single dates, multiple dates, or date ranges — always embed it inside a Popover for full date-picker UX; use DatePicker (add `range` for a from/to pair) instead when you need a form-submittable input. `components={{ DayButton }}` is the documented seam for marking a day (a shift, a price, a badge): import `DayButton` and its types from `@godxjp/ui/data-entry` rather than from react-day-picker, so the type is this package's copy and not a second one (gh#797).",
|
|
242
|
+
"usage": [
|
|
243
|
+
"DO set mode explicitly ('single', 'multiple', 'range') — omitting it renders a display-only grid with no selection. The value passed to selected and the argument shape of onSelect both depend on mode.",
|
|
244
|
+
"DO embed Calendar inside a Popover + PopoverContent when building a date-picker UI — `<PopoverContent flush width=\"auto\">`. `flush` drops the panel padding (Calendar brings its own) and `width=\"auto\"` lets the calendar set the measure, which the panel's own 18rem would otherwise clip at two months. For form-submittable single-date or range inputs prefer the higher-level DatePicker (with `range` for a from/to pair) — it owns the input, icon, locale wiring, and ISO form submission natively.",
|
|
245
|
+
"DO pass a locale object imported from 'react-day-picker/locale' (e.g. import { ja } from 'react-day-picker/locale') for i18n — weekday names, month names, and first-day-of-week all come from the locale.",
|
|
246
|
+
"DO use the disabled prop with Matcher objects ({ before: minDate }, { after: maxDate }, { dayOfWeek: [0, 6] }) to restrict selectable days — never render your own disabled overlay on top.",
|
|
247
|
+
"DON'T zero the panel padding or pin its width with utilities on className. Those are per-call-site constants no service theme can retune; `flush` and `width=\"auto\"` set the same two tokens the panel already reads.",
|
|
248
|
+
"DON'T hand-roll a calendar grid — Calendar wraps react-day-picker which is keyboard-navigable, ARIA-annotated, and screen-reader friendly out of the box. Provide a footer string for screen-reader status announcements when the selection changes.",
|
|
249
|
+
"The month frame is two knobs, not a stack of them (gh#730). `--calendar-space-inset` is the ONE inset the caption row, the `‹`/`›` nav buttons and the day grid all sit at — `--calendar-nav-space-inline` is declared as that same value, because the nav is absolutely positioned and would otherwise get its own (measured 4px against the grid's 12px, so the header read wider than the body). `--calendar-grid-space-block-start` is the ONE caption→weekday-row step (space-3, 12px; it used to stack with the month column gap for 32px). Retune those tokens rather than adding padding on the call site."
|
|
250
|
+
],
|
|
251
|
+
"useCases": [
|
|
252
|
+
"Inline date picker within a form section where the calendar grid must always be visible (e.g., a booking page or a date-of-issue field on an invoice creation form).",
|
|
253
|
+
"Date range selection inside a Popover triggered by a filter button on an accounting report page (use mode='range', pass selected={dateRange}, onSelect updates the filter state).",
|
|
254
|
+
"Multi-date selection for picking recurring reminder dates or batch-action target dates (mode='multiple').",
|
|
255
|
+
"Custom calendar with highlighted days (e.g., marking invoice due dates or shipment ETDs with a custom modifier + modifiersClassNames) overlaid on a standard single-select grid.",
|
|
256
|
+
"Month navigator with year/month dropdowns for jumping to a historical accounting period quickly (captionLayout='dropdown', startMonth set to earliest fiscal year).",
|
|
257
|
+
"Display-only calendar (no mode set) showing booked or blocked dates using the modifiers prop with read-only styling, embedded in a dashboard card."
|
|
258
|
+
]
|
|
259
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
{
|
|
2
|
+
"example": "import { Callout } from \"@godxjp/ui/feedback\";\n\n<Callout kind=\"warning\">\n <Callout.Title>この操作は取り消せません</Callout.Title>\n <Callout.Description>\n リポジトリを削除すると、Issue と Pull Request も一緒に削除されます。\n </Callout.Description>\n</Callout>",
|
|
3
|
+
"group": "feedback",
|
|
4
|
+
"importPath": "@godxjp/ui/feedback",
|
|
5
|
+
"name": "Callout",
|
|
6
|
+
"props": [
|
|
7
|
+
{
|
|
8
|
+
"defaultValue": "\"note\"",
|
|
9
|
+
"description": "GitHub/Obsidian admonition preset; resolves the tone AND the leading glyph. A preset, not a second colour axis — `tone` and `icon` still override per instance.",
|
|
10
|
+
"name": "kind",
|
|
11
|
+
"type": "\"note\" | \"tip\" | \"important\" | \"warning\" | \"caution\""
|
|
12
|
+
},
|
|
13
|
+
{
|
|
14
|
+
"description": "Overrides the tone the `kind` resolves to. Drives surface colour and the leading rail ONLY — unlike Alert, tone never changes live-region politeness here, because a Callout has none.",
|
|
15
|
+
"name": "tone",
|
|
16
|
+
"type": "\"default\" | \"success\" | \"warning\" | \"destructive\" | \"info\" | \"muted\" | \"neutral\""
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
"description": "Override or hide (false) the kind's default leading glyph.",
|
|
20
|
+
"name": "icon",
|
|
21
|
+
"type": "LucideIcon | false"
|
|
22
|
+
}
|
|
23
|
+
],
|
|
24
|
+
"related": [
|
|
25
|
+
"Alert — the SAME primitive in its inline-card presentation, and a LIVE REGION. Use it for an update to the page; Callout is for part of the page.",
|
|
26
|
+
"Banner — the same primitive as the full-bleed page/shell strip, also a live region.",
|
|
27
|
+
"Prose — the typographic column a Callout normally sits inside; the callout's block margin is tuned to that rhythm."
|
|
28
|
+
],
|
|
29
|
+
"rules": [],
|
|
30
|
+
"storyPath": "feedback/Callout.stories.tsx",
|
|
31
|
+
"tagline": "Static aside INSIDE a document body (docs admonition, CMS note, GitHub `> [!NOTE]`). role=\"note\", never a live region. Parts: Callout.Title/Description/Content/Actions.",
|
|
32
|
+
"usage": [
|
|
33
|
+
"CANONICAL CALLOUT CONTRACT: `Callout` is `Alert` with the structural axis fixed to `variant=\"callout\"` — same tone system, same slots, but ASIDE geometry owned by the `--callout-*` tokens (leading rail, prose insets, block margin) and, uniquely, NO live region. Never fake a callout with `className` on an `Alert`, and never hand-roll a coloured div with a left border.",
|
|
34
|
+
"DO: Use Callout for content that is part of the document the reader is reading — a docs admonition, a note in a CMS article, a caveat inside a policy page. It is rendered with the page, so it must not announce.",
|
|
35
|
+
"DON'T: Use `<Alert role=\"note\">` for this. That worked only because `{...props}` is spread after the computed `role`, which the package never promised; one refactor would have silently restored the live region. A consumer neutralising a component's own semantics is the tell that it is the wrong primitive (gh#765).",
|
|
36
|
+
"DON'T: Reach for Callout to report something that just HAPPENED (a save failed, a session expired). That is an update to the page, not part of it — use `Alert` (inline), `Banner` (page/shell strip) or `toast()`, all of which announce.",
|
|
37
|
+
"DON'T: Pass `onDismiss` — the type excludes it. Prose does not get dismissed; if the reader can remove it, it is an Alert.",
|
|
38
|
+
"MARKDOWN RENDERERS: map the five GitHub types straight onto `kind` — `[!NOTE]`→note, `[!TIP]`→tip, `[!IMPORTANT]`→important, `[!WARNING]`→warning, `[!CAUTION]`→caution. Obsidian's lower-case spelling is the same set. `important` takes the NEUTRAL tone (this system has no purple role); its glyph, not its colour, is what tells it from `note`."
|
|
39
|
+
],
|
|
40
|
+
"useCases": [
|
|
41
|
+
"Docs/handbook admonition inside a prose column — `kind=\"note\"` for an aside, `kind=\"tip\"` for a shortcut worth knowing.",
|
|
42
|
+
"A caveat inside a rendered CMS article (react-markdown + rehype-sanitize), drawn from `> [!WARNING]` in the source.",
|
|
43
|
+
"A legal or policy page clause that needs emphasis without interrupting a screen-reader user reading the page top to bottom — `kind=\"important\"`.",
|
|
44
|
+
"A destructive-consequence note beside a runbook step — `kind=\"caution\"`, still silent on load."
|
|
45
|
+
]
|
|
46
|
+
}
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
{
|
|
2
|
+
"example": "import { Card, CardHeader, CardTitle, CardContent } from \"@godxjp/ui/data-display\";\n\n<Card accent=\"success\">\n <CardHeader><CardTitle>注文サマリー</CardTitle></CardHeader>\n <CardContent>総売上: ¥1,234,567</CardContent>\n</Card>",
|
|
3
|
+
"group": "data-display",
|
|
4
|
+
"importPath": "@godxjp/ui/data-display",
|
|
5
|
+
"name": "Card",
|
|
6
|
+
"props": [
|
|
7
|
+
{
|
|
8
|
+
"description": "Semantic accent TONE. Where it is drawn is `accentPlacement`'s job — by default a leading-edge stripe on `border-inline-start` at the `--card-accent-rail-width` measure (6px).",
|
|
9
|
+
"name": "accent",
|
|
10
|
+
"type": "\"primary\" | \"success\" | \"warning\" | \"info\" | \"attention\" | \"destructive\""
|
|
11
|
+
},
|
|
12
|
+
{
|
|
13
|
+
"defaultValue": "\"edge\"",
|
|
14
|
+
"description": "Where `accent` is drawn. \"edge\" is the classic leading rail. \"perimeter\" is the FULL attention border — the whole edge in the accent tone, at the same optical weight as `variant=\"featured\"` but tone-owned, so a card can read as \"action required\" (accent=\"attention\") or \"failed\" (accent=\"destructive\") without borrowing the brand colour. Inert without `accent`. LIMIT (gh#750): the perimeter ring is painted OUTSIDE the border box, and a scroll container clips it — a horizontal ScrollArea is `overflow: auto hidden`, and `overflow-clip-margin` is honoured only by `clip`, not by `auto`. A perimeter card flush against a scroller edge loses 1px of ring on that side; inside a scroller use the default \"edge\" placement (its rail is inside the box) or a tone fill.",
|
|
15
|
+
"name": "accentPlacement",
|
|
16
|
+
"type": "\"edge\" | \"perimeter\""
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
"defaultValue": "\"default\"",
|
|
20
|
+
"description": "Surface fill AND edge. `outline` is Ant Design's `outlined` — no fill, hairline kept. `borderless` is Ant Design's `variant=\"borderless\"` (its deprecated `bordered={false}`) — no hairline, fill kept. The two are mirror images and neither substitutes for the other. `featured` is the BRAND perimeter; its colour is the `--card-featured-border-color` knob rather than a hard-coded `--primary`. For a perimeter in a semantic tone use `accent` + `accentPlacement=\"perimeter\"` instead.",
|
|
21
|
+
"name": "variant",
|
|
22
|
+
"type": "\"default\" | \"muted\" | \"outline\" | \"borderless\" | \"featured\""
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
"description": "Ant Design `hoverable` — the card lifts to `--card-hover-shadow` on hover and takes a pointer cursor. PRESENTATION ONLY: it announces nothing and binds no handler, so pair it with a real control (a Link/Button inside, or the whole card rendered as one via `asChild`). Never with a bare onClick on the Card div — a keyboard or screen-reader user cannot reach that. Composes with `accent`/`accentPlacement=\"perimeter\"`: the hover raises the shadow TOKEN, so the attention ring survives the hover.",
|
|
26
|
+
"name": "hoverable",
|
|
27
|
+
"type": "boolean"
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
"defaultValue": "false",
|
|
31
|
+
"description": "Borrow the child's element for the card BOX instead of rendering a div — the standard Slot passthrough (Button, AspectRatio, ListRow). This is the other half of `hoverable`: `<Card asChild hoverable><a href=\"…\">` IS \"the whole card rendered as one control\" — one tab stop, announced as one link, with the focus ring on the card box (measured in Chromium: `<div>`, `<a>` and `<button>` identical on box, border, radius, fill, padding inset, shadow and cursor at 1440 and 390). For a click-only card hand it your router's Link component as the child. NESTING CAVEAT: the card is now ONE control, so it may not contain another — an <a>/<Button>/menu trigger inside a card-as-link or card-as-button is invalid HTML, and `tabList` (a strip of button triggers) is for the same reason not drawn under `asChild` and warns in development. A card that needs interactive children is not one control: drop `asChild` and put the Link/Button inside it, which is the other branch `hoverable` names. Exactly one child — two throws React.Children.only, the same error `Button asChild` throws.",
|
|
32
|
+
"name": "asChild",
|
|
33
|
+
"type": "boolean"
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
"description": "Internal padding density (base 16 / tight 12 / cozy 20). This IS Ant Design's `size` axis; there is deliberately no `size` prop (removed 2026-08-24) — see docs/DESIGN-AUTHORITY.md, a capability this library already has keeps its own name.",
|
|
37
|
+
"name": "density",
|
|
38
|
+
"type": "\"tight\" | \"cozy\""
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
"description": "Ant Design `tabList` — the tab strip that lives IN THE CARD'S HEAD: under the title, on the same surface, inside the same border, so the card and its tabs read as ONE object. The entry keeps antd's own field names (`key`/`tab`/`disabled`), NOT the Tabs component's `value`/`label`/`content` — a card tab carries only the trigger, because the panel is the card body. The Card's children become the selected tab's body; wrap them in <CardContent> (or <CardContent flush> for an edge-to-edge DataTable, which still reaches the card edge inside a tab).",
|
|
42
|
+
"name": "tabList",
|
|
43
|
+
"type": "{ key: string; tab: ReactNode; disabled?: boolean }[]"
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
"description": "Ant Design `activeTabKey` — the CONTROLLED selection. With it set the card never moves itself; pair it with `onTabChange` and swap the children yourself, exactly as in antd.",
|
|
47
|
+
"name": "activeTabKey",
|
|
48
|
+
"type": "string"
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
"description": "Ant Design `defaultActiveTabKey` — the uncontrolled initial selection. Without it the first selectable entry of `tabList` opens (antd's own fallback); a disabled tab is never the open one.",
|
|
52
|
+
"name": "defaultActiveTabKey",
|
|
53
|
+
"type": "string"
|
|
54
|
+
},
|
|
55
|
+
{
|
|
56
|
+
"description": "Ant Design `onTabChange` — fires with the newly selected `key`, however the selection moved (pointer or keyboard).",
|
|
57
|
+
"name": "onTabChange",
|
|
58
|
+
"type": "(key: string) => void"
|
|
59
|
+
},
|
|
60
|
+
{
|
|
61
|
+
"description": "Ant Design `tabBarExtraContent`, RENAMED to `extra` and made logical — the same precedent `Tabs.extra` already set in this package, and antd's `left`/`right` keys are `start`/`end` here so an RTL locale gets the slot on the correct edge. It rides the TAB BAR beside the strip, so it is inert without `tabList`; a header-level action is <CardAction> inside <CardHeader>.",
|
|
62
|
+
"name": "extra",
|
|
63
|
+
"type": "ReactNode | { start?: ReactNode; end?: ReactNode }"
|
|
64
|
+
},
|
|
65
|
+
{
|
|
66
|
+
"description": "Ant Design `tabProps` — passed straight to the Tabs that draws the strip, so `variant`, `size`, `centered`, `overflow`, `indicator` and the rest are reachable. The fields the CARD owns are omitted rather than silently overwritten: `items` comes from `tabList`, `value`/`defaultValue`/`onValueChange` from `activeTabKey`/`defaultActiveTabKey`/`onTabChange`, and `extra` is the Card's own slot. antd drops the same fields — it writes its own over `tabProps` — so this is that behaviour made visible in the type.",
|
|
67
|
+
"name": "tabProps",
|
|
68
|
+
"type": "Omit<TabsProps, 'items' | 'value' | 'defaultValue' | 'onValueChange' | 'extra' | 'children'>"
|
|
69
|
+
}
|
|
70
|
+
],
|
|
71
|
+
"related": [
|
|
72
|
+
"StatCard — use instead of a plain Card when rendering a KPI/metric tile (label + value + optional delta/hint). StatCard is a Card internally; do not re-wrap it in another Card.",
|
|
73
|
+
"CardContent — mandatory inner wrapper for all body content inside Card. Provides the correct padding and supports flush/tight/solo variants. The only correct way to put padded content inside Card.",
|
|
74
|
+
"Descriptions — use inside <CardContent> when body content is a label-value metadata list (e.g. entity details, invoice fields); do not hand-roll a dl/dt/dd grid.",
|
|
75
|
+
"DataState / InfiniteQueryState — use instead of Card when the content is a TanStack Query-driven list that needs automatic skeleton, empty, and error states; Card does not manage loading lifecycle."
|
|
76
|
+
],
|
|
77
|
+
"rules": [],
|
|
78
|
+
"storyPath": "data-display/Card.stories.tsx",
|
|
79
|
+
"subParts": [
|
|
80
|
+
"CardAction",
|
|
81
|
+
"CardCover",
|
|
82
|
+
"CardDescription",
|
|
83
|
+
"CardFooter",
|
|
84
|
+
"CardHeader",
|
|
85
|
+
"CardTitle"
|
|
86
|
+
],
|
|
87
|
+
"tagline": "Surface container with optional accent stripe, variant fill (including the Ant Design borderless edge), hoverable lift, and density. ⚠️ The bare <Card> has NO inner padding — body content MUST be wrapped in <CardContent> (titles in <CardHeader>), or it sits FLUSH against the card edges. Never hand-roll padding with className=\"p-4\"; use <CardContent>. Compose with CardHeader/CardTitle/CardContent/CardFooter. For Ant Design's card-head TAB STRIP (tabs under the title, inside the card border) use the `tabList`/`activeTabKey`/`defaultActiveTabKey`/`onTabChange`/`extra`/`tabProps` props — the Card renders the strip and the children become the selected tab's body. For a non-tab toolbar/filter strip (list controls, filter chips) use <CardBar extra={…}> — a positionable bar that auto-draws its separator from its position (top→bottom border, bottom→top border, middle→both) and pins `extra` content to the inline-end edge; place it as first/last child of the Card.",
|
|
88
|
+
"usage": [
|
|
89
|
+
"DO always wrap body content in <CardContent> — the bare <Card> div has zero inner padding; content renders flush against card edges without it. Never add className=\"p-4\" directly on <Card> as a substitute.",
|
|
90
|
+
"DO put titles/descriptions in <CardHeader>/<CardTitle>/<CardDescription>. Use <CardHeader banded> for a visually separated muted-background header band (mirrors <CardFooter separated>). Pair with <CardAction> inside a flex-row CardHeader for header-level action buttons.",
|
|
91
|
+
"DO set <CardTitle level={n}> to keep a valid document outline (h1 → h2 → h3, no skipped levels): CardTitle renders <h3> by default, so a section card directly under a page <h1> needs level={2}. Pick the level by OUTLINE position, NEVER for visual size — the title size is fixed by tokens and does not change with level. When the card title is a styled label rather than a section heading, use <CardTitle as=\"p\"> so it is not announced as a heading.",
|
|
92
|
+
"DO use <CardContent flush> for edge-to-edge children such as DataTable, Table, or a Tabs list — this removes horizontal padding. Combine with <CardContent tight> when there is no visual gap needed after the header, and <CardContent solo> when there is no CardHeader above (top padding matches the card shell).",
|
|
93
|
+
"DO use <CardFooter separated> to render a top-bordered action band (Save/Cancel buttons, table summary row). Use <CardFooter flush> for a full-bleed footer bar.",
|
|
94
|
+
"DO use <CardFooter actions> for Ant Design's `actions` row — N EQUAL-WIDTH cells split by vertical hairlines (複製 / 共有 / 削除 under a profile or entity card). It is a different band from `separated`, which packs children at the inline end at their natural widths: that is the right shape for a Save/Cancel pair and the wrong one for a divided strip. `actions` is self-sufficient — it draws its own top rule and full-bleed edges, so it needs neither `separated` nor `flush` beside it. The dividers are logical (border-inline-start), so the strip mirrors under RTL.",
|
|
95
|
+
"DO use <CardCover> as the first child for full-bleed cover media — the header below it uses card-section top spacing, not the card shell.",
|
|
96
|
+
"DO make the WHOLE card the control with `asChild` when the whole card is the click target: `<Card asChild hoverable><a href={href}><CardHeader><CardTitle level={2}>…</CardTitle></CardHeader><CardContent>…</CardContent></a></Card>` (or your router's Link as the child when there is no href, e.g. a nav.push handler). One tab stop, announced as one link, focus ring on the card box. DON'T wrap the card in a raw <button> (that is a `no-raw-button` error) and DON'T put a bare onClick on the Card div (unreachable by keyboard and screen reader — `hoverable`'s own docblock forbids it). NESTING CAVEAT: a card-as-link/button may not CONTAIN another control — an <a>, a <Button>, a DropdownMenu trigger or a `tabList` strip inside it is invalid HTML (`tabList` is dropped with a development warning). When the card needs interactive children it is not one control: drop `asChild` and use the other branch — `hoverable` plus a real Link/Button inside <CardHeader>/<CardAction>/<CardFooter>.",
|
|
97
|
+
"ANT DESIGN PROPS THIS FAMILY ANSWERS BY COMPOSITION, not by a prop of the same name — do not ask for these to be added: `title` is <CardHeader> + <CardTitle> (and CardTitle.level emits a real heading, which antd does not); a header-level action is <CardAction> inside <CardHeader>. `cover` is <CardCover>. `actions` is <CardFooter actions>. `loading` is a Skeleton in the body — antd renders a Skeleton with paragraph rows and no title, so the equivalent is <CardContent solo><SkeletonRows rows={4} /></CardContent>. `type=\"inner\"` is variant=\"muted\" plus <CardHeader banded>. `size` is `density`. `Card.Grid` is <ResponsiveGrid>; `Card.Meta` is <ListRow leading title description trailing>.",
|
|
98
|
+
"DO use `tabList` for a tab strip that belongs to the CARD — antd's card-head tabs, ported name for name (gh#570): `tabList={[{ key, tab, disabled? }]}` plus `activeTabKey`/`defaultActiveTabKey`/`onTabChange`, with `extra` for antd's `tabBarExtraContent` and `tabProps` for everything else on the Tabs underneath. The strip renders INSIDE the card head, under the title, on the same surface and inside the same border, and the Card's children become the selected tab's body (wrap them in <CardContent>, or <CardContent flush> for an edge-to-edge DataTable). DON'T hand-roll it as a <Tabs> parked on the page above the card (the strip floats off the card and the two read as two objects) or as a <Card> repeated inside each tab (the shell is copied per view). A <Tabs> INSIDE <CardContent tight flush> is still correct for a strip that belongs to the BODY rather than to the card head.",
|
|
99
|
+
"DO reach for `accentPlacement=\"perimeter\"` when the whole card needs attention, not one edge: `<Card accent=\"attention\" accentPlacement=\"perimeter\">` is the semantic-tone equivalent of `variant=\"featured\"` (which is brand-toned by definition). Never hand-roll it with `className=\"border-2 border-[--attention]\"` or a page-local `.card--attention` rule — the placement owns the border weight, the outer ring AND the slot-padding compensation, so text stays on the same column as an unaccented sibling.",
|
|
100
|
+
"DON'T hand-roll a stat/KPI tile with <Card> + raw divs — use <StatCard> (label, value, hint, delta, layout, inverse props) which is already a Card internally with correct token-driven layout.",
|
|
101
|
+
"SPACING IS BORDER-AWARE & token-driven (theme via src/tokens/components/card.css, never hard-code padding on slots): `--card-space-inset` is the shared horizontal column every slot (header/content/footer) aligns to. A DIVIDED section — a `banded` header or a `separated` footer, i.e. one carrying a divider border — pads SYMMETRICALLY top+bottom from `--card-space-divided-y` (a band reads as its own region). A PLAIN header flows into the body instead: top `--card-space-shell-y`, no bottom, and the body supplies the gap via `--card-space-body-y`. THE TWO AXES ARE INDEPENDENT: `--card-space-inset` is inline-only, while `--card-space-shell-y` owns the BLOCK shell edges (plain-header top, `solo` body top, terminal slot bottom) and defaults to the inset — so a shell/theme can make a card SHORTER without narrowing its column by overriding `--card-space-shell-y` alone (this is how AuthShell's `--auth-shell-card-padding-block-compact` reaches CardContent). Never bridge it with a consumer selector on the card-content slot. Special case: `<CardContent flush>` zeroes BOTH of its block edges — for ANY full-bleed body, not only one containing a <Table>` gate left a flush file LIST floating 18px off its header while the flush table beside it sat at 0) — so the plain header above it supplies the gap from its own `--card-space-body-y` bottom padding instead. `tight` and `solo` still own that axis themselves. `--card-space-gap` is the in-slot stack gap (title↕description). Tune the band rhythm once at `--card-space-divided-y`; tune the accent stripe width at `--card-accent-rail-width` (default 6px)."
|
|
102
|
+
],
|
|
103
|
+
"useCases": [
|
|
104
|
+
"Dashboard KPI summary row: wrap each metric in <StatCard> (or a plain <Card density=\"tight\"> with <CardContent>) to render a uniform grid of labeled value tiles with optional trend deltas.",
|
|
105
|
+
"Invoice or order detail panel: <Card accent=\"primary\"> with <CardHeader banded><CardTitle>, <CardContent> body rows (use <Descriptions> inside), and <CardFooter separated> holding approve/reject buttons.",
|
|
106
|
+
"Section container on a settings or form page: a single <Card> wrapping a <CardHeader><CardTitle> plus <CardContent> containing <FormField> groups, with <CardFooter separated> for Save/Cancel.",
|
|
107
|
+
"Data table with toolbar: <Card> + <CardHeader> (title + filter controls in <CardAction>) + <CardContent flush> containing <DataTable> — <CardContent flush> removes horizontal padding so the table header spans full width.",
|
|
108
|
+
"Detail screen with views: <Card tabList={[{key,tab}]} activeTabKey onTabChange extra={<Button/>}> with <CardHeader><CardTitle> above the strip and <CardContent flush><DataTable/></CardContent> as the body — one card, tabs in its head, and a table that reaches the card edge inside the tab (docs/data-display/card/examples/tab-list.tsx).",
|
|
109
|
+
"Featured announcement or alert card: <Card variant=\"featured\"> with an accent stripe (<accent=\"warning\">) to visually elevate a card above sibling cards on the page.",
|
|
110
|
+
"Media/cover card (e.g. entity profile): <CardCover> first (full-bleed image), then <CardHeader> + <CardContent> below it for structured metadata."
|
|
111
|
+
]
|
|
112
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
{
|
|
2
|
+
"docPath": "docs/data-display/card/index.tsx",
|
|
3
|
+
"example": "<Card><CardBar pad={{block:2,inline:3}} border=\"block-start\">Tools</CardBar></Card>",
|
|
4
|
+
"group": "data-display",
|
|
5
|
+
"importPath": "@godxjp/ui/data-display",
|
|
6
|
+
"name": "CardBar",
|
|
7
|
+
"props": [
|
|
8
|
+
{
|
|
9
|
+
"description": "Instance padding on the token scale.",
|
|
10
|
+
"name": "pad",
|
|
11
|
+
"type": "PadProp"
|
|
12
|
+
},
|
|
13
|
+
{
|
|
14
|
+
"description": "Measured padding escape.",
|
|
15
|
+
"name": "padRaw",
|
|
16
|
+
"type": "PadRawProp"
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
"description": "Spacing between main and extra slots.",
|
|
20
|
+
"name": "gap",
|
|
21
|
+
"type": "GapProp"
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
"description": "Optional muted ground.",
|
|
25
|
+
"name": "surface",
|
|
26
|
+
"type": "\"muted\""
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
"description": "Override positional divider edges for stacked bars.",
|
|
30
|
+
"name": "border",
|
|
31
|
+
"type": "\"none\" | \"block-start\" | \"block-end\" | \"both\""
|
|
32
|
+
}
|
|
33
|
+
],
|
|
34
|
+
"related": [
|
|
35
|
+
"Card",
|
|
36
|
+
"Flex"
|
|
37
|
+
],
|
|
38
|
+
"rules": [
|
|
39
|
+
9
|
|
40
|
+
],
|
|
41
|
+
"storyPath": "data-display/Card.stories.tsx",
|
|
42
|
+
"tagline": "Inline card toolbar with scoped inset and divider edges.",
|
|
43
|
+
"usage": [
|
|
44
|
+
"Compose inside Card. Unset border follows its position; explicit border prevents double rules in stacked bars."
|
|
45
|
+
],
|
|
46
|
+
"useCases": [
|
|
47
|
+
"Composer tool strips and view tabs."
|
|
48
|
+
]
|
|
49
|
+
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
{
|
|
2
|
+
"example": "import { Card, CardContent, DataTable } from \"@godxjp/ui/data-display\";\n\n<Card>\n <CardContent flush>\n <DataTable data={rows} columns={columns} />\n </CardContent>\n</Card>",
|
|
3
|
+
"group": "data-display",
|
|
4
|
+
"importPath": "@godxjp/ui/data-display",
|
|
5
|
+
"name": "CardContent",
|
|
6
|
+
"props": [
|
|
7
|
+
{
|
|
8
|
+
"description": "Remove horizontal padding for edge-to-edge tables / tabs lists.",
|
|
9
|
+
"name": "flush",
|
|
10
|
+
"type": "boolean"
|
|
11
|
+
},
|
|
12
|
+
{
|
|
13
|
+
"description": "No top gap after header — pair with flush toolbars/tabs.",
|
|
14
|
+
"name": "tight",
|
|
15
|
+
"type": "boolean"
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
"description": "No header above: top padding matches the card shell.",
|
|
19
|
+
"name": "solo",
|
|
20
|
+
"type": "boolean"
|
|
21
|
+
}
|
|
22
|
+
],
|
|
23
|
+
"related": [
|
|
24
|
+
"Card — the parent container; CardContent is always a direct child of Card. Card itself has zero internal padding; every visible body padding comes from CardContent (or CardHeader/CardFooter). Never put content directly inside Card.",
|
|
25
|
+
"StatCard — a self-contained KPI tile that IS already a Card; do not wrap it in <Card><CardContent>. Use StatCard directly inside a ResponsiveGrid.",
|
|
26
|
+
"ScrollArea — place ScrollArea inside CardContent (non-flush) when the card body needs to scroll; do not put ScrollArea outside CardContent or you lose the card's internal padding.",
|
|
27
|
+
"SkeletonStat — the loading placeholder for a StatCard tile; swap in SkeletonStat while KPI data is loading. For general Card loading shapes, use SkeletonTable or Skeleton primitives."
|
|
28
|
+
],
|
|
29
|
+
"rules": [
|
|
30
|
+
37,
|
|
31
|
+
38
|
|
32
|
+
],
|
|
33
|
+
"storyPath": "data-display/Card.stories.tsx",
|
|
34
|
+
"tagline": "Card body. flush = edge-to-edge (for DataTable/tabs); tight = no top gap; solo = no header above. NEVER put a Toolbar inside flush (it loses padding).",
|
|
35
|
+
"usage": [
|
|
36
|
+
"DO: Always wrap body content in <CardContent> — a bare <Card> has no internal padding, so any child placed directly inside it renders flush against the card edges.",
|
|
37
|
+
"DO: Use <CardContent flush> for DataTable, Table, or Tabs — the flush prop removes horizontal padding so the content spans edge-to-edge inside the card border. Never add manual p-0 on the Card itself instead.",
|
|
38
|
+
"DO: Use <CardContent tight> when placing a flush toolbar or a Tabs list directly below a CardHeader — tight removes the top gap so the header and the body connect without an awkward spacing gap.",
|
|
39
|
+
"DO: Use <CardContent solo> when the card has no CardHeader above it — solo gives the top padding that matches the card shell, ensuring visual balance.",
|
|
40
|
+
"DON'T: Nest a Toolbar inside <CardContent flush> — flush strips horizontal padding and Toolbar will lose its own padding. Put Toolbar outside the flush CardContent or in a separate non-flush CardContent above it.",
|
|
41
|
+
"DON'T: Wrap a StatCard inside <Card><CardContent> — StatCard already renders its own Card border; double-wrapping produces a double border. Render StatCard directly in a ResponsiveGrid."
|
|
42
|
+
],
|
|
43
|
+
"useCases": [
|
|
44
|
+
"Wrapping a form body (Input, Select, Textarea fields) inside a Card that has a CardHeader title — ensures the form fields have correct internal padding.",
|
|
45
|
+
"Hosting a DataTable inside a Card edge-to-edge: <CardContent flush><DataTable .../></CardContent> — the table occupies the full card width with the card's border acting as the table container.",
|
|
46
|
+
"Dashboard detail panels where the card has no title — <CardContent solo> gives top padding equivalent to the card shell so the content doesn't sit too close to the top border.",
|
|
47
|
+
"Placing a Descriptions or Timeline inside a card to display invoice/accounting details — <CardContent> provides the standard 16px (or density-adjusted) padding without needing manual className.",
|
|
48
|
+
"Pairing with <CardHeader banded> and <CardFooter separated> in a multi-section layout such as a payment summary card — each section slot (header, content, footer) carries its own semantic spacing tokens.",
|
|
49
|
+
"Putting a ScrollArea inside <CardContent> (not flush) to create a scrollable card body with consistent padding, e.g. a chat or log viewer panel."
|
|
50
|
+
]
|
|
51
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
{
|
|
2
|
+
"example": "import { Carousel, CarouselContent, CarouselItem, CarouselPrevious, CarouselNext, CarouselDots } from \"@godxjp/ui/data-display\";\n\n// CarouselDots reads the Embla api from context — no setApi wiring needed.\n<Carousel opts={{ loop: true }}>\n <CarouselContent>\n <CarouselItem>1</CarouselItem>\n <CarouselItem>2</CarouselItem>\n </CarouselContent>\n <CarouselPrevious />\n <CarouselNext />\n <CarouselDots />\n</Carousel>",
|
|
3
|
+
"group": "data-display",
|
|
4
|
+
"importPath": "@godxjp/ui/data-display",
|
|
5
|
+
"name": "Carousel",
|
|
6
|
+
"props": [
|
|
7
|
+
{
|
|
8
|
+
"description": "Embla options.",
|
|
9
|
+
"name": "opts",
|
|
10
|
+
"type": "Parameters<typeof useEmblaCarousel>[0]"
|
|
11
|
+
},
|
|
12
|
+
{
|
|
13
|
+
"description": "Embla plugins.",
|
|
14
|
+
"name": "plugins",
|
|
15
|
+
"type": "Parameters<typeof useEmblaCarousel>[1]"
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
"description": "Receive the Embla api for custom logic (autoplay, external prev/next). NOT needed for dots — CarouselDots reads the api from context itself.",
|
|
19
|
+
"name": "setApi",
|
|
20
|
+
"type": "(api: CarouselApi) => void"
|
|
21
|
+
}
|
|
22
|
+
],
|
|
23
|
+
"rules": [
|
|
24
|
+
3,
|
|
25
|
+
6
|
|
26
|
+
],
|
|
27
|
+
"storyPath": "data-display/Carousel.stories.tsx",
|
|
28
|
+
"subParts": [
|
|
29
|
+
"CarouselContent",
|
|
30
|
+
"CarouselDots",
|
|
31
|
+
"CarouselItem",
|
|
32
|
+
"CarouselNext",
|
|
33
|
+
"CarouselPrevious"
|
|
34
|
+
],
|
|
35
|
+
"tagline": "Embla-backed carousel primitives: previous/next controls, CarouselDots indicators, and a context API.",
|
|
36
|
+
"usage": [
|
|
37
|
+
"DO compose the full set: `<Carousel>` › `<CarouselContent>` › many `<CarouselItem>`, with `<CarouselPrevious>`/`<CarouselNext>` for arrows and `<CarouselDots>` for the indicator row. Don't render items outside `<CarouselContent>` — the track is the scroll container.",
|
|
38
|
+
"DO use `<CarouselDots>` for the active-slide indicator instead of wiring `setApi` by hand — it reads `selectedIndex`/`scrollSnaps` from the Carousel context, renders one `aria-current` dot per snap, and auto-hides when there is ≤1 slide.",
|
|
39
|
+
"DON'T use a Carousel where ALL items must be seen/compared at once or be keyboard-reachable in reading order (e.g. a list of selectable options, a data table, primary navigation) — hiding content behind a swipe is an anti-pattern there; use a Grid/`ResponsiveGrid`, `ScrollArea`, or `Tabs`.",
|
|
40
|
+
"DON'T autoplay without a pause-on-hover/focus control and reduced-motion respect — pass the Embla autoplay plugin via `plugins` only for non-essential decorative content, never for content the user must read.",
|
|
41
|
+
"DO set `opts={{ loop: true }}` for galleries that wrap, and rely on the built-in disabling: `CarouselPrevious`/`CarouselNext` auto-disable at the ends (via `canScrollPrev`/`canScrollNext`) — don't hide them, let them grey out.",
|
|
42
|
+
"DO give each `<CarouselItem>` real, meaningful content; the component already injects an 'N of M' slide label for screen readers, so don't add a redundant one (a consumer `aria-label` on the item overrides the default)."
|
|
43
|
+
],
|
|
44
|
+
"useCases": [
|
|
45
|
+
"Feature / onboarding highlight cards on a dashboard or landing surface, with CarouselDots showing position.",
|
|
46
|
+
"Image or document thumbnail gallery (e.g. uploaded receipts / 物件写真) with looping and prev/next arrows.",
|
|
47
|
+
"Horizontal stepping list of compact KPI or announcement cards that overflow the viewport width.",
|
|
48
|
+
"Product/plan comparison cards on a marketing page where swiping between a few options is acceptable (not the primary action)."
|
|
49
|
+
]
|
|
50
|
+
}
|