@godxjp/ui 19.4.1 → 19.5.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/app/app-provider.js +10 -1
- package/dist/app/theme-axes.d.ts +18 -3
- package/dist/app/theme-axes.js +15 -3
- package/dist/components/data-display/badge.js +4 -1
- package/dist/components/data-display/data-table.js +9 -2
- package/dist/components/data-display/list-row.d.ts +2 -0
- package/dist/components/data-display/list-row.js +16 -12
- package/dist/components/data-display/timeline-grid.js +5 -3
- package/dist/components/data-entry/checkbox.d.ts +12 -0
- package/dist/components/data-entry/checkbox.js +35 -4
- package/dist/components/data-entry/form-field.js +5 -5
- package/dist/components/data-entry/index.d.ts +2 -0
- package/dist/components/data-entry/index.js +2 -0
- package/dist/components/data-entry/input.js +1 -1
- package/dist/components/data-entry/radio.js +1 -1
- package/dist/components/data-entry/search-input.d.ts +2 -18
- package/dist/components/data-entry/search-input.js +3 -0
- package/dist/components/data-entry/segmented.d.ts +2 -0
- package/dist/components/data-entry/segmented.js +5 -0
- package/dist/components/data-entry/select.d.ts +2 -0
- package/dist/components/data-entry/select.js +9 -4
- package/dist/components/feedback/sheet.js +1 -1
- package/dist/components/feedback/sonner.d.ts +7 -1
- package/dist/components/feedback/sonner.js +27 -7
- package/dist/components/general/button.d.ts +2 -0
- package/dist/components/general/button.js +11 -2
- package/dist/components/general/inert-background.d.ts +8 -3
- package/dist/components/general/inert-background.js +28 -3
- package/dist/components/general/logo.d.ts +53 -0
- package/dist/components/general/logo.js +57 -3
- package/dist/components/layout/app-shell.js +1 -1
- package/dist/components/layout/index.d.ts +4 -0
- package/dist/components/layout/index.js +4 -0
- package/dist/components/layout/master-detail.d.ts +1 -1
- package/dist/components/layout/master-detail.js +47 -3
- package/dist/components/layout/nav-list.d.ts +26 -0
- package/dist/components/layout/nav-list.js +21 -0
- package/dist/components/layout/responsive-grid.js +7 -4
- package/dist/components/layout/topbar-item.d.ts +17 -0
- package/dist/components/layout/topbar-item.js +21 -0
- package/dist/components/navigation/app-setting-picker.js +31 -5
- package/dist/components/navigation/context-menu.js +2 -2
- package/dist/components/navigation/dropdown-menu.js +2 -2
- package/dist/components/navigation/tabs.js +42 -10
- package/dist/components/ui/segmented.d.ts +48 -0
- package/dist/components/ui/segmented.js +48 -0
- package/dist/email/tokens.generated.d.ts +4 -4
- package/dist/email/tokens.generated.js +4 -4
- package/dist/i18n/messages/en.json +2 -1
- package/dist/i18n/messages/ja.json +2 -1
- package/dist/i18n/messages/vi.json +2 -1
- package/dist/props/components/app.prop.d.ts +9 -2
- package/dist/props/components/data-entry.prop.d.ts +10 -5
- package/dist/props/components/general.prop.d.ts +4 -0
- package/dist/props/components/layout.prop.d.ts +54 -2
- package/dist/props/registry.d.ts +21 -2
- package/dist/props/registry.js +29 -1
- package/dist/props/vocabulary/shared.prop.d.ts +11 -2
- package/dist/styles/alert-layout.css +4 -0
- package/dist/styles/base.css +2 -0
- package/dist/styles/control.css +123 -26
- package/dist/styles/data-display-layout.css +24 -2
- package/dist/styles/dialog-layout.css +2 -1
- package/dist/styles/focus-ring.css +84 -22
- package/dist/styles/form-layout.css +6 -0
- package/dist/styles/layout.css +38 -2
- package/dist/styles/logo-layout.css +56 -0
- package/dist/styles/navigation-layout.css +17 -1
- package/dist/styles/shell-layout.css +64 -10
- package/dist/tokens/antd.generated.css +40 -0
- package/dist/tokens/axes.css +6 -0
- package/dist/tokens/base.css +3 -0
- package/dist/tokens/components/control.css +5 -1
- package/dist/tokens/components/data-display.css +2 -1
- package/dist/tokens/components/feedback.css +2 -0
- package/dist/tokens/components/legal-document.css +0 -2
- package/dist/tokens/components/logo.css +13 -0
- package/dist/tokens/components/navigation.css +2 -0
- package/dist/tokens/components/segmented.css +27 -0
- package/dist/tokens/components/shell.css +15 -2
- package/dist/tokens/foundation.css +21 -13
- package/docs/DESIGN-AUTHORITY.md +346 -0
- package/docs/FRAME-COVERAGE-REPORT.md +5 -2
- package/docs/README.md +14 -13
- package/docs/data-display/list-row.tsx +21 -0
- package/docs/data-entry/search-input.tsx +1 -0
- package/docs/data-entry/segmented.tsx +124 -0
- package/docs/general/button/index.md +4 -0
- package/docs/layout/master-detail.tsx +3 -0
- package/docs/layout/nav-list.tsx +63 -0
- package/docs/layout/responsive-grid.tsx +19 -2
- package/docs/layout/topbar-item.tsx +157 -0
- package/package.json +8 -2
|
@@ -47,9 +47,28 @@ function Tabs({
|
|
|
47
47
|
"data-slot": "tabs-list",
|
|
48
48
|
variant: variant === "line" ? "line" : "default",
|
|
49
49
|
className: cn(
|
|
50
|
-
// The
|
|
51
|
-
// stay a UTILITY so tailwind-merge still drops the strip's own padding step
|
|
52
|
-
|
|
50
|
+
// The inset override is an arbitrary value reading the knob (never `p-0`): it must
|
|
51
|
+
// stay a UTILITY so tailwind-merge still drops the strip's own padding step.
|
|
52
|
+
//
|
|
53
|
+
// IT IS SPLIT INTO `px-`/`py-` FOR THE FOCUS RING (gh#376). The strip clips its
|
|
54
|
+
// block axis (`overflow-y: hidden` beside `overflow-x: auto`), and this variant's
|
|
55
|
+
// inset is 0px, so a focused trigger had NO block headroom at all — measured in
|
|
56
|
+
// Chromium, 0px top and bottom, i.e. the entire ring was shaved. The headroom has to
|
|
57
|
+
// come from layout: `overflow-y: visible` next to `overflow-x: auto` computes back
|
|
58
|
+
// to `auto` per spec (a second scroll container, not a ring), and Chromium honours
|
|
59
|
+
// `overflow-clip-margin` only when BOTH axes are `clip`. So the block padding carries
|
|
60
|
+
// the ring's outer reach and an equal negative block margin hands it straight back —
|
|
61
|
+
// the ring paints inside the scrollport and the strip's OUTER box is unchanged
|
|
62
|
+
// (measured: 38px before and after). Both values read the same token the ring is
|
|
63
|
+
// sized from, so the two can never drift apart.
|
|
64
|
+
//
|
|
65
|
+
// The cost, recorded rather than hidden: the rail hairline (`border-b`, drawn at the
|
|
66
|
+
// border box) now sits the ring's reach below the triggers instead of flush. That is
|
|
67
|
+
// where a hand-composed <TabsList variant="line"> already put it — its `p-1` gives
|
|
68
|
+
// the same block inset — so the two construction paths now agree. A service that
|
|
69
|
+
// wants the active bar parked back on the hairline raises `--tabs-indicator-offset`,
|
|
70
|
+
// which exists for exactly that.
|
|
71
|
+
variant === "line" && "my-[calc(-1_*_var(--tabs-list-focus-ring-space-inset,calc(var(--focus-ring-width)_+_var(--focus-ring-glow-width))))] h-auto w-full justify-start border-b px-[var(--tabs-list-line-space-inset)] py-[calc(var(--tabs-list-line-space-inset)_+_var(--tabs-list-focus-ring-space-inset,calc(var(--focus-ring-width)_+_var(--focus-ring-glow-width))))]",
|
|
53
72
|
variant === "card" && "w-full justify-start",
|
|
54
73
|
listClassName
|
|
55
74
|
),
|
|
@@ -134,12 +153,25 @@ const TabsTrigger = React.forwardRef(({ className, ...props }, ref) => /* @__PUR
|
|
|
134
153
|
ref,
|
|
135
154
|
"data-slot": "tabs-trigger",
|
|
136
155
|
className: cn(
|
|
137
|
-
//
|
|
138
|
-
//
|
|
139
|
-
//
|
|
140
|
-
//
|
|
141
|
-
//
|
|
142
|
-
|
|
156
|
+
// SELECTED IS A BORDER TINT, NOT A RING — and that is a WCAG fix, not a style preference.
|
|
157
|
+
// It used to be `ring-1 ring-primary/25`, which writes `--tw-ring-shadow` in the UTILITIES
|
|
158
|
+
// layer and therefore overwrote the focus ring that focus-ring.css feeds from `components`.
|
|
159
|
+
// Measured: a focused ACTIVE tab painted `oklab(… / 0.25) 0 0 0 1px` and nothing else — a
|
|
160
|
+
// 1px indicator at 25% alpha, failing both clauses of SC 2.4.13 (2px perimeter, ≥3:1),
|
|
161
|
+
// while every other control in the library carried a full 2px ring. The trigger already
|
|
162
|
+
// owns `border border-transparent`, so tinting that border reproduces the selected hairline
|
|
163
|
+
// at the same colour and width with no layout change, and leaves `--tw-ring-shadow` free for
|
|
164
|
+
// the focus ring. `shadow-sm` stays: its composite READS `--tw-ring-shadow`, so the lift and
|
|
165
|
+
// the ring coexist.
|
|
166
|
+
//
|
|
167
|
+
// No `focus-visible:outline-1` either. It was the fallback that survived the clobber — a 1px
|
|
168
|
+
// currentColor line squeezed between the border and the ring once both paint. The ring is
|
|
169
|
+
// the indicator now; two marks for one state is what this pass exists to remove.
|
|
170
|
+
//
|
|
171
|
+
// The line indicator lives in src/styles/navigation-layout.css so it reads --tabs-indicator-*.
|
|
172
|
+
// Selected and focused stay visually distinct (WCAG 2.4.7): selected is a 1px hairline in the
|
|
173
|
+
// border, focused is the 2px ring plus its halo outside it.
|
|
174
|
+
"text-muted-foreground ring-offset-background hover:text-foreground ui-focus-ring data-[state=active]:bg-background data-[state=active]:text-foreground group-data-[variant=default]/tabs-list:data-[state=active]:border-primary/25 relative inline-flex flex-1 items-center justify-center gap-1.5 rounded-md border border-transparent px-3 py-1 text-sm font-medium whitespace-nowrap transition-all group-data-[orientation=vertical]/tabs:w-full group-data-[orientation=vertical]/tabs:justify-start group-data-[variant=line]/tabs-list:border-e-0 group-data-[variant=line]/tabs-list:border-b-0 disabled:pointer-events-none disabled:opacity-50 group-data-[variant=default]/tabs-list:data-[state=active]:shadow-sm group-data-[variant=line]/tabs-list:data-[state=active]:bg-transparent group-data-[variant=line]/tabs-list:data-[state=active]:shadow-none",
|
|
143
175
|
className
|
|
144
176
|
),
|
|
145
177
|
...props
|
|
@@ -151,7 +183,7 @@ const TabsContent = React.forwardRef(({ className, ...props }, ref) => /* @__PUR
|
|
|
151
183
|
{
|
|
152
184
|
ref,
|
|
153
185
|
"data-slot": "tabs-content",
|
|
154
|
-
className: cn("focus-
|
|
186
|
+
className: cn("ui-focus-ring flex-1 outline-none", className),
|
|
155
187
|
...props
|
|
156
188
|
}
|
|
157
189
|
));
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
/** One choice in a {@link Segmented}. */
|
|
3
|
+
export type SegmentedOption = {
|
|
4
|
+
/** Wire value — what `onValueChange` reports and what a form submits. */
|
|
5
|
+
value: string;
|
|
6
|
+
/** Visible label. It is also the item's accessible name, so it is required. */
|
|
7
|
+
label: React.ReactNode;
|
|
8
|
+
/** Optional leading glyph, rendered `aria-hidden` beside the label. */
|
|
9
|
+
icon?: React.ReactNode;
|
|
10
|
+
/** Disable this one choice; the rest of the group stays operable. */
|
|
11
|
+
disabled?: boolean;
|
|
12
|
+
};
|
|
13
|
+
export type SegmentedProp = {
|
|
14
|
+
/** The closed set of choices, in reading order. */
|
|
15
|
+
options: readonly SegmentedOption[];
|
|
16
|
+
/** Controlled selection. */
|
|
17
|
+
value?: string;
|
|
18
|
+
/** Uncontrolled initial selection. */
|
|
19
|
+
defaultValue?: string;
|
|
20
|
+
onValueChange?: (value: string) => void;
|
|
21
|
+
/** Disable the whole group. */
|
|
22
|
+
disabled?: boolean;
|
|
23
|
+
/** Form field name — submits the selected value with the form. */
|
|
24
|
+
name?: string;
|
|
25
|
+
id?: string;
|
|
26
|
+
className?: string;
|
|
27
|
+
/** Accessible name of the group. Required unless a visible label points at `id`. */
|
|
28
|
+
"aria-label"?: string;
|
|
29
|
+
"aria-labelledby"?: string;
|
|
30
|
+
};
|
|
31
|
+
export type SegmentedProps = SegmentedProp;
|
|
32
|
+
/**
|
|
33
|
+
* Segmented — one-of-N from a small, closed, always-visible set. antd's `Segmented`
|
|
34
|
+
* (docs/DESIGN-AUTHORITY.md names Ant Design the taxonomy authority) drawn on Radix's RadioGroup,
|
|
35
|
+
* which is this repo's authority for behaviour primitives.
|
|
36
|
+
*
|
|
37
|
+
* WHY NOT `ToggleGroup`. A ToggleGroup is a row of PRESSED buttons: `aria-pressed`, independently
|
|
38
|
+
* togglable, and — even at `type="single"` — deselectable, so "no theme at all" is a state the
|
|
39
|
+
* markup permits. A segmented control is a radio group: exactly one member is always chosen, the
|
|
40
|
+
* arrow keys move between members rather than Tab, and a screen reader must say "Light, radio
|
|
41
|
+
* button, 1 of 3, selected" and not "Light, toggle button, pressed". WAI-ARIA APG owns that
|
|
42
|
+
* distinction and it is not a skin.
|
|
43
|
+
*
|
|
44
|
+
* The primitive gives roving tabindex, arrow-key traversal (RTL-aware), the radiogroup/radio roles
|
|
45
|
+
* and the hidden input a native form submit needs. This file adds the antd geometry and nothing
|
|
46
|
+
* else — the focus mark comes from `ui-focus-ring`, the ONE source in styles/focus-ring.css.
|
|
47
|
+
*/
|
|
48
|
+
export declare const Segmented: React.ForwardRefExoticComponent<SegmentedProp & React.RefAttributes<HTMLDivElement>>;
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
3
|
+
import * as React from "react";
|
|
4
|
+
import * as RadioGroupPrimitive from "@radix-ui/react-radio-group";
|
|
5
|
+
import { cn } from "../../lib/utils.js";
|
|
6
|
+
const Segmented = React.forwardRef(function Segmented2({ options, value, defaultValue, onValueChange, disabled, name, id, className, ...props }, ref) {
|
|
7
|
+
return /* @__PURE__ */ jsx(
|
|
8
|
+
RadioGroupPrimitive.Root,
|
|
9
|
+
{
|
|
10
|
+
ref,
|
|
11
|
+
id,
|
|
12
|
+
"data-slot": "segmented",
|
|
13
|
+
className: cn("ui-segmented", className),
|
|
14
|
+
orientation: "horizontal",
|
|
15
|
+
value,
|
|
16
|
+
defaultValue,
|
|
17
|
+
onValueChange,
|
|
18
|
+
disabled,
|
|
19
|
+
name,
|
|
20
|
+
...props,
|
|
21
|
+
children: options.map((option) => /* @__PURE__ */ jsxs(
|
|
22
|
+
RadioGroupPrimitive.Item,
|
|
23
|
+
{
|
|
24
|
+
value: option.value,
|
|
25
|
+
disabled: option.disabled,
|
|
26
|
+
"data-slot": "segmented-item",
|
|
27
|
+
className: "ui-segmented-item ui-focus-ring",
|
|
28
|
+
children: [
|
|
29
|
+
option.icon == null ? null : /* @__PURE__ */ jsx(
|
|
30
|
+
"span",
|
|
31
|
+
{
|
|
32
|
+
"data-slot": "segmented-item-icon",
|
|
33
|
+
className: "ui-segmented-item-icon",
|
|
34
|
+
"aria-hidden": "true",
|
|
35
|
+
children: option.icon
|
|
36
|
+
}
|
|
37
|
+
),
|
|
38
|
+
/* @__PURE__ */ jsx("span", { "data-slot": "segmented-item-label", className: "ui-segmented-item-label", children: option.label })
|
|
39
|
+
]
|
|
40
|
+
},
|
|
41
|
+
option.value
|
|
42
|
+
))
|
|
43
|
+
}
|
|
44
|
+
);
|
|
45
|
+
});
|
|
46
|
+
export {
|
|
47
|
+
Segmented
|
|
48
|
+
};
|
|
@@ -29,7 +29,7 @@ export declare const EMAIL_COLOR_SOURCE: {
|
|
|
29
29
|
};
|
|
30
30
|
readonly mutedForeground: {
|
|
31
31
|
readonly cssVar: "--muted-foreground";
|
|
32
|
-
readonly hsl: "44 5%
|
|
32
|
+
readonly hsl: "44 5% 39%";
|
|
33
33
|
};
|
|
34
34
|
readonly border: {
|
|
35
35
|
readonly cssVar: "--border";
|
|
@@ -44,8 +44,8 @@ export declare const EMAIL_COLOR_SOURCE: {
|
|
|
44
44
|
readonly hsl: "60 33% 99%";
|
|
45
45
|
};
|
|
46
46
|
readonly focus: {
|
|
47
|
-
readonly cssVar: "--
|
|
48
|
-
readonly hsl: "204 100%
|
|
47
|
+
readonly cssVar: "--primary";
|
|
48
|
+
readonly hsl: "204 100% 37%";
|
|
49
49
|
};
|
|
50
50
|
readonly brand: {
|
|
51
51
|
readonly cssVar: "--brand";
|
|
@@ -103,7 +103,7 @@ export declare const EMAIL_COLOR_SOURCE_DARK: {
|
|
|
103
103
|
readonly hsl: "48 9% 9%";
|
|
104
104
|
};
|
|
105
105
|
readonly focus: {
|
|
106
|
-
readonly cssVar: "--
|
|
106
|
+
readonly cssVar: "--primary";
|
|
107
107
|
readonly hsl: "204 90% 60%";
|
|
108
108
|
};
|
|
109
109
|
readonly brand: {
|
|
@@ -21,7 +21,7 @@ const EMAIL_COLOR_SOURCE = {
|
|
|
21
21
|
},
|
|
22
22
|
"mutedForeground": {
|
|
23
23
|
"cssVar": "--muted-foreground",
|
|
24
|
-
"hsl": "44 5%
|
|
24
|
+
"hsl": "44 5% 39%"
|
|
25
25
|
},
|
|
26
26
|
"border": {
|
|
27
27
|
"cssVar": "--border",
|
|
@@ -36,8 +36,8 @@ const EMAIL_COLOR_SOURCE = {
|
|
|
36
36
|
"hsl": "60 33% 99%"
|
|
37
37
|
},
|
|
38
38
|
"focus": {
|
|
39
|
-
"cssVar": "--
|
|
40
|
-
"hsl": "204 100%
|
|
39
|
+
"cssVar": "--primary",
|
|
40
|
+
"hsl": "204 100% 37%"
|
|
41
41
|
},
|
|
42
42
|
"brand": {
|
|
43
43
|
"cssVar": "--brand",
|
|
@@ -94,7 +94,7 @@ const EMAIL_COLOR_SOURCE_DARK = {
|
|
|
94
94
|
"hsl": "48 9% 9%"
|
|
95
95
|
},
|
|
96
96
|
"focus": {
|
|
97
|
-
"cssVar": "--
|
|
97
|
+
"cssVar": "--primary",
|
|
98
98
|
"hsl": "204 90% 60%"
|
|
99
99
|
},
|
|
100
100
|
"brand": {
|
|
@@ -28,7 +28,11 @@ export type AppProviderProp = {
|
|
|
28
28
|
storageKey?: string;
|
|
29
29
|
/** Persist user choices. Default: true. */
|
|
30
30
|
persist?: boolean;
|
|
31
|
-
/**
|
|
31
|
+
/**
|
|
32
|
+
* Initial theme choice. `"light"` / `"dark"` are written straight to `<html data-theme>`;
|
|
33
|
+
* `"system"` defers to `prefers-color-scheme` and is re-resolved whenever the OS changes.
|
|
34
|
+
* Default: `"light"`.
|
|
35
|
+
*/
|
|
32
36
|
theme?: AppTheme;
|
|
33
37
|
/**
|
|
34
38
|
* Initial brand palette preset — written to `<html data-brand>`. OPT-IN: omit
|
|
@@ -101,7 +105,10 @@ export type AppContextValue = {
|
|
|
101
105
|
requestHeaders: AppRequestHeaders;
|
|
102
106
|
/** Configured timezone list; `undefined` → full IANA in the timezone-picker recipe. */
|
|
103
107
|
timezoneOptions?: readonly AppTimezone[];
|
|
104
|
-
/**
|
|
108
|
+
/**
|
|
109
|
+
* Current theme axes (mirror `<html data-*>` / inline `--scaling`). `theme` is the user's
|
|
110
|
+
* CHOICE — it can be `"system"`, which `<html data-theme>` never is.
|
|
111
|
+
*/
|
|
105
112
|
theme: AppTheme;
|
|
106
113
|
brand: AppBrand | null;
|
|
107
114
|
density: AppDensity;
|
|
@@ -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,
|
|
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";
|
|
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";
|
|
@@ -214,12 +214,17 @@ export type FormErrorsProviderProp = {
|
|
|
214
214
|
export type SearchInputProp = FieldA11yProps & {
|
|
215
215
|
id?: IdProp;
|
|
216
216
|
label?: LabelProp;
|
|
217
|
+
ariaLabel?: string;
|
|
217
218
|
placeholder?: PlaceholderProp;
|
|
218
|
-
value?:
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
219
|
+
value?: string;
|
|
220
|
+
defaultValue?: string;
|
|
221
|
+
onValueChange?: (query: string) => void;
|
|
222
|
+
/** Emits changed, debounced queries; does not run for the initial value. */
|
|
223
|
+
onSearch?: (query: string) => void;
|
|
224
|
+
debounce?: number;
|
|
225
|
+
disabled?: DisabledProp;
|
|
222
226
|
className?: ClassNameProp;
|
|
227
|
+
inputClassName?: ClassNameProp;
|
|
223
228
|
};
|
|
224
229
|
/** @see Checkbox — extends Radix checkbox root props. */
|
|
225
230
|
export type CheckboxProp = React.ComponentPropsWithoutRef<typeof CheckboxPrimitive.Root>;
|
|
@@ -43,6 +43,10 @@ export type ButtonProp = React.ButtonHTMLAttributes<HTMLButtonElement> & {
|
|
|
43
43
|
/** Corner shape — `default` (control radius) · `pill` (fully rounded) · `sharp` (square). */
|
|
44
44
|
shape?: ShapeProp;
|
|
45
45
|
fullWidth?: boolean;
|
|
46
|
+
/** Allow a text button to grow vertically for multi-line labels. */
|
|
47
|
+
wrap?: boolean;
|
|
48
|
+
/** Logical content alignment, especially for full-width collection actions. */
|
|
49
|
+
align?: TextAlignProp;
|
|
46
50
|
asChild?: AsChildProp;
|
|
47
51
|
onClick?: OnClickProp;
|
|
48
52
|
disabled?: DisabledProp;
|
|
@@ -127,7 +127,9 @@ export type FlexProp = React.HTMLAttributes<HTMLDivElement> & {
|
|
|
127
127
|
*/
|
|
128
128
|
hideFrom?: BreakpointProp;
|
|
129
129
|
};
|
|
130
|
+
/** Container column counts; omitted steps inherit from the previous step. Base defaults to 1. */
|
|
130
131
|
export type ResponsiveGridColumnsProp = number | {
|
|
132
|
+
base?: number;
|
|
131
133
|
sm?: number;
|
|
132
134
|
md?: number;
|
|
133
135
|
lg?: number;
|
|
@@ -147,6 +149,10 @@ export type MasterDetailRailProp = "master" | "detail";
|
|
|
147
149
|
export type MasterDetailMasterViewportProp = "auto" | "compact" | "standard";
|
|
148
150
|
/** @see MasterDetail */
|
|
149
151
|
export type MasterDetailProp = {
|
|
152
|
+
/** Opt into one-pane navigation on mobile (below the token-owned collapse threshold); desktop retains both panes. */
|
|
153
|
+
mobilePane?: "master" | "detail";
|
|
154
|
+
/** Back link shown above detail only in mobile navigation mode. */
|
|
155
|
+
detailBack?: ReactNode;
|
|
150
156
|
/** Selectable collection; always first in DOM order, so the stacked order stays list-then-detail. */
|
|
151
157
|
master: ReactNode;
|
|
152
158
|
/** Detail surface for the current selection. */
|
|
@@ -625,6 +631,25 @@ export type SidebarItemProp = {
|
|
|
625
631
|
/** Nested rows — renders a collapsible submenu group (the parent reads active when any child is). */
|
|
626
632
|
children?: SidebarItemProp[];
|
|
627
633
|
};
|
|
634
|
+
/**
|
|
635
|
+
* A vertical route navigation that lives INSIDE a page, not in the shell (gh#374).
|
|
636
|
+
*
|
|
637
|
+
* Reuses `SidebarItemProp` and `SidebarLinkComponentProp` verbatim rather than minting a parallel
|
|
638
|
+
* vocabulary: the row is the same row, so a service that learnt the rail's item shape does not
|
|
639
|
+
* learn a second one, and a fix to the row reaches both.
|
|
640
|
+
*/
|
|
641
|
+
export type NavListProp = Omit<React.HTMLAttributes<HTMLElement>, "onSelect"> & {
|
|
642
|
+
/** Rows, in reading order. `icon` is required by `SidebarItemProp` — the label aligns to it. */
|
|
643
|
+
items: SidebarItemProp[];
|
|
644
|
+
/** `SidebarItemProp.id` of the current route; that row gets `aria-current="page"`. */
|
|
645
|
+
activeId?: string;
|
|
646
|
+
/** Accessible name for the `<nav>` landmark. Required: a page may hold more than one. */
|
|
647
|
+
label: string;
|
|
648
|
+
/** Router link component — same contract as `Sidebar.linkComponent`. */
|
|
649
|
+
linkComponent?: SidebarLinkComponentProp;
|
|
650
|
+
/** Reports the activated row's id, for consumers driving navigation themselves. */
|
|
651
|
+
onSelect?: (id: string) => void;
|
|
652
|
+
};
|
|
628
653
|
/** @see Sidebar */
|
|
629
654
|
export type SidebarItemData = SidebarItemProp;
|
|
630
655
|
/**
|
|
@@ -648,8 +673,15 @@ export type SidebarLinkProp = {
|
|
|
648
673
|
"aria-label"?: string;
|
|
649
674
|
/** `"menuitem"` inside the collapsed rail's portaled flyout menu; absent for ordinary rows. */
|
|
650
675
|
role?: "menuitem";
|
|
651
|
-
/**
|
|
652
|
-
|
|
676
|
+
/**
|
|
677
|
+
* Reports selection to `Sidebar.onSelect` after the router link runs its own handler.
|
|
678
|
+
*
|
|
679
|
+
* Typed on `Element`, NOT `HTMLElement`. Handler parameters are contravariant, so a link
|
|
680
|
+
* component that accepts the wider `MouseEvent<Element>` — Inertia's `<Link>`, react-router's,
|
|
681
|
+
* TanStack's — cannot receive a prop narrowed to `HTMLElement`, and the anchor-safe contract
|
|
682
|
+
* this type promises would only hold behind a cast at every call site.
|
|
683
|
+
*/
|
|
684
|
+
onClick?: React.MouseEventHandler<Element>;
|
|
653
685
|
};
|
|
654
686
|
/**
|
|
655
687
|
* A framework router link component driven by {@link SidebarLinkProp} — Inertia's `<Link href>`,
|
|
@@ -803,6 +835,26 @@ export type TopbarProp = Omit<React.HTMLAttributes<HTMLDivElement>, "children">
|
|
|
803
835
|
/** Escape hatch — render fully custom bar content instead of the three slots. */
|
|
804
836
|
children?: ReactNode;
|
|
805
837
|
};
|
|
838
|
+
/**
|
|
839
|
+
* @see TopbarItem — ONE interactive cell of a {@link TopbarProp} slot: the account button, a
|
|
840
|
+
* settings trigger, a notifications bell.
|
|
841
|
+
*
|
|
842
|
+
* It exists because the alternative is a `Button`, and a Button in a bar is a control that landed
|
|
843
|
+
* in the bar rather than a part of it — a pill of its own height floating in a taller strip, with
|
|
844
|
+
* its own hover surface and its own focus ring drawn around that pill. Fluent, SLDS, Atlassian and
|
|
845
|
+
* antd's ProLayout all draw a top-bar trigger the other way: the cell is as tall as the bar, its
|
|
846
|
+
* hover is the bar's own surface, and the focus mark is hosted INSIDE the cell because a
|
|
847
|
+
* full-bleed cell has nothing outside itself to ring.
|
|
848
|
+
*/
|
|
849
|
+
export type TopbarItemProp = Omit<React.ButtonHTMLAttributes<HTMLButtonElement>, "children"> & {
|
|
850
|
+
/**
|
|
851
|
+
* Render the bar-cell shape ONTO the child instead of emitting a `<button>` — for a router link,
|
|
852
|
+
* or for a menu/popover trigger that needs to own the element itself.
|
|
853
|
+
*/
|
|
854
|
+
asChild?: boolean;
|
|
855
|
+
children?: ReactNode;
|
|
856
|
+
className?: ClassNameProp;
|
|
857
|
+
};
|
|
806
858
|
/**
|
|
807
859
|
* @see LegalDocumentShell — one entry of the table of contents + the matching document section.
|
|
808
860
|
* `id` is the REAL anchor target (`href="#{id}"`, `<section id>`), so it must be unique on the page
|
package/dist/props/registry.d.ts
CHANGED
|
@@ -927,10 +927,24 @@ export declare const COMPONENT_PROP_REGISTRY: {
|
|
|
927
927
|
readonly file: "components/layout.prop.ts";
|
|
928
928
|
readonly vocabulary: readonly ["ChildrenProp"];
|
|
929
929
|
};
|
|
930
|
+
readonly TopbarItemProp: {
|
|
931
|
+
readonly group: "layout";
|
|
932
|
+
readonly file: "components/layout.prop.ts";
|
|
933
|
+
readonly vocabulary: readonly ["ChildrenProp", "ClassNameProp", {
|
|
934
|
+
readonly field: "asChild";
|
|
935
|
+
readonly local: true;
|
|
936
|
+
readonly reason: "Radix Slot passthrough — merges onto the child";
|
|
937
|
+
}];
|
|
938
|
+
};
|
|
939
|
+
readonly NavListProp: {
|
|
940
|
+
readonly group: "layout";
|
|
941
|
+
readonly file: "components/layout.prop.ts";
|
|
942
|
+
readonly vocabulary: readonly ["IdProp", "ClassNameProp"];
|
|
943
|
+
};
|
|
930
944
|
readonly ButtonProp: {
|
|
931
945
|
readonly group: "general";
|
|
932
946
|
readonly file: "components/general.prop.ts";
|
|
933
|
-
readonly vocabulary: readonly ["ButtonVariantProp", "SizeProp", "ShapeProp", "AsChildProp", "DisabledProp", "OnClickProp", "PendingProp"];
|
|
947
|
+
readonly vocabulary: readonly ["TextAlignProp", "ButtonVariantProp", "SizeProp", "ShapeProp", "AsChildProp", "DisabledProp", "OnClickProp", "PendingProp"];
|
|
934
948
|
};
|
|
935
949
|
readonly RevealProp: {
|
|
936
950
|
readonly group: "general";
|
|
@@ -998,7 +1012,7 @@ export declare const COMPONENT_PROP_REGISTRY: {
|
|
|
998
1012
|
readonly SearchInputProp: {
|
|
999
1013
|
readonly group: "data-entry";
|
|
1000
1014
|
readonly file: "components/data-entry.prop.ts";
|
|
1001
|
-
readonly vocabulary: readonly ["LabelProp", "PlaceholderProp", "
|
|
1015
|
+
readonly vocabulary: readonly ["LabelProp", "PlaceholderProp", "DisabledProp", "ClassNameProp", "IdProp"];
|
|
1002
1016
|
};
|
|
1003
1017
|
readonly CheckboxProp: {
|
|
1004
1018
|
readonly group: "data-entry";
|
|
@@ -1734,6 +1748,11 @@ export declare const COMPONENT_PROP_REGISTRY: {
|
|
|
1734
1748
|
readonly file: "components/ui/rating.tsx";
|
|
1735
1749
|
readonly vocabulary: readonly ["ValueProp", "OnValueChangeProp", "DisabledProp", "ClassNameProp"];
|
|
1736
1750
|
};
|
|
1751
|
+
readonly SegmentedProp: {
|
|
1752
|
+
readonly group: "data-entry";
|
|
1753
|
+
readonly file: "components/ui/segmented.tsx";
|
|
1754
|
+
readonly vocabulary: readonly ["ValueProp", "DefaultValueProp", "OnValueChangeProp", "DisabledProp", "NameProp", "IdProp", "ClassNameProp"];
|
|
1755
|
+
};
|
|
1737
1756
|
readonly TagInputProp: {
|
|
1738
1757
|
readonly group: "data-entry";
|
|
1739
1758
|
readonly file: "components/ui/tag-input.tsx";
|
package/dist/props/registry.js
CHANGED
|
@@ -1020,10 +1020,25 @@ const COMPONENT_PROP_REGISTRY = {
|
|
|
1020
1020
|
file: "components/layout.prop.ts",
|
|
1021
1021
|
vocabulary: ["ChildrenProp"]
|
|
1022
1022
|
},
|
|
1023
|
+
TopbarItemProp: {
|
|
1024
|
+
group: "layout",
|
|
1025
|
+
file: "components/layout.prop.ts",
|
|
1026
|
+
vocabulary: [
|
|
1027
|
+
"ChildrenProp",
|
|
1028
|
+
"ClassNameProp",
|
|
1029
|
+
{ field: "asChild", local: true, reason: "Radix Slot passthrough \u2014 merges onto the child" }
|
|
1030
|
+
]
|
|
1031
|
+
},
|
|
1032
|
+
NavListProp: {
|
|
1033
|
+
group: "layout",
|
|
1034
|
+
file: "components/layout.prop.ts",
|
|
1035
|
+
vocabulary: ["IdProp", "ClassNameProp"]
|
|
1036
|
+
},
|
|
1023
1037
|
ButtonProp: {
|
|
1024
1038
|
group: "general",
|
|
1025
1039
|
file: "components/general.prop.ts",
|
|
1026
1040
|
vocabulary: [
|
|
1041
|
+
"TextAlignProp",
|
|
1027
1042
|
"ButtonVariantProp",
|
|
1028
1043
|
"SizeProp",
|
|
1029
1044
|
"ShapeProp",
|
|
@@ -1147,7 +1162,7 @@ const COMPONENT_PROP_REGISTRY = {
|
|
|
1147
1162
|
SearchInputProp: {
|
|
1148
1163
|
group: "data-entry",
|
|
1149
1164
|
file: "components/data-entry.prop.ts",
|
|
1150
|
-
vocabulary: ["LabelProp", "PlaceholderProp", "
|
|
1165
|
+
vocabulary: ["LabelProp", "PlaceholderProp", "DisabledProp", "ClassNameProp", "IdProp"]
|
|
1151
1166
|
},
|
|
1152
1167
|
CheckboxProp: {
|
|
1153
1168
|
group: "data-entry",
|
|
@@ -1937,6 +1952,19 @@ const COMPONENT_PROP_REGISTRY = {
|
|
|
1937
1952
|
file: "components/ui/rating.tsx",
|
|
1938
1953
|
vocabulary: ["ValueProp", "OnValueChangeProp", "DisabledProp", "ClassNameProp"]
|
|
1939
1954
|
},
|
|
1955
|
+
SegmentedProp: {
|
|
1956
|
+
group: "data-entry",
|
|
1957
|
+
file: "components/ui/segmented.tsx",
|
|
1958
|
+
vocabulary: [
|
|
1959
|
+
"ValueProp",
|
|
1960
|
+
"DefaultValueProp",
|
|
1961
|
+
"OnValueChangeProp",
|
|
1962
|
+
"DisabledProp",
|
|
1963
|
+
"NameProp",
|
|
1964
|
+
"IdProp",
|
|
1965
|
+
"ClassNameProp"
|
|
1966
|
+
]
|
|
1967
|
+
},
|
|
1940
1968
|
TagInputProp: {
|
|
1941
1969
|
group: "data-entry",
|
|
1942
1970
|
file: "components/ui/tag-input.tsx",
|
|
@@ -62,5 +62,14 @@ export type FlushProp = boolean;
|
|
|
62
62
|
* px; a `string` is any CSS length (`"32rem"`, `"90vw"`, `"50%"`).
|
|
63
63
|
*/
|
|
64
64
|
export type WidthProp = number | string;
|
|
65
|
-
/**
|
|
66
|
-
|
|
65
|
+
/**
|
|
66
|
+
* How a control sizes on the inline axis: fill its column, hug its label, or sit at a bounded
|
|
67
|
+
* width the theme owns.
|
|
68
|
+
*
|
|
69
|
+
* `bounded` exists because neither of the other two is right for a control whose VALUE varies in
|
|
70
|
+
* length — an organization switcher in a shell top bar is the canonical case. `full` swallows the
|
|
71
|
+
* bar; `auto` makes the bar reflow every time the selected value changes length. `bounded` reads
|
|
72
|
+
* `--control-bounded-width`, so the width is a knob rather than geometry hand-written at the call
|
|
73
|
+
* site (gh#375).
|
|
74
|
+
*/
|
|
75
|
+
export type ControlWidthProp = "full" | "auto" | "bounded";
|
|
@@ -191,6 +191,10 @@
|
|
|
191
191
|
block-size: var(--toast-icon-size);
|
|
192
192
|
}
|
|
193
193
|
|
|
194
|
+
[data-sonner-toast][data-expanded="false"][data-front="false"][data-styled="true"] > * {
|
|
195
|
+
visibility: hidden;
|
|
196
|
+
}
|
|
197
|
+
|
|
194
198
|
.ui-skeleton-block {
|
|
195
199
|
border-radius: var(--skeleton-radius);
|
|
196
200
|
background: var(--skeleton-background, hsl(var(--muted)));
|