@godxjp/ui 28.8.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/lib/variants.js +4 -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/props/vocabulary/layout.prop.d.ts +1 -1
- package/dist/styles/base.css +47 -14
- package/dist/styles/card-layout.css +6 -6
- package/dist/styles/chart-layout.css +6 -6
- package/dist/styles/control.css +41 -6
- package/dist/styles/data-display-layout.css +21 -6
- package/dist/styles/density.css +2 -0
- package/dist/styles/dialog-layout.css +4 -1
- package/dist/styles/focus-ring.css +4 -1
- package/dist/styles/layout.css +30 -3
- package/dist/styles/navigation-layout.css +3 -1
- package/dist/styles/shell-layout.css +27 -21
- package/dist/styles/table-layout.css +50 -9
- package/dist/styles/text-layout.css +94 -23
- package/dist/tokens/components/activity.css +13 -4
- package/dist/tokens/components/attachments.css +1 -1
- package/dist/tokens/components/badge.css +1 -1
- package/dist/tokens/components/card.css +28 -7
- package/dist/tokens/components/chart.css +4 -1
- package/dist/tokens/components/chat-composer.css +4 -1
- package/dist/tokens/components/control.css +69 -30
- package/dist/tokens/components/conversations.css +4 -1
- package/dist/tokens/components/data-display.css +42 -15
- package/dist/tokens/components/data-entry.css +8 -2
- package/dist/tokens/components/descriptions.css +1 -1
- package/dist/tokens/components/feedback.css +8 -5
- package/dist/tokens/components/float-button.css +8 -2
- package/dist/tokens/components/legal-document.css +12 -3
- package/dist/tokens/components/logo.css +15 -6
- package/dist/tokens/components/mega-menu.css +14 -5
- package/dist/tokens/components/navigation.css +37 -13
- package/dist/tokens/components/segmented.css +9 -2
- package/dist/tokens/components/separator.css +4 -1
- package/dist/tokens/components/shell.css +96 -31
- package/dist/tokens/components/table.css +13 -6
- package/dist/tokens/components/thought-chain.css +4 -1
- package/dist/tokens/components/toggle.css +4 -1
- package/dist/tokens/components/tree.css +1 -1
- package/dist/tokens/components/upload.css +21 -9
- package/dist/tokens/foundation.css +24 -30
- package/dist/tokens/semantic/layout.css +19 -5
- package/docs/COMPOSITION-VS-COMPONENT.md +41 -0
- package/docs/DESIGN-AUTHORITY.md +14 -0
- package/docs/DEVELOPMENT.md +81 -6
- package/docs/TOKENS.md +16 -1
- 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/case4-login.tsx +10 -2
- package/docs/showcase/case5-shift-calendar.tsx +1 -1
- package/docs/showcase/case6-agency-handy.tsx +6 -6
- package/docs/showcase/futurelastic-web.tsx +7 -9
- package/docs/showcase/marketing-page.tsx +61 -52
- package/docs/showcase/table-expandable-rows.tsx +4 -1
- package/docs/showcase/table-pagination.tsx +88 -18
- package/docs/showcase/theme-customization.tsx +25 -2
- package/package.json +8 -5
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
{
|
|
2
|
+
"example": "import { PieChart } from \"@godxjp/ui/charts\";\n\n<PieChart\n label={t(\"dashboard.expenseSplit\")}\n data={data}\n dataKey=\"amount\"\n nameKey=\"category\"\n numberFormat={{ style: \"currency\", currency: \"JPY\" }}\n donut\n/>",
|
|
3
|
+
"group": "data-display",
|
|
4
|
+
"importPath": "@godxjp/ui/charts",
|
|
5
|
+
"name": "PieChart",
|
|
6
|
+
"props": [
|
|
7
|
+
{
|
|
8
|
+
"description": "Row data: one slice per row.",
|
|
9
|
+
"name": "data",
|
|
10
|
+
"required": true,
|
|
11
|
+
"type": "ChartDatum[]"
|
|
12
|
+
},
|
|
13
|
+
{
|
|
14
|
+
"description": "Key into each datum holding the slice's numeric value.",
|
|
15
|
+
"name": "dataKey",
|
|
16
|
+
"required": true,
|
|
17
|
+
"type": "string"
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
"description": "Key into each datum holding the slice's category label.",
|
|
21
|
+
"name": "nameKey",
|
|
22
|
+
"required": true,
|
|
23
|
+
"type": "string"
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
"description": "Accessible name + visible caption.",
|
|
27
|
+
"name": "label",
|
|
28
|
+
"required": true,
|
|
29
|
+
"type": "string"
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
"defaultValue": "true",
|
|
33
|
+
"description": "Paint `label` as a visible caption. Set false when a CardTitle or section heading already says it — the caption stays in the DOM as sr-only, so role=img keeps its accessible name.",
|
|
34
|
+
"name": "showCaption",
|
|
35
|
+
"type": "boolean"
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
"description": "Per-slice colours by index (defaults to the --chart-1..6 palette).",
|
|
39
|
+
"name": "colors",
|
|
40
|
+
"type": "string[]"
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
"description": "Extra context appended to the screen-reader description.",
|
|
44
|
+
"name": "description",
|
|
45
|
+
"type": "string"
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
"defaultValue": "\"md\"",
|
|
49
|
+
"description": "Canvas height preset. Ignored when `height` is set.",
|
|
50
|
+
"name": "size",
|
|
51
|
+
"type": "\"xs\" | \"sm\" | \"md\" | \"lg\""
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
"description": "Explicit canvas height in px (overrides `size`).",
|
|
55
|
+
"name": "height",
|
|
56
|
+
"type": "number"
|
|
57
|
+
},
|
|
58
|
+
{
|
|
59
|
+
"defaultValue": "true",
|
|
60
|
+
"description": "Show the slice legend.",
|
|
61
|
+
"name": "showLegend",
|
|
62
|
+
"type": "boolean"
|
|
63
|
+
},
|
|
64
|
+
{
|
|
65
|
+
"description": "Locale-aware formatting for tooltip values.",
|
|
66
|
+
"name": "numberFormat",
|
|
67
|
+
"type": "Intl.NumberFormatOptions"
|
|
68
|
+
},
|
|
69
|
+
{
|
|
70
|
+
"defaultValue": "false",
|
|
71
|
+
"description": "Render a donut (hollow centre) instead of a full pie.",
|
|
72
|
+
"name": "donut",
|
|
73
|
+
"type": "boolean"
|
|
74
|
+
},
|
|
75
|
+
{
|
|
76
|
+
"description": "Message shown when `data` is empty.",
|
|
77
|
+
"name": "emptyMessage",
|
|
78
|
+
"type": "string"
|
|
79
|
+
}
|
|
80
|
+
],
|
|
81
|
+
"related": [
|
|
82
|
+
"BarChart — when there are many categories or precise comparison matters.",
|
|
83
|
+
"Progress — single ratio against a target rather than a multi-slice split."
|
|
84
|
+
],
|
|
85
|
+
"rules": [],
|
|
86
|
+
"storyPath": "charts/PieChart.stories.tsx",
|
|
87
|
+
"tagline": "Part-to-whole composition across a small set of slices — `donut` option, localized tooltips, and a screen-reader breakdown of every slice. Data-visualization graph / diagram.",
|
|
88
|
+
"usage": [
|
|
89
|
+
"DO import from the charts entry: `import { PieChart } from \"@godxjp/ui/charts\";` (recharts optional peer required).",
|
|
90
|
+
"DO import only the chart a screen uses — `import { PieChart } from \"@godxjp/ui/charts/pie-chart\";` — when the `./charts` barrel should not link the whole chart family. Without the `recharts` peer the build then fails ONCE, naming the package and the fix.",
|
|
91
|
+
"DO keep slices few (≈2–6) — pies are unreadable past a handful; use BarChart for many categories.",
|
|
92
|
+
"DO pass `numberFormat` (e.g. percent or currency) so tooltip values localize.",
|
|
93
|
+
"DON'T use a pie for trends over time (LineChart/AreaChart) or precise comparison (BarChart)."
|
|
94
|
+
],
|
|
95
|
+
"useCases": [
|
|
96
|
+
"Budget / expense split across a few categories.",
|
|
97
|
+
"Market or status share (e.g. paid vs overdue vs draft)."
|
|
98
|
+
]
|
|
99
|
+
}
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
{
|
|
2
|
+
"example": "import {\n Popover,\n PopoverTrigger,\n PopoverContent,\n PopoverHeader,\n PopoverTitle,\n PopoverDescription,\n} from \"@godxjp/ui/data-display\";\nimport { Button } from \"@godxjp/ui/general\";\n\n// Uncontrolled — basic usage\nexport function InvoiceFilterPopover() {\n return (\n <Popover>\n <PopoverTrigger asChild>\n <Button variant=\"outline\">Advanced filters</Button>\n </PopoverTrigger>\n <PopoverContent align=\"start\" width=\"trigger\">\n <PopoverHeader>\n <PopoverTitle>Filter invoices</PopoverTitle>\n <PopoverDescription>Narrow results by date range and status.</PopoverDescription>\n </PopoverHeader>\n {/* place form controls here */}\n </PopoverContent>\n </Popover>\n );\n}\n\n// Controlled — programmatic open/close\nimport * as React from \"react\";\n\nexport function ControlledPopover() {\n const [open, setOpen] = React.useState(false);\n return (\n <Popover open={open} onOpenChange={setOpen}>\n <PopoverTrigger asChild>\n <Button variant=\"ghost\" size=\"icon\" aria-label=\"Show details\">\n ?\n </Button>\n </PopoverTrigger>\n <PopoverContent side=\"right\" sideOffset={8}>\n <PopoverHeader>\n <PopoverTitle>About this field</PopoverTitle>\n <PopoverDescription>\n The MF ID is the unique identifier assigned by Money Forward.\n </PopoverDescription>\n </PopoverHeader>\n </PopoverContent>\n </Popover>\n );\n}",
|
|
3
|
+
"group": "data-display",
|
|
4
|
+
"importPath": "@godxjp/ui/data-display",
|
|
5
|
+
"name": "Popover",
|
|
6
|
+
"props": [
|
|
7
|
+
{
|
|
8
|
+
"description": "Controls open state in controlled mode. Pair with onOpenChange.",
|
|
9
|
+
"name": "open",
|
|
10
|
+
"type": "boolean"
|
|
11
|
+
},
|
|
12
|
+
{
|
|
13
|
+
"defaultValue": "false",
|
|
14
|
+
"description": "Initial open state for uncontrolled usage.",
|
|
15
|
+
"name": "defaultOpen",
|
|
16
|
+
"type": "boolean"
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
"description": "Callback fired when the popover open state changes. Required when using controlled mode (open prop).",
|
|
20
|
+
"name": "onOpenChange",
|
|
21
|
+
"type": "(open: boolean) => void"
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
"defaultValue": "false",
|
|
25
|
+
"description": "When true, interaction outside the popover is blocked and focus is trapped inside (Radix Root prop).",
|
|
26
|
+
"name": "modal",
|
|
27
|
+
"type": "boolean"
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
"defaultValue": "\"center\"",
|
|
31
|
+
"description": "PopoverContent prop. Horizontal alignment of the popover relative to the trigger.",
|
|
32
|
+
"name": "align",
|
|
33
|
+
"type": "'start' | 'center' | 'end'"
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
"defaultValue": "4",
|
|
37
|
+
"description": "PopoverContent prop. Distance in pixels between the popover panel and its anchor.",
|
|
38
|
+
"name": "sideOffset",
|
|
39
|
+
"type": "number"
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
"defaultValue": "\"bottom\"",
|
|
43
|
+
"description": "PopoverContent prop. Which side of the trigger the panel prefers to open on (auto-flips on overflow).",
|
|
44
|
+
"name": "side",
|
|
45
|
+
"type": "'top' | 'right' | 'bottom' | 'left'"
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
"defaultValue": "false",
|
|
49
|
+
"description": "PopoverTrigger prop. Merges trigger props onto the immediate child element (e.g. a Button) instead of rendering an extra DOM node. Strongly recommended to avoid a wrapping <button>.",
|
|
50
|
+
"name": "asChild",
|
|
51
|
+
"type": "boolean"
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
"defaultValue": "false",
|
|
55
|
+
"description": "PopoverContent prop. The panel's CONTENT owns its inset: the popover zeroes its own --popover-space-inset so a Command list, a menu or a table runs edge to edge and draws its separators across the full width. Reach for it whenever the child already paints its own rows; leave it off for prose panels, which want the panel padding.",
|
|
56
|
+
"name": "flush",
|
|
57
|
+
"type": "boolean"
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
"defaultValue": "\"panel\"",
|
|
61
|
+
"description": "PopoverContent prop. How the panel is MEASURED across the inline axis. \"panel\" (default) is the popover's own --popover-width (18rem) — right for prose and for a list the panel sizes itself. \"auto\" lets the CONTENT decide, the only correct answer for something with a width of its own (a two-month Calendar is far wider than 18rem and was being clipped by it). \"trigger\" matches the anchor. It is the counterpart of `flush`: both set a token the panel already reads, so a service theme keeps owning them, where a `w-*` utility on className is a per-call-site constant nothing can retune.",
|
|
62
|
+
"name": "width",
|
|
63
|
+
"type": "\"panel\" | \"auto\" | \"trigger\""
|
|
64
|
+
},
|
|
65
|
+
{
|
|
66
|
+
"description": "PopoverContent prop. Extra Tailwind classes merged onto the panel (default: w-72 p-4 rounded-md border shadow-md z-50).",
|
|
67
|
+
"name": "className",
|
|
68
|
+
"type": "string"
|
|
69
|
+
}
|
|
70
|
+
],
|
|
71
|
+
"related": [
|
|
72
|
+
"Tooltip — use Tooltip for brief, non-interactive label-like hints (hover-only, no inputs). Use Popover when the floating content is interactive (buttons, inputs, forms).",
|
|
73
|
+
"Dialog/Sheet — use Dialog or Sheet for full modal actions that require user confirmation or significant input. Use Popover for lightweight, anchor-relative panels that dismiss on outside click.",
|
|
74
|
+
"DropdownMenu — use DropdownMenu for a flat list of clickable actions or links. Use Popover when the floating panel needs arbitrary layout (forms, grids, rich content) rather than a menu list."
|
|
75
|
+
],
|
|
76
|
+
"rules": [
|
|
77
|
+
3,
|
|
78
|
+
23,
|
|
79
|
+
31,
|
|
80
|
+
35
|
|
81
|
+
],
|
|
82
|
+
"storyPath": "data-display/Popover.stories.tsx",
|
|
83
|
+
"subParts": [
|
|
84
|
+
"PopoverAnchor",
|
|
85
|
+
"PopoverContent",
|
|
86
|
+
"PopoverDescription",
|
|
87
|
+
"PopoverHeader",
|
|
88
|
+
"PopoverTitle",
|
|
89
|
+
"PopoverTrigger"
|
|
90
|
+
],
|
|
91
|
+
"tagline": "Radix-backed floating panel anchored to a trigger — always compose with PopoverTrigger + PopoverContent; never use a raw div overlay.",
|
|
92
|
+
"usage": [
|
|
93
|
+
"DO compose: <Popover> → <PopoverTrigger asChild> → <Button/> and <PopoverContent>. All four parts are required for any popover to function; omitting PopoverTrigger or PopoverContent produces nothing.",
|
|
94
|
+
"DO set `<PopoverContent width=\"auto\">` when the child brings its own measure — a Calendar, a chart, a fixed-width preview. The panel's own 18rem clips them, and a `w-*` utility on className is a per-call-site constant no service theme can retune, which is exactly what `flush` exists to avoid on the padding axis. `width=\"trigger\"` matches the anchor, the shape every select-like control wants.",
|
|
95
|
+
"DO set `<PopoverContent flush>` when the panel holds a Command list, a menu or a table — the child owns its own inset, so its rows and separators reach the panel edges. Never zero the padding with a utility on className: that is a per-call-site constant no service theme can retune, while `flush` keeps the inset on --popover-space-inset.",
|
|
96
|
+
"DO use asChild on PopoverTrigger when the trigger is already a Button or link — this avoids a nested <button><button> violation and extra DOM nesting.",
|
|
97
|
+
"DO use controlled mode (open + onOpenChange) when external code must open/close the popover programmatically (e.g., form validation reveal, keyboard shortcut). For toggle-only interactions, uncontrolled (defaultOpen) is simpler.",
|
|
98
|
+
"DO structure panel content with PopoverHeader > PopoverTitle + PopoverDescription for labelled panels. This is purely presentational but establishes the correct font-weight and muted-foreground on the description.",
|
|
99
|
+
"DON'T hand-roll a floating div or use a CSS show/hide toggle — Popover provides portal rendering, focus trap, Escape-to-close, and ARIA automatically.",
|
|
100
|
+
"DON'T place a Popover inside a Dialog without setting modal={false} on the Popover — nested modals conflict with Radix's focus management and produce stuck focus."
|
|
101
|
+
],
|
|
102
|
+
"useCases": [
|
|
103
|
+
"Advanced filter panel: a Filters Button triggers a Popover containing filter inputs (date range, status selects); panel measured with `<PopoverContent width='auto'>` so the filters set the width, or `width='trigger'` to match the button.",
|
|
104
|
+
"Row action menu overflow: when a DataTable row has too many actions for inline display, a Popover holds the secondary actions (Edit, Archive, Delete) without navigating away.",
|
|
105
|
+
"Contextual help / tooltip-rich: a small '?' icon button opens a Popover with PopoverTitle + PopoverDescription explaining a form field — richer than a Tooltip but less intrusive than a Dialog.",
|
|
106
|
+
"Inline record preview: clicking a reference number in an invoice list opens a Popover showing a summary card of the linked document before the user decides to navigate.",
|
|
107
|
+
"Column visibility picker: a 'Columns' button above a DataTable opens a Popover containing checkboxes to show/hide columns, with controlled state managed in parent.",
|
|
108
|
+
"Quick-edit cell: for an admin table, clicking a status badge opens a Popover with a RadioGroup to change status in-place without a full Dialog."
|
|
109
|
+
]
|
|
110
|
+
}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
{
|
|
2
|
+
"example": "import { PrefetchLink } from \"@godxjp/ui/query\";\nimport { fetchInvoice } from \"@/api/invoices\";\n\n// Inside a table row or list item:\n<PrefetchLink\n to={`/invoices/${invoice.id}`}\n queryKey={[\"invoice\", invoice.id]}\n queryFn={() => fetchInvoice(invoice.id)}\n staleTime={60_000}\n className=\"font-medium hover:underline\"\n>\n {invoice.number}\n</PrefetchLink>\n\n// Disable prefetch for rows where data is not yet stable:\n<PrefetchLink\n to={`/invoices/${invoice.id}`}\n queryKey={[\"invoice\", invoice.id]}\n queryFn={() => fetchInvoice(invoice.id)}\n prefetchOn=\"none\"\n>\n {invoice.number}\n</PrefetchLink>",
|
|
3
|
+
"group": "data-display",
|
|
4
|
+
"importPath": "@godxjp/ui/query",
|
|
5
|
+
"name": "PrefetchLink",
|
|
6
|
+
"props": [
|
|
7
|
+
{
|
|
8
|
+
"description": "TanStack Query cache key for the data to prefetch. Must match the key used by the destination page's useQuery call.",
|
|
9
|
+
"name": "queryKey",
|
|
10
|
+
"required": true,
|
|
11
|
+
"type": "QueryKey"
|
|
12
|
+
},
|
|
13
|
+
{
|
|
14
|
+
"description": "Fetch function passed to queryClient.prefetchQuery. Same function (or equivalent) as the one used in the destination page's useQuery.",
|
|
15
|
+
"name": "queryFn",
|
|
16
|
+
"required": true,
|
|
17
|
+
"type": "() => Promise<unknown>"
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
"defaultValue": "\"both\"",
|
|
21
|
+
"description": "Which interaction triggers prefetching. 'both' fires on either mouseenter or focus. 'none' disables prefetching entirely (useful for conditional opt-out without unmounting the component).",
|
|
22
|
+
"name": "prefetchOn",
|
|
23
|
+
"type": "\"hover\" | \"focus\" | \"both\" | \"none\""
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
"defaultValue": "30000",
|
|
27
|
+
"description": "Milliseconds before the prefetched cache entry is considered stale. Matches queryClient.prefetchQuery staleTime. Defaults to 30 s — set higher for rarely-changing data (e.g. reference tables), lower for live feeds.",
|
|
28
|
+
"name": "staleTime",
|
|
29
|
+
"type": "number"
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
"description": "All standard React Router v6 Link props are spread through: to, replace, state, relative, reloadDocument, preventScrollReset, viewTransition, className, children, etc. onMouseEnter and onFocus are merged (your handler still fires).",
|
|
33
|
+
"name": "...linkProps",
|
|
34
|
+
"type": "LinkProps (react-router-dom)"
|
|
35
|
+
}
|
|
36
|
+
],
|
|
37
|
+
"related": [
|
|
38
|
+
"Link (react-router-dom) — use bare Link when no prefetching is needed or when the destination has no TanStack Query data (e.g. a static page or a form page that fetches nothing on load).",
|
|
39
|
+
"DataState — the companion lifecycle widget for the destination page; ensures PrefetchLink's prefetch is consumed correctly via useQuery.",
|
|
40
|
+
"InfiniteQueryState — use instead of PrefetchLink when the list itself is infinitely paginated and items are loaded lazily rather than navigated to.",
|
|
41
|
+
"ButtonRefetch — for triggering a manual cache refresh on an already-loaded page, not for navigation prefetching."
|
|
42
|
+
],
|
|
43
|
+
"rules": [
|
|
44
|
+
2,
|
|
45
|
+
3,
|
|
46
|
+
31
|
|
47
|
+
],
|
|
48
|
+
"storyPath": "data-display/PrefetchLink.stories.tsx",
|
|
49
|
+
"tagline": "React Router Link that fires prefetchQuery on hover/focus so detail pages feel instant — requires a TanStack Query QueryClient in context.",
|
|
50
|
+
"usage": [
|
|
51
|
+
"DO: provide a queryKey that exactly matches the destination page's useQuery key — a mismatch means the prefetch populates a different cache slot and the page still loads cold.",
|
|
52
|
+
"DO: keep queryFn lightweight and side-effect-free; it runs speculatively on hover. Avoid mutations or write operations inside queryFn.",
|
|
53
|
+
"DO: tune staleTime to your data's freshness requirement. The default 30 s is fine for most detail views; set it lower (e.g. 5000) for real-time data or higher (e.g. 300_000) for static reference data.",
|
|
54
|
+
"DON'T: use PrefetchLink when the destination page's data is user-specific per request (e.g. contains a nonce or CSRF token embedded in the payload) — the prefetched response may be stale or unusable.",
|
|
55
|
+
"DON'T: hand-roll a Link + useQueryClient prefetch pattern when PrefetchLink already ships it. Using raw Link loses the hover/focus prefetch behaviour and duplicates logic.",
|
|
56
|
+
"REQUIRES: a TanStack Query QueryClient provider (QueryClientProvider) above this component in the tree. It calls useQueryClient internally — rendering without a provider throws."
|
|
57
|
+
],
|
|
58
|
+
"useCases": [
|
|
59
|
+
"List-to-detail navigation in an accounting app: hovering an invoice row in a DataTable triggers prefetch of that invoice's detail data so the detail page renders immediately on click.",
|
|
60
|
+
"Sidebar navigation links where the destination is a dashboard or summary page — prefetch on focus covers keyboard-only users tabbing through the nav.",
|
|
61
|
+
"Paginated table rows where each row links to a resource detail page (partner, journal entry, account). prefetchOn='hover' avoids wasted prefetches from keyboard navigation.",
|
|
62
|
+
"Admin list pages with 'Edit' action links: the edit form data is prefetched on hover so the form appears populated without a loading spinner.",
|
|
63
|
+
"Breadcrumb links on deep-nested pages where clicking 'back' should feel instant — prefetch the parent page's query on mount/focus of the breadcrumb link."
|
|
64
|
+
]
|
|
65
|
+
}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
{
|
|
2
|
+
"example": "import { Progress } from \"@godxjp/ui/data-display\";\n\n<Progress value={pct} label={pct + \"% 使用中\"} tone={pct >= 80 ? \"warning\" : \"success\"} />\n<Progress value={252} over label=\"252% 積載\" />\n<Progress\n segments={[\n { value: 2, tone: \"destructive\", label: \"期限超過\" },\n { value: 3, tone: \"warning\", label: \"期限間近\" },\n { value: 12, tone: \"success\", label: \"対応済\" },\n ]}\n aria-labelledby={companyNameId}\n/>",
|
|
3
|
+
"group": "data-display",
|
|
4
|
+
"importPath": "@godxjp/ui/data-display",
|
|
5
|
+
"name": "Progress",
|
|
6
|
+
"props": [
|
|
7
|
+
{
|
|
8
|
+
"description": "METER mode: progress percentage 0–100 (clamped unless `over`). Required unless you pass `segments` — the two modes are a discriminated union, so `value` and `segments` can never appear together.",
|
|
9
|
+
"name": "value",
|
|
10
|
+
"required": true,
|
|
11
|
+
"type": "number"
|
|
12
|
+
},
|
|
13
|
+
{
|
|
14
|
+
"description": "BREAKDOWN mode: one total split into slices. Pass ABSOLUTE amounts in one unit (counts, bytes, yen) — the bar computes each share, so three numbers never have to be rounded into 100. Renders role=\"img\" named from every slice (a partition is not three progressbars), on a taller track (--progress-breakdown-block-size 1.375rem, --progress-breakdown-radius var(--radius)) because three abutting fills on the meter's 0.5rem pill read as a coloured hairline. `label` on each slice is REQUIRED — colour alone never carries meaning (WCAG 1.4.1). Mutually exclusive with value/tone/over.",
|
|
15
|
+
"name": "segments",
|
|
16
|
+
"type": "{ value: number; tone: \"success\" | \"warning\" | \"destructive\"; label: string }[]"
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
"description": "Text label beside/below the bar; it also becomes the accessible name. Pass `aria-labelledby` instead when the name is ALREADY on screen (a row's company name, a card heading) — the bar then borrows it rather than repeating it.",
|
|
20
|
+
"name": "label",
|
|
21
|
+
"type": "string"
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
"defaultValue": "\"success\"",
|
|
25
|
+
"description": "Bar colour tone. Over-capacity defaults to destructive.",
|
|
26
|
+
"name": "tone",
|
|
27
|
+
"type": "\"success\" | \"warning\" | \"destructive\""
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
"defaultValue": "false",
|
|
31
|
+
"description": "Allow value > 100 to render an over-capacity fill: bar caps at 100% width but gets a diagonal hatch + destructive tone (e.g. 252%). aria-valuetext reports the real ratio. Off by default (clamps to 100). On shape='ring' there is no hatch — diagonal stripes are a rectangle drawing — so the destructive tone and aria-valuetext carry it.",
|
|
32
|
+
"name": "over",
|
|
33
|
+
"type": "boolean"
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
"defaultValue": "\"bar\"",
|
|
37
|
+
"description": "METER geometry — the SAME measurement drawn as a full-width bar or as an arc. Same value, tone, size and ARIA either way; `label` moves INSIDE the ring, which is the point of it: a phone app bar showing '18 of 42 done' beside a title has one square of space, and a bar plus its caption needs two stacked rows. Reach for it when the SPACE is square, not when the number is important. It is meter-only: a ring around a `segments` breakdown is a pie chart, which is `PieChart donut` in the charts entry point — a part-to-whole across CATEGORIES with a legend, announced as an image rather than as a progressbar. The arc reads the MARK token tier, exactly as the bar does, so a warning ring and a warning bar on one screen are one colour.",
|
|
38
|
+
"name": "shape",
|
|
39
|
+
"type": "\"bar\" | \"ring\""
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
"defaultValue": "\"md\"",
|
|
43
|
+
"description": "Bar THICKNESS, on both modes. `md` is what each mode was designed at and stays the default. `sm` is for a bar that annotates a row rather than being the subject of the screen — an in-table capacity column, where a 1.375rem breakdown outweighs the row and sets the height of the whole table. Thickness only: the ARIA, the spoken breakdown and the corner are untouched. Never hand-write CSS to thin a bar — ui-audit blocks that in a consumer, and the two steps come from --progress-meter-block-size(-sm) / --progress-breakdown-block-size(-sm) so a theme retunes the scale instead of one call site.",
|
|
44
|
+
"name": "size",
|
|
45
|
+
"type": "\"sm\" | \"md\""
|
|
46
|
+
}
|
|
47
|
+
],
|
|
48
|
+
"related": [
|
|
49
|
+
"Slider — use Slider when the user must drag or set a bounded numeric value (volume, priority, price range); use Progress when the value is read-only and must not be interacted with.",
|
|
50
|
+
"Steps — use Steps for a discrete, named sequence of phases (onboarding wizard, checkout flow) where each step has a label and a clear current/done/pending state; use Progress for a continuous 0–100 fill.",
|
|
51
|
+
"Badge / Badge — use Badge or Badge to communicate a categorical status label (e.g. \"Paid\", \"Overdue\") without a fill metaphor; use Progress when the numeric proportion itself is the information.",
|
|
52
|
+
"StatCard — use StatCard to headline a single KPI metric with a title; compose Progress inside or alongside StatCard when a visual fill adds meaning to the number.",
|
|
53
|
+
"Legend — the key for a breakdown: which tone means what, spelled out in words once for the whole card instead of on every bar.",
|
|
54
|
+
"BarChart / PieChart / LineChart (@godxjp/ui/charts) — a Progress breakdown handles ONE total split into a few named states, inline and without a charting runtime; move up to a chart when you have several series, many categories, or a value changing over time."
|
|
55
|
+
],
|
|
56
|
+
"rules": [],
|
|
57
|
+
"storyPath": "data-display/Progress.stories.tsx",
|
|
58
|
+
"tagline": "Progress in two modes: a METER (`value` 0–100, optional tone, over-capacity striped state, drawn as a bar or — with `shape='ring'` — as an arc with the readout inside it) and a BREAKDOWN (`segments` — one total split into tone-coloured slices on a taller track).",
|
|
59
|
+
"usage": [
|
|
60
|
+
"DO import from `@godxjp/ui/data-display`, not from a generic UI path: `import { Progress } from \"@godxjp/ui/data-display\";`",
|
|
61
|
+
"DO pass `value` as a 0–100 number — the component clamps it internally via `Math.max(0, Math.min(100, value))`, so out-of-range values are safe but misleading; compute the real percentage before passing it.",
|
|
62
|
+
"DO drive `tone` dynamically from business logic — e.g. `variant={pct >= 80 ? \"warning\" : \"success\"}` — to communicate threshold status semantically rather than with raw colour classes.",
|
|
63
|
+
"DON'T use a `disabled` Slider as a read-only progress bar — Slider is semantically an interactive control even when disabled, which pollutes the a11y tree and exposes the wrong ARIA role (`slider` vs `progressbar`). Progress renders the correct read-only indicator.",
|
|
64
|
+
"DON'T pass children or sub-components — Progress is a single self-contained element (track + bar + label). The `label` prop is the only text injection point; don't wrap it in a custom parent div to add a label alongside it.",
|
|
65
|
+
"DON'T hand-roll a stacked bar out of three divs to show a part-to-whole split — pass `segments`. Hand-rolled slices need a hex fill, an arbitrary height and an arbitrary radius, which ui-audit blocks three ways (no-arbitrary-hex, no-arbitrary-size, no-arbitrary-radius), and they leave the picture with no accessible name at all.",
|
|
66
|
+
"DON'T convert segment amounts to percentages yourself — pass the raw counts. The component divides by the total, so the slices always sum to the whole; pre-rounded percentages do not.",
|
|
67
|
+
"DO pair a breakdown with `Legend` so each tone is spelled out in words once, instead of repeating the labels on every bar.",
|
|
68
|
+
"DON'T use Progress for editable numeric input or range selection — it has no callbacks, no interactivity, and no form `name` prop. Use Slider (bounded range input) or Input (free-form number) for data-entry scenarios."
|
|
69
|
+
],
|
|
70
|
+
"useCases": [
|
|
71
|
+
"Budget utilisation in an accounting dashboard — show how much of a monthly budget has been consumed, switching to `tone=\"warning\"` when the figure crosses 80%.",
|
|
72
|
+
"Invoice payment progress — display the proportion of an invoice total that has been settled (e.g. partial payments), with a label like `\"¥45,000 / ¥60,000 支払済\"` computed before passing `value`.",
|
|
73
|
+
"Storage or quota indicator in an admin panel — visualise disk usage, API quota, or seat licence consumption against a fixed limit.",
|
|
74
|
+
"Sync / import job completion feedback — surface the completion percentage of a long-running background job (polling the server) without giving the user an interactive control.",
|
|
75
|
+
"StatCard companion — pair with a `StatCard` metric to add a visual fill below the KPI number, reinforcing how close a target is to being met.",
|
|
76
|
+
"Multi-step onboarding or setup checklist — render one Progress per section (e.g. 3/5 steps complete = 60%) to give users a quick scan of overall progress across areas.",
|
|
77
|
+
"Over-capacity meter — an air-cargo weight/volume load or an over-booked resource pushed past its limit (e.g. 252%): pass `over` with the real ratio to get a red diagonal-hatched bar that reads unmistakably as over-limit, not merely full."
|
|
78
|
+
]
|
|
79
|
+
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
{
|
|
2
|
+
"example": "import { Prose } from \"@godxjp/ui/data-display\";\nimport Markdown from \"react-markdown\";\nimport remarkGfm from \"remark-gfm\";\n\n<Prose size=\"sm\">\n <Markdown remarkPlugins={[remarkGfm]}>{issue.description}</Markdown>\n</Prose>",
|
|
3
|
+
"group": "data-display",
|
|
4
|
+
"importPath": "@godxjp/ui/data-display",
|
|
5
|
+
"name": "Prose",
|
|
6
|
+
"props": [
|
|
7
|
+
{
|
|
8
|
+
"defaultValue": "\"md\"",
|
|
9
|
+
"description": "Body size. `md` is the page body size (a wiki page); `sm` is the compact step (an issue description, a comment).",
|
|
10
|
+
"name": "size",
|
|
11
|
+
"type": "\"sm\" | \"md\""
|
|
12
|
+
},
|
|
13
|
+
{
|
|
14
|
+
"defaultValue": "\"fit\"",
|
|
15
|
+
"description": "`fit` scales images to the column; `original` shows them at their authored size and the container scrolls horizontally.",
|
|
16
|
+
"name": "imageSize",
|
|
17
|
+
"type": "\"fit\" | \"original\""
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
"description": "The rendered content.",
|
|
21
|
+
"name": "children",
|
|
22
|
+
"type": "ReactNode"
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
"description": "Extra classes on the container.",
|
|
26
|
+
"name": "className",
|
|
27
|
+
"type": "string"
|
|
28
|
+
}
|
|
29
|
+
],
|
|
30
|
+
"related": [
|
|
31
|
+
"CodeBlock - a standalone block of preformatted text; Prose delegates its `pre` to the same tokens.",
|
|
32
|
+
"Text / Heading - UI copy, not a document.",
|
|
33
|
+
"LegalDocumentShell - a whole legal document with its own table of contents and section anchors; use Prose for the body of arbitrary rendered content.",
|
|
34
|
+
"ScrollArea - if a very long document needs its own scroll viewport, wrap Prose in ScrollArea."
|
|
35
|
+
],
|
|
36
|
+
"rules": [],
|
|
37
|
+
"storyPath": "data-display/Prose.stories.tsx",
|
|
38
|
+
"tagline": "Typography for rendered content (Markdown, CMS bodies, issue descriptions): styles the semantic HTML inside it from the tokens, with no opinion about where the HTML comes from.",
|
|
39
|
+
"usage": [
|
|
40
|
+
"DO import from `@godxjp/ui/data-display`: `import { Prose } from \"@godxjp/ui/data-display\";`",
|
|
41
|
+
"DO wrap the OUTPUT of your Markdown pipeline (react-markdown + remark-gfm + rehype-sanitize), a sanitised CMS string via `dangerouslySetInnerHTML`, or plain JSX. Prose styles descendants: h1..h4, p, ul/ol/li, blockquote, code, pre, table/th/td, a, img, hr.",
|
|
42
|
+
"DO keep soft line breaks the pipeline's job (remark-breaks or the renderer's `breaks` option). Prose does not turn single newlines into `<br>`; it is typography, not parsing.",
|
|
43
|
+
"DON'T restate the heading scale, table cell measures or list rhythm with `[&_h1]:text-lg [&_td]:border …` utilities: they copy token values and never follow a retune. Prose reads --heading-h1..h4, --table-cell-padding-* and --prose-* directly.",
|
|
44
|
+
"DO tune the link through --prose-link-color and --prose-link-decoration-line (gh#717). The ink defaults to hsl(var(--primary)) resolved at the anchor, so a scoped [data-tenant] re-tint reaches it; the resting underline defaults to `underline` and is a SEPARATE knob from --text-link-decoration-line, because Prose is running text and there the underline is a WCAG 1.4.1 requirement, not a taste.",
|
|
45
|
+
"DO style a state your own renderer knows about by marking the anchor and selecting it: `a[data-unresolved]` (a wiki link whose target does not exist yet), then re-declare --prose-link-color inside that selector. Prose writes data-* on its ROOT ONLY — never on a descendant — so every data-* on an `a` inside it is yours and stays selectable. That is a promise held by a test (prose-link-717.test.tsx), not a coincidence; there is no prop for it, the same way `TableRow data-expanded-row` is an attribute rather than an API.",
|
|
46
|
+
"DON'T sanitise inside Prose: it renders whatever HTML it is given. Sanitise before (rehype-sanitize, or the server).",
|
|
47
|
+
"DON'T use Prose for UI text (labels, descriptions, empty states): those are Text / Heading. Prose is for a document."
|
|
48
|
+
],
|
|
49
|
+
"useCases": [
|
|
50
|
+
"A wiki page rendered from Markdown, at the page body size.",
|
|
51
|
+
"A wiki page whose renderer marks links it knows something extra about: `<a data-unresolved=\"true\">` for a target nobody has written yet, re-declaring --prose-link-color as --text-error inside `a[data-unresolved]` so it reads differently from a link that resolves.",
|
|
52
|
+
"An issue description or a comment in a tracker, `size=\"sm\"`.",
|
|
53
|
+
"A bug-report intake inbox that renders the report body (description, steps, environment table) sent by a browser extension.",
|
|
54
|
+
"A CMS article body delivered as sanitised HTML.",
|
|
55
|
+
"An email preview rendered from stored HTML."
|
|
56
|
+
]
|
|
57
|
+
}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
{
|
|
2
|
+
"example": "import { CredentialReveal, QrCode } from \"@godxjp/ui/data-display\";\nimport { Flex } from \"@godxjp/ui/layout\";\n\n<Flex direction=\"col\" gap=\"md\">\n <QrCode\n value={security.qr_code_url}\n label=\"二要素認証の登録用QRコード\"\n size=\"lg\"\n />\n <CredentialReveal\n secret={security.secret}\n label=\"手動設定キー\"\n warning={null}\n defaultRevealed\n />\n</Flex>",
|
|
3
|
+
"group": "data-display",
|
|
4
|
+
"importPath": "@godxjp/ui/data-display",
|
|
5
|
+
"name": "QrCode",
|
|
6
|
+
"props": [
|
|
7
|
+
{
|
|
8
|
+
"description": "Value encoded in-process. It is never used as accessible text or a URL.",
|
|
9
|
+
"name": "value",
|
|
10
|
+
"required": true,
|
|
11
|
+
"type": "string"
|
|
12
|
+
},
|
|
13
|
+
{
|
|
14
|
+
"description": "Localized, purpose-specific accessible name for the QR image.",
|
|
15
|
+
"name": "label",
|
|
16
|
+
"required": true,
|
|
17
|
+
"type": "string"
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
"defaultValue": "\"md\"",
|
|
21
|
+
"description": "Natural display-size tier; remains bounded by the available inline space.",
|
|
22
|
+
"name": "size",
|
|
23
|
+
"type": "\"xs\" | \"sm\" | \"md\" | \"lg\""
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
"description": "Root SVG class override.",
|
|
27
|
+
"name": "className",
|
|
28
|
+
"type": "string"
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
"description": "Root SVG element id.",
|
|
32
|
+
"name": "id",
|
|
33
|
+
"type": "string"
|
|
34
|
+
}
|
|
35
|
+
],
|
|
36
|
+
"related": [
|
|
37
|
+
"CredentialReveal — pair it with QrCode for the manual setup-key fallback without exposing the full encoded URI.",
|
|
38
|
+
"Card — supplies the one outer enrollment surface; QrCode intentionally adds no nested border or card chrome.",
|
|
39
|
+
"Text — provides concise localized scan/manual guidance around the non-text QR image."
|
|
40
|
+
],
|
|
41
|
+
"rules": [
|
|
42
|
+
6,
|
|
43
|
+
7,
|
|
44
|
+
23,
|
|
45
|
+
24
|
|
46
|
+
],
|
|
47
|
+
"storyPath": "data-display/QrCode.stories.tsx",
|
|
48
|
+
"tagline": "Local-only SVG QR renderer for enrollment links, device pairing and other values that must never be sent to a third-party image service.",
|
|
49
|
+
"usage": [
|
|
50
|
+
"DO use QrCode when the encoded payload must remain inside the browser, especially an otpauth enrollment URI containing a TOTP secret.",
|
|
51
|
+
"DO provide a localized label that describes the job, such as 'Two-factor authentication setup code'; the encoded value is intentionally excluded from the accessibility tree.",
|
|
52
|
+
"DO compose an adjacent CredentialReveal with the manual key when users need a non-camera fallback. Keep both inside one parent Card rather than adding a bordered QR card.",
|
|
53
|
+
"DON'T create an image URL with the payload, call a remote QR service, add a logo/image overlay, or expose raw colour/size props. The local encoder, four-module quiet zone and scanner-safe colours are security and reliability invariants.",
|
|
54
|
+
"DON'T encode the manual secret alone for TOTP. Encode the canonical otpauth URI returned by the backend so issuer, account, algorithm, digits and period stay intact."
|
|
55
|
+
],
|
|
56
|
+
"useCases": [
|
|
57
|
+
"TOTP authenticator enrollment",
|
|
58
|
+
"Device pairing or application handoff",
|
|
59
|
+
"Locally rendered invitation or deep link",
|
|
60
|
+
"Payment or ticket payload that must not reach a third-party renderer"
|
|
61
|
+
]
|
|
62
|
+
}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
{
|
|
2
|
+
"example": "{`import { Radio } from \"@godxjp/ui/data-entry\";\n\n// --- Options-array API (recommended for most cases) ---\nconst PAYMENT_METHODS = [\n { label: \"Credit Card\", value: \"card\", description: \"Charged immediately on save.\" },\n { label: \"Bank Transfer\", value: \"bank\" },\n { label: \"Invoice\", value: \"invoice\", disabled: true },\n];\n\nfunction PaymentMethodPicker() {\n const [method, setMethod] = React.useState(\"card\");\n\n return (\n <Radio.Group\n name=\"payment_method\"\n value={method}\n onValueChange={setMethod}\n options={PAYMENT_METHODS}\n orientation=\"vertical\"\n />\n );\n}\n\n// --- Manual composition (when you need custom layout) ---\nfunction CustomRadioGroup() {\n return (\n <Radio.Group name=\"account_type\" defaultValue=\"asset\">\n <Radio.Item id=\"opt-asset\" value=\"asset\" />\n {/* wrap each item in Field for label + description */}\n </Radio.Group>\n );\n}`}",
|
|
3
|
+
"group": "data-entry",
|
|
4
|
+
"importPath": "@godxjp/ui/data-entry",
|
|
5
|
+
"name": "Radio",
|
|
6
|
+
"props": [
|
|
7
|
+
{
|
|
8
|
+
"defaultValue": "\"default\"",
|
|
9
|
+
"description": "antd `optionType` — how each choice is DRAWN. `default` is a radio dot beside its label; `button` welds them into one segmented bar. It is paint, never semantics: the roles stay radiogroup/radio, so arrow-key traversal and native submission keep working. That is also why this is not a ToggleGroup: a ToggleGroup's single mode is a row of aria-pressed buttons that permits 'none chosen' unless it is given `disallowEmptySelection` (gh#744), and Radio is a form control with a `name` that submits.",
|
|
10
|
+
"name": "optionType",
|
|
11
|
+
"type": "\"default\" | \"button\""
|
|
12
|
+
},
|
|
13
|
+
{
|
|
14
|
+
"defaultValue": "\"outline\"",
|
|
15
|
+
"description": "antd `buttonStyle` — fill of the selected choice while `optionType` is `button`. Ignored otherwise.",
|
|
16
|
+
"name": "buttonStyle",
|
|
17
|
+
"type": "\"outline\" | \"solid\""
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
"description": "Controlled selected value. Must be paired with onValueChange to update state.",
|
|
21
|
+
"name": "value",
|
|
22
|
+
"type": "string"
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
"description": "Uncontrolled initial value. Use when you do not need to track selection in state.",
|
|
26
|
+
"name": "defaultValue",
|
|
27
|
+
"type": "string"
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
"description": "Callback fired when the user selects a different option. Required when value is controlled.",
|
|
31
|
+
"name": "onValueChange",
|
|
32
|
+
"type": "(value: string) => void"
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
"description": "Declarative option list: { label: ReactNode; value: string; disabled?: boolean; description?: ReactNode }[]. When provided, Radio.Group renders each option as a labelled Field automatically. Omit to compose children manually.",
|
|
36
|
+
"name": "options",
|
|
37
|
+
"type": "ChoiceOptionProp[]"
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
"defaultValue": "\"vertical\"",
|
|
41
|
+
"description": "Layout direction for the option list. Vertical stacks options; horizontal lays them side by side.",
|
|
42
|
+
"name": "orientation",
|
|
43
|
+
"type": "\"vertical\" | \"horizontal\""
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
"description": "Disables the entire group when true. Individual options can also be disabled via options[].disabled.",
|
|
47
|
+
"name": "disabled",
|
|
48
|
+
"type": "boolean"
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
"description": "HTML form field name. Required for native form submission — each option is a real `<input type=\"radio\">` under this name, so the browser serialises the selected value with no extra wiring.",
|
|
52
|
+
"name": "name",
|
|
53
|
+
"type": "string"
|
|
54
|
+
},
|
|
55
|
+
{
|
|
56
|
+
"description": "Additional CSS class applied to the group root.",
|
|
57
|
+
"name": "className",
|
|
58
|
+
"type": "string"
|
|
59
|
+
},
|
|
60
|
+
{
|
|
61
|
+
"description": "Manual composition fallback — used only when options is not provided. Render Radio.Item (+ Field wrapper) children directly inside Radio.Group.",
|
|
62
|
+
"name": "children",
|
|
63
|
+
"type": "React.ReactNode"
|
|
64
|
+
}
|
|
65
|
+
],
|
|
66
|
+
"related": [
|
|
67
|
+
"Checkbox.Group — use when users may select multiple options simultaneously; Radio.Group enforces single-selection only.",
|
|
68
|
+
"Switch / Field — use for a single boolean on/off toggle (e.g. enable notifications); Radio.Group is for choosing one among three or more named options.",
|
|
69
|
+
"Select — use when there are many options (5+) and vertical screen space is limited; Radio.Group is preferable for 2-4 short options where all choices should be visible at a glance."
|
|
70
|
+
],
|
|
71
|
+
"rules": [
|
|
72
|
+
3,
|
|
73
|
+
6,
|
|
74
|
+
13,
|
|
75
|
+
23
|
|
76
|
+
],
|
|
77
|
+
"storyPath": "data-entry/Radio.stories.tsx",
|
|
78
|
+
"subParts": [
|
|
79
|
+
"RadioItem"
|
|
80
|
+
],
|
|
81
|
+
"tagline": "Radio group on react-aria-components, with an options-array shorthand — always use Radio.Group, never a bare radio input. `role=\"radio\"` is the real `<input>`; the painted dot is the `<label>` around it and carries `data-state`.",
|
|
82
|
+
"usage": [
|
|
83
|
+
"DO use Radio.Group (not the bare Radio export) as the root — it wires up the group context, keyboard navigation, and the shared input name. A lone Radio.Item outside a Radio.Group has no context and will not function.",
|
|
84
|
+
"DO prefer the options array API for static/data-driven option lists: pass options={[{ label, value, description?, disabled? }]} and Radio.Group renders each as a correctly-labelled Field automatically — no manual id/label wiring needed.",
|
|
85
|
+
"DO pass name to Radio.Group when the selection must be submitted via a native HTML form — the options ARE `<input type=\"radio\" name={name}>`, so FormData/fetch pick the value up without extra wiring.",
|
|
86
|
+
"DO use controlled mode (value + onValueChange) when the selection drives other UI (conditional fields, preview panels). Use defaultValue for fire-and-forget uncontrolled forms.",
|
|
87
|
+
"DON'T hand-roll a label-plus-radio row with raw <input type='radio'> — use Radio.Group with options or compose Radio.Item inside Field for custom markup. Every option must be wrapped in Field (or equivalent) for the label htmlFor/id linkage.",
|
|
88
|
+
"DON'T disable individual options inside the options array and ALSO set disabled on the group — group-level disabled wins and overrides all per-item disabled states."
|
|
89
|
+
],
|
|
90
|
+
"useCases": [
|
|
91
|
+
"Payment method selection (Credit Card / Bank Transfer / Invoice) on a checkout or invoice-creation form — mutually exclusive, 2-4 options, use options array + name for form submission.",
|
|
92
|
+
"Account type picker (Asset / Liability / Equity / Revenue / Expense) on a chart-of-accounts create/edit page — use options with descriptions to explain each type.",
|
|
93
|
+
"Report frequency chooser (Daily / Weekly / Monthly / Quarterly) in a scheduled-report settings panel — horizontal orientation when options are short labels.",
|
|
94
|
+
"Tax regime selector on an entity or vendor profile form where exactly one option must always be active — controlled mode so adjacent fields can react to the selection.",
|
|
95
|
+
"Approval workflow step type (Automatic / Manual / Conditional) in a workflow builder — use descriptions inside options to explain each mode without extra tooltip markup.",
|
|
96
|
+
"Filter scope toggle (All entities / Current entity only) in an admin dashboard filter bar — horizontal orientation, no name needed (state managed in React, not submitted)."
|
|
97
|
+
]
|
|
98
|
+
}
|