@godxjp/ui 19.6.0 → 20.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +8 -2
- package/dist/app/theme-axes.d.ts +2 -0
- package/dist/app/theme-axes.js +45 -0
- package/dist/components/charts/chart-cartesian.d.ts +2 -1
- package/dist/components/charts/chart-cartesian.js +52 -3
- package/dist/components/charts/chart-category-axis.d.ts +55 -0
- package/dist/components/charts/chart-category-axis.js +93 -0
- package/dist/components/charts/chart-frame.d.ts +10 -1
- package/dist/components/charts/chart-frame.js +19 -3
- package/dist/components/charts/compact-bar-trend.d.ts +1 -1
- package/dist/components/charts/compact-bar-trend.js +2 -0
- package/dist/components/charts/pie-chart.d.ts +1 -1
- package/dist/components/charts/pie-chart.js +12 -1
- package/dist/components/charts/recharts-peer.d.ts +49 -0
- package/dist/components/charts/recharts-peer.js +45 -0
- package/dist/components/data-display/card.d.ts +14 -3
- package/dist/components/data-display/card.js +22 -4
- package/dist/components/data-display/code-block.js +6 -2
- package/dist/components/data-display/collapsible.d.ts +23 -4
- package/dist/components/data-display/collapsible.js +119 -4
- package/dist/components/data-display/data-table.d.ts +39 -4
- package/dist/components/data-display/data-table.js +802 -270
- package/dist/components/data-display/descriptions.d.ts +27 -6
- package/dist/components/data-display/descriptions.js +58 -17
- package/dist/components/data-display/index.d.ts +5 -1
- package/dist/components/data-display/index.js +4 -0
- package/dist/components/data-display/legend.d.ts +15 -0
- package/dist/components/data-display/legend.js +11 -0
- package/dist/components/data-display/list-row.d.ts +10 -1
- package/dist/components/data-display/list-row.js +8 -2
- package/dist/components/data-display/popover.d.ts +60 -7
- package/dist/components/data-display/popover.js +268 -39
- package/dist/components/data-display/progress.d.ts +50 -2
- package/dist/components/data-display/progress.js +57 -9
- package/dist/components/data-display/range-timeline.d.ts +38 -0
- package/dist/components/data-display/range-timeline.js +161 -0
- package/dist/components/data-display/scroll-area.js +13 -2
- package/dist/components/data-display/service-launcher-card.js +10 -10
- package/dist/components/data-display/table.d.ts +11 -3
- package/dist/components/data-display/table.js +48 -18
- package/dist/components/data-display/tree-list.js +4 -9
- package/dist/components/data-entry/calendar.d.ts +2 -2
- package/dist/components/data-entry/calendar.js +79 -33
- package/dist/components/data-entry/cascader.d.ts +1 -1
- package/dist/components/data-entry/cascader.js +188 -24
- package/dist/components/data-entry/checkbox.d.ts +19 -6
- package/dist/components/data-entry/checkbox.js +55 -16
- package/dist/components/data-entry/choice-option.d.ts +1 -1
- package/dist/components/data-entry/color-picker.d.ts +1 -1
- package/dist/components/data-entry/color-picker.js +17 -5
- package/dist/components/data-entry/control-appearance.d.ts +64 -0
- package/dist/components/data-entry/control-appearance.js +39 -0
- package/dist/components/data-entry/control-surface.d.ts +61 -0
- package/dist/components/data-entry/control-surface.js +39 -0
- package/dist/components/data-entry/date-picker.d.ts +1 -1
- package/dist/components/data-entry/date-picker.js +344 -113
- package/dist/components/data-entry/date-range-picker.d.ts +2 -2
- package/dist/components/data-entry/date-range-picker.js +278 -140
- package/dist/components/data-entry/field.js +0 -1
- package/dist/components/data-entry/form-field.d.ts +1 -1
- package/dist/components/data-entry/form-field.js +39 -4
- package/dist/components/data-entry/form.d.ts +4 -0
- package/dist/components/data-entry/form.js +5 -3
- package/dist/components/data-entry/index.d.ts +7 -3
- package/dist/components/data-entry/index.js +10 -1
- package/dist/components/data-entry/input-otp.d.ts +1 -1
- package/dist/components/data-entry/input.d.ts +12 -34
- package/dist/components/data-entry/input.js +92 -24
- package/dist/components/data-entry/label.d.ts +3 -2
- package/dist/components/data-entry/label.js +23 -10
- package/dist/components/data-entry/month-picker.d.ts +2 -2
- package/dist/components/data-entry/month-picker.js +47 -10
- package/dist/components/data-entry/month-range-picker.d.ts +2 -2
- package/dist/components/data-entry/month-range-picker.js +51 -11
- package/dist/components/data-entry/number-input.d.ts +7 -0
- package/dist/components/data-entry/number-input.js +147 -98
- package/dist/components/data-entry/password-input.d.ts +1 -1
- package/dist/components/data-entry/radio.d.ts +1 -1
- package/dist/components/data-entry/radio.js +61 -13
- package/dist/components/data-entry/search-input.d.ts +1 -1
- package/dist/components/data-entry/search-input.js +16 -2
- package/dist/components/data-entry/search-select.d.ts +2 -2
- package/dist/components/data-entry/search-select.js +209 -78
- package/dist/components/data-entry/select.d.ts +22 -4
- package/dist/components/data-entry/select.js +215 -163
- package/dist/components/data-entry/slider.d.ts +9 -1
- package/dist/components/data-entry/slider.js +87 -9
- package/dist/components/data-entry/switch.d.ts +3 -0
- package/dist/components/data-entry/switch.js +29 -3
- package/dist/components/data-entry/textarea.d.ts +14 -56
- package/dist/components/data-entry/textarea.js +80 -33
- package/dist/components/data-entry/time-picker.d.ts +2 -2
- package/dist/components/data-entry/time-picker.js +333 -109
- package/dist/components/data-entry/time-range-picker.d.ts +5 -0
- package/dist/components/data-entry/time-range-picker.js +89 -0
- package/dist/components/data-entry/transfer.d.ts +1 -1
- package/dist/components/data-entry/transfer.js +99 -31
- package/dist/components/data-entry/tree-select-strategy.d.ts +1 -1
- package/dist/components/data-entry/tree-select.d.ts +1 -1
- package/dist/components/data-entry/tree-select.js +197 -92
- package/dist/components/data-entry/tree-utils.d.ts +1 -1
- package/dist/components/data-entry/tree-utils.js +7 -14
- package/dist/components/data-entry/upload-files.d.ts +2 -0
- package/dist/components/data-entry/upload-files.js +31 -0
- package/dist/components/data-entry/upload-request.d.ts +4 -0
- package/dist/components/data-entry/upload-request.js +53 -0
- package/dist/components/data-entry/upload-types.d.ts +28 -0
- package/dist/components/data-entry/upload-types.js +2 -0
- package/dist/components/data-entry/upload.d.ts +2 -2
- package/dist/components/data-entry/upload.js +482 -117
- package/dist/components/feedback/dialog.d.ts +105 -38
- package/dist/components/feedback/dialog.js +268 -193
- package/dist/components/feedback/overlay-close-focus.d.ts +31 -0
- package/dist/components/feedback/overlay-close-focus.js +31 -0
- package/dist/components/feedback/overlay-header-tone.d.ts +1 -1
- package/dist/components/feedback/sheet.d.ts +53 -11
- package/dist/components/feedback/sheet.js +150 -81
- package/dist/components/feedback/tooltip.d.ts +51 -7
- package/dist/components/feedback/tooltip.js +107 -25
- package/dist/components/general/button.d.ts +1 -1
- package/dist/components/general/button.js +7 -3
- package/dist/components/general/index.d.ts +1 -0
- package/dist/components/general/index.js +2 -0
- package/dist/components/general/logo.d.ts +17 -0
- package/dist/components/general/logo.js +22 -16
- package/dist/components/general/typography.d.ts +3 -0
- package/dist/components/general/typography.js +15 -1
- package/dist/components/general/visually-hidden.d.ts +3 -0
- package/dist/components/general/visually-hidden.js +9 -0
- package/dist/components/layout/app-launcher.d.ts +34 -0
- package/dist/components/layout/app-launcher.js +228 -0
- package/dist/components/layout/app-shell.d.ts +3 -1
- package/dist/components/layout/app-shell.js +69 -12
- package/dist/components/layout/aspect-ratio.js +0 -1
- package/dist/components/layout/auth-divider.js +0 -1
- package/dist/components/layout/breadcrumb.d.ts +14 -2
- package/dist/components/layout/breadcrumb.js +46 -4
- package/dist/components/layout/flex.d.ts +1 -1
- package/dist/components/layout/flex.js +41 -3
- package/dist/components/layout/index.d.ts +3 -0
- package/dist/components/layout/index.js +5 -1
- package/dist/components/layout/nav-surface.d.ts +26 -0
- package/dist/components/layout/nav-surface.js +17 -0
- package/dist/components/layout/org-switcher.d.ts +5 -1
- package/dist/components/layout/org-switcher.js +25 -4
- package/dist/components/layout/page-container.d.ts +1 -1
- package/dist/components/layout/page-container.js +5 -3
- package/dist/components/layout/responsive-grid.d.ts +16 -2
- package/dist/components/layout/responsive-grid.js +29 -2
- package/dist/components/layout/separator.js +0 -1
- package/dist/components/layout/sidebar.js +4 -1
- package/dist/components/layout/split-pane.d.ts +14 -1
- package/dist/components/layout/split-pane.js +26 -13
- package/dist/components/layout/topbar-item.d.ts +3 -0
- package/dist/components/layout/topbar-item.js +19 -5
- package/dist/components/layout/topbar.d.ts +1 -1
- package/dist/components/layout/topbar.js +27 -6
- package/dist/components/navigation/app-setting-picker.js +21 -2
- package/dist/components/navigation/app-setting-toggle.d.ts +16 -0
- package/dist/components/navigation/app-setting-toggle.js +96 -0
- package/dist/components/navigation/dropdown-menu.d.ts +227 -18
- package/dist/components/navigation/dropdown-menu.js +402 -118
- package/dist/components/navigation/index.d.ts +2 -0
- package/dist/components/navigation/index.js +2 -0
- package/dist/components/navigation/pagination-utils.d.ts +2 -1
- package/dist/components/navigation/pagination.d.ts +2 -2
- package/dist/components/navigation/pagination.js +155 -83
- package/dist/components/navigation/steps.d.ts +2 -2
- package/dist/components/navigation/steps.js +29 -4
- package/dist/components/navigation/tabs.d.ts +29 -16
- package/dist/components/navigation/tabs.js +374 -144
- package/dist/components/ui/accordion.d.ts +50 -5
- package/dist/components/ui/accordion.js +239 -33
- package/dist/components/ui/aspect-ratio.d.ts +23 -2
- package/dist/components/ui/aspect-ratio.js +15 -13
- package/dist/components/ui/avatar.d.ts +29 -4
- package/dist/components/ui/avatar.js +111 -25
- package/dist/components/ui/hover-card.d.ts +42 -4
- package/dist/components/ui/hover-card.js +183 -27
- package/dist/components/ui/input-otp.d.ts +26 -28
- package/dist/components/ui/input-otp.js +50 -7
- package/dist/components/ui/label.js +0 -1
- package/dist/components/ui/password-input.d.ts +36 -2
- package/dist/components/ui/password-input.js +27 -7
- package/dist/components/ui/rating.d.ts +25 -0
- package/dist/components/ui/rating.js +67 -27
- package/dist/components/ui/segmented.d.ts +12 -3
- package/dist/components/ui/segmented.js +17 -2
- package/dist/components/ui/separator.d.ts +12 -2
- package/dist/components/ui/separator.js +30 -9
- package/dist/components/ui/tag-input.d.ts +45 -0
- package/dist/components/ui/tag-input.js +109 -27
- package/dist/components/ui/toggle-group.d.ts +50 -5
- package/dist/components/ui/toggle-group.js +79 -20
- package/dist/components/ui/toggle.d.ts +31 -5
- package/dist/components/ui/toggle.js +42 -3
- package/dist/form/form-context.d.ts +29 -0
- package/dist/form/form-context.js +44 -4
- package/dist/form/form-field-array.d.ts +22 -0
- package/dist/form/form-field-array.js +50 -0
- package/dist/form/form-field-control.d.ts +2 -1
- package/dist/form/form-field-control.js +116 -40
- package/dist/form/form-root.d.ts +2 -1
- package/dist/form/form-root.js +142 -23
- package/dist/form/index.d.ts +3 -1
- package/dist/form/index.js +12 -1
- package/dist/i18n/messages/en.json +64 -5
- package/dist/i18n/messages/ja.json +64 -5
- package/dist/i18n/messages/vi.json +64 -5
- package/dist/inertia/index.d.ts +20 -0
- package/dist/inertia/index.js +60 -1
- package/dist/lib/control-styles.d.ts +25 -3
- package/dist/lib/control-styles.js +9 -3
- package/dist/lib/datetime/picker-format.d.ts +8 -0
- package/dist/lib/datetime/picker-format.js +54 -0
- package/dist/lib/slot.d.ts +32 -0
- package/dist/lib/slot.js +22 -0
- package/dist/lib/variants.d.ts +22 -3
- package/dist/lib/variants.js +56 -1
- package/dist/props/components/app.prop.d.ts +25 -1
- package/dist/props/components/charts.prop.d.ts +21 -0
- package/dist/props/components/data-display.prop.d.ts +72 -4
- package/dist/props/components/data-entry.prop.d.ts +718 -46
- package/dist/props/components/form.prop.d.ts +142 -4
- package/dist/props/components/general.prop.d.ts +17 -1
- package/dist/props/components/index.d.ts +3 -3
- package/dist/props/components/layout.prop.d.ts +281 -11
- package/dist/props/components/navigation.prop.d.ts +114 -4
- package/dist/props/registry.d.ts +397 -11
- package/dist/props/registry.js +526 -11
- package/dist/props/vocabulary/content.prop.d.ts +1 -1
- package/dist/props/vocabulary/data.prop.d.ts +179 -1
- package/dist/props/vocabulary/index.d.ts +5 -5
- package/dist/props/vocabulary/interaction.prop.d.ts +68 -3
- package/dist/props/vocabulary/layout.prop.d.ts +57 -1
- package/dist/props/vocabulary/navigation.prop.d.ts +40 -0
- package/dist/props/vocabulary/shared.prop.d.ts +33 -0
- package/dist/styles/badge-layout.css +2 -1
- package/dist/styles/card-layout.css +26 -4
- package/dist/styles/chart-layout.css +15 -0
- package/dist/styles/control.css +657 -15
- package/dist/styles/core.css +5 -2
- package/dist/styles/data-display-layout.css +313 -6
- package/dist/styles/data-entry-layout.css +13 -0
- package/dist/styles/focus-ring.css +4 -0
- package/dist/styles/index.css +5 -2
- package/dist/styles/layout.css +327 -4
- package/dist/styles/navigation-layout.css +227 -0
- package/dist/styles/shell-layout.css +369 -13
- package/dist/styles/table-layout.css +95 -6
- package/dist/styles/text-layout.css +10 -4
- package/dist/tokens/base.css +2 -1
- package/dist/tokens/components/badge.css +1 -0
- package/dist/tokens/components/chart.css +6 -0
- package/dist/tokens/components/control.css +79 -2
- package/dist/tokens/components/data-display.css +20 -0
- package/dist/tokens/components/descriptions.css +11 -0
- package/dist/tokens/components/flex.css +8 -0
- package/dist/tokens/components/navigation.css +55 -0
- package/dist/tokens/components/shell.css +53 -3
- package/dist/tokens/components/table.css +14 -0
- package/dist/tokens/foundation.css +2 -0
- package/dist/tokens/semantic/layout.css +9 -0
- package/docs/COMPONENTS.md +9 -3
- package/docs/CONSUMER-RULES.md +13 -0
- package/docs/DESIGN-AUTHORITY.md +145 -83
- package/docs/DEVELOPMENT.md +4 -3
- package/docs/FORMS.md +151 -6
- package/docs/FRAME-COVERAGE-REPORT.md +32 -17
- package/docs/README.md +15 -15
- package/docs/STANDARDS-vocabulary-tokens.md +1 -1
- package/docs/TESTING.md +15 -6
- package/docs/WHAT-BELONGS-HERE.md +179 -0
- package/docs/charts/cjk-category-axis.tsx +81 -0
- package/docs/data-display/card/index.tsx +22 -0
- package/docs/data-display/data-table/examples/antd-parity.tsx +257 -0
- package/docs/data-display/data-table/index.tsx +23 -0
- package/docs/data-display/descriptions.tsx +41 -0
- package/docs/data-display/legend.tsx +145 -0
- package/docs/data-display/progress.tsx +32 -0
- package/docs/data-display/scroll-area.tsx +31 -25
- package/docs/data-display/table.tsx +104 -45
- package/docs/data-display/timeline.tsx +41 -0
- package/docs/data-entry/date-picker.tsx +85 -0
- package/docs/data-entry/date-range-picker.tsx +26 -0
- package/docs/data-entry/form-dynamic-fields.tsx +199 -0
- package/docs/data-entry/form.tsx +74 -4
- package/docs/data-entry/input-otp.tsx +24 -0
- package/docs/data-entry/input.tsx +46 -1
- package/docs/data-entry/month-range-picker.tsx +1 -1
- package/docs/data-entry/segmented.tsx +1 -1
- package/docs/data-entry/select.tsx +29 -2
- package/docs/data-entry/switch.tsx +41 -0
- package/docs/data-entry/textarea.tsx +38 -0
- package/docs/data-entry/time-picker.tsx +85 -1
- package/docs/data-entry/time-range-picker.tsx +55 -0
- package/docs/data-entry/transfer.tsx +17 -0
- package/docs/data-entry/upload.tsx +56 -12
- package/docs/feedback/sheet.tsx +1 -1
- package/docs/feedback/tooltip.tsx +1 -1
- package/docs/general/activity.tsx +2 -2
- package/docs/general/button/index.tsx +14 -1
- package/docs/general/typography.tsx +14 -1
- package/docs/layout/app-launcher.tsx +151 -0
- package/docs/layout/app-shell-arrangements.tsx +225 -0
- package/docs/layout/app-shell.tsx +11 -0
- package/docs/layout/aspect-ratio.tsx +1 -1
- package/docs/layout/flex.tsx +50 -0
- package/docs/layout/responsive-grid.tsx +21 -1
- package/docs/layout/topbar.tsx +5 -9
- package/docs/navigation/app-setting-picker.tsx +37 -1
- package/docs/navigation/app-setting-toggle.tsx +111 -0
- package/docs/navigation/breadcrumb.tsx +48 -0
- package/docs/navigation/dropdown-menu.tsx +21 -0
- package/docs/navigation/pagination.tsx +52 -0
- package/docs/navigation/steps.tsx +37 -0
- package/docs/navigation/tabs.tsx +97 -1
- package/docs/query/button-refetch.tsx +1 -0
- package/package.json +28 -8
- package/scripts/_agent-setup.mjs +182 -3
- package/scripts/consumer-rule.md +98 -0
- package/scripts/guinea-pig-skill.md +322 -0
- package/scripts/init-guinea-pig.mjs +84 -0
- package/scripts/postinstall.mjs +13 -2
- package/scripts/ui-audit.mjs +351 -37
- /package/dist/tokens/{antd.generated.css → derived.css} +0 -0
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
/** Form module prop types — react-hook-form + Zod 4 only. */
|
|
2
2
|
import type * as React from "react";
|
|
3
|
-
import type { FieldPath, FieldValues, UseFormProps, UseFormReturn } from "react-hook-form";
|
|
3
|
+
import type { FieldArray, FieldArrayPath, FieldErrors, FieldPath, FieldValues, UseFormProps, UseFormReturn } from "react-hook-form";
|
|
4
4
|
import type { z } from "zod";
|
|
5
|
-
import type { ErrorProp, HelperProp, IdProp, LabelProp, RequiredProp } from "../vocabulary/index.js";
|
|
5
|
+
import type { BreakpointProp, DensityProp, DisabledProp, ErrorBagProp, ErrorProp, FormLayoutProp, HelperProp, IdProp, LabelProp, RequiredProp, WidthProp } from "../vocabulary/index.js";
|
|
6
6
|
/** Schema passed to useZodForm — must be Zod 4 object schema. */
|
|
7
7
|
export type ZodSchemaProp<T extends z.ZodType = z.ZodType> = T;
|
|
8
8
|
/** Options for useZodForm (resolver injected automatically). */
|
|
@@ -27,6 +27,11 @@ export interface FormStateAdapter {
|
|
|
27
27
|
/** Optional blur handler (e.g. touch-tracking); called with the field name. */
|
|
28
28
|
onBlur?(name: string): void;
|
|
29
29
|
getValues?(): unknown;
|
|
30
|
+
/**
|
|
31
|
+
* Restore the store's initial values (e.g. Inertia's `form.reset()`). `FormRoot` calls it for a
|
|
32
|
+
* native `<Button type="reset">`, so the reset button behaves identically on both paths.
|
|
33
|
+
*/
|
|
34
|
+
reset?(): void;
|
|
30
35
|
}
|
|
31
36
|
/** @see FormRoot */
|
|
32
37
|
export type FormRootProp<TFieldValues extends FieldValues> = {
|
|
@@ -39,26 +44,159 @@ export type FormRootProp<TFieldValues extends FieldValues> = {
|
|
|
39
44
|
* Framework-agnostic form-state adapter (e.g. `inertiaAdapter(form)` from `@godxjp/ui/inertia`).
|
|
40
45
|
*/
|
|
41
46
|
adapter?: FormStateAdapter;
|
|
42
|
-
/** Submit handler. */
|
|
47
|
+
/** Submit handler — runs only after validation passes (antd `onFinish`). */
|
|
43
48
|
onSubmit: (values: TFieldValues) => void | Promise<void>;
|
|
49
|
+
/**
|
|
50
|
+
* Validation FAILED (antd `onFinishFailed`) — receives react-hook-form's error tree. Use it to
|
|
51
|
+
* announce a summary; the first invalid field is focused (and scrolled to) regardless.
|
|
52
|
+
* react-hook-form path only: on the adapter path the server owns validation.
|
|
53
|
+
*/
|
|
54
|
+
onSubmitFailed?: (errors: FieldErrors<TFieldValues>) => void;
|
|
55
|
+
/**
|
|
56
|
+
* `onSubmit` REJECTED (the network call failed). Without this the rejection escapes as an
|
|
57
|
+
* unhandled promise rejection, which is what an async `onSubmit` does today — pass a handler to
|
|
58
|
+
* render a form-level error instead.
|
|
59
|
+
*/
|
|
60
|
+
onSubmitError?: (error: unknown) => void;
|
|
61
|
+
/**
|
|
62
|
+
* A native `<Button type="reset">` inside the form restores `defaultValues` (adapter path:
|
|
63
|
+
* `adapter.reset()`); this runs afterwards for any extra app state (a status banner, a step).
|
|
64
|
+
*/
|
|
65
|
+
onReset?: () => void;
|
|
66
|
+
/**
|
|
67
|
+
* Scroll the first invalid field into view after a failed submit (antd `scrollToFirstError`).
|
|
68
|
+
* Honours `prefers-reduced-motion`. Default `true`.
|
|
69
|
+
*/
|
|
70
|
+
scrollToFirstError?: boolean;
|
|
71
|
+
/**
|
|
72
|
+
* Disable EVERY field under this form (antd Form `disabled`) — read by `FormFieldControl`
|
|
73
|
+
* (which hands `disabled` to its render prop) and by `useFormDisabled()` for the action buttons.
|
|
74
|
+
* Values are NOT dropped from the submitted payload.
|
|
75
|
+
*/
|
|
76
|
+
disabled?: DisabledProp;
|
|
77
|
+
/**
|
|
78
|
+
* Field layout for every `FormFieldControl` below (antd `layout`). Setting ANY layout prop makes
|
|
79
|
+
* `FormRoot` render the `Form` layout shell, whose `--form-block-gap` spacing replaces the plain
|
|
80
|
+
* `ui-stack-md` stack used by a bare `FormRoot`.
|
|
81
|
+
*/
|
|
82
|
+
layout?: FormLayoutProp;
|
|
83
|
+
/** Label column width in the `horizontal` layout (antd `labelCol`). */
|
|
84
|
+
labelWidth?: WidthProp;
|
|
85
|
+
/** Control column width (antd `wrapperCol`). */
|
|
86
|
+
controlWidth?: WidthProp;
|
|
87
|
+
/** Label text alignment in the `horizontal` layout (antd `labelAlign`). */
|
|
88
|
+
labelAlign?: "start" | "end";
|
|
89
|
+
/** Viewport below which a `horizontal`/`inline` layout stacks; `false` never stacks. */
|
|
90
|
+
collapseBelow?: BreakpointProp | false;
|
|
91
|
+
/** Control density for the fields below (antd Form `size`). */
|
|
92
|
+
density?: DensityProp;
|
|
93
|
+
columns?: import("./data-entry.prop.js").FormProp["columns"];
|
|
94
|
+
/** How required/optional fields are marked in their labels (antd `requiredMark`). */
|
|
95
|
+
requiredMark?: boolean | "optional";
|
|
96
|
+
/**
|
|
97
|
+
* Server validation error bag. Fields claim their own key and `<FormErrors />` renders the
|
|
98
|
+
* unclaimed remainder — the same mechanism as `Form errors`, without a second `Form` wrapper.
|
|
99
|
+
*/
|
|
100
|
+
errors?: ErrorBagProp;
|
|
44
101
|
children: React.ReactNode;
|
|
45
102
|
className?: string;
|
|
46
103
|
id?: IdProp;
|
|
47
104
|
};
|
|
48
105
|
/** @see FormFieldControl */
|
|
49
|
-
export type FormFieldControlProp<TFieldValues extends FieldValues> = {
|
|
106
|
+
export type FormFieldControlProp<TFieldValues extends FieldValues> = Pick<import("./data-entry.prop.js").FormFieldProp, "id" | "field" | "labelAddon" | "layout" | "labelWidth" | "controlWidth" | "colSpan"> & {
|
|
50
107
|
name: FieldPath<TFieldValues>;
|
|
51
108
|
label: LabelProp;
|
|
52
109
|
required?: RequiredProp;
|
|
53
110
|
helper?: HelperProp;
|
|
111
|
+
/**
|
|
112
|
+
* Disable this field only. Defaults to the surrounding `FormRoot disabled`. The resolved state
|
|
113
|
+
* reaches the control through the render prop's `disabled`; the field's value is still submitted
|
|
114
|
+
* (antd semantics), unlike react-hook-form's own `disabled`.
|
|
115
|
+
*/
|
|
116
|
+
disabled?: DisabledProp;
|
|
117
|
+
/**
|
|
118
|
+
* Re-validate this field whenever one of these fields changes (antd `dependencies`) — the
|
|
119
|
+
* confirm-password / date-range case, where the schema's cross-field `.superRefine()` reports on
|
|
120
|
+
* THIS field but only re-runs when the OTHER one is edited. Runs only once the form has been
|
|
121
|
+
* submitted, so a dependency edit never flags a field the user has not reached yet.
|
|
122
|
+
*/
|
|
123
|
+
dependencies?: FieldPath<TFieldValues>[];
|
|
124
|
+
/**
|
|
125
|
+
* Read the value out of the control's change payload (antd `getValueFromEvent`). Replaces the
|
|
126
|
+
* built-in DOM-event/raw-value detection — needed by a control that reports `(value, option)`.
|
|
127
|
+
*/
|
|
128
|
+
getValueFromEvent?: (...args: unknown[]) => unknown;
|
|
129
|
+
/**
|
|
130
|
+
* Transform the extracted value before it is stored (antd `normalize`) — trim, upper-case,
|
|
131
|
+
* digits-only. Receives the previous value so a normaliser can reject a change.
|
|
132
|
+
*/
|
|
133
|
+
normalize?: (value: unknown, previousValue: unknown) => unknown;
|
|
134
|
+
/**
|
|
135
|
+
* Message shown in the error slot INSTEAD of the resolved validation error (antd `help`) — for a
|
|
136
|
+
* server error the schema cannot know about.
|
|
137
|
+
*/
|
|
138
|
+
help?: ErrorProp;
|
|
139
|
+
/**
|
|
140
|
+
* Force the validation state shown by the field (antd `validateStatus`) — `"validating"` for a
|
|
141
|
+
* remote check in flight, `"success"` for a confirmed-unique value. A real validation error
|
|
142
|
+
* always wins; mirrors `FormField validateStatus`.
|
|
143
|
+
*/
|
|
144
|
+
validateStatus?: "success" | "warning" | "error" | "validating";
|
|
145
|
+
/** Render the status icon + localized status text for `validateStatus` (antd `hasFeedback`). */
|
|
146
|
+
hasFeedback?: boolean;
|
|
147
|
+
/** Replace the default feedback text next to the `hasFeedback` icon. */
|
|
148
|
+
feedback?: React.ReactNode;
|
|
149
|
+
/**
|
|
150
|
+
* Keep the value in the form state after the field unmounts (antd `preserve`, default `true`).
|
|
151
|
+
* `false` unregisters it — a conditional branch that must not submit a stale value.
|
|
152
|
+
*/
|
|
153
|
+
preserve?: boolean;
|
|
54
154
|
className?: string;
|
|
55
155
|
children: (field: {
|
|
56
156
|
id: string;
|
|
57
157
|
name: string;
|
|
58
158
|
value: unknown;
|
|
59
159
|
onChange: (...args: unknown[]) => void;
|
|
160
|
+
onValueChange: (...args: unknown[]) => void;
|
|
60
161
|
onBlur: () => void;
|
|
61
162
|
ref: React.Ref<HTMLInputElement>;
|
|
163
|
+
/** Present (and `true`) only when the field is disabled, so `{...field}` never re-enables a control. */
|
|
164
|
+
disabled?: DisabledProp;
|
|
165
|
+
}) => React.ReactNode;
|
|
166
|
+
};
|
|
167
|
+
/**
|
|
168
|
+
* @see FormFieldArray — dynamic repeating fields (antd `Form.List`) on react-hook-form's
|
|
169
|
+
* `useFieldArray`. `name` is the array field; each row hands back the dotted path prefix to build
|
|
170
|
+
* the child `FormFieldControl name`.
|
|
171
|
+
*/
|
|
172
|
+
export type FormFieldArrayProp<TFieldValues extends FieldValues, TName extends FieldArrayPath<TFieldValues> = FieldArrayPath<TFieldValues>> = {
|
|
173
|
+
/** Path of the array in the schema (`"contacts"`, `"invoice.lines"`). */
|
|
174
|
+
name: TName;
|
|
175
|
+
children: (list: {
|
|
176
|
+
/** One entry per row, in order. `key` is react-hook-form's stable row id — use it as the React key. */
|
|
177
|
+
fields: Array<{
|
|
178
|
+
key: string;
|
|
179
|
+
name: `${TName}.${number}`;
|
|
180
|
+
index: number;
|
|
181
|
+
}>;
|
|
182
|
+
/** Append one row (or several) at the end. */
|
|
183
|
+
append: (value: FieldArray<TFieldValues, TName> | FieldArray<TFieldValues, TName>[]) => void;
|
|
184
|
+
/** Insert one row (or several) at the front. */
|
|
185
|
+
prepend: (value: FieldArray<TFieldValues, TName> | FieldArray<TFieldValues, TName>[]) => void;
|
|
186
|
+
/** Insert at `index`. */
|
|
187
|
+
insert: (index: number, value: FieldArray<TFieldValues, TName> | FieldArray<TFieldValues, TName>[]) => void;
|
|
188
|
+
/** Remove `index` (or several); omit to clear every row. */
|
|
189
|
+
remove: (index?: number | number[]) => void;
|
|
190
|
+
/** Move a row, keeping its state (drag-reorder). */
|
|
191
|
+
move: (from: number, to: number) => void;
|
|
192
|
+
/** Exchange two rows. */
|
|
193
|
+
swap: (indexA: number, indexB: number) => void;
|
|
194
|
+
/** Replace every row at once. */
|
|
195
|
+
replace: (values: FieldArray<TFieldValues, TName>[]) => void;
|
|
196
|
+
/** Array-LEVEL validation message (a `.min(1)` on the array itself), not a row's. */
|
|
197
|
+
error?: string;
|
|
198
|
+
/** Resolved `FormRoot disabled` — gate the add/remove buttons on it. */
|
|
199
|
+
disabled: DisabledProp;
|
|
62
200
|
}) => React.ReactNode;
|
|
63
201
|
};
|
|
64
202
|
/** Mapped field error from RHF — displayed via FormField error slot. */
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/** Foundation component prop types — @see docs/COMPONENTS.md#foundation */
|
|
2
2
|
import type * as React from "react";
|
|
3
|
-
import type { ActivityAnnounceProp, ActivityVariantProp, AsChildProp, ButtonSizeProp, ButtonVariantProp, ChildrenProp, ClassNameProp, DisabledProp, FontWeightProp, HeadingLevelProp, LabelProp, OnClickProp, PendingProp, RevealDelayProp, ShapeProp, SizeProp, TextAlignProp, TextSizeProp, TextToneProp } from "../vocabulary/index.js";
|
|
3
|
+
import type { ActivityAnnounceProp, ActivityVariantProp, AsChildProp, ButtonSizeProp, ButtonVariantProp, ChildrenProp, ClassNameProp, DisabledProp, FontWeightProp, HeadingLevelProp, LabelProp, OnClickProp, PendingProp, RevealDelayProp, ShapeProp, SizeProp, TextAlignProp, TextSizeProp, TextToneProp, TextWhitespaceProp } from "../vocabulary/index.js";
|
|
4
4
|
/** @see Text — typographic primitive; replaces hand-rolled `<span className="text-[13px] …">`. */
|
|
5
5
|
export type TextProp = Omit<React.HTMLAttributes<HTMLElement>, "color"> & {
|
|
6
6
|
/** Render element. Default `span`. */
|
|
@@ -37,8 +37,24 @@ export type TextProp = Omit<React.HTMLAttributes<HTMLElement>, "color"> & {
|
|
|
37
37
|
* line-clamp styling (never write the `line-clamp-N` utility page-side).
|
|
38
38
|
*/
|
|
39
39
|
clamp?: number;
|
|
40
|
+
/**
|
|
41
|
+
* Whitespace handling. Default `normal` (CSS's own: newlines and space runs collapse).
|
|
42
|
+
*
|
|
43
|
+
* `pre-wrap` is for text a PERSON typed — a plain-text note, an issue description, a pasted log
|
|
44
|
+
* — where the line breaks and the indentation are CONTENT, not formatting. It preserves both and
|
|
45
|
+
* still wraps long lines at the container edge, and it breaks an over-long unbroken token (a URL,
|
|
46
|
+
* an id) rather than letting it overflow.
|
|
47
|
+
*
|
|
48
|
+
* Precedence is explicit and resolved in the component, not by CSS ordering: `truncate` is a
|
|
49
|
+
* single-line contract and WINS (dev builds warn, and `data-whitespace` is not emitted), while
|
|
50
|
+
* `clamp` composes with it — a clamped pre-wrap block shows its first N real lines.
|
|
51
|
+
*/
|
|
52
|
+
whitespace?: TextWhitespaceProp;
|
|
40
53
|
/** Tabular figures for aligned numbers. */
|
|
41
54
|
tabular?: boolean;
|
|
55
|
+
decoration?: "none" | "underline" | "line-through";
|
|
56
|
+
/** Inline code chip; use with as="code". */
|
|
57
|
+
chip?: boolean;
|
|
42
58
|
/** Monospace family (codes, ids). */
|
|
43
59
|
mono?: boolean;
|
|
44
60
|
htmlFor?: string;
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
export type { AppShellProp, AuthFooterProp, AuthIdentityProp, OrgSwitcherLabels, OrgSwitcherOrganization, OrgSwitcherProp, PageContainerProp, PageInsetProp, SidebarItemProp, SidebarProductProp, SidebarProp, SidebarSectionProp, TopbarProp, } from "./layout.prop.js";
|
|
1
|
+
export type { AppLauncherApp, AppLauncherGroup, AppLauncherLabels, AppLauncherProp, AppShellProp, AuthFooterProp, AuthIdentityProp, OrgSwitcherLabels, OrgSwitcherOrganization, OrgSwitcherProp, PageContainerProp, PageInsetProp, SidebarItemProp, SidebarProductProp, SidebarProp, SidebarSectionProp, TopbarProp, } from "./layout.prop.js";
|
|
2
2
|
export type { ButtonProp } from "./general.prop.js";
|
|
3
3
|
export type { InputProp, TextareaProp, FormFieldProp, SearchInputProp, CheckboxProp, CheckboxGroupProp, ChoiceOptionProp, RadioProp, RadioGroupProp, SwitchProp, SliderProp, CalendarProp, DatePickerProp, DateRangePickerProp, TimePickerProp, ColorPickerProp, UploadProp, UploadFileItemProp, UploadVariantProp, TreeOptionProp, TreeFieldNamesProp, CascaderProp, TreeSelectProp, ShowCheckedStrategyProp, TransferProp, TransferItemProp, } from "./data-entry.prop.js";
|
|
4
4
|
export type { AvatarProp, EmptyStateProp, DescriptionsProp, DescriptionsItemProp, BadgeProp, DataTableProp, QrCodeProp, } from "./data-display.prop.js";
|
|
5
5
|
export type { ChartDatum, ChartSeriesProp, LineChartProp, BarChartProp, AreaChartProp, PieChartProp, } from "./charts.prop.js";
|
|
6
6
|
export type { AlertQueryErrorProp, AlertProp, AlertTitleProp, AlertContentProp, AlertDescriptionProp, AlertActionsProp, SheetResponsiveProp, SkeletonRowsProp, } from "./feedback.prop.js";
|
|
7
7
|
export type { DataStateProp, InfiniteQueryStateProp, InfiniteQueryHelpers, PrefetchLinkProp, } from "./query.prop.js";
|
|
8
|
-
export type { PaginationProp, StepsProp, StepItemProp, StepStatusProp, TabsProp, TabItemProp, } from "./navigation.prop.js";
|
|
9
|
-
export type { AppProviderProp, AppContextValue, AppSettingKind, AppSettingPickerProp, } from "./app.prop.js";
|
|
8
|
+
export type { DropdownMenuPlacementProp, PaginationProp, PaginationSizeProp, PaginationAlignProp, StepsProp, StepItemProp, StepStatusProp, StepsTypeProp, TabsProp, TabItemProp, TabsVariantProp, TabsPlacementProp, TabsExtraProp, TabsOnEditProp, } from "./navigation.prop.js";
|
|
9
|
+
export type { AppProviderProp, AppContextValue, AppSettingKind, AppSettingPickerProp, AppSettingToggleKind, AppSettingToggleProp, } from "./app.prop.js";
|
|
10
10
|
export type { ZodSchemaProp, UseZodFormOptionsProp, UseZodFormReturnProp, FormRootProp, FormFieldControlProp, FieldErrorMessageProp, } from "./form.prop.js";
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/** Layout component prop types — @see docs/COMPONENTS.md#layout */
|
|
2
2
|
import type * as React from "react";
|
|
3
3
|
import type { ComponentType, ReactNode, SVGProps } from "react";
|
|
4
|
-
import type { BreadcrumbProp, TitleProp, SubtitleProp, StatusProp, ExtraProp, FooterProp, PageDensityProp, PageContainerVariantProp, CenteredShellWidthProp, CenteredShellAlignProp, CenteredShellPresetProp, ErrorSurfaceModeProp, ErrorSurfaceStatusProp, AuthShellPresetProp, MobileShellHeightProp, OrientationProp, TextAlignProp, TextToneProp, BreakpointProp, GapProp, ClassNameProp, ChildrenProp, IdProp, DisabledProp, DescriptionProp, ActionProp, IconProp, HeadingLevelProp, ToneProp } from "../vocabulary/index.js";
|
|
4
|
+
import type { BreadcrumbProp, TitleProp, SubtitleProp, StatusProp, ExtraProp, FooterProp, PageDensityProp, PageContainerVariantProp, CenteredShellWidthProp, CenteredShellAlignProp, CenteredShellPresetProp, ErrorSurfaceModeProp, ErrorSurfaceStatusProp, AuthShellPresetProp, MobileShellHeightProp, OrientationProp, TextAlignProp, TextToneProp, BreakpointProp, GapProp, PadProp, PadRawProp, ClassNameProp, ChildrenProp, IdProp, DisabledProp, DescriptionProp, ActionProp, IconProp, HeadingLevelProp, ToneProp, WidthProp } from "../vocabulary/index.js";
|
|
5
5
|
import type { EmptyStateToneProp } from "./data-display.prop.js";
|
|
6
6
|
/**
|
|
7
7
|
* Arrangement of the page header's title band and its `extra` slot below the 640px step.
|
|
@@ -24,6 +24,8 @@ export type PageContainerMeasureProp = "default" | "narrow" | "medium";
|
|
|
24
24
|
export type PageContainerHeaderScaleProp = "document" | "chrome";
|
|
25
25
|
/** @see PageContainer */
|
|
26
26
|
export type PageContainerProp = {
|
|
27
|
+
toolbarPad?: PadProp;
|
|
28
|
+
footerPad?: PadProp;
|
|
27
29
|
title: TitleProp;
|
|
28
30
|
subtitle?: SubtitleProp;
|
|
29
31
|
/**
|
|
@@ -101,7 +103,7 @@ export type FlexDirectionProp = "row" | "col";
|
|
|
101
103
|
export type FlexAlignProp = "start" | "center" | "end" | "stretch" | "baseline";
|
|
102
104
|
export type FlexJustifyProp = "start" | "center" | "end" | "between" | "around" | "evenly";
|
|
103
105
|
/** @see Flex */
|
|
104
|
-
export type FlexProp = React.HTMLAttributes<
|
|
106
|
+
export type FlexProp = React.HTMLAttributes<HTMLElement> & {
|
|
105
107
|
/**
|
|
106
108
|
* Render element — `div` (default) or `span` when the Flex sits in a PHRASING context and a
|
|
107
109
|
* `<div>` would be invalid HTML: inside a `TabsTrigger`/`PopoverTrigger`/`Button` (all of which
|
|
@@ -109,9 +111,66 @@ export type FlexProp = React.HTMLAttributes<HTMLDivElement> & {
|
|
|
109
111
|
* inside a `<p>`. Same closed shape as `ListRow`'s `as` — it swaps the TAG, nothing else: the
|
|
110
112
|
* `.ui-flex` rules carry `display: flex`, so the box is identical either way.
|
|
111
113
|
*/
|
|
112
|
-
as?: "div" | "span";
|
|
113
|
-
|
|
114
|
+
as?: "div" | "span" | "ul" | "ol" | "li";
|
|
115
|
+
/** Lightweight surfaces for rows and notices; no Card elevation by default. */
|
|
116
|
+
surface?: "muted" | "popover" | "warning";
|
|
117
|
+
/** Negative inline inset, using the same spacing scale as pad. */
|
|
118
|
+
bleed?: GapProp;
|
|
119
|
+
/** Floating row actions: show on parent hover, focus-within, and touch. */
|
|
120
|
+
reveal?: "hover";
|
|
121
|
+
direction?: FlexDirectionProp | Partial<Record<"base" | BreakpointProp, FlexDirectionProp>>;
|
|
122
|
+
grow?: boolean;
|
|
123
|
+
shrink?: boolean;
|
|
114
124
|
gap?: GapProp;
|
|
125
|
+
/**
|
|
126
|
+
* CỬA THOÁT: một khoảng cách tính bằng pixel, ngoài mọi bậc của thang.
|
|
127
|
+
*
|
|
128
|
+
* ## Vì sao một design system lại mở cửa thoát
|
|
129
|
+
*
|
|
130
|
+
* Vì bịt nó lại không làm thiết kế biến mất — nó chỉ làm cách làm ĐÚNG trở
|
|
131
|
+
* thành bất hợp pháp. Một bản thiết kế thật dùng 2px, 5px, 6px, 10px; thang
|
|
132
|
+
* gốc không có bậc nào như thế. Người viết mã khi ấy có ba nước, và cả ba
|
|
133
|
+
* đều tệ: làm tròn xuống bậc gần nhất (lệch bố cục, và "gần nhất" giữa hai
|
|
134
|
+
* số cách đều vốn đã là một phép đoán), viết literal (audit chặn), hoặc mở
|
|
135
|
+
* issue ngược lên rồi CHỜ. Đó là lý do mọi dự án đều lệch design — không
|
|
136
|
+
* phải người viết cẩu thả.
|
|
137
|
+
*
|
|
138
|
+
* ## Cái giá của nó
|
|
139
|
+
*
|
|
140
|
+
* Nó phát ra `data-gap-raw` lên DOM. Đó không phải trang trí: nó làm mỗi lần
|
|
141
|
+
* thoát trở nên ĐẾM ĐƯỢC — grep mã nguồn hoặc quét DOM đều ra, nên một kho
|
|
142
|
+
* đang trôi dần khỏi thang sẽ tự lộ ra bằng con số thay vì bằng cảm giác.
|
|
143
|
+
*
|
|
144
|
+
* ## Khi nào ĐỪNG dùng
|
|
145
|
+
*
|
|
146
|
+
* Khi giá trị bạn cần có trong thang. `gap={3}` là 12px và nó đọc theo
|
|
147
|
+
* `--scaling` của người dùng; `gapRaw={12}` thì không, nó đứng yên khi người
|
|
148
|
+
* ta phóng to giao diện. Thang có mười bậc — hãy tiêu hết chúng trước.
|
|
149
|
+
*
|
|
150
|
+
* Khi có mặt, nó THẮNG `gap`, và `gap` không phát lớp nào nữa để hai bên
|
|
151
|
+
* không tranh độ đặc hiệu.
|
|
152
|
+
*/
|
|
153
|
+
gapRaw?: number;
|
|
154
|
+
/**
|
|
155
|
+
* Đệm TRONG, theo thang token. Nhận một bậc cho cả bốn cạnh, hoặc một object
|
|
156
|
+
* theo cạnh LOGIC (`inline`, `block`, `inlineStart`, `blockEnd`…).
|
|
157
|
+
*
|
|
158
|
+
* Vì sao có: chạy `ui-audit` trên consumer thật (godx-chat, 08/09/2026) ra
|
|
159
|
+
* **42 trong 51 lỗi** là `no-utility-spacing`, và gần như tất cả xin cùng
|
|
160
|
+
* một thứ — padding. `<Flex className="p-3">` không phải cẩu thả; đó là nước
|
|
161
|
+
* đi duy nhất còn lại khi primitive không có prop đệm. Một prop thiếu đẻ ra
|
|
162
|
+
* 42 lỗi (gh#408).
|
|
163
|
+
*/
|
|
164
|
+
pad?: PadProp;
|
|
165
|
+
/**
|
|
166
|
+
* Đệm bằng pixel THÔ, cho giá trị ngoài thang — cùng lý do và cùng cái giá
|
|
167
|
+
* với `gapRaw`: nó để lại `data-pad-raw` trên DOM nên mỗi lần thoát đều đếm
|
|
168
|
+
* được. Đo trên 51 lỗi ấy: thiết kế cần 2px, 6px, 10px, 14px, 44px, không
|
|
169
|
+
* bậc nào có.
|
|
170
|
+
*
|
|
171
|
+
* Ghi đè `pad` ở TỪNG CẠNH, không phải cả cụm.
|
|
172
|
+
*/
|
|
173
|
+
padRaw?: PadRawProp;
|
|
115
174
|
align?: FlexAlignProp;
|
|
116
175
|
justify?: FlexJustifyProp;
|
|
117
176
|
wrap?: boolean;
|
|
@@ -126,6 +185,31 @@ export type FlexProp = React.HTMLAttributes<HTMLDivElement> & {
|
|
|
126
185
|
* only on the narrow side (a compact-only affordance). Omit for no attribute and no rule.
|
|
127
186
|
*/
|
|
128
187
|
hideFrom?: BreakpointProp;
|
|
188
|
+
/**
|
|
189
|
+
* Take the space the siblings leave — the Flex becomes the row's ELASTIC column.
|
|
190
|
+
*
|
|
191
|
+
* ## Vì sao là một trục, không phải một tiện ích
|
|
192
|
+
*
|
|
193
|
+
* Một hàng thật gần như luôn có hình `cố định | co giãn | cố định`: tên bên trái, thước đo ở
|
|
194
|
+
* giữa, con số bên phải. Không có trục này thì nước đi duy nhất là `className="flex-1 min-w-0"`
|
|
195
|
+
* — mà `ui-audit` chặn `no-utility-spacing`, nên cách làm ĐÚNG lại là cách bất hợp pháp.
|
|
196
|
+
* `PageContainer` đã có `fill` với đúng nghĩa ấy; `Flex` không có là bất đối xứng, không phải
|
|
197
|
+
* quyết định (gh#405 §2).
|
|
198
|
+
*
|
|
199
|
+
* Nó kèm luôn `min-inline-size: 0`. Đó không phải chi tiết thừa: một flex item mặc định không
|
|
200
|
+
* co nhỏ hơn nội dung, nên một `Text truncate` bên trong sẽ ĐẨY hàng rộng ra thay vì cắt bớt.
|
|
201
|
+
*/
|
|
202
|
+
fill?: boolean;
|
|
203
|
+
/**
|
|
204
|
+
* Bề rộng CỐ ĐỊNH của một cột trong hàng — số là px, chuỗi là mọi CSS length (`"12rem"`, `"40%"`).
|
|
205
|
+
*
|
|
206
|
+
* Đi kèm `flex: none`. Một `inline-size` mà sibling vẫn bóp được thì không phải cột, nó chỉ là
|
|
207
|
+
* một đề nghị — và sáu thanh xếp dọc dưới nhau sẽ bắt đầu ở sáu toạ độ x khác nhau.
|
|
208
|
+
*
|
|
209
|
+
* Nó để lại `data-width-raw` trên DOM, cùng lý do với `gapRaw`/`padRaw`: mỗi số đo cứng viết ở
|
|
210
|
+
* call site đều ĐẾM ĐƯỢC, nên một kho đang trôi khỏi thang tự lộ ra bằng con số.
|
|
211
|
+
*/
|
|
212
|
+
width?: WidthProp;
|
|
129
213
|
};
|
|
130
214
|
/** Container column counts; omitted steps inherit from the previous step. Base defaults to 1. */
|
|
131
215
|
export type ResponsiveGridColumnsProp = number | {
|
|
@@ -139,8 +223,9 @@ export type ResponsiveGridColumnsProp = number | {
|
|
|
139
223
|
* `pricing-plans` — the canonical billing/pricing-plan collection: 1 column until the `lg` step
|
|
140
224
|
* (container ≥ 64rem), then 3 columns from `lg` upward.
|
|
141
225
|
*/
|
|
226
|
+
export type ResponsiveGridFlowProp = "rows" | "columns";
|
|
142
227
|
export type ResponsiveGridPresetProp = "pricing-plans";
|
|
143
|
-
export type MasterDetailRailWidthProp = "compact" | "standard";
|
|
228
|
+
export type MasterDetailRailWidthProp = "narrow" | "compact" | "standard" | "wide";
|
|
144
229
|
export type MasterDetailRailProp = "master" | "detail";
|
|
145
230
|
/**
|
|
146
231
|
* Bounded viewport preset for the master collection. `auto` (default) never bounds it — the region
|
|
@@ -188,7 +273,8 @@ export type PageInsetProp = React.HTMLAttributes<HTMLDivElement> & {
|
|
|
188
273
|
};
|
|
189
274
|
/** @see AppShell */
|
|
190
275
|
export type AppShellProp = {
|
|
191
|
-
sidebar
|
|
276
|
+
/** Omit or pass null/false for a shell without the sidebar landmark or grid track. */
|
|
277
|
+
sidebar?: ReactNode;
|
|
192
278
|
children: ReactNode;
|
|
193
279
|
topbar?: ReactNode;
|
|
194
280
|
topbarLeft?: ReactNode;
|
|
@@ -213,11 +299,50 @@ export type AppShellProp = {
|
|
|
213
299
|
* belonging to it.
|
|
214
300
|
*/
|
|
215
301
|
topbarSpan?: "content" | "full";
|
|
302
|
+
/**
|
|
303
|
+
* A SECOND navigation column, narrower than `sidebar` and placed before it — the
|
|
304
|
+
* workspace/organization switcher shape (Slack, Teams, Discord). Passing a node adds the track;
|
|
305
|
+
* omitting it leaves the two-column shell exactly as it was. Width is
|
|
306
|
+
* `--app-shell-nav-rail-width` (3.5rem — deliberately NOT the collapsed sidebar's 4rem: at equal
|
|
307
|
+
* widths the two navigation tracks fuse into one block the moment the sidebar collapses).
|
|
308
|
+
*
|
|
309
|
+
* THE THREE COLUMNS ARE THREE SCOPES, and the scope — not the free space — is what decides where
|
|
310
|
+
* a control goes. The rail is PLATFORM scope: whatever is true across every app in the
|
|
311
|
+
* organization (which organization, which app, notifications, messages, events, organization
|
|
312
|
+
* settings, cross-app shortcuts). The sidebar is APP scope: this app's own sections. The topbar
|
|
313
|
+
* is PAGE scope: where you are and what you can do here.
|
|
314
|
+
*
|
|
315
|
+
* So app navigation never goes in the rail, a platform switch never goes in the sidebar, and a
|
|
316
|
+
* destination that would fit both belongs to the rail — because it survives changing apps. A
|
|
317
|
+
* rail that repeats the sidebar's own entries is a second chrome band carrying the first one's
|
|
318
|
+
* rank, just vertical instead of horizontal.
|
|
319
|
+
*
|
|
320
|
+
* Orthogonal to `topbarSpan`: the rail says how many navigation COLUMNS there are, `topbarSpan`
|
|
321
|
+
* says how far the BAR reaches, and every combination of the two is a real shape, so they never
|
|
322
|
+
* need to be reconciled. `sidebarCollapsed` folds the sidebar track only — the rail keeps its
|
|
323
|
+
* width, which is what keeps its destinations reachable while collapsed.
|
|
324
|
+
*
|
|
325
|
+
* Building this by hand inside the single `sidebar` slot is the trap it replaces: `Sidebar`
|
|
326
|
+
* renders `.sb-root { display: contents }`, so two of them dropped side by side dissolve into
|
|
327
|
+
* one flex row and both collapse to zero unless each is separately wrapped — and sizing the one
|
|
328
|
+
* available track for two columns means overriding `--app-shell-sidebar-width`, which is how a
|
|
329
|
+
* shipped consumer moved its content edge by 64px between routes.
|
|
330
|
+
*/
|
|
331
|
+
navRail?: ReactNode;
|
|
332
|
+
/**
|
|
333
|
+
* Accessible name for the `navRail` landmark. Defaults to the localized "Workspaces".
|
|
334
|
+
*
|
|
335
|
+
* The rail and the sidebar are two `complementary` landmarks on one page, so ARIA requires them
|
|
336
|
+
* to be tellable apart by name; the shell always supplies both defaults rather than requiring
|
|
337
|
+
* this prop, so the two columns of equal rank behave the same way.
|
|
338
|
+
*/
|
|
339
|
+
navRailLabel?: string;
|
|
216
340
|
/**
|
|
217
341
|
* Navigation shown in the mobile drawer at the DXS 900px breakpoint, where the docked sidebar is
|
|
218
|
-
* hidden. Defaults to `
|
|
219
|
-
*
|
|
220
|
-
*
|
|
342
|
+
* hidden. Defaults to `navRail` followed by `sidebar` — both docked columns are hidden at that
|
|
343
|
+
* width, so a default of `sidebar` alone would silently strip every app-level destination the
|
|
344
|
+
* rail carries. Pass a distinct node for a mobile-tailored menu, or `null` to opt out (only when
|
|
345
|
+
* navigation lives elsewhere, e.g. a bottom bar).
|
|
221
346
|
*/
|
|
222
347
|
mobileNav?: ReactNode;
|
|
223
348
|
/** Accessible title for the mobile navigation drawer. Defaults to the localized "Menu". */
|
|
@@ -354,6 +479,10 @@ export type MobileShellProp = {
|
|
|
354
479
|
* so a service retunes a day divider or an unread watermark from its theme and never forks CSS.
|
|
355
480
|
*/
|
|
356
481
|
export type SeparatorProp = Omit<React.HTMLAttributes<HTMLDivElement>, "children"> & {
|
|
482
|
+
labelSize?: "2xs" | "xs" | "sm" | "md";
|
|
483
|
+
space?: GapProp;
|
|
484
|
+
hideBelow?: BreakpointProp;
|
|
485
|
+
hideFrom?: BreakpointProp;
|
|
357
486
|
/** Rule axis. Default `"horizontal"`. */
|
|
358
487
|
orientation?: OrientationProp;
|
|
359
488
|
/**
|
|
@@ -756,12 +885,132 @@ export type OrgSwitcherProp = {
|
|
|
756
885
|
error?: ReactNode;
|
|
757
886
|
onRetry?: () => void;
|
|
758
887
|
labels: OrgSwitcherLabels;
|
|
888
|
+
/**
|
|
889
|
+
* WHICH SURFACE the panel opens on.
|
|
890
|
+
*
|
|
891
|
+
* - `"auto"` (default) — popover above `--sheet-responsive-breakpoint-width`, focus-trapped
|
|
892
|
+
* bottom Sheet at or below it.
|
|
893
|
+
* - `"dialog"` — a centred modal above that breakpoint, the same bottom Sheet below it. Reach for
|
|
894
|
+
* this once the panel carries more than a name per row — a role, a plan, a member count, a
|
|
895
|
+
* "create organization" action. A popover is anchored to its trigger, clipped by the viewport
|
|
896
|
+
* and sized by `--org-switcher-menu-width`; a dialog has a real title, a scrolling body and a
|
|
897
|
+
* footer, and takes the reader's full attention, which is the right trade when switching
|
|
898
|
+
* organization re-scopes everything on screen.
|
|
899
|
+
* - `"popover"` / `"sheet"` — pinned to one surface at every width. Useful for a deterministic
|
|
900
|
+
* embedded surface or a component test, rarely in a product.
|
|
901
|
+
*
|
|
902
|
+
* `auto` and `dialog` are the two RESPONSIVE pairs and differ only in their desktop half; the
|
|
903
|
+
* mobile half is the same Sheet, because a centred modal on a phone is a Sheet with worse
|
|
904
|
+
* ergonomics. All four resolve the breakpoint through the shared `useSheetResponsiveMode()`
|
|
905
|
+
* hook, so a service moves the line once for every overlay.
|
|
906
|
+
*/
|
|
907
|
+
responsive?: "auto" | "popover" | "sheet" | "dialog";
|
|
908
|
+
open?: boolean;
|
|
909
|
+
onOpenChange?: (open: boolean) => void;
|
|
910
|
+
className?: ClassNameProp;
|
|
911
|
+
};
|
|
912
|
+
/**
|
|
913
|
+
* One app tile in the public {@link AppLauncher} contract.
|
|
914
|
+
*
|
|
915
|
+
* A tile is a REAL LINK, always. There is no `onClick`-only entry and no `disabled` entry: an app
|
|
916
|
+
* the viewer may not open is an app the consumer does not pass. A launcher that renders inert tiles
|
|
917
|
+
* is a launcher that teaches its users to stop trusting the grid.
|
|
918
|
+
*/
|
|
919
|
+
export type AppLauncherApp = {
|
|
920
|
+
/** Stable app identifier — the React key, and the `data-app` hook an end-to-end test holds. */
|
|
921
|
+
id: string;
|
|
922
|
+
/** Visible app name. It is also the tile's accessible name — the mark is presentational. */
|
|
923
|
+
name: string;
|
|
924
|
+
/** The destination. Required, because the tile IS an `<a href>` (WCAG 2.2 / APG: link, not button). */
|
|
925
|
+
href: string;
|
|
926
|
+
/**
|
|
927
|
+
* Owned mark — a Lucide icon, a `<Logo>`, an `<img>`, an `<Avatar>`. Rendered `aria-hidden`;
|
|
928
|
+
* when omitted the launcher falls back to the first character of `name`, exactly as
|
|
929
|
+
* `OrgSwitcher` does for an organization with no avatar.
|
|
930
|
+
*/
|
|
931
|
+
icon?: ReactNode;
|
|
932
|
+
/** The app the viewer is currently inside. That tile carries `aria-current="page"`. */
|
|
933
|
+
current?: boolean;
|
|
934
|
+
/**
|
|
935
|
+
* The destination leaves this SPA. Such a tile renders a plain `<a target="_blank" rel="noreferrer
|
|
936
|
+
* noopener">` and DELIBERATELY bypasses `linkComponent`: a client-side router link to another
|
|
937
|
+
* origin is a router asked to route somewhere it does not own, which is how a launcher entry
|
|
938
|
+
* turns into a blank screen. Pair it with `labels.externalHint` (WCAG 3.2.5).
|
|
939
|
+
*/
|
|
940
|
+
external?: boolean;
|
|
941
|
+
};
|
|
942
|
+
/** A labelled section of the launcher grid — the "more from …" band of the Google-style panel. */
|
|
943
|
+
export type AppLauncherGroup = {
|
|
944
|
+
/** Section heading. Rendered as a real heading and used to name the section's own grid. */
|
|
945
|
+
label: string;
|
|
946
|
+
apps: readonly AppLauncherApp[];
|
|
947
|
+
};
|
|
948
|
+
/** Localized copy owned by the consuming product, never hard-coded by the component. */
|
|
949
|
+
export type AppLauncherLabels = {
|
|
950
|
+
/**
|
|
951
|
+
* Accessible name of the nine-dot trigger ("Apps" / "アプリ"). A plain string, NOT a function of
|
|
952
|
+
* the current app the way `OrgSwitcherLabels.trigger` is a function of the organization: the
|
|
953
|
+
* launcher's trigger shows no current value, so naming one in the trigger would announce a
|
|
954
|
+
* destination the button does not go to.
|
|
955
|
+
*/
|
|
956
|
+
trigger: string;
|
|
957
|
+
/** Panel name — the popover's accessible name and the bottom Sheet's header title. */
|
|
958
|
+
title: string;
|
|
959
|
+
empty: string;
|
|
960
|
+
loading: string;
|
|
961
|
+
retry?: string;
|
|
962
|
+
/** Screen-reader suffix for an `external` tile, e.g. "(opens in a new tab)" (WCAG 3.2.5). */
|
|
963
|
+
externalHint?: string;
|
|
964
|
+
};
|
|
965
|
+
/**
|
|
966
|
+
* @see AppLauncher — the PLATFORM-scope app switcher that lives in the topbar.
|
|
967
|
+
*
|
|
968
|
+
* Related, and repeatedly confused with it:
|
|
969
|
+
*
|
|
970
|
+
* - `ServiceLauncherCard` (data-display) is also a launcher tile, but a PAGE-SIZED one: status,
|
|
971
|
+
* hostname, plan, an action button, a reason it is locked. It belongs on a service-catalogue
|
|
972
|
+
* page, where choosing is a considered act. `AppLauncher`'s tile is bar-sized — mark plus name,
|
|
973
|
+
* the whole tile a link — because switching app is a reflex, not a decision. Neither is built
|
|
974
|
+
* out of the other; a grid of `ServiceLauncherCard`s inside a popover is the wrong component.
|
|
975
|
+
* - `AppShellProp.navRail` expresses the SAME platform scope as a docked column. These are the two
|
|
976
|
+
* ways to say it, and a product picks ONE: the launcher suits a platform with MANY apps where
|
|
977
|
+
* switching is occasional (the Google Workspace shape), the rail suits a single product where
|
|
978
|
+
* switching workspace is a constant action worth permanent screen width (the Slack shape).
|
|
979
|
+
* Shipping both puts one scope in two places and makes neither authoritative.
|
|
980
|
+
*/
|
|
981
|
+
export type AppLauncherProp = {
|
|
982
|
+
/** Ungrouped apps, rendered first, with no heading above them. */
|
|
983
|
+
apps: readonly AppLauncherApp[];
|
|
984
|
+
/** Labelled sections rendered after `apps`, in order. */
|
|
985
|
+
groups?: readonly AppLauncherGroup[];
|
|
986
|
+
labels: AppLauncherLabels;
|
|
987
|
+
/**
|
|
988
|
+
* Grid column count. Omit it and the panel keeps the stylesheet's own `--app-launcher-columns`
|
|
989
|
+
* (3, the Google-launcher shape, declared on `.ui-app-launcher-panel`): the default is where a
|
|
990
|
+
* theme can reach it, and this prop is the per-instance override written inline on top.
|
|
991
|
+
*/
|
|
992
|
+
columns?: number;
|
|
993
|
+
/**
|
|
994
|
+
* THE framework-router contract, reusing `SidebarLinkComponentProp` VERBATIM — the same type
|
|
995
|
+
* `Sidebar` and `NavList` take, so a service that already wrote `inertiaSidebarLink(Link)` or
|
|
996
|
+
* `createSidebarLink(Link, "to")` for its rail hands the same value here. The launcher still
|
|
997
|
+
* composes the tile (mark, name, `aria-current`, the external hint); the consumer supplies only
|
|
998
|
+
* the element type. `external` apps bypass it — see {@link AppLauncherApp.external}.
|
|
999
|
+
*/
|
|
1000
|
+
linkComponent?: SidebarLinkComponentProp;
|
|
1001
|
+
loading?: boolean;
|
|
1002
|
+
/** Error content replaces the grid while preserving the trigger and the retry affordance. */
|
|
1003
|
+
error?: ReactNode;
|
|
1004
|
+
onRetry?: () => void;
|
|
759
1005
|
/**
|
|
760
1006
|
* `"auto"` (default) uses the desktop popover above `--sheet-responsive-breakpoint-width` and a
|
|
761
1007
|
* focus-trapped bottom Sheet at/below it — the SAME token that drives `SheetContent
|
|
762
1008
|
* responsive="auto"`, resolved through the shared `useSheetResponsiveMode()` hook, so a service
|
|
763
1009
|
* moves the drawer line once for every overlay instead of per component.
|
|
764
|
-
*
|
|
1010
|
+
*
|
|
1011
|
+
* No `"dialog"` here, unlike `OrgSwitcher`: a launcher grid is a jump table, and a modal that
|
|
1012
|
+
* takes over the screen to offer nine links is heavier than the errand. Switching ORGANIZATION
|
|
1013
|
+
* re-scopes everything on screen and earns the interruption; opening an app does not.
|
|
765
1014
|
*/
|
|
766
1015
|
responsive?: "auto" | "popover" | "sheet";
|
|
767
1016
|
open?: boolean;
|
|
@@ -826,6 +1075,8 @@ export type SidebarProp = {
|
|
|
826
1075
|
* configured via THEIR own props and dropped into a slot.
|
|
827
1076
|
*/
|
|
828
1077
|
export type TopbarProp = Omit<React.HTMLAttributes<HTMLDivElement>, "children"> & {
|
|
1078
|
+
height?: "bar" | "auto";
|
|
1079
|
+
pad?: PadProp;
|
|
829
1080
|
/** Inline-start cluster — typically the sidebar toggle + a brand mark (`Avatar`) + primary nav. */
|
|
830
1081
|
start?: ReactNode;
|
|
831
1082
|
/** Center cluster — optional (e.g. a search trigger or a page/entity switcher). */
|
|
@@ -842,7 +1093,7 @@ export type TopbarProp = Omit<React.HTMLAttributes<HTMLDivElement>, "children">
|
|
|
842
1093
|
* It exists because the alternative is a `Button`, and a Button in a bar is a control that landed
|
|
843
1094
|
* in the bar rather than a part of it — a pill of its own height floating in a taller strip, with
|
|
844
1095
|
* its own hover surface and its own focus ring drawn around that pill. Fluent, SLDS, Atlassian and
|
|
845
|
-
*
|
|
1096
|
+
* and enterprise pro-layouts all draw a top-bar trigger the other way: the cell is as tall as the bar, its
|
|
846
1097
|
* hover is the bar's own surface, and the focus mark is hosted INSIDE the cell because a
|
|
847
1098
|
* full-bleed cell has nothing outside itself to ring.
|
|
848
1099
|
*/
|
|
@@ -851,6 +1102,25 @@ export type TopbarItemProp = Omit<React.ButtonHTMLAttributes<HTMLButtonElement>,
|
|
|
851
1102
|
* Render the bar-cell shape ONTO the child instead of emitting a `<button>` — for a router link,
|
|
852
1103
|
* or for a menu/popover trigger that needs to own the element itself.
|
|
853
1104
|
*/
|
|
1105
|
+
/** Hide below a shared responsive breakpoint, without changing cell height. */
|
|
1106
|
+
hideBelow?: BreakpointProp;
|
|
1107
|
+
/**
|
|
1108
|
+
* Unread count OVERLAID on the cell's glyph — the notification-bell affordance the cell's own use
|
|
1109
|
+
* cases name (gh#398). Pass the CONTENT ONLY, exactly like `SidebarItemProp.badge`: a number, a
|
|
1110
|
+
* string, `"99+"`. Position, size and colour come from `--topbar-item-badge-*`, so the count does
|
|
1111
|
+
* NOT widen the cell (an inline chip pushes the end cluster's shrink budget around every time the
|
|
1112
|
+
* count crosses a digit boundary) and a theme can retune the overlay once.
|
|
1113
|
+
*
|
|
1114
|
+
* The count is not an accessible name: give the cell an `aria-label` that says what the number
|
|
1115
|
+
* means (`aria-label={t("topbar.notifications.unread", { count })}`).
|
|
1116
|
+
*/
|
|
1117
|
+
badge?: ReactNode;
|
|
1118
|
+
/**
|
|
1119
|
+
* Emphasis of `badge`. Vocabulary shared VERBATIM with `SidebarItemProp.badgeTone` so one count
|
|
1120
|
+
* pill reads the same in the rail and in the bar: `destructive` when the count is addressed to
|
|
1121
|
+
* the user rather than merely unread.
|
|
1122
|
+
*/
|
|
1123
|
+
badgeTone?: SidebarBadgeToneProp;
|
|
854
1124
|
asChild?: boolean;
|
|
855
1125
|
children?: ReactNode;
|
|
856
1126
|
className?: ClassNameProp;
|