@godxjp/ui 28.9.0 → 28.12.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 +77 -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 +93 -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 +15515 -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 +8427 -0
- package/agent/vocabulary.json +198 -0
- package/dist/components/data-display/service-launcher-card.d.ts +19 -0
- package/dist/components/data-display/service-launcher-card.js +14 -1
- package/dist/components/data-entry/attachments.js +77 -33
- 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/avatar.d.ts +1 -18
- package/dist/components/ui/avatar.js +1 -36
- 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 +190 -1
- package/dist/i18n/messages/ja.json +188 -1
- package/dist/i18n/messages/vi.json +188 -1
- package/dist/lib/image-loading-status.d.ts +25 -0
- package/dist/lib/image-loading-status.js +41 -0
- 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 +14 -1
- package/dist/props/registry.js +18 -1
- package/dist/styles/card-layout.css +10 -4
- package/dist/styles/control.css +33 -4
- package/dist/styles/data-display-layout.css +1 -1
- package/dist/styles/data-entry-layout.css +245 -2
- 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/attachments.css +18 -9
- package/dist/tokens/components/segmented.css +7 -3
- package/dist/tokens/components/table.css +2 -1
- package/docs/COMPOSITION-VS-COMPONENT.md +41 -0
- package/docs/DESIGN-AUTHORITY.md +52 -0
- package/docs/DEVELOPMENT.md +81 -6
- package/docs/assets/service-mark-rose.svg +6 -0
- package/docs/assets/service-mark-teal.svg +5 -0
- package/docs/data-display/service-launcher-card.tsx +232 -92
- 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 +99 -18
- package/docs/showcase/theme-customization.tsx +25 -2
- package/package.json +8 -5
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
{
|
|
2
|
+
"docPath": "data-entry/attachments.tsx",
|
|
3
|
+
"example": "import { Attachments } from \"@godxjp/ui/data-entry\";\n\n<Attachments\n items={files}\n onChange={({ fileList }) => setFiles(fileList)}\n overflow=\"scrollX\"\n maxCount={5}\n/>",
|
|
4
|
+
"group": "data-entry",
|
|
5
|
+
"importPath": "@godxjp/ui/data-entry",
|
|
6
|
+
"name": "Attachments",
|
|
7
|
+
"props": [
|
|
8
|
+
{
|
|
9
|
+
"description": "Controlled attachment list. Ant Design X `items` (= antd Upload `fileList`).",
|
|
10
|
+
"name": "items",
|
|
11
|
+
"type": "AttachmentsItemProp[]"
|
|
12
|
+
},
|
|
13
|
+
{
|
|
14
|
+
"description": "antd Upload `onChange` — NOT `onValueChange`.",
|
|
15
|
+
"name": "onChange",
|
|
16
|
+
"type": "(info: { file: AttachmentsItemProp; fileList: AttachmentsItemProp[] }) => void"
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
"description": "Ant Design X `overflow`.",
|
|
20
|
+
"name": "overflow",
|
|
21
|
+
"type": "\"wrap\" | \"scrollX\" | \"scrollY\""
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
"description": "Empty-state copy for inline and drop surfaces.",
|
|
25
|
+
"name": "placeholder",
|
|
26
|
+
"type": "AttachmentsPlaceholderProp | ((type) => AttachmentsPlaceholderProp)"
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
"description": "Host for a full-screen drop overlay.",
|
|
30
|
+
"name": "getDropContainer",
|
|
31
|
+
"type": "() => HTMLElement | null"
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
"description": "Maximum files (antd Upload `maxCount`).",
|
|
35
|
+
"name": "maxCount",
|
|
36
|
+
"type": "number"
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
"defaultValue": "false",
|
|
40
|
+
"description": "Blocks selection and drop; the control stays focusable so a reader can still reach it.",
|
|
41
|
+
"name": "disabled",
|
|
42
|
+
"type": "boolean"
|
|
43
|
+
},
|
|
44
|
+
{
|
|
45
|
+
"description": "Forwarded to the hidden file input.",
|
|
46
|
+
"name": "accept",
|
|
47
|
+
"type": "string"
|
|
48
|
+
},
|
|
49
|
+
{
|
|
50
|
+
"description": "Child mode: visible trigger; upload runs through a hidden input beside it.",
|
|
51
|
+
"name": "children",
|
|
52
|
+
"type": "ReactElement"
|
|
53
|
+
}
|
|
54
|
+
],
|
|
55
|
+
"related": [
|
|
56
|
+
"Upload",
|
|
57
|
+
"ChatComposer",
|
|
58
|
+
"ChatBubbleList"
|
|
59
|
+
],
|
|
60
|
+
"rules": [
|
|
61
|
+
6,
|
|
62
|
+
44,
|
|
63
|
+
45
|
|
64
|
+
],
|
|
65
|
+
"storyPath": "data-entry/Attachments.stories.tsx",
|
|
66
|
+
"tagline": "The chat-surface attachment collection (Ant Design X Attachments): file cards, inline placeholder, optional full-screen drop target, and ref.select/ref.upload — inherits antd Upload props but names the list `items`.",
|
|
67
|
+
"usage": [
|
|
68
|
+
"DO keep antd field names on each item (`thumbUrl`, `originFileObj`, `uid`) — an Ant X call site should compile unchanged.",
|
|
69
|
+
"DO use `ref.select({ accept, multiple })` to open the picker programmatically (Ant X 2.0).",
|
|
70
|
+
"DON'T expect `styles`/`classNames` from Ant X — retune through `--attachments-*` tokens.",
|
|
71
|
+
"The card is a FIXED box — 268x68 (Ant X's own), from `--attachments-card-size` (inline) and `--attachments-card-block-size`. The block size is also the `+` tile's square and the `overflow=\"scrollY\"` one-row viewport, so retune it once and all three follow. The file input is `sr-only`: never style it visible."
|
|
72
|
+
],
|
|
73
|
+
"useCases": [
|
|
74
|
+
"The attachment tray above a ChatComposer in an assistant surface.",
|
|
75
|
+
"A Sender.Header slot showing picked files before send."
|
|
76
|
+
]
|
|
77
|
+
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
{
|
|
2
|
+
"example": "import { AuthAccountSummary } from \"@godxjp/ui/layout\";\n\n<AuthAccountSummary email={user.email} actionLabel={t(\"auth.switchAccount\")} onAction={switchAccount} />",
|
|
3
|
+
"group": "layout",
|
|
4
|
+
"importPath": "@godxjp/ui/layout",
|
|
5
|
+
"name": "AuthAccountSummary",
|
|
6
|
+
"props": [
|
|
7
|
+
{
|
|
8
|
+
"description": "Authoritative signed-in email.",
|
|
9
|
+
"name": "email",
|
|
10
|
+
"required": true,
|
|
11
|
+
"type": "string"
|
|
12
|
+
},
|
|
13
|
+
{
|
|
14
|
+
"description": "Optional real avatar URL.",
|
|
15
|
+
"name": "avatarSrc",
|
|
16
|
+
"type": "string"
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
"description": "Optional localized/text fallback; defaults to a user glyph.",
|
|
20
|
+
"name": "avatarFallback",
|
|
21
|
+
"type": "ReactNode"
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
"description": "Localized visible switch-account action label.",
|
|
25
|
+
"name": "actionLabel",
|
|
26
|
+
"required": true,
|
|
27
|
+
"type": "ReactNode"
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
"description": "Consumer-owned account-switch navigation/action.",
|
|
31
|
+
"name": "onAction",
|
|
32
|
+
"required": true,
|
|
33
|
+
"type": "() => void"
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
"description": "Disable the action while the consumer cannot switch.",
|
|
37
|
+
"name": "disabled",
|
|
38
|
+
"type": "boolean"
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
"description": "Optional structural class override.",
|
|
42
|
+
"name": "className",
|
|
43
|
+
"type": "string"
|
|
44
|
+
}
|
|
45
|
+
],
|
|
46
|
+
"related": [
|
|
47
|
+
"AuthIdentity — page identity heading and requesting-client context; use AuthAccountSummary inside the card for the signed-in user.",
|
|
48
|
+
"Avatar — use Avatar directly for general profile surfaces; AuthAccountSummary owns only the compact hosted-auth row."
|
|
49
|
+
],
|
|
50
|
+
"rules": [
|
|
51
|
+
45
|
|
52
|
+
],
|
|
53
|
+
"storyPath": "layout/AuthAccountSummary.stories.tsx",
|
|
54
|
+
"tagline": "Compact signed-in account row for hosted auth: avatar fallback, authoritative email and switch action.",
|
|
55
|
+
"usage": [
|
|
56
|
+
"Pass only the authoritative signed-in email; AuthAccountSummary never fetches or invents identity data.",
|
|
57
|
+
"Pass localized actionLabel and the existing account-switch handler. The component owns no route, mutation or permission behavior.",
|
|
58
|
+
"The package owns avatar fallback, long-email truncation, responsive action wrapping and keyboard focus. Retune only through --auth-account-summary-* tokens."
|
|
59
|
+
],
|
|
60
|
+
"useCases": [
|
|
61
|
+
"OAuth device consent and authorization cards where the user must confirm or switch the signed-in account.",
|
|
62
|
+
"Hosted consent screens that need a compact identity confirmation row without a second profile card."
|
|
63
|
+
]
|
|
64
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
{
|
|
2
|
+
"example": "import { AuthDivider } from \"@godxjp/ui/layout\";\n\n<AuthDivider label=\"or\" />",
|
|
3
|
+
"group": "layout",
|
|
4
|
+
"importPath": "@godxjp/ui/layout",
|
|
5
|
+
"name": "AuthDivider",
|
|
6
|
+
"props": [
|
|
7
|
+
{
|
|
8
|
+
"description": "Localized conjunction such as “or”.",
|
|
9
|
+
"name": "label",
|
|
10
|
+
"required": true,
|
|
11
|
+
"type": "string"
|
|
12
|
+
},
|
|
13
|
+
{
|
|
14
|
+
"description": "Optional structural class override.",
|
|
15
|
+
"name": "className",
|
|
16
|
+
"type": "string"
|
|
17
|
+
}
|
|
18
|
+
],
|
|
19
|
+
"related": [
|
|
20
|
+
"Separator — the primitive this presets; use it directly for any labelled rule outside auth."
|
|
21
|
+
],
|
|
22
|
+
"rules": [
|
|
23
|
+
44,
|
|
24
|
+
45
|
|
25
|
+
],
|
|
26
|
+
"storyPath": "layout/AuthDivider.stories.tsx",
|
|
27
|
+
"tagline": "The auth-scoped PRESET over `Separator label` — a localized conjunction between two equal rules.",
|
|
28
|
+
"usage": [
|
|
29
|
+
"DO use AuthDivider only INSIDE an auth form. It is a thin preset over `<Separator label>`: it re-points the --separator-* knobs at the --auth-shell-divider-* layer (the 11px auth micro-scale, the auth rule/label colours), so using it elsewhere drags auth geometry into an unrelated screen.",
|
|
30
|
+
"DON'T use it for a message stream's day divider or a \"new messages\" watermark — that is `<Separator label>` with a `labelAlign` and a `tone`. Misusing AuthDivider recreates the exact defect the preset removed: a service retuning its login divider silently retuned every divider in its chat."
|
|
31
|
+
],
|
|
32
|
+
"useCases": [
|
|
33
|
+
"An “or” conjunction between a credential form and a provider action row"
|
|
34
|
+
]
|
|
35
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
{
|
|
2
|
+
"example": "import { AuthFooter } from \"@godxjp/ui/layout\";\n\n<AuthFooter product=\"Acme ID\" terms={<a href=\"/terms\">Terms</a>} privacy={<a href=\"/privacy\">Privacy</a>} locale=\"English\" />",
|
|
3
|
+
"group": "layout",
|
|
4
|
+
"importPath": "@godxjp/ui/layout",
|
|
5
|
+
"name": "AuthFooter",
|
|
6
|
+
"props": [
|
|
7
|
+
{
|
|
8
|
+
"description": "Product identity content.",
|
|
9
|
+
"name": "product",
|
|
10
|
+
"required": true,
|
|
11
|
+
"type": "ReactNode"
|
|
12
|
+
},
|
|
13
|
+
{
|
|
14
|
+
"description": "Terms link or localized text.",
|
|
15
|
+
"name": "terms",
|
|
16
|
+
"required": true,
|
|
17
|
+
"type": "ReactNode"
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
"description": "Privacy link or localized text.",
|
|
21
|
+
"name": "privacy",
|
|
22
|
+
"required": true,
|
|
23
|
+
"type": "ReactNode"
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
"description": "Optional consumer-owned locale control.",
|
|
27
|
+
"name": "locale",
|
|
28
|
+
"type": "ReactNode"
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
"description": "Optional structural class override merged onto the footer root.",
|
|
32
|
+
"name": "className",
|
|
33
|
+
"type": "string"
|
|
34
|
+
}
|
|
35
|
+
],
|
|
36
|
+
"rules": [
|
|
37
|
+
45
|
|
38
|
+
],
|
|
39
|
+
"storyPath": "layout/AuthFooter.stories.tsx",
|
|
40
|
+
"tagline": "Compact hosted-auth footer for consumer-owned product, legal, privacy, and locale content.",
|
|
41
|
+
"usage": [
|
|
42
|
+
"Pass real links and locale controls from the consumer; AuthFooter never invents navigation.",
|
|
43
|
+
"DO drop it into AuthShell's `footer` slot — that slot supplies the contentinfo landmark, so AuthFooter itself renders a plain div and can also sit inside an existing footer without nesting landmarks.",
|
|
44
|
+
"AuthFooter owns ONLY the geometry: mono ramp, wrap, and a `·` separator between the slots that are actually PRESENT (omit `locale` and its separator disappears). Don't hand-write separators into the slot content.",
|
|
45
|
+
"Public type: `AuthFooterProp` (alias `AuthFooterProps`) from `@godxjp/ui/layout` — registered in the prop registry, not a local interface.",
|
|
46
|
+
"Retune the line through `--auth-footer-content-gap` / `--auth-footer-text-font-size`, never page CSS (rule #45)."
|
|
47
|
+
]
|
|
48
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
{
|
|
2
|
+
"example": "import { AuthIdentity } from \"@godxjp/ui/layout\";\nimport { Logo } from \"@godxjp/ui/general\";\n\n<AuthIdentity title=\"Sign in\" requester=\"Acme Portal is requesting access\" />\n\n// The product's own lockup, with no artwork in the consumer's repo:\n<AuthIdentity title=\"GoDX ID\" brand={<Logo mark=\"godx-lockup\" productSuffix=\"ID\" />} />",
|
|
3
|
+
"group": "layout",
|
|
4
|
+
"importPath": "@godxjp/ui/layout",
|
|
5
|
+
"name": "AuthIdentity",
|
|
6
|
+
"props": [
|
|
7
|
+
{
|
|
8
|
+
"description": "Primary auth heading.",
|
|
9
|
+
"name": "title",
|
|
10
|
+
"required": true,
|
|
11
|
+
"type": "ReactNode"
|
|
12
|
+
},
|
|
13
|
+
{
|
|
14
|
+
"description": "Brand artwork in the MARK's place, for a service whose design ships a real lockup (mark + wordmark, sometimes a product suffix). Omit it and the canonical GoDX mark renders. data-slot, .ui-auth-identity spacing and the h1 are untouched, so swapping artwork never forks the block.",
|
|
15
|
+
"name": "brand",
|
|
16
|
+
"type": "ReactNode"
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
"description": "Optional real requesting-client context.",
|
|
20
|
+
"name": "requester",
|
|
21
|
+
"type": "ReactNode"
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
"description": "Optional structural class override merged onto the identity root.",
|
|
25
|
+
"name": "className",
|
|
26
|
+
"type": "string"
|
|
27
|
+
}
|
|
28
|
+
],
|
|
29
|
+
"rules": [
|
|
30
|
+
45
|
|
31
|
+
],
|
|
32
|
+
"storyPath": "layout/AuthIdentity.stories.tsx",
|
|
33
|
+
"tagline": "Hosted-auth identity heading with the shared mark (or the product's own lockup) and optional requesting-client context.",
|
|
34
|
+
"usage": [
|
|
35
|
+
"Only show `requester` when the consumer has authoritative client context.",
|
|
36
|
+
"It ALREADY renders the canonical brand-green GoDX mark (`Logo mark=\"godx\" tone=\"success\"`, independent of --primary) plus the page h1 — don't add a second Logo or heading above it.",
|
|
37
|
+
"To show YOUR OWN lockup instead, pass it as `brand` — never wrap or rebuild the block. `brand` replaces the mark only, so the h1 stays; if your lockup already spells the product name, make `title` the SCREEN'S PURPOSE (\"Sign in\") rather than repeating the brand.",
|
|
38
|
+
"DO keep `brand` non-interactive. The slot is DECORATIVE at every fill: the mark it replaces was always aria-hidden, and a real lockup is not a mark — `Logo mark=\"godx-lockup\" productSuffix=\"ID\"` exposes \"GoDX ID\" as real text, so left in the tree beside the h1 the block announces the product twice (measured: \"GoDXIDGoDX ID\"). aria-hidden is merged onto your element, and aria-hidden over a focusable child is a WCAG failure.",
|
|
39
|
+
"Centring and rhythm are token-owned (`--auth-identity-gap` / `--auth-requester-*`); no page CSS (rule #45).",
|
|
40
|
+
"Public type: `AuthIdentityProp` (alias `AuthIdentityProps`) from `@godxjp/ui/layout` — registered in the prop registry, not a local interface."
|
|
41
|
+
]
|
|
42
|
+
}
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
{
|
|
2
|
+
"absorbed": [
|
|
3
|
+
"OrganizationChoiceList"
|
|
4
|
+
],
|
|
5
|
+
"example": "import { AuthShell, AuthIdentity, AuthFooter } from \"@godxjp/ui/layout\";\nimport { Reveal, Logo, Button } from \"@godxjp/ui/general\";\nimport { Card, CardContent, CardHeader, CardTitle } from \"@godxjp/ui/data-display\";\nimport { AppSettingPicker } from \"@godxjp/ui/navigation\";\n\nexport function DeviceAuthorizationPage() {\n return (\n // 380px card at 1440/1024 · 5px inline gutter at 390 — all token-owned, no page CSS.\n <AuthShell\n variant=\"canonical\"\n preset=\"device-authorization\"\n brand={<Logo mark=\"godx\" tone=\"success\" />}\n footer={\n <AuthFooter\n product=\"GoDX ID\"\n terms=\"Terms\"\n privacy=\"Privacy\"\n locale={<AppSettingPicker kind=\"locale\" appearance=\"labeled\" compact />}\n />\n }\n >\n <Reveal>\n <Card>\n <CardHeader>\n <AuthIdentity title=\"デバイスを認証\" requester=\"勤怠管理が認証を要求しています\" />\n <CardTitle level={2}>確認コードを入力</CardTitle>\n </CardHeader>\n <CardContent>\n {/* InputOTP + actions */}\n <Button fullWidth>デバイスを承認</Button>\n </CardContent>\n </Card>\n </Reveal>\n </AuthShell>\n );\n}",
|
|
6
|
+
"group": "layout",
|
|
7
|
+
"importPath": "@godxjp/ui/layout",
|
|
8
|
+
"name": "AuthShell",
|
|
9
|
+
"props": [
|
|
10
|
+
{
|
|
11
|
+
"description": "Centred content — typically a single auth <Card> holding the form.",
|
|
12
|
+
"name": "children",
|
|
13
|
+
"required": true,
|
|
14
|
+
"type": "ReactNode"
|
|
15
|
+
},
|
|
16
|
+
{
|
|
17
|
+
"description": "Brand bar slot pinned to the top (e.g. a <Logo> / product mark).",
|
|
18
|
+
"name": "brand",
|
|
19
|
+
"type": "ReactNode"
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
"description": "Page-level controls pinned to the TOP-RIGHT of the same banner row as `brand` — a locale <Select>/<AppSettingPicker>, a theme <ToggleGroup>, a \"need help?\" link. They belong to the PAGE, not the auth form, so they sit in the bar, not in the card. The banner renders as soon as `brand` OR `actions` is present.",
|
|
23
|
+
"name": "actions",
|
|
24
|
+
"type": "ReactNode"
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
"description": "Footer slot pinned to the bottom (legal links, locale switch, support).",
|
|
28
|
+
"name": "footer",
|
|
29
|
+
"type": "ReactNode"
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
"defaultValue": "\"default\"",
|
|
33
|
+
"description": "Visual contract for the auth surface. \"canonical\" applies the shared DXS compact geometry (36px controls, 22.5rem/360px card measure, responsive page insets, tighter field labels) through component tokens. \"default\" keeps the comfortable 44px shell with the 24rem card.",
|
|
34
|
+
"name": "variant",
|
|
35
|
+
"type": "\"default\" | \"canonical\""
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
"defaultValue": "\"default\"",
|
|
39
|
+
"description": "Named flow GEOMETRY — the package-owned layout contract for a canonical hosted-identity flow. \"device-authorization\" = a 380px card at 1440/1024 with a 5px inline page gutter at 390, AND the code field itself: the preset hands --otp-slot-{inline,block}-size the canonical 27.5x52 device-grant slot, so two 4-slot grouped boxes measure 112x54 instead of the 146x38 the square --control-height tier produced. \"registration\" = the 360px sign-up measure with a 15px inline gutter at 390 (the same page rhythm as \"login\", so sign-in to sign-up never jumps on a phone). START-aligned like login: a sign-up card is the tallest surface in the set (name/email/password/confirm/strength/consent/submit/providers) and a vertically centred tall card overflows ABOVE the scroll origin on a short viewport, putting its first field out of reach.",
|
|
40
|
+
"name": "preset",
|
|
41
|
+
"type": "\"default\" | \"login\" | \"registration\" | \"device-authorization\" | \"context-selection\" | \"account-recovery\""
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
"defaultValue": "\"default\"",
|
|
45
|
+
"description": "Inline MEASURE of the shell content slot. \"default\" is the single auth card (24rem, or 22.5rem under variant=\"canonical\"). \"wide\" opens the slot to --auth-shell-wide-card-max-width (64rem) for a SPLIT login: a brand/marketing panel beside the auth card, laid out with <ResponsiveGrid columns={{ sm: 1, lg: 2 }}>. The wide slot centres with auto margins, so a tall two-column layout starts at the top instead of overflowing above the scroll origin. Ignored under a `preset` — a preset already owns its flow geometry.",
|
|
46
|
+
"name": "measure",
|
|
47
|
+
"type": "\"default\" | \"wide\""
|
|
48
|
+
},
|
|
49
|
+
{
|
|
50
|
+
"description": "Block-axis placement of the auth column — ORTHOGONAL to `preset` the way `variant` is: the preset owns the page MEASURE (card width, inline gutters, section rhythm), `align` owns where that column sits vertically. Omit it to keep the preset's own choice: \"login\" and \"registration\" anchor so a requester/identity line that wraps to two lines cannot move the card (gh#237), every other preset centres. Pass \"center\" for a vertically centred column — the block-start inset collapses to the preset's block-end one on desktop AND mobile, so the padding is symmetric and justify-content has nothing to fight — or \"anchored\" for a top-anchored one. This is what replaces re-declaring a preset's offset tokens from consumer CSS, the page-local-vertical-offset anti-pattern presets exist to remove. HAZARD on a tall flow: a vertically centred tall card overflows ABOVE the scroll origin on a short viewport, putting its first field out of reach — which is why \"registration\" anchors by default; \"center\" is legal there but is the caller's judgement.",
|
|
51
|
+
"name": "align",
|
|
52
|
+
"type": "\"anchored\" | \"center\""
|
|
53
|
+
},
|
|
54
|
+
{
|
|
55
|
+
"description": "Vertical density scoped to auth-card descendants. Defaults to \"compact\" under variant=\"canonical\" and \"comfortable\" otherwise.",
|
|
56
|
+
"name": "density",
|
|
57
|
+
"type": "\"comfortable\" | \"compact\""
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
"description": "Extra CSS classes merged onto the shell root.",
|
|
61
|
+
"name": "className",
|
|
62
|
+
"type": "string"
|
|
63
|
+
}
|
|
64
|
+
],
|
|
65
|
+
"related": [
|
|
66
|
+
"AppShell — the shell for AUTHENTICATED app pages (sidebar + topbar + main). AuthShell is its unauthenticated counterpart (brand bar + centred card + footer). Never nest the two.",
|
|
67
|
+
"Reveal — wrap the auth <Card> in <Reveal> for the entrance animation; AuthShell delegates motion (and prefers-reduced-motion handling) to it rather than baking an animation in.",
|
|
68
|
+
"Card — the canonical container for the auth form; place the form inside <CardContent>. AuthShell centres and width-constrains it.",
|
|
69
|
+
"EmptyState — with `tone=\"success\"` for a confirmation card inside the shell (e.g. device approved).",
|
|
70
|
+
"AuthIdentity / AuthFooter / AuthStack / AuthDivider — the auth composites that fill the shell: the GoDX identity mark + heading + requesting-client line, the mono legal footer (its `locale` slot takes an <AppSettingPicker kind=\"locale\" appearance=\"labeled\" compact />), the 12px section rhythm, and the labelled \"or\" rule.",
|
|
71
|
+
"ListRow — compose the organisation choice list for `preset=\"context-selection\"` as <Card><CardContent flush><Flex as=\"ul\" marker=\"none\"> of <ListRow as=\"li\">: shared row dividers, no per-row card outline. There is no separate OrganizationChoiceList component — that is a composition pattern (rule #46), not a framework component."
|
|
72
|
+
],
|
|
73
|
+
"rules": [
|
|
74
|
+
23
|
|
75
|
+
],
|
|
76
|
+
"storyPath": "layout/AuthShell.stories.tsx",
|
|
77
|
+
"tagline": "Centred auth/login page shell — brand bar (top) + centred card (main) + footer, over min-h-dvh, at comfortable control density.",
|
|
78
|
+
"usage": [
|
|
79
|
+
"DO pass a single <Card> (with the form inside <CardContent>) as `children` — AuthShell centres it and constrains its width via `--auth-shell-card-max-width`; do NOT hand-roll a `.auth-shell-main` / `.ui-auth-scope` wrapper.",
|
|
80
|
+
"DO use `variant=\"canonical\" preset=\"login\"` for SCR-001 and pass <AuthIdentity>, <Card>, <AuthFooter> as direct children in that order (an anchor may wrap AuthIdentity). The preset owns the identity slot, card anchor, 20px section rhythm and compact card block inset for standalone and real requester states. Do not wrap the three sections in a consumer Flex/Stack or the semantic grid cannot anchor them.",
|
|
81
|
+
"DO select a `preset` instead of overriding geometry: `preset=\"login\"` for the stable SCR-001 identity/card/footer anchor, `preset=\"registration\"` for the sign-up form and its pending-email state, `preset=\"device-authorization\"` for the 380px OAuth device-grant measure, `preset=\"context-selection\"` for the 25rem organisation/context picker, `preset=\"account-recovery\"` for the 432px SCR-008 recovery/MFA panel. Page-local width/inset/vertical-offset variables are the exact anti-pattern these presets replace.",
|
|
82
|
+
"DO build the SOCIAL / PROVIDER ACTION row as a COMPOSITION — there is NO SocialLinks component: `<AuthDivider label=\"or\" />` followed by a `Flex direction=\"col\" gap=\"sm\"` of real `Button variant=\"outline\"` with the provider glyph as an aria-hidden icon. The package deliberately does not own it: which providers a product offers, in what order, and what consent they imply are product decisions, and a component would have to invent them. `disabled` / `loading` are the Button's own props — do not add a provider-specific API.",
|
|
83
|
+
"DO build the ORGANIZATION CHOICE LIST as a COMPOSITION — there is NO OrganizationChoiceList component: `Card` > `CardContent flush` > a `<Flex as=\"ul\" marker=\"none\">` of `ListRow as=\"li\"` (leading Avatar, title, description, trailing Button). `CardContent flush` is what gives shared row dividers instead of a card outline per row. Its states are existing exports, never bespoke markup: Skeleton rows for loading, `EmptyState` for no invitations, `Alert tone=\"destructive\"` for a failed fetch and `Alert tone=\"warning\"` for permission-denied. See the auth-shell-context and auth-shell-registration frames.",
|
|
84
|
+
"DO build the password-recovery and sign-in MFA CHALLENGE panels as a COMPOSITION inside `preset=\"account-recovery\"` — there is NO PasswordRecoveryPanel and NO MfaChallengePanel component: Card > CardHeader(CardTitle + CardDescription, INSIDE the bordered surface) > CardContent > AuthStack[ Alert notice · FormField fields · Button fullWidth · Flex justify=\"between\" wrap fallback row ]. Do NOT put AuthIdentity above the panel there (it always renders the hosted mark), and NEVER reuse TwoFactorSetup — that is the ENROLLMENT dialog, not a sign-in challenge. See the `auth-recovery-panels` pattern.",
|
|
85
|
+
"DO combine `variant` and `preset` — they are orthogonal: `variant` owns control density + heading size, `preset` owns the page measure. `variant=\"canonical\" preset=\"device-authorization\"` is the canonical device screen.",
|
|
86
|
+
"DO let `preset=\"context-selection\"` space the auth column: it turns the card slot into a flex column with a tokenized `--auth-shell-card-stack-gap`, so an intro (<AuthIdentity>), the choice <Card> and a trailing \"remember\" row pass as three siblings with NO page-local spacing.",
|
|
87
|
+
"DO NOT add a page-local width, inset or colour to hit an artboard — if a measure is missing, it is a library gap: a new preset or token, never consumer CSS (rules #44/#45).",
|
|
88
|
+
"DO state the block placement with `align` when a product wants the opposite of its preset's default — align=\"center\" on preset=\"login\" for a vertically centred SCR-001, align=\"anchored\" to top-anchor a preset that centres. It collapses the preset's block-start inset to its block-end one on desktop AND mobile, so justify-content has nothing to fight. Re-declaring --auth-shell-login-flow-offset-block (or any preset offset token) from a consumer stylesheet is the anti-pattern it replaces.",
|
|
89
|
+
"DO put the product/brand mark in `brand` (a <Logo> or an <Avatar>) — it renders as the top banner landmark; omit it and the banner is not rendered.",
|
|
90
|
+
"DO put page-level controls in `actions` — the locale picker, the theme <ToggleGroup>, a \"need help?\" link. They land at the banner's inline end at a tokenized gap (`--auth-shell-bar-gap`), and the banner appears even with no `brand`. Do NOT hand-roll a top-right row with `ms-auto` on the `brand` content, and do NOT reach for CenteredShell just to get a topbar with actions: CenteredShell is the AUTHENTICATED shell.",
|
|
91
|
+
"DO use `measure=\"wide\"` for the SPLIT login — a brand/marketing panel beside the auth card. The content slot opens to 64rem (`--auth-shell-wide-card-max-width`) and centres with auto margins, so the tall two-column layout starts at the top instead of overflowing above the scroll origin; lay the two halves out with <ResponsiveGrid columns={{ sm: 1, lg: 2 }}> and hide the panel below `lg`. It is IGNORED under a `preset` (a preset owns its flow geometry), so pick one or the other.",
|
|
92
|
+
"DO use `footer` for compliance/legal/support links or a locale switch — it renders as the contentinfo landmark below the card.",
|
|
93
|
+
"DO wrap the card in <Reveal> for the entrance animation (`<AuthShell><Reveal><Card/></Reveal></AuthShell>`) — Reveal honours prefers-reduced-motion; AuthShell itself stays layout-only.",
|
|
94
|
+
"DO NOT re-scope control height or heading size in the app — AuthShell already sets the comfortable control tier (44px, WCAG touch floor) and the larger auth heading via `--auth-shell-control-height` / `--auth-shell-heading-size`; a service retunes those tokens, not a bespoke class.",
|
|
95
|
+
"DO tune the COMPACT auth card through its three independent knobs, never a consumer selector on `[data-slot=\"card-content\"]`: `--auth-shell-compact-card-inset` = the inline column, `--auth-shell-card-padding-block-compact` = the card's block (top/bottom) padding — it is wired to the card's `--card-space-shell-y` and really moves CardContent's block edges — and `--auth-shell-card-body-gap-compact` = the header↔body gap. Each defaults to today's canonical rhythm, so overriding one moves ONLY that axis.",
|
|
96
|
+
"DO NOT nest AuthShell inside AppShell (or vice-versa) — AuthShell is the ROOT shell for unauthenticated pages (login/mfa/passkey/device/reset); AppShell is for the authenticated app."
|
|
97
|
+
],
|
|
98
|
+
"useCases": [
|
|
99
|
+
"Canonical Login (SCR-001): <AuthShell variant=\"canonical\" preset=\"login\"> with direct AuthIdentity · Card · AuthFooter children; the card remains anchored when requester is absent, one line or wraps to two lines.",
|
|
100
|
+
"Login page: <AuthShell brand={<Logo/>} footer={<AuthFooter/>}> wrapping a <Card> with the email/password form and a primary <Button fullWidth>.",
|
|
101
|
+
"MFA / passkey / device-authorisation step: same shell, a <Card> with the one-time-code <InputOTP> or a passkey prompt.",
|
|
102
|
+
"OAuth device-grant screen (SCR-004): <AuthShell variant=\"canonical\" preset=\"device-authorization\"> — a 380px card at 1440/1024 and a 5px inline gutter at 390, with zero page-local CSS.",
|
|
103
|
+
"Organisation / context selection (/select-context): <AuthShell variant=\"canonical\" preset=\"context-selection\" brand={<Logo mark=\"godx\" />}> with an <AuthIdentity> intro, a <Card><CardContent flush> list of <ListRow as=\"li\"> organisations, and a trailing \"remember this choice\" <Checkbox> — the preset spaces the three sections.",
|
|
104
|
+
"Split product login: <AuthShell measure=\"wide\" brand={<Logo/>} actions={<><Select locale/><ToggleGroup theme/></>}> around a <ResponsiveGrid columns={{ sm: 1, lg: 2 }}> whose first cell is the brand/value panel (hidden below lg) and whose second is the auth <Card>. See docs/showcase/case4-login.",
|
|
105
|
+
"Password reset / forgot-password / accept-invite: the centred single-card flow with a brand bar and a legal footer.",
|
|
106
|
+
"SSO landing / success confirmation: pair with an <EmptyState tone=\"success\"> inside the card for an approved-device confirmation."
|
|
107
|
+
]
|
|
108
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
{
|
|
2
|
+
"example": "import { AuthStack } from \"@godxjp/ui/layout\";\n\n<AuthStack><PasskeyAction /><CredentialsForm /></AuthStack>",
|
|
3
|
+
"group": "layout",
|
|
4
|
+
"importPath": "@godxjp/ui/layout",
|
|
5
|
+
"name": "AuthStack",
|
|
6
|
+
"props": [
|
|
7
|
+
{
|
|
8
|
+
"description": "Auth sections in visual order.",
|
|
9
|
+
"name": "children",
|
|
10
|
+
"type": "ReactNode"
|
|
11
|
+
},
|
|
12
|
+
{
|
|
13
|
+
"description": "Optional structural class override.",
|
|
14
|
+
"name": "className",
|
|
15
|
+
"type": "string"
|
|
16
|
+
}
|
|
17
|
+
],
|
|
18
|
+
"rules": [],
|
|
19
|
+
"storyPath": "layout/AuthStack.stories.tsx",
|
|
20
|
+
"tagline": "Token-spaced vertical stack for direct sections inside a canonical auth card."
|
|
21
|
+
}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
{
|
|
2
|
+
"example": "import { Avatar, AvatarFallback, AvatarImage } from \"@godxjp/ui/data-display\";\n\n<Avatar>\n <AvatarImage src=\"/user.png\" alt=\"User\" />\n <AvatarFallback>UI</AvatarFallback>\n</Avatar>\n\n// Organization entity header mark\n<Avatar shape=\"square\">\n <AvatarFallback>山</AvatarFallback>\n</Avatar>\n\n// A chat member with realtime presence — dot + localized sr-only text, never colour alone\n<Avatar presence=\"busy\">\n <AvatarImage src=\"/rei.png\" alt=\"佐藤 玲\" />\n <AvatarFallback>佐</AvatarFallback>\n</Avatar>",
|
|
3
|
+
"group": "data-display",
|
|
4
|
+
"importPath": "@godxjp/ui/data-display",
|
|
5
|
+
"name": "Avatar",
|
|
6
|
+
"props": [
|
|
7
|
+
{
|
|
8
|
+
"defaultValue": "\"circle\"",
|
|
9
|
+
"description": "Identity geometry. `circle` (default, inert) is the PERSON avatar — the round --radius-pill mark on the muted surface. `square` is the ENTITY-HEADER organization/service mark: a compact rounded square on the brand surface, whose radius, box size, fill and glyph colour are all --avatar-square-{radius,size,background,foreground} tokens. Pick the shape by WHAT the mark represents; never hand-roll it with className=\"rounded-md bg-primary\".",
|
|
10
|
+
"name": "shape",
|
|
11
|
+
"type": "\"circle\" | \"square\""
|
|
12
|
+
},
|
|
13
|
+
{
|
|
14
|
+
"defaultValue": "\"md\"",
|
|
15
|
+
"description": "Box size on the SHARED CONTROL LADDER — md 32px (--control-height, the inert default), sm 28px, xs 24px, lg 36px, the same --control-height-* tier Button and Input read. STATE IT WHENEVER THE ROW'S HEIGHT IS ALREADY DECIDED: a mark inside a `<Button size=\"icon-sm\">` trigger, a mark in a 24/28px dense table row, a mark beside a `size=\"sm\"` Button. A `size=\"sm\"` avatar measures exactly as tall as a `size=\"sm\"` Button, so the row stays level. Before gh#716 the box was welded to --control-height: a 32px mark inside a 28px icon-sm trigger OVERFLOWED it, and a consumer sweeping control heights across 38 routes had no legal move but to raise the whole row to 32px. The initials' type step and a glyph's box move WITH the box (one step of the type scale, one step of the --icon-size-* scale), and shape=\"square\" rides the identical ladder — so a small mark is small, never clipped. A size BEYOND the control ladder (a 96px profile mark) is still a className size utility; the prop is for the control row.",
|
|
16
|
+
"name": "size",
|
|
17
|
+
"type": "\"xs\" | \"sm\" | \"md\" | \"lg\""
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
"defaultValue": "\"default\"",
|
|
21
|
+
"description": "Fill treatment, ORTHOGONAL to `shape`. `default` (inert) is the identity fill — --muted for a person, the solid brand mark for `shape=\"square\"`. `tinted` is the CAPABILITY MEDALLION: a soft role wash behind a role-coloured glyph, with the glyph sized by the component. `shape=\"square\" appearance=\"tinted\"` is the canonical rounded-square medallion a feature/capability icon sits on.",
|
|
22
|
+
"name": "appearance",
|
|
23
|
+
"type": "\"default\" | \"tinted\""
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
"description": "Which side of the trigger the panel opens on. Defaults from `appearance` — a bar drops the grid below, anything else opens to the inline-end. State it when the chrome can be RE-DOCKED: `appearance` says the trigger is not in a bar but cannot say which way is out, and a rail pinned to the top edge still opens downward. Ignored by responsive=\"fullscreen\" and by the Sheet surface, which are not anchored to the trigger.",
|
|
27
|
+
"name": "side",
|
|
28
|
+
"type": "\"top\" | \"right\" | \"bottom\" | \"left\""
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
"description": "How the panel aligns to the trigger. Defaults from `appearance` — end in a bar, start otherwise. Same rule as `side`: state it only for chrome that knows its own orientation.",
|
|
32
|
+
"name": "align",
|
|
33
|
+
"type": "\"start\" | \"center\" | \"end\""
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
"description": "Realtime reachability, drawn as an indicator at the block-end/inline-end corner of the mark. Ships the dot, its geometry tokens and a localized sr-only label TOGETHER, so presence is never colour-only (WCAG 1.4.1): each value also has its own silhouette — online = filled disc (--success), away = half-filled (--warning), busy = filled + a horizontal do-not-disturb bar (--destructive), offline = hollow ring (--muted-foreground). OMIT the prop for an entity with no presence concept (an organization mark, a capability medallion): no node and no attribute are emitted. `presence=\"offline\"` is the DIFFERENT, positive statement \"known to be unreachable\" — the same distinction ListRow draws between an omitted and a `false` `unread`.",
|
|
37
|
+
"name": "presence",
|
|
38
|
+
"type": "\"online\" | \"away\" | \"busy\" | \"offline\""
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
"description": "Override the localized presence text (t(\"dataDisplay.avatar.presence.online\") …) when the product has a more precise phrasing (\"In a meeting until 15:00\"). Visually hidden either way — a presence dot never carries visible text; that is Badge status.",
|
|
42
|
+
"name": "presenceLabel",
|
|
43
|
+
"type": "string"
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
"description": "Compose AvatarImage and AvatarFallback.",
|
|
47
|
+
"name": "children",
|
|
48
|
+
"type": "ReactNode"
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
"description": "Extra classes on the avatar root.",
|
|
52
|
+
"name": "className",
|
|
53
|
+
"type": "string"
|
|
54
|
+
}
|
|
55
|
+
],
|
|
56
|
+
"related": [
|
|
57
|
+
"Badge — use beside Avatar for role/status metadata. Badge `status` is the LIFECYCLE chip (a record's state, with a visible label); Avatar `presence` is the realtime person dot. Different vocabularies on purpose — do not swap them.",
|
|
58
|
+
"ListRow — its `unread` prop is the same bargain one level up (a dot + localized sr-only text + tokens). Use ListRow `unread` for a row's read state, Avatar `presence` for the person on it."
|
|
59
|
+
],
|
|
60
|
+
"rules": [
|
|
61
|
+
3,
|
|
62
|
+
35
|
|
63
|
+
],
|
|
64
|
+
"storyPath": "data-display/Avatar.stories.tsx",
|
|
65
|
+
"subParts": [
|
|
66
|
+
"AvatarFallback",
|
|
67
|
+
"AvatarImage"
|
|
68
|
+
],
|
|
69
|
+
"tagline": "Radix Avatar wrapper with image and fallback slots for users, teams, and entities.",
|
|
70
|
+
"usage": [
|
|
71
|
+
"DO compose Avatar > AvatarImage + AvatarFallback so broken or missing images still show a readable fallback.",
|
|
72
|
+
"DO use `presence` for who is reachable RIGHT NOW — a chat member list, a DM row, a message-stream author, the topbar account mark. It is the only supported way to put a status dot on an avatar: the dot's inset is a function of the mark's own --avatar-* radius/size and of the root's clip, neither of which a page can read, which is why the hand-rolled `<span className=\"relative\"><Avatar/><span className=\"absolute -end-0.5 -bottom-0.5 size-2.5 rounded-full bg-green-500 ring-2 ring-background\"/></span>` wrapper can never be got right from outside (and fails the DS audit on the raw palette).",
|
|
73
|
+
"DON'T announce a presence CHANGE from the avatar — it carries no aria-live on purpose. A roster of 40 marks resyncing over a socket would flood a screen reader; announce the change in the consumer's own live region if the product wants it.",
|
|
74
|
+
"DON'T reach for `Badge status` for presence, or `presence` for lifecycle. Presence is volatile, per-person and realtime and renders as a dot; a lifecycle status is a record's state and renders as a labelled chip.",
|
|
75
|
+
"DO render a capability / feature icon as `<Avatar shape=\"square\" appearance=\"tinted\"><AvatarFallback><Sparkles aria-hidden /></AvatarFallback></Avatar>` — the medallion is a COMPOSITION (Avatar + a Lucide glyph, per docs/COMPOSITION-VS-COMPONENT.md), and `appearance=\"tinted\"` is the token-owned tint that composition needs. A BARE glyph beside a card title, or a hand-derived `hsl(var(--primary) / 0.1)` plate in page CSS, are both the anti-pattern this replaces. Left-aligned capability card: `<Card><CardHeader><Flex align=\"center\" gap={3}><Avatar shape=\"square\" appearance=\"tinted\">…</Avatar><CardTitle>…</CardTitle></Flex></CardHeader>…`. The row is a `Flex`, NOT `className=\"flex flex-row items-center gap-3\"` on the CardHeader — that spelling shipped here for a while and it is two ui-audit errors in a consumer (`no-utility-layout` + `no-utility-spacing`), i.e. this catalog was prescribing what the audit forbids. `CardTitle` has no `icon` prop and does not need one: the medallion is its SIBLING, not its content, and inside CardTitle it would get neither the gap nor the glyph sizing.",
|
|
76
|
+
"DO use `shape=\"square\"` for an organization / service / tenant mark in an entity header, and keep the default `shape=\"circle\"` for people. The square appearance already carries the brand surface and an AA-contrast glyph colour — a className/colour override on the call site is never needed (and is forbidden by the API-first redesign policy).",
|
|
77
|
+
"DON'T retune the entity mark per call site: set --avatar-square-{radius,size,background,foreground} ONCE in the service theme (e.g. --avatar-square-background: hsl(var(--muted)) for a neutral mark).",
|
|
78
|
+
"DON'T use Avatar for decorative thumbnails; use CardCover or an img when the image is content rather than identity.",
|
|
79
|
+
"DO set `size` from the ROW, not from the mark: a row whose height is already fixed (an icon-sm trigger, a 24/28px dense table row, a toolbar of sm controls) takes the matching avatar step, and the mark then measures exactly what a Button of the same step measures. `<Button size=\"icon-sm\"><Avatar size=\"sm\">…</Avatar></Button>` fits; the default md mark in that same trigger overflows it.",
|
|
80
|
+
"DON'T raise a whole row's control height just to fit a person's mark, and DON'T reach for a className size utility for a step that is ON the ladder (size-6 / size-7 re-derive 24/28px outside the density axis, so they stop tracking --control-height and drift from the controls beside them). className stays the escape hatch for sizes OFF the ladder — a 96px profile mark."
|
|
81
|
+
],
|
|
82
|
+
"useCases": [
|
|
83
|
+
"User profile chips",
|
|
84
|
+
"Team member lists",
|
|
85
|
+
"Account owner cells in a DataTable",
|
|
86
|
+
"Organization / service entity headers (shape=\"square\" beside the entity name and code)",
|
|
87
|
+
"Chat / collaboration people surfaces (presence=\"online|away|busy|offline\" on DM rows, channel member lists, message-stream authors)"
|
|
88
|
+
]
|
|
89
|
+
}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
{
|
|
2
|
+
"example": "import { Badge } from \"@godxjp/ui/data-display\";\n\n<Badge variant=\"secondary\">A/B</Badge>\n<Badge status=\"active\">公開中</Badge>\n<Badge status=\"プレミアム\" tone=\"success\" icon={null}>プレミアム</Badge>\n<Badge shape=\"pill\" color=\"#4488c5\">処理中</Badge>",
|
|
3
|
+
"group": "data-display",
|
|
4
|
+
"importPath": "@godxjp/ui/data-display",
|
|
5
|
+
"name": "Badge",
|
|
6
|
+
"props": [
|
|
7
|
+
{
|
|
8
|
+
"defaultValue": "\"div\"",
|
|
9
|
+
"description": "Render element. Swaps the TAG only — the chip keeps its own inline-flex box, icon and label. Pass \"span\" when the chip sits in a PHRASING context where a <div> is invalid HTML: inside a TabsTrigger, a PopoverTrigger or a Button (each renders a <button>, whose content model is phrasing content only), inside a <label>, or inside a <p>.",
|
|
10
|
+
"name": "as",
|
|
11
|
+
"type": "\"div\" | \"span\""
|
|
12
|
+
},
|
|
13
|
+
{
|
|
14
|
+
"defaultValue": "\"default\"",
|
|
15
|
+
"description": "STRUCTURAL emphasis only (fill/border style) — NOT colour. Use `tone` for semantic colour. `dashed` = dashed border.",
|
|
16
|
+
"name": "variant",
|
|
17
|
+
"type": "\"default\" | \"secondary\" | \"outline\" | \"dashed\""
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
"description": "SEMANTIC colour intent (BadgeTone = ToneProp + `primary`). This is the colour knob — success/warning/destructive/info/etc. `primary` is a SOFT brand pill (tinted brand fill + brand text) for the dashboard role-pill pattern; for a SOLID brand fill use `variant=\"default\"`. Keep variant for structure, tone for meaning.",
|
|
21
|
+
"name": "tone",
|
|
22
|
+
"type": "\"default\" | \"primary\" | \"success\" | \"warning\" | \"destructive\" | \"info\" | \"muted\" | \"neutral\""
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
"defaultValue": "\"default\"",
|
|
26
|
+
"description": "Corner radius from the tokens — `default` (badge radius), `pill` (fully rounded), `sharp` (square). Use the prop instead of a `rounded-*` className.",
|
|
27
|
+
"name": "shape",
|
|
28
|
+
"type": "\"default\" | \"pill\" | \"sharp\""
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
"defaultValue": "false",
|
|
32
|
+
"description": "Lining, fixed-width figures — for a chip whose content is a COUNT sitting in a column with other counts (a queue length per row, an unread tally per tab). Proportional figures make a `1` narrower than a `0`, so the digits do not line up and the chips jitter. The same axis Text, TableCell and StatCard already carry. Off by default: tabular figures are wider, and a chip carrying WORDS should not pay for them. Prefer it over `<Badge><Text size=\"xs\" tabular>` — that composition works, but it asks the call site to know the chip's own type step.",
|
|
33
|
+
"name": "tabular",
|
|
34
|
+
"type": "boolean"
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
"description": "The entity's OWN colour as a CSS colour — DATA, not a semantic tone: a status colour, an issue type, a tag, whatever a person picked in a settings screen. A third axis beside `variant` (structure) and `tone` (meaning), and it wins over both. The chip is WASHED rather than filled (`--badge-tint-fill` into `--badge-tint-surface`, label from `--badge-tint-foreground`) because no foreground clears WCAG AA against every colour a picker can produce — near-black and white measure equal at luminance 0.2029, both 4.15:1. Washed, the ratio is a function of the tokens instead: 8.52:1 worst case across the sRGB cube, both themes.",
|
|
38
|
+
"name": "color",
|
|
39
|
+
"type": "string"
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
"description": "Lifecycle key. Known keys auto-map to tone + icon + i18n label; unknown keys fall back to neutral.",
|
|
43
|
+
"name": "status",
|
|
44
|
+
"type": "string"
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
"description": "Leading icon override. Pass null to suppress the auto status icon.",
|
|
48
|
+
"name": "icon",
|
|
49
|
+
"type": "React.ComponentType<{ className?: string }> | null"
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
"description": "Badge label. When omitted with status, Badge renders the translated lifecycle label or raw status.",
|
|
53
|
+
"name": "children",
|
|
54
|
+
"type": "ReactNode"
|
|
55
|
+
},
|
|
56
|
+
{
|
|
57
|
+
"description": "antd Tag `closable` + `onClose` — draws a × on the chip and calls this when the user activates it. Omit for a plain badge (no ×). Accessible name quotes the string label via `navigation.filterBar.removeFilter`.",
|
|
58
|
+
"name": "onRemove",
|
|
59
|
+
"type": "() => void"
|
|
60
|
+
},
|
|
61
|
+
{
|
|
62
|
+
"description": "The × button's full accessible name, verbatim — antd 5.15+ `closable={{ 'aria-label' }}` (gh#706). Without it the name quotes the chip's label: a string `children`, or the label's RENDERED TEXT when `children` is a link or other node (so a row of saved-filter link chips never shares one bare \"Delete\"). Use it when the chip text alone doesn't say what removing does.",
|
|
63
|
+
"name": "removeLabel",
|
|
64
|
+
"type": "string"
|
|
65
|
+
}
|
|
66
|
+
],
|
|
67
|
+
"related": [
|
|
68
|
+
"Button — use instead of Badge when the chip must be interactive (clickable, toggleable). Badge carries no button role or keyboard handler; a naked `onClick` on Badge is inaccessible."
|
|
69
|
+
],
|
|
70
|
+
"rules": [
|
|
71
|
+
35
|
|
72
|
+
],
|
|
73
|
+
"storyPath": "data-display/Badge.stories.tsx",
|
|
74
|
+
"subParts": [
|
|
75
|
+
"StatusBadge"
|
|
76
|
+
],
|
|
77
|
+
"tagline": "Plain or lifecycle badge. Use `variant` for static chips, or `status` to auto-map lifecycle keys to semantic tone + icon. Labels never wrap.",
|
|
78
|
+
"usage": [
|
|
79
|
+
"DO pick the correct variant semantically: `success` (approved/paid), `warning` (pending/overdue), `destructive` (rejected/error), `secondary` (neutral category), `outline` (subtle label), `default` (primary accent). Never force a colour just for aesthetics — agents and screen readers read the variant as intent.",
|
|
80
|
+
"DO use `status` for entity lifecycle statuses (active, draft, pending, cancelled, failed, scheduled, etc.) so the component resolves the correct tone, icon, and i18n label.",
|
|
81
|
+
"DO pass `variant` explicitly for localized labels or categorical tiers, and pass `icon={null}` when a lifecycle glyph would be misleading.",
|
|
82
|
+
"Badge renders as a `<div>` by default (HTMLAttributes<HTMLDivElement>) — pass `as=\"span\"` when it sits inside a <button>, <label> or <p>, where a <div> is invalid HTML. With `onRemove`, the chip draws its own × (antd Tag closable); without it the chip is non-interactive. Do not add a naked `onClick` without an accessible role.",
|
|
83
|
+
"With `onRemove`, the × is part of the chip (antd Tag closable) — do not bolt a separate Button beside the label. Pass a string `children` label so the remover's accessible name quotes the chip.",
|
|
84
|
+
"Without `onRemove`, Badge is a leaf — pass plain text or a short ReactNode as children. Do NOT nest another Badge or interactive controls inside it.",
|
|
85
|
+
"Use semantic tokens for any className overrides (`text-muted-foreground`, `bg-destructive`) — never raw Tailwind palette classes like `bg-green-500`.",
|
|
86
|
+
"DO pass `color` — never an inline `backgroundColor` — when the colour belongs to the RECORD rather than to its meaning (a status an administrator coloured, an issue type, a tag). A hand-filled chip has to choose a foreground, and no choice is readable for every colour a picker can produce; `color` moves the ground instead and keeps the label on the surface's own foreground."
|
|
87
|
+
],
|
|
88
|
+
"useCases": [
|
|
89
|
+
"Category or tier labels on table rows — e.g. plan tier (`<Badge variant=\"secondary\">Pro</Badge>`), document type (`<Badge variant=\"outline\">Invoice</Badge>`), or locale tag (`<Badge variant=\"secondary\">EN</Badge>`).",
|
|
90
|
+
"Approval or review state in an accounting list where the value is not a lifecycle key in Badge's STATUS_MAP — e.g. a custom approval tier like `<Badge tone=\"success\">承認済</Badge>` or `<Badge tone=\"warning\">要確認</Badge>`.",
|
|
91
|
+
"Inline count or highlight next to a heading or nav item — e.g. `<Badge variant=\"destructive\">3</Badge>` beside 'Overdue invoices' to draw attention to a non-zero count.",
|
|
92
|
+
"Feature flags or experiment variant labels on admin records — e.g. `<Badge variant=\"outline\">A/B</Badge>` alongside a campaign row to indicate it is in a split test.",
|
|
93
|
+
"Read-only metadata chips inside a Descriptions.Item or Card header where a lifecycle icon would be visually heavy — e.g. currency code, payment method, or region tag.",
|
|
94
|
+
"A status or category an administrator coloured themselves, in an issue tracker or a CRM — `<Badge shape=\"pill\" color={status.color}>{status.name}</Badge>`. The colour comes out of a picker and is stored on the row, so it cannot be mapped to a tone."
|
|
95
|
+
]
|
|
96
|
+
}
|