@godxjp/ui 19.5.0 → 20.0.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/dist/components/data-display/card.d.ts +2 -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/index.d.ts +3 -1
- package/dist/components/data-display/index.js +2 -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.js +1 -1
- package/dist/components/data-display/popover.d.ts +58 -5
- package/dist/components/data-display/popover.js +206 -27
- package/dist/components/data-display/progress.d.ts +50 -2
- package/dist/components/data-display/progress.js +57 -9
- package/dist/components/data-entry/calendar.d.ts +1 -1
- package/dist/components/data-entry/calendar.js +67 -32
- 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/date-range-picker.d.ts +1 -1
- package/dist/components/data-entry/field.js +0 -1
- package/dist/components/data-entry/form.js +1 -1
- 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 +1 -1
- package/dist/components/data-entry/month-range-picker.d.ts +1 -1
- package/dist/components/data-entry/transfer.js +16 -6
- package/dist/components/data-entry/tree-select-strategy.d.ts +1 -1
- package/dist/components/data-entry/tree-select.js +29 -12
- package/dist/components/data-entry/tree-utils.d.ts +1 -1
- package/dist/components/data-entry/upload.js +7 -2
- package/dist/components/feedback/dialog.d.ts +105 -38
- package/dist/components/feedback/dialog.js +272 -194
- 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.js +2 -2
- package/dist/components/general/logo.d.ts +17 -0
- package/dist/components/general/logo.js +22 -16
- package/dist/components/general/typography.d.ts +7 -1
- package/dist/components/general/typography.js +20 -5
- package/dist/components/layout/app-shell.d.ts +1 -1
- package/dist/components/layout/app-shell.js +52 -8
- package/dist/components/layout/aspect-ratio.js +0 -1
- package/dist/components/layout/auth-divider.js +0 -1
- package/dist/components/layout/flex.d.ts +1 -1
- package/dist/components/layout/flex.js +19 -2
- 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 +5 -3
- 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.js +1 -2
- 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 +199 -18
- package/dist/components/navigation/dropdown-menu.js +344 -117
- 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/tabs.d.ts +47 -6
- package/dist/components/navigation/tabs.js +152 -90
- 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/label.js +0 -1
- package/dist/components/ui/segmented.d.ts +3 -3
- package/dist/components/ui/separator.d.ts +8 -2
- package/dist/components/ui/separator.js +17 -9
- 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/i18n/messages/en.json +8 -0
- package/dist/i18n/messages/ja.json +8 -0
- package/dist/i18n/messages/vi.json +8 -0
- package/dist/lib/control-styles.d.ts +1 -1
- package/dist/lib/control-styles.js +1 -1
- 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/data-display.prop.d.ts +17 -0
- package/dist/props/components/data-entry.prop.d.ts +32 -4
- package/dist/props/components/general.prop.d.ts +31 -1
- package/dist/props/components/index.d.ts +1 -1
- package/dist/props/components/layout.prop.d.ts +118 -5
- package/dist/props/components/navigation.prop.d.ts +1 -1
- package/dist/props/registry.d.ts +22 -2
- package/dist/props/registry.js +33 -2
- package/dist/props/vocabulary/content.prop.d.ts +1 -1
- package/dist/props/vocabulary/index.d.ts +2 -2
- package/dist/props/vocabulary/interaction.prop.d.ts +17 -1
- package/dist/props/vocabulary/layout.prop.d.ts +57 -1
- package/dist/styles/control.css +142 -1
- package/dist/styles/core.css +5 -2
- package/dist/styles/data-display-layout.css +72 -0
- package/dist/styles/focus-ring.css +13 -1
- package/dist/styles/index.css +5 -2
- package/dist/styles/layout.css +106 -0
- package/dist/styles/shell-layout.css +140 -8
- package/dist/styles/text-layout.css +16 -4
- package/dist/tokens/base.css +2 -1
- package/dist/tokens/components/data-display.css +11 -0
- package/dist/tokens/components/shell.css +3 -1
- package/dist/tokens/components/text.css +7 -0
- package/dist/tokens/foundation.css +2 -0
- package/docs/COMPONENTS.md +9 -3
- package/docs/DESIGN-AUTHORITY.md +96 -71
- package/docs/FRAME-COVERAGE-REPORT.md +5 -3
- package/docs/README.md +14 -14
- package/docs/WHAT-BELONGS-HERE.md +179 -0
- package/docs/data-display/legend.tsx +145 -0
- package/docs/data-display/progress.tsx +32 -0
- package/docs/data-entry/segmented.tsx +1 -1
- package/docs/data-entry/select.tsx +2 -2
- package/docs/feedback/sheet.tsx +1 -1
- package/docs/general/typography.tsx +84 -1
- package/docs/layout/app-shell-arrangements.tsx +225 -0
- package/docs/layout/aspect-ratio.tsx +1 -1
- package/docs/navigation/app-setting-picker.tsx +26 -1
- package/docs/navigation/app-setting-toggle.tsx +111 -0
- package/package.json +11 -8
- package/scripts/_agent-setup.mjs +165 -3
- package/scripts/consumer-rule.md +98 -0
- package/scripts/guinea-pig-skill.md +322 -0
- package/scripts/init-guinea-pig.mjs +62 -0
- package/scripts/postinstall.mjs +13 -2
- package/scripts/ui-audit.mjs +115 -14
- /package/dist/tokens/{antd.generated.css → derived.css} +0 -0
|
@@ -27,6 +27,23 @@ export type ProseProp = {
|
|
|
27
27
|
children?: ChildrenProp;
|
|
28
28
|
};
|
|
29
29
|
import type { ActionProp, ClassNameProp, DescriptionProp, IconProp, TitleProp, ColumnDefProp, GetRowIdProp, OnRowClickProp, OnSelectChangeProp, OnSortChangeProp, OnTableDensityChangeProp, SelectedIdsProp, SortStateProp, TableDensityProp, TablePresetProp, BreakpointProp, DensityProp, ChildrenProp, ToneProp, AvatarShapeProp, HeadingLevelProp, HandlerProp, SizeProp, LabelProp, IdProp, DescriptionsLayoutProp } from "../vocabulary/index.js";
|
|
30
|
+
/**
|
|
31
|
+
* One key in a `Legend`: a tone, and the words that tone stands for.
|
|
32
|
+
*
|
|
33
|
+
* `label` is required and there is no way to omit it. That is the point of a key — colour alone
|
|
34
|
+
* never carries meaning (WCAG 1.4.1), and a legend whose entries could be wordless would be a
|
|
35
|
+
* component that lets a caller build the exact failure it exists to prevent.
|
|
36
|
+
*/
|
|
37
|
+
export type LegendItemProp = {
|
|
38
|
+
/** The tone this key explains — the SAME tone the marks it stands for are drawn in. */
|
|
39
|
+
tone: ToneProp;
|
|
40
|
+
label: LabelProp;
|
|
41
|
+
};
|
|
42
|
+
/** @see Legend — the key for a colour-coded surface: a breakdown bar, a chart, a status column. */
|
|
43
|
+
export type LegendProp = Omit<React.HTMLAttributes<HTMLUListElement>, "children"> & {
|
|
44
|
+
items: LegendItemProp[];
|
|
45
|
+
className?: ClassNameProp;
|
|
46
|
+
};
|
|
30
47
|
/** @see EmptyState */
|
|
31
48
|
/**
|
|
32
49
|
* Semantic intent of the EmptyState icon medallion — a subset of the shared `ToneProp` vocabulary
|
|
@@ -8,7 +8,7 @@ import type { DateRange } from "react-day-picker";
|
|
|
8
8
|
import type * as React from "react";
|
|
9
9
|
import type { UploadFileItem } from "../../components/data-entry/upload-types.js";
|
|
10
10
|
import type { FieldA11yProps } from "../../lib/field-a11y.js";
|
|
11
|
-
import type { ClassNameProp, DisabledProp, EmptyMessageProp, ErrorBagProp, ErrorProp, HelperProp, IdProp, LabelProp, NameProp, OnValueChangeProp, OnSearchChangeProp, OpenProp, OnOpenChangeProp, PlaceholderProp, RequiredProp, ValueProp, DefaultValueProp, FormLayoutProp, WidthProp, BreakpointProp, DensityProp, SizeProp, TitleProp } from "../vocabulary/index.js";
|
|
11
|
+
import type { ClassNameProp, ControlWidthProp, DisabledProp, EmptyMessageProp, ErrorBagProp, ErrorProp, HelperProp, IdProp, LabelProp, NameProp, OnValueChangeProp, OnSearchChangeProp, OpenProp, OnOpenChangeProp, PlaceholderProp, RequiredProp, ValueProp, DefaultValueProp, FormLayoutProp, WidthProp, BreakpointProp, DensityProp, SizeProp, TitleProp } from "../vocabulary/index.js";
|
|
12
12
|
import type { ResponsiveGridColumnsProp } from "./layout.prop.js";
|
|
13
13
|
/** One-outline-per-group appearance for the compound InputOTP control. */
|
|
14
14
|
export type InputOTPGroupAppearanceProp = "slots" | "grouped";
|
|
@@ -228,7 +228,7 @@ export type SearchInputProp = FieldA11yProps & {
|
|
|
228
228
|
};
|
|
229
229
|
/** @see Checkbox — extends Radix checkbox root props. */
|
|
230
230
|
export type CheckboxProp = React.ComponentPropsWithoutRef<typeof CheckboxPrimitive.Root>;
|
|
231
|
-
/** Shared option row —
|
|
231
|
+
/** Shared option row — the conventional `CheckboxOptionType` shape. */
|
|
232
232
|
export type ChoiceOptionProp = {
|
|
233
233
|
label: React.ReactNode;
|
|
234
234
|
value: string;
|
|
@@ -283,6 +283,34 @@ export type SliderProp = React.ComponentPropsWithoutRef<typeof SliderPrimitive.R
|
|
|
283
283
|
export type CalendarProp = DayPickerProps & CalendarFooterProp & {
|
|
284
284
|
/** Replaces the built-in footer actions. */
|
|
285
285
|
footer?: React.ReactNode;
|
|
286
|
+
/**
|
|
287
|
+
* How the grid claims horizontal space. Default `auto` shrink-wraps to seven fixed day
|
|
288
|
+
* columns — the shape a picker popover needs, because the panel is shrink-to-fit and takes
|
|
289
|
+
* ITS width from the calendar inside it.
|
|
290
|
+
*
|
|
291
|
+
* `full` is for an EMBEDDED calendar — a shift board, a booking month — where the calendar is
|
|
292
|
+
* the content of a card rather than a dropdown. It stacks the months, lets each one grow, and
|
|
293
|
+
* lets the day cells share the row.
|
|
294
|
+
*
|
|
295
|
+
* Opt-in on purpose, and the default is load-bearing: making the calendar fluid globally was
|
|
296
|
+
* measured to collapse the DatePicker popover from 250px to 157.8px with 18.8px day cells.
|
|
297
|
+
* `Calendar` and `DatePicker` want opposite answers here, which is why the enterprise
|
|
298
|
+
* libraries split them too
|
|
299
|
+
* (`Calendar fullscreen` is 100% of its container; the DatePicker dropdown is a fixed 288px).
|
|
300
|
+
*/
|
|
301
|
+
width?: Extract<ControlWidthProp, "auto" | "full">;
|
|
302
|
+
/**
|
|
303
|
+
* Rule the grid: one border per day cell, weekday header included.
|
|
304
|
+
*
|
|
305
|
+
* NOT a box around the calendar — that is what `Card` is for, and nesting one inside a section
|
|
306
|
+
* card was measured on a real page as two rounded edges 16px apart with both paddings stacked.
|
|
307
|
+
* What a month grid needs is the ruling BETWEEN days, so a week reads as a row of cells the
|
|
308
|
+
* eye can track across.
|
|
309
|
+
*
|
|
310
|
+
* Default `false`, because a picker popover wants the opposite: floating day buttons with no
|
|
311
|
+
* ruling, so the selected day is the only shape in the panel.
|
|
312
|
+
*/
|
|
313
|
+
bordered?: boolean;
|
|
286
314
|
};
|
|
287
315
|
/** Footer actions shared by Calendar and the pickers that embed it. Both default to off. */
|
|
288
316
|
export type CalendarFooterProp = {
|
|
@@ -430,10 +458,10 @@ export type SearchSelectProp = {
|
|
|
430
458
|
/** Remote fetcher — debounced search + infinite-scroll pagination call into this. Provide this
|
|
431
459
|
* OR `options`. */
|
|
432
460
|
loadOptions?: (params: SearchSelectLoadParamsProp) => Promise<SearchSelectLoadResultProp>;
|
|
433
|
-
/** Custom per-option renderer
|
|
461
|
+
/** Custom per-option renderer. Defaults to label + optional sublabel. */
|
|
434
462
|
renderOption?: (option: SearchSelectOptionProp) => React.ReactNode;
|
|
435
463
|
/**
|
|
436
|
-
* Custom renderer for the SELECTED value shown on the trigger (
|
|
464
|
+
* Custom renderer for the SELECTED value shown on the trigger (the conventional `labelRender`).
|
|
437
465
|
* Receives the value, the resolved label, and the full option when it is loaded (undefined for
|
|
438
466
|
* an async preset whose page hasn't arrived).
|
|
439
467
|
*/
|
|
@@ -4,7 +4,25 @@ import type { ActivityAnnounceProp, ActivityVariantProp, AsChildProp, ButtonSize
|
|
|
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`. */
|
|
7
|
-
as?: "span" | "p" | "div" | "label" | "strong" | "em" | "small" | "code" | "kbd" | "dt" | "dd" | "caption" | "abbr";
|
|
7
|
+
as?: "span" | "p" | "div" | "a" | "label" | "strong" | "em" | "small" | "code" | "kbd" | "dt" | "dd" | "caption" | "abbr";
|
|
8
|
+
/**
|
|
9
|
+
* Render the typography onto the child element instead of emitting one — for a router link
|
|
10
|
+
* (`<Text asChild link><Link href=…>…</Link></Text>`). The child owns the element and its
|
|
11
|
+
* navigation; Text owns the type step, tone, weight and truncation.
|
|
12
|
+
*/
|
|
13
|
+
asChild?: AsChildProp;
|
|
14
|
+
/**
|
|
15
|
+
* This text IS a link: underline on hover and on keyboard focus, at the token underline offset,
|
|
16
|
+
* and the focus mark every other interactive element draws.
|
|
17
|
+
*
|
|
18
|
+
* It is an AFFORDANCE, not a colour — `tone` still owns the colour and simply defaults to
|
|
19
|
+
* `primary` here, so a destructive link (`link tone="destructive"`) reads destructive and still
|
|
20
|
+
* underlines. Use this INSTEAD of `className="text-primary hover:underline"`, and instead of
|
|
21
|
+
* `Button variant="link"` whenever the link sits in running content: `.ui-button` is a control
|
|
22
|
+
* box (`white-space: nowrap`, `flex-shrink: 0`, a `--control-height` tier and inline padding),
|
|
23
|
+
* so in a table cell it cannot wrap and cannot share the cell's line height.
|
|
24
|
+
*/
|
|
25
|
+
link?: boolean;
|
|
8
26
|
/** Size from the type scale — never an arbitrary px. Default `sm` (base). */
|
|
9
27
|
size?: TextSizeProp;
|
|
10
28
|
/** Semantic colour intent. Default `default` (foreground). */
|
|
@@ -24,6 +42,18 @@ export type TextProp = Omit<React.HTMLAttributes<HTMLElement>, "color"> & {
|
|
|
24
42
|
/** Monospace family (codes, ids). */
|
|
25
43
|
mono?: boolean;
|
|
26
44
|
htmlFor?: string;
|
|
45
|
+
/**
|
|
46
|
+
* Anchor attributes, for `as="a"` (and for the `<a>` a router link supplies under `asChild`).
|
|
47
|
+
*
|
|
48
|
+
* Declared explicitly rather than by widening the base to `AnchorHTMLAttributes`, and for the
|
|
49
|
+
* same reason `htmlFor` is declared explicitly for `as="label"`: the element union is the
|
|
50
|
+
* contract, so each polymorphic branch names the attributes it actually accepts instead of every
|
|
51
|
+
* span silently offering an `href` it will never render.
|
|
52
|
+
*/
|
|
53
|
+
href?: string;
|
|
54
|
+
target?: React.HTMLAttributeAnchorTarget;
|
|
55
|
+
rel?: string;
|
|
56
|
+
download?: React.AnchorHTMLAttributes<HTMLAnchorElement>["download"];
|
|
27
57
|
};
|
|
28
58
|
/** @see Heading — h1..h4 sized from the `--heading-h*` tokens. */
|
|
29
59
|
export type HeadingProp = Omit<React.HTMLAttributes<HTMLHeadingElement>, "color"> & {
|
|
@@ -6,5 +6,5 @@ export type { ChartDatum, ChartSeriesProp, LineChartProp, BarChartProp, AreaChar
|
|
|
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
8
|
export type { PaginationProp, StepsProp, StepItemProp, StepStatusProp, TabsProp, TabItemProp, } from "./navigation.prop.js";
|
|
9
|
-
export type { AppProviderProp, AppContextValue, AppSettingKind, AppSettingPickerProp, } from "./app.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.
|
|
@@ -112,6 +112,55 @@ export type FlexProp = React.HTMLAttributes<HTMLDivElement> & {
|
|
|
112
112
|
as?: "div" | "span";
|
|
113
113
|
direction?: FlexDirectionProp;
|
|
114
114
|
gap?: GapProp;
|
|
115
|
+
/**
|
|
116
|
+
* CỬA THOÁT: một khoảng cách tính bằng pixel, ngoài mọi bậc của thang.
|
|
117
|
+
*
|
|
118
|
+
* ## Vì sao một design system lại mở cửa thoát
|
|
119
|
+
*
|
|
120
|
+
* 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ở
|
|
121
|
+
* thành bất hợp pháp. Một bản thiết kế thật dùng 2px, 5px, 6px, 10px; thang
|
|
122
|
+
* 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
|
|
123
|
+
* đề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
|
|
124
|
+
* số cách đều vốn đã là một phép đoán), viết literal (audit chặn), hoặc mở
|
|
125
|
+
* issue ngược lên rồi CHỜ. Đó là lý do mọi dự án đều lệch design — không
|
|
126
|
+
* phải người viết cẩu thả.
|
|
127
|
+
*
|
|
128
|
+
* ## Cái giá của nó
|
|
129
|
+
*
|
|
130
|
+
* Nó phát ra `data-gap-raw` lên DOM. Đó không phải trang trí: nó làm mỗi lần
|
|
131
|
+
* thoát trở nên ĐẾM ĐƯỢC — grep mã nguồn hoặc quét DOM đều ra, nên một kho
|
|
132
|
+
* đang trôi dần khỏi thang sẽ tự lộ ra bằng con số thay vì bằng cảm giác.
|
|
133
|
+
*
|
|
134
|
+
* ## Khi nào ĐỪNG dùng
|
|
135
|
+
*
|
|
136
|
+
* Khi giá trị bạn cần có trong thang. `gap={3}` là 12px và nó đọc theo
|
|
137
|
+
* `--scaling` của người dùng; `gapRaw={12}` thì không, nó đứng yên khi người
|
|
138
|
+
* ta phóng to giao diện. Thang có mười bậc — hãy tiêu hết chúng trước.
|
|
139
|
+
*
|
|
140
|
+
* Khi có mặt, nó THẮNG `gap`, và `gap` không phát lớp nào nữa để hai bên
|
|
141
|
+
* không tranh độ đặc hiệu.
|
|
142
|
+
*/
|
|
143
|
+
gapRaw?: number;
|
|
144
|
+
/**
|
|
145
|
+
* Đệm TRONG, theo thang token. Nhận một bậc cho cả bốn cạnh, hoặc một object
|
|
146
|
+
* theo cạnh LOGIC (`inline`, `block`, `inlineStart`, `blockEnd`…).
|
|
147
|
+
*
|
|
148
|
+
* Vì sao có: chạy `ui-audit` trên consumer thật (godx-chat, 08/09/2026) ra
|
|
149
|
+
* **42 trong 51 lỗi** là `no-utility-spacing`, và gần như tất cả xin cùng
|
|
150
|
+
* một thứ — padding. `<Flex className="p-3">` không phải cẩu thả; đó là nước
|
|
151
|
+
* đi duy nhất còn lại khi primitive không có prop đệm. Một prop thiếu đẻ ra
|
|
152
|
+
* 42 lỗi (gh#408).
|
|
153
|
+
*/
|
|
154
|
+
pad?: PadProp;
|
|
155
|
+
/**
|
|
156
|
+
* Đệm bằng pixel THÔ, cho giá trị ngoài thang — cùng lý do và cùng cái giá
|
|
157
|
+
* với `gapRaw`: nó để lại `data-pad-raw` trên DOM nên mỗi lần thoát đều đếm
|
|
158
|
+
* được. Đo trên 51 lỗi ấy: thiết kế cần 2px, 6px, 10px, 14px, 44px, không
|
|
159
|
+
* bậc nào có.
|
|
160
|
+
*
|
|
161
|
+
* Ghi đè `pad` ở TỪNG CẠNH, không phải cả cụm.
|
|
162
|
+
*/
|
|
163
|
+
padRaw?: PadRawProp;
|
|
115
164
|
align?: FlexAlignProp;
|
|
116
165
|
justify?: FlexJustifyProp;
|
|
117
166
|
wrap?: boolean;
|
|
@@ -126,6 +175,31 @@ export type FlexProp = React.HTMLAttributes<HTMLDivElement> & {
|
|
|
126
175
|
* only on the narrow side (a compact-only affordance). Omit for no attribute and no rule.
|
|
127
176
|
*/
|
|
128
177
|
hideFrom?: BreakpointProp;
|
|
178
|
+
/**
|
|
179
|
+
* Take the space the siblings leave — the Flex becomes the row's ELASTIC column.
|
|
180
|
+
*
|
|
181
|
+
* ## Vì sao là một trục, không phải một tiện ích
|
|
182
|
+
*
|
|
183
|
+
* 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 ở
|
|
184
|
+
* 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"`
|
|
185
|
+
* — 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.
|
|
186
|
+
* `PageContainer` đã có `fill` với đúng nghĩa ấy; `Flex` không có là bất đối xứng, không phải
|
|
187
|
+
* quyết định (gh#405 §2).
|
|
188
|
+
*
|
|
189
|
+
* 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
|
|
190
|
+
* 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.
|
|
191
|
+
*/
|
|
192
|
+
fill?: boolean;
|
|
193
|
+
/**
|
|
194
|
+
* 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%"`).
|
|
195
|
+
*
|
|
196
|
+
* Đ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à
|
|
197
|
+
* 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.
|
|
198
|
+
*
|
|
199
|
+
* 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 ở
|
|
200
|
+
* call site đều ĐẾM ĐƯỢC, nên một kho đang trôi khỏi thang tự lộ ra bằng con số.
|
|
201
|
+
*/
|
|
202
|
+
width?: WidthProp;
|
|
129
203
|
};
|
|
130
204
|
/** Container column counts; omitted steps inherit from the previous step. Base defaults to 1. */
|
|
131
205
|
export type ResponsiveGridColumnsProp = number | {
|
|
@@ -213,11 +287,50 @@ export type AppShellProp = {
|
|
|
213
287
|
* belonging to it.
|
|
214
288
|
*/
|
|
215
289
|
topbarSpan?: "content" | "full";
|
|
290
|
+
/**
|
|
291
|
+
* A SECOND navigation column, narrower than `sidebar` and placed before it — the
|
|
292
|
+
* workspace/organization switcher shape (Slack, Teams, Discord). Passing a node adds the track;
|
|
293
|
+
* omitting it leaves the two-column shell exactly as it was. Width is
|
|
294
|
+
* `--app-shell-nav-rail-width` (3.5rem — deliberately NOT the collapsed sidebar's 4rem: at equal
|
|
295
|
+
* widths the two navigation tracks fuse into one block the moment the sidebar collapses).
|
|
296
|
+
*
|
|
297
|
+
* THE THREE COLUMNS ARE THREE SCOPES, and the scope — not the free space — is what decides where
|
|
298
|
+
* a control goes. The rail is PLATFORM scope: whatever is true across every app in the
|
|
299
|
+
* organization (which organization, which app, notifications, messages, events, organization
|
|
300
|
+
* settings, cross-app shortcuts). The sidebar is APP scope: this app's own sections. The topbar
|
|
301
|
+
* is PAGE scope: where you are and what you can do here.
|
|
302
|
+
*
|
|
303
|
+
* So app navigation never goes in the rail, a platform switch never goes in the sidebar, and a
|
|
304
|
+
* destination that would fit both belongs to the rail — because it survives changing apps. A
|
|
305
|
+
* rail that repeats the sidebar's own entries is a second chrome band carrying the first one's
|
|
306
|
+
* rank, just vertical instead of horizontal.
|
|
307
|
+
*
|
|
308
|
+
* Orthogonal to `topbarSpan`: the rail says how many navigation COLUMNS there are, `topbarSpan`
|
|
309
|
+
* says how far the BAR reaches, and every combination of the two is a real shape, so they never
|
|
310
|
+
* need to be reconciled. `sidebarCollapsed` folds the sidebar track only — the rail keeps its
|
|
311
|
+
* width, which is what keeps its destinations reachable while collapsed.
|
|
312
|
+
*
|
|
313
|
+
* Building this by hand inside the single `sidebar` slot is the trap it replaces: `Sidebar`
|
|
314
|
+
* renders `.sb-root { display: contents }`, so two of them dropped side by side dissolve into
|
|
315
|
+
* one flex row and both collapse to zero unless each is separately wrapped — and sizing the one
|
|
316
|
+
* available track for two columns means overriding `--app-shell-sidebar-width`, which is how a
|
|
317
|
+
* shipped consumer moved its content edge by 64px between routes.
|
|
318
|
+
*/
|
|
319
|
+
navRail?: ReactNode;
|
|
320
|
+
/**
|
|
321
|
+
* Accessible name for the `navRail` landmark. Defaults to the localized "Workspaces".
|
|
322
|
+
*
|
|
323
|
+
* The rail and the sidebar are two `complementary` landmarks on one page, so ARIA requires them
|
|
324
|
+
* to be tellable apart by name; the shell always supplies both defaults rather than requiring
|
|
325
|
+
* this prop, so the two columns of equal rank behave the same way.
|
|
326
|
+
*/
|
|
327
|
+
navRailLabel?: string;
|
|
216
328
|
/**
|
|
217
329
|
* Navigation shown in the mobile drawer at the DXS 900px breakpoint, where the docked sidebar is
|
|
218
|
-
* hidden. Defaults to `
|
|
219
|
-
*
|
|
220
|
-
*
|
|
330
|
+
* hidden. Defaults to `navRail` followed by `sidebar` — both docked columns are hidden at that
|
|
331
|
+
* width, so a default of `sidebar` alone would silently strip every app-level destination the
|
|
332
|
+
* rail carries. Pass a distinct node for a mobile-tailored menu, or `null` to opt out (only when
|
|
333
|
+
* navigation lives elsewhere, e.g. a bottom bar).
|
|
221
334
|
*/
|
|
222
335
|
mobileNav?: ReactNode;
|
|
223
336
|
/** Accessible title for the mobile navigation drawer. Defaults to the localized "Menu". */
|
|
@@ -842,7 +955,7 @@ export type TopbarProp = Omit<React.HTMLAttributes<HTMLDivElement>, "children">
|
|
|
842
955
|
* It exists because the alternative is a `Button`, and a Button in a bar is a control that landed
|
|
843
956
|
* in the bar rather than a part of it — a pill of its own height floating in a taller strip, with
|
|
844
957
|
* its own hover surface and its own focus ring drawn around that pill. Fluent, SLDS, Atlassian and
|
|
845
|
-
*
|
|
958
|
+
* and enterprise pro-layouts all draw a top-bar trigger the other way: the cell is as tall as the bar, its
|
|
846
959
|
* hover is the bar's own surface, and the focus mark is hosted INSIDE the cell because a
|
|
847
960
|
* full-bleed cell has nothing outside itself to ring.
|
|
848
961
|
*/
|
|
@@ -168,7 +168,7 @@ export type StepsProp = {
|
|
|
168
168
|
};
|
|
169
169
|
/** @see Steps — inline separator glyph. */
|
|
170
170
|
export type StepsSeparatorProp = "chevron" | "arrow";
|
|
171
|
-
/** Tab pane —
|
|
171
|
+
/** Tab pane — the conventional `items` entry. */
|
|
172
172
|
export type TabItemProp = {
|
|
173
173
|
value: string;
|
|
174
174
|
label: React.ReactNode;
|
package/dist/props/registry.d.ts
CHANGED
|
@@ -289,6 +289,11 @@ export declare const VOCABULARY_REGISTRY: {
|
|
|
289
289
|
readonly category: "interaction";
|
|
290
290
|
readonly description: "AppSettingPicker trigger presentation: labeled (icon + value) | icon (square icon-only topbar trigger) | inline (compact text footer trigger)";
|
|
291
291
|
};
|
|
292
|
+
readonly AppSettingToggleAppearanceProp: {
|
|
293
|
+
readonly file: "vocabulary/interaction.prop.ts";
|
|
294
|
+
readonly category: "interaction";
|
|
295
|
+
readonly description: "AppSettingToggle box: bar (default — a full-height CELL of the bar, TopbarItem shape) | icon (square --control-height ghost button for anywhere that is not a bar)";
|
|
296
|
+
};
|
|
292
297
|
readonly ShapeProp: {
|
|
293
298
|
readonly file: "vocabulary/interaction.prop.ts";
|
|
294
299
|
readonly category: "interaction";
|
|
@@ -491,6 +496,11 @@ export declare const COMPONENT_PROP_REGISTRY: {
|
|
|
491
496
|
readonly reason: "Trigger DENSITY for the picker only (sm control tier + content-hugging width) — orthogonal to `appearance`, and not the page-level DensityProp scope.";
|
|
492
497
|
}];
|
|
493
498
|
};
|
|
499
|
+
readonly AppSettingToggleProp: {
|
|
500
|
+
readonly group: "app";
|
|
501
|
+
readonly file: "components/app.prop.ts";
|
|
502
|
+
readonly vocabulary: readonly ["ValueProp", "OnValueChangeProp", "DisabledProp", "IdProp", "ClassNameProp", "AppSettingToggleAppearanceProp"];
|
|
503
|
+
};
|
|
494
504
|
readonly PageContainerHeaderLayoutProp: {
|
|
495
505
|
readonly group: "layout";
|
|
496
506
|
readonly file: "components/layout.prop.ts";
|
|
@@ -1057,7 +1067,7 @@ export declare const COMPONENT_PROP_REGISTRY: {
|
|
|
1057
1067
|
readonly CalendarProp: {
|
|
1058
1068
|
readonly group: "data-entry";
|
|
1059
1069
|
readonly file: "components/data-entry.prop.ts";
|
|
1060
|
-
readonly vocabulary: readonly [];
|
|
1070
|
+
readonly vocabulary: readonly ["ControlWidthProp"];
|
|
1061
1071
|
};
|
|
1062
1072
|
readonly CalendarFooterProp: {
|
|
1063
1073
|
readonly group: "data-entry";
|
|
@@ -1771,7 +1781,17 @@ export declare const COMPONENT_PROP_REGISTRY: {
|
|
|
1771
1781
|
readonly ProgressProp: {
|
|
1772
1782
|
readonly group: "data-display";
|
|
1773
1783
|
readonly file: "components/data-display/progress.tsx";
|
|
1774
|
-
readonly vocabulary: readonly ["ValueProp", "LabelProp", "ClassNameProp"];
|
|
1784
|
+
readonly vocabulary: readonly ["ValueProp", "LabelProp", "ToneProp", "ClassNameProp"];
|
|
1785
|
+
};
|
|
1786
|
+
readonly LegendItemProp: {
|
|
1787
|
+
readonly group: "data-display";
|
|
1788
|
+
readonly file: "components/data-display.prop.ts";
|
|
1789
|
+
readonly vocabulary: readonly ["ToneProp", "LabelProp"];
|
|
1790
|
+
};
|
|
1791
|
+
readonly LegendProp: {
|
|
1792
|
+
readonly group: "data-display";
|
|
1793
|
+
readonly file: "components/data-display.prop.ts";
|
|
1794
|
+
readonly vocabulary: readonly ["ClassNameProp"];
|
|
1775
1795
|
};
|
|
1776
1796
|
readonly CodeBlockProp: {
|
|
1777
1797
|
readonly group: "data-display";
|
package/dist/props/registry.js
CHANGED
|
@@ -288,6 +288,11 @@ const VOCABULARY_REGISTRY = {
|
|
|
288
288
|
category: "interaction",
|
|
289
289
|
description: "AppSettingPicker trigger presentation: labeled (icon + value) | icon (square icon-only topbar trigger) | inline (compact text footer trigger)"
|
|
290
290
|
},
|
|
291
|
+
AppSettingToggleAppearanceProp: {
|
|
292
|
+
file: "vocabulary/interaction.prop.ts",
|
|
293
|
+
category: "interaction",
|
|
294
|
+
description: "AppSettingToggle box: bar (default \u2014 a full-height CELL of the bar, TopbarItem shape) | icon (square --control-height ghost button for anywhere that is not a bar)"
|
|
295
|
+
},
|
|
291
296
|
ShapeProp: {
|
|
292
297
|
file: "vocabulary/interaction.prop.ts",
|
|
293
298
|
category: "interaction",
|
|
@@ -495,6 +500,18 @@ const COMPONENT_PROP_REGISTRY = {
|
|
|
495
500
|
}
|
|
496
501
|
]
|
|
497
502
|
},
|
|
503
|
+
AppSettingToggleProp: {
|
|
504
|
+
group: "app",
|
|
505
|
+
file: "components/app.prop.ts",
|
|
506
|
+
vocabulary: [
|
|
507
|
+
"ValueProp",
|
|
508
|
+
"OnValueChangeProp",
|
|
509
|
+
"DisabledProp",
|
|
510
|
+
"IdProp",
|
|
511
|
+
"ClassNameProp",
|
|
512
|
+
"AppSettingToggleAppearanceProp"
|
|
513
|
+
]
|
|
514
|
+
},
|
|
498
515
|
PageContainerHeaderLayoutProp: {
|
|
499
516
|
group: "layout",
|
|
500
517
|
file: "components/layout.prop.ts",
|
|
@@ -1204,7 +1221,11 @@ const COMPONENT_PROP_REGISTRY = {
|
|
|
1204
1221
|
file: "components/data-entry.prop.ts",
|
|
1205
1222
|
vocabulary: ["DisabledProp"]
|
|
1206
1223
|
},
|
|
1207
|
-
CalendarProp: {
|
|
1224
|
+
CalendarProp: {
|
|
1225
|
+
group: "data-entry",
|
|
1226
|
+
file: "components/data-entry.prop.ts",
|
|
1227
|
+
vocabulary: ["ControlWidthProp"]
|
|
1228
|
+
},
|
|
1208
1229
|
CalendarFooterProp: {
|
|
1209
1230
|
group: "data-entry",
|
|
1210
1231
|
file: "components/data-entry.prop.ts",
|
|
@@ -1983,7 +2004,17 @@ const COMPONENT_PROP_REGISTRY = {
|
|
|
1983
2004
|
ProgressProp: {
|
|
1984
2005
|
group: "data-display",
|
|
1985
2006
|
file: "components/data-display/progress.tsx",
|
|
1986
|
-
vocabulary: ["ValueProp", "LabelProp", "ClassNameProp"]
|
|
2007
|
+
vocabulary: ["ValueProp", "LabelProp", "ToneProp", "ClassNameProp"]
|
|
2008
|
+
},
|
|
2009
|
+
LegendItemProp: {
|
|
2010
|
+
group: "data-display",
|
|
2011
|
+
file: "components/data-display.prop.ts",
|
|
2012
|
+
vocabulary: ["ToneProp", "LabelProp"]
|
|
2013
|
+
},
|
|
2014
|
+
LegendProp: {
|
|
2015
|
+
group: "data-display",
|
|
2016
|
+
file: "components/data-display.prop.ts",
|
|
2017
|
+
vocabulary: ["ClassNameProp"]
|
|
1987
2018
|
},
|
|
1988
2019
|
CodeBlockProp: {
|
|
1989
2020
|
group: "data-display",
|
|
@@ -14,7 +14,7 @@ export type DescriptionProp = React.ReactNode;
|
|
|
14
14
|
* Owned by the canonical page-header contract so consumers never hand-lay a badge row.
|
|
15
15
|
*/
|
|
16
16
|
export type StatusProp = React.ReactNode;
|
|
17
|
-
/** Top-right action slot on pages (
|
|
17
|
+
/** Top-right action slot on pages (the conventional `extra` slot). */
|
|
18
18
|
export type ExtraProp = React.ReactNode;
|
|
19
19
|
/** Bottom action bar on pages — save/cancel, pagination controls. */
|
|
20
20
|
export type FooterProp = React.ReactNode;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/** Barrel — all vocabulary prop types. */
|
|
2
2
|
export type { ClassNameProp, ChildrenProp, IdProp, OpenProp, DefaultOpenProp, OnOpenChangeProp, HandlerProp, PendingProp, RequiredProp, DisabledProp, LabelProp, HelperProp, ErrorProp, ErrorBagProp, PlaceholderProp, NameProp, ValueProp, DefaultValueProp, OnValueChangeProp, OnChangeProp, OnClickProp, AsChildProp, FlushProp, WidthProp, ControlWidthProp, } from "./shared.prop.js";
|
|
3
3
|
export type { TitleProp, SubtitleProp, StatusProp, DescriptionProp, ExtraProp, FooterProp, ActionProp, IconProp, ConfirmLabelProp, CancelLabelProp, ActionsProp, EmptyMessageProp, } from "./content.prop.js";
|
|
4
|
-
export type { PageDensityProp, PageContainerVariantProp, CenteredShellWidthProp, CenteredShellAlignProp, CenteredShellPresetProp, ErrorSurfaceModeProp, ErrorSurfaceStatusProp, AuthShellPresetProp, MobileShellHeightProp, OrientationProp, TableDensityProp, DensityProp, GapProp, } from "./layout.prop.js";
|
|
5
|
-
export type { ButtonVariantProp, ButtonSizeProp, BadgeVariantProp, AppSettingPickerAppearanceProp, ShapeProp, AvatarShapeProp, TextSizeProp, TextToneProp, FontWeightProp, HeadingLevelProp, TextAlignProp, SizeProp, FormLayoutProp, DescriptionsLayoutProp, BreakpointProp, ConfirmVariantProp, ToneProp, AlertVariantProp, SortDirectionProp, ColumnAlignProp, SortStateProp, RevealDelayProp, ActivityVariantProp, ActivityAnnounceProp, } from "./interaction.prop.js";
|
|
4
|
+
export type { PageDensityProp, PageContainerVariantProp, CenteredShellWidthProp, CenteredShellAlignProp, CenteredShellPresetProp, ErrorSurfaceModeProp, ErrorSurfaceStatusProp, AuthShellPresetProp, MobileShellHeightProp, OrientationProp, TableDensityProp, DensityProp, GapNameProp, PadProp, PadRawProp, PadSides, GapProp, GapStepProp, } from "./layout.prop.js";
|
|
5
|
+
export type { ButtonVariantProp, ButtonSizeProp, BadgeVariantProp, AppSettingPickerAppearanceProp, AppSettingToggleAppearanceProp, ShapeProp, AvatarShapeProp, TextSizeProp, TextToneProp, FontWeightProp, HeadingLevelProp, TextAlignProp, SizeProp, FormLayoutProp, DescriptionsLayoutProp, BreakpointProp, ConfirmVariantProp, ToneProp, AlertVariantProp, SortDirectionProp, ColumnAlignProp, SortStateProp, RevealDelayProp, ActivityVariantProp, ActivityAnnounceProp, } from "./interaction.prop.js";
|
|
6
6
|
export type { BreadcrumbItemProp, BreadcrumbProp } from "./navigation.prop.js";
|
|
7
7
|
export type { GetRowIdProp, OnRowClickProp, ColumnDefProp, TablePresetProp, TableColumnPriorityProp, TableCellIndentProp, SelectedIdsProp, OnSelectChangeProp, OnTableDensityChangeProp, OnSortChangeProp, OnSearchChangeProp, OnClearFiltersProp, HasActiveFiltersProp, StickyProp, } from "./data.prop.js";
|
|
@@ -39,8 +39,24 @@ export type BadgeVariantProp = "default" | "secondary" | "outline" | "dashed";
|
|
|
39
39
|
* STRUCTURALLY drops the value text and the picker's owned trigger width, keeping the localized
|
|
40
40
|
* `aria-label`, focus ring, keyboard behaviour and a `--control-height` tap target (which is
|
|
41
41
|
* ≥44px on coarse/touch pointers per Rule #24) — so consumers never hide internal nodes via CSS.
|
|
42
|
+
* - `bar` — the same structural drops as `icon`, re-shaped as a CELL OF THE BAR rather than a
|
|
43
|
+
* control dropped into it: it fills the bar's height and squares its corners, so the hover
|
|
44
|
+
* surface paints the whole strip. Reach for it in a `Topbar` slot or AppShell's own bar, where
|
|
45
|
+
* `icon` leaves a --control-height pill floating in a taller strip and reads as a different
|
|
46
|
+
* control family from the bar's own chrome (`TopbarItem`).
|
|
42
47
|
*/
|
|
43
|
-
export type AppSettingPickerAppearanceProp = "labeled" | "icon" | "inline";
|
|
48
|
+
export type AppSettingPickerAppearanceProp = "labeled" | "icon" | "bar" | "inline";
|
|
49
|
+
/**
|
|
50
|
+
* AppSettingToggle presentation. The toggle has no menu, so it has no `labeled`/`inline` form —
|
|
51
|
+
* the two members here are the two BOXES a one-tap cycler can take.
|
|
52
|
+
* - `bar` (default) — a CELL of the bar (`TopbarItem`): full bar height, the bar's own hover
|
|
53
|
+
* surface, square corners (`--topbar-item-radius`). This is the canonical placement, which is
|
|
54
|
+
* why it is the default: a toggle exists for a top bar.
|
|
55
|
+
* - `icon` — a square `--control-height` ghost button for everywhere that is NOT a bar (a
|
|
56
|
+
* settings row, a card header). In a taller bar this leaves a pill floating mid-strip, which is
|
|
57
|
+
* the defect `bar` exists to avoid.
|
|
58
|
+
*/
|
|
59
|
+
export type AppSettingToggleAppearanceProp = "bar" | "icon";
|
|
44
60
|
/** Button size preset. */
|
|
45
61
|
export type SizeProp = "xs" | "sm" | "md" | "lg";
|
|
46
62
|
/** Button size preset; icon-only sizes are a documented Button subset. */
|
|
@@ -59,7 +59,63 @@ export type AuthShellPresetProp = "default" | "login" | "registration" | "device
|
|
|
59
59
|
* Without it those stacks had to carry `gap="xs"`, which is a visual change forced by a missing
|
|
60
60
|
* step rather than by design.
|
|
61
61
|
*/
|
|
62
|
-
export type
|
|
62
|
+
export type GapNameProp = "none" | "xs" | "sm" | "md" | "lg" | "xl";
|
|
63
|
+
/**
|
|
64
|
+
* Bậc SỐ, ánh xạ thẳng vào `--space-{n}` của thang gốc.
|
|
65
|
+
*
|
|
66
|
+
* Vì sao cần, dù đã có sáu tên ở trên: thang gốc có MƯỜI bậc
|
|
67
|
+
* (0·4·8·12·16·20·24·32·40·48px) nhưng lớp tên chỉ với tới năm trong số đó.
|
|
68
|
+
* `md` là 16px, `lg` là 24px — và `--space-5` (20px) tồn tại mà không có đường
|
|
69
|
+
* nào gọi tới. Người viết mã gặp một thiết kế 20px thì không còn nước đi hợp
|
|
70
|
+
* lệ nào: làm tròn thì lệch, viết literal thì `no-arbitrary-spacing` chặn.
|
|
71
|
+
*
|
|
72
|
+
* Bậc số KHÔNG theo trục — `gap={3}` là 12px ở cả hàng lẫn cột. Đó là chủ ý:
|
|
73
|
+
* tên mang ý ĐỊNH ("cách nhau vừa phải, tuỳ trục"), số mang GIÁ TRỊ ("đúng
|
|
74
|
+
* 12px"). Trộn hai nghĩa vào một thang là lý do thang cũ vừa thô vừa khó đoán.
|
|
75
|
+
*/
|
|
76
|
+
export type GapStepProp = 0 | 1 | 2 | 3 | 4 | 5 | 6 | 8 | 10 | 12;
|
|
77
|
+
export type GapProp = GapNameProp | GapStepProp;
|
|
78
|
+
/**
|
|
79
|
+
* Đệm TRONG của một primitive bố cục.
|
|
80
|
+
*
|
|
81
|
+
* ## Vì sao tồn tại
|
|
82
|
+
*
|
|
83
|
+
* Chạy `ui-audit` trên consumer thật (godx-chat, 08/09/2026): **42 trong 51
|
|
84
|
+
* lỗi** là `no-utility-spacing`, và gần như toàn bộ chúng xin cùng một thứ —
|
|
85
|
+
* padding. `<Flex className="p-3">` không phải người viết cẩu thả; đó là nước
|
|
86
|
+
* đi duy nhất còn lại khi primitive không có prop đệm. Một prop thiếu đẻ ra 42
|
|
87
|
+
* lỗi, và mỗi lỗi ấy trước nay chỉ có hai đường: để đỏ, hoặc mở issue rồi chờ.
|
|
88
|
+
*
|
|
89
|
+
* ## Vì sao ba tầng chứ không phải một
|
|
90
|
+
*
|
|
91
|
+
* Đo trên chính 51 lỗi ấy: có `p-3` (bốn cạnh), có `px-4`/`py-1` (theo trục),
|
|
92
|
+
* và **16 dòng cần cạnh riêng** (`pt-2.5` khác `pb-2.5` trên cùng phần tử).
|
|
93
|
+
* Một prop chỉ nhận một số sẽ không phủ nổi, và ép người ta quay lại class.
|
|
94
|
+
*
|
|
95
|
+
* Tên cạnh là LOGIC (`inlineStart`, `blockEnd`), không phải vật lý (`left`,
|
|
96
|
+
* `top`) — cùng luật với `ms-`/`me-` mà audit đang bắt, và là thứ giữ cho giao
|
|
97
|
+
* diện RTL không phải viết lại.
|
|
98
|
+
*/
|
|
99
|
+
export type PadSides<T> = T | {
|
|
100
|
+
/** Hai cạnh theo trục viết (trái+phải ở LTR). */
|
|
101
|
+
inline?: T;
|
|
102
|
+
/** Hai cạnh theo trục khối (trên+dưới). */
|
|
103
|
+
block?: T;
|
|
104
|
+
inlineStart?: T;
|
|
105
|
+
inlineEnd?: T;
|
|
106
|
+
blockStart?: T;
|
|
107
|
+
blockEnd?: T;
|
|
108
|
+
};
|
|
109
|
+
/** Đệm theo thang token — bậc tên hoặc bậc số, cùng thang với `gap`. */
|
|
110
|
+
export type PadProp = PadSides<GapProp>;
|
|
111
|
+
/**
|
|
112
|
+
* Đệm bằng pixel THÔ, cho giá trị ngoài thang.
|
|
113
|
+
*
|
|
114
|
+
* Cùng lý do với `gapRaw`, và cùng cái giá: nó để lại `data-pad-raw` trên DOM
|
|
115
|
+
* nên mỗi lần thoát đều đếm được. Thiết kế thật cần 2px, 6px, 10px, 14px, 44px
|
|
116
|
+
* — thang không có bậc nào như thế, và bịt lại không làm chúng biến mất.
|
|
117
|
+
*/
|
|
118
|
+
export type PadRawProp = PadSides<number>;
|
|
63
119
|
/** DataTable row density subset. */
|
|
64
120
|
export type TableDensityProp = Exclude<DensityProp, "default">;
|
|
65
121
|
/**
|