@godxjp/ui 18.9.0 → 18.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +202 -0
- package/dist/components/data-display/badge.d.ts +7 -0
- package/dist/components/data-display/badge.js +1 -1
- package/dist/components/data-display/card.d.ts +3 -27
- package/dist/components/data-display/card.js +1 -4
- package/dist/components/data-display/data-table.js +5 -4
- package/dist/components/data-display/index.d.ts +2 -0
- package/dist/components/data-display/index.js +2 -0
- package/dist/components/data-display/permission-matrix.d.ts +26 -0
- package/dist/components/data-display/permission-matrix.js +219 -0
- package/dist/components/data-display/table.d.ts +12 -0
- package/dist/components/data-entry/branch-scope-picker.d.ts +43 -0
- package/dist/components/data-entry/branch-scope-picker.js +200 -0
- package/dist/components/data-entry/command-palette.d.ts +1 -42
- package/dist/components/data-entry/command-palette.js +2 -31
- 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-otp.d.ts +1 -1
- package/dist/components/feedback/alert.d.ts +2 -20
- package/dist/components/feedback/alert.js +1 -11
- package/dist/components/feedback/banner.d.ts +21 -0
- package/dist/components/feedback/banner.js +15 -0
- package/dist/components/feedback/index.d.ts +4 -2
- package/dist/components/feedback/index.js +2 -2
- package/dist/components/general/typography.d.ts +1 -0
- package/dist/components/general/typography.js +32 -13
- package/dist/components/layout/auth-shell.d.ts +2 -2
- package/dist/components/layout/index.d.ts +2 -2
- package/dist/components/layout/index.js +2 -2
- package/dist/components/layout/page-container.d.ts +1 -1
- package/dist/components/layout/page-container.js +45 -19
- package/dist/components/layout/service-role-panel.d.ts +25 -0
- package/dist/components/layout/service-role-panel.js +206 -0
- package/dist/components/navigation/filter-bar.d.ts +2 -2
- package/dist/components/navigation/filter-bar.js +113 -34
- package/dist/components/navigation/index.d.ts +1 -1
- package/dist/components/navigation/steps.d.ts +2 -2
- package/dist/components/navigation/steps.js +2 -4
- package/dist/components/ui/avatar.d.ts +1 -1
- package/dist/components/ui/avatar.js +1 -2
- package/dist/components/ui/input-otp.d.ts +3 -15
- package/dist/components/ui/input-otp.js +1 -2
- package/dist/email/tokens.generated.d.ts +2 -2
- package/dist/email/tokens.generated.js +2 -2
- package/dist/i18n/messages/en.json +56 -4
- package/dist/i18n/messages/ja.json +51 -5
- package/dist/i18n/messages/vi.json +50 -4
- package/dist/props/components/data-display.prop.d.ts +66 -16
- package/dist/props/components/data-entry.prop.d.ts +54 -7
- package/dist/props/components/feedback.prop.d.ts +3 -3
- package/dist/props/components/general.prop.d.ts +8 -1
- package/dist/props/components/layout.prop.d.ts +75 -54
- package/dist/props/components/navigation.prop.d.ts +77 -59
- package/dist/props/registry.d.ts +274 -73
- package/dist/props/registry.js +362 -93
- package/dist/props/vocabulary/content.prop.d.ts +5 -0
- package/dist/props/vocabulary/index.d.ts +1 -1
- package/dist/props/vocabulary/interaction.prop.d.ts +4 -7
- package/dist/props/vocabulary/layout.prop.d.ts +2 -2
- package/dist/styles/alert-layout.css +15 -32
- package/dist/styles/badge-layout.css +5 -0
- package/dist/styles/base.css +0 -28
- package/dist/styles/card-layout.css +13 -49
- package/dist/styles/control.css +2 -12
- package/dist/styles/data-display-layout.css +0 -16
- package/dist/styles/layout.css +102 -108
- package/dist/styles/navigation-layout.css +3 -8
- package/dist/styles/shell-layout.css +17 -17
- package/dist/styles/table-layout.css +77 -29
- package/dist/styles/text-layout.css +13 -0
- package/dist/tokens/base.css +1 -0
- package/dist/tokens/components/badge.css +5 -0
- package/dist/tokens/components/banner.css +16 -0
- package/dist/tokens/components/card.css +0 -12
- package/dist/tokens/components/control.css +0 -16
- package/dist/tokens/components/data-display.css +0 -12
- package/dist/tokens/components/email.css +2 -8
- package/dist/tokens/components/feedback.css +0 -20
- package/dist/tokens/components/navigation.css +10 -34
- package/dist/tokens/components/shell.css +24 -36
- package/dist/tokens/components/table.css +41 -22
- package/dist/tokens/semantic/layout.css +5 -12
- package/package.json +15 -2
- package/dist/components/layout/page-header.d.ts +0 -22
- package/dist/components/layout/page-header.js +0 -89
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import type { BranchScopeValueProp } from "../../props/components/data-entry.prop.js";
|
|
3
|
+
export type { BranchScopeModeProp, BranchScopeOptionProp, BranchScopePickerProp, BranchScopePickerProp as BranchScopePickerProps, BranchScopeValueProp, } from "../../props/components/data-entry.prop.js";
|
|
4
|
+
/**
|
|
5
|
+
* BranchScopePicker — the canonical "all branches vs an explicit subset" scope control
|
|
6
|
+
* (gh#257 / DXS platform#311).
|
|
7
|
+
*
|
|
8
|
+
* A THIN formalized composition (the gh#251 lesson: a consumer cannot import a docs page): the
|
|
9
|
+
* mode switch is the real `RadioGroup`, the subset is the real `CheckboxGroup`, search is the real
|
|
10
|
+
* `SearchInput` — so keyboard behaviour (roving radios, Space on checkboxes) and the field-a11y
|
|
11
|
+
* contract (`aria-labelledby`/`aria-errormessage` via `FormField`) come from the primitives, not
|
|
12
|
+
* from new machinery. Domain data (the branches) is 100% consumer-supplied.
|
|
13
|
+
*
|
|
14
|
+
* - **Value** is a single controlled/uncontrolled object `{ mode, branchIds }`, so a form treats
|
|
15
|
+
* scope as ONE field. Switching back to `all` PRESERVES `branchIds` — an accidental mode flip
|
|
16
|
+
* must not destroy a curated subset.
|
|
17
|
+
* - **Validation** (`error`) renders the message and wires `aria-invalid`/`aria-errormessage` onto
|
|
18
|
+
* the radiogroup widget; collection READ failures are `listError`/`denied`, mirroring the
|
|
19
|
+
* DataTable #216 vocabulary (precedence `loading` → `denied` → `listError` → `empty`).
|
|
20
|
+
* - **`readOnly`** renders the current scope as a static summary (mode + branch badges) with no
|
|
21
|
+
* editable affordance; `disabled` keeps the controls visible but inert.
|
|
22
|
+
* - **Responsive**: a single-column stack; the branch list scrolls inside its own bounded box, so
|
|
23
|
+
* the control keeps one measure at 1440/1024/390.
|
|
24
|
+
*/
|
|
25
|
+
export declare const BranchScopePicker: React.ForwardRefExoticComponent<import("../../lib/field-a11y.js").FieldA11yProps & {
|
|
26
|
+
branches: readonly import("./branch-scope-picker.js").BranchScopeOptionProp[];
|
|
27
|
+
value?: BranchScopeValueProp;
|
|
28
|
+
defaultValue?: BranchScopeValueProp;
|
|
29
|
+
onValueChange?: (value: BranchScopeValueProp) => void;
|
|
30
|
+
disabled?: import("../../props/index.js").DisabledProp;
|
|
31
|
+
readOnly?: boolean;
|
|
32
|
+
searchable?: boolean;
|
|
33
|
+
error?: import("../../props/index.js").ErrorProp;
|
|
34
|
+
loading?: boolean;
|
|
35
|
+
empty?: React.ReactNode;
|
|
36
|
+
listError?: React.ReactNode;
|
|
37
|
+
denied?: React.ReactNode;
|
|
38
|
+
allLabel?: React.ReactNode;
|
|
39
|
+
selectedLabel?: React.ReactNode;
|
|
40
|
+
name?: import("../../props/index.js").NameProp;
|
|
41
|
+
id?: import("../../props/index.js").IdProp;
|
|
42
|
+
className?: import("../../props/index.js").ClassNameProp;
|
|
43
|
+
} & React.RefAttributes<HTMLDivElement>>;
|
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
3
|
+
import * as React from "react";
|
|
4
|
+
import { AlertCircle, ShieldAlert } from "lucide-react";
|
|
5
|
+
import { useTranslation } from "../../i18n/use-translation.js";
|
|
6
|
+
import { mergeAriaIds, pickFieldA11y } from "../../lib/field-a11y.js";
|
|
7
|
+
import { cn } from "../../lib/utils.js";
|
|
8
|
+
import { Badge } from "../data-display/badge.js";
|
|
9
|
+
import { EmptyState } from "../data-display/empty-state.js";
|
|
10
|
+
import { SkeletonRows } from "../feedback/skeleton.js";
|
|
11
|
+
import { Text } from "../general/typography.js";
|
|
12
|
+
import { CheckboxGroup } from "./checkbox-group.js";
|
|
13
|
+
import { RadioGroup } from "./radio.js";
|
|
14
|
+
import { SearchInput } from "./search-input.js";
|
|
15
|
+
const DEFAULT_VALUE = { mode: "all" };
|
|
16
|
+
const BranchScopePicker = React.forwardRef(
|
|
17
|
+
function BranchScopePicker2({
|
|
18
|
+
branches,
|
|
19
|
+
value: controlledValue,
|
|
20
|
+
defaultValue = DEFAULT_VALUE,
|
|
21
|
+
onValueChange,
|
|
22
|
+
disabled = false,
|
|
23
|
+
readOnly = false,
|
|
24
|
+
searchable = true,
|
|
25
|
+
error,
|
|
26
|
+
loading = false,
|
|
27
|
+
empty,
|
|
28
|
+
listError,
|
|
29
|
+
denied,
|
|
30
|
+
allLabel,
|
|
31
|
+
selectedLabel,
|
|
32
|
+
name,
|
|
33
|
+
id,
|
|
34
|
+
className,
|
|
35
|
+
...ariaProps
|
|
36
|
+
}, ref) {
|
|
37
|
+
const { t } = useTranslation();
|
|
38
|
+
const reactId = React.useId();
|
|
39
|
+
const rootId = id ?? `branch-scope-${reactId}`;
|
|
40
|
+
const errorId = `${rootId}-error`;
|
|
41
|
+
const [uncontrolled, setUncontrolled] = React.useState(defaultValue);
|
|
42
|
+
const value = controlledValue ?? uncontrolled;
|
|
43
|
+
const branchIds = React.useMemo(() => value.branchIds ?? [], [value.branchIds]);
|
|
44
|
+
const commit = (next) => {
|
|
45
|
+
if (controlledValue === void 0) setUncontrolled(next);
|
|
46
|
+
onValueChange?.(next);
|
|
47
|
+
};
|
|
48
|
+
const [search, setSearch] = React.useState("");
|
|
49
|
+
const filtered = React.useMemo(() => {
|
|
50
|
+
const term = search.trim().toLocaleLowerCase();
|
|
51
|
+
if (term === "") return branches;
|
|
52
|
+
return branches.filter(
|
|
53
|
+
(branch) => `${branch.name} ${branch.description ?? ""}`.toLocaleLowerCase().includes(term)
|
|
54
|
+
);
|
|
55
|
+
}, [branches, search]);
|
|
56
|
+
const fieldA11y = pickFieldA11y(ariaProps);
|
|
57
|
+
const invalid = error !== void 0 && error !== null && error !== false;
|
|
58
|
+
const isDenied = denied !== void 0 && denied !== null && denied !== false;
|
|
59
|
+
const isListError = listError !== void 0 && listError !== null && listError !== false;
|
|
60
|
+
const resolvedAllLabel = allLabel ?? t("dataEntry.branchScope.all");
|
|
61
|
+
const resolvedSelectedLabel = selectedLabel ?? t("dataEntry.branchScope.selected");
|
|
62
|
+
const surface = (children) => /* @__PURE__ */ jsx(
|
|
63
|
+
"div",
|
|
64
|
+
{
|
|
65
|
+
ref,
|
|
66
|
+
id: rootId,
|
|
67
|
+
"data-slot": "branch-scope-picker",
|
|
68
|
+
"data-readonly": readOnly || void 0,
|
|
69
|
+
className: cn("ui-branch-scope-picker flex flex-col gap-3", className),
|
|
70
|
+
children
|
|
71
|
+
}
|
|
72
|
+
);
|
|
73
|
+
if (loading) {
|
|
74
|
+
return surface(
|
|
75
|
+
/* @__PURE__ */ jsx("div", { "aria-busy": "true", "aria-label": t("dataEntry.branchScope.loading"), role: "status", children: /* @__PURE__ */ jsx(SkeletonRows, { rows: 4, columns: 2 }) })
|
|
76
|
+
);
|
|
77
|
+
}
|
|
78
|
+
if (isDenied) {
|
|
79
|
+
return surface(
|
|
80
|
+
/* @__PURE__ */ jsx("div", { "aria-live": "polite", children: denied === true ? /* @__PURE__ */ jsx(
|
|
81
|
+
EmptyState,
|
|
82
|
+
{
|
|
83
|
+
icon: ShieldAlert,
|
|
84
|
+
tone: "warning",
|
|
85
|
+
variant: "compact",
|
|
86
|
+
title: t("dataEntry.branchScope.denied"),
|
|
87
|
+
titleAs: "p"
|
|
88
|
+
}
|
|
89
|
+
) : denied })
|
|
90
|
+
);
|
|
91
|
+
}
|
|
92
|
+
if (isListError) {
|
|
93
|
+
return surface(
|
|
94
|
+
/* @__PURE__ */ jsx("div", { role: "alert", children: listError === true ? /* @__PURE__ */ jsx(
|
|
95
|
+
EmptyState,
|
|
96
|
+
{
|
|
97
|
+
icon: AlertCircle,
|
|
98
|
+
tone: "destructive",
|
|
99
|
+
variant: "compact",
|
|
100
|
+
title: t("dataEntry.branchScope.error"),
|
|
101
|
+
titleAs: "p"
|
|
102
|
+
}
|
|
103
|
+
) : listError })
|
|
104
|
+
);
|
|
105
|
+
}
|
|
106
|
+
if (branches.length === 0) {
|
|
107
|
+
return surface(
|
|
108
|
+
/* @__PURE__ */ jsx("div", { "aria-live": "polite", children: empty ?? /* @__PURE__ */ jsx(EmptyState, { variant: "compact", title: t("dataEntry.branchScope.empty"), titleAs: "p" }) })
|
|
109
|
+
);
|
|
110
|
+
}
|
|
111
|
+
if (readOnly) {
|
|
112
|
+
const selectedBranches = branches.filter((branch) => branchIds.includes(branch.id));
|
|
113
|
+
return surface(
|
|
114
|
+
/* @__PURE__ */ jsxs(Fragment, { children: [
|
|
115
|
+
/* @__PURE__ */ jsx(Text, { size: "sm", weight: "medium", children: value.mode === "all" ? resolvedAllLabel : resolvedSelectedLabel }),
|
|
116
|
+
value.mode === "selected" && /* @__PURE__ */ jsx("div", { className: "flex flex-wrap gap-1.5", children: selectedBranches.map((branch) => /* @__PURE__ */ jsx(Badge, { variant: "outline", children: branch.name }, branch.id)) })
|
|
117
|
+
] })
|
|
118
|
+
);
|
|
119
|
+
}
|
|
120
|
+
return surface(
|
|
121
|
+
/* @__PURE__ */ jsxs(Fragment, { children: [
|
|
122
|
+
/* @__PURE__ */ jsx(
|
|
123
|
+
RadioGroup,
|
|
124
|
+
{
|
|
125
|
+
value: value.mode,
|
|
126
|
+
onValueChange: (mode) => {
|
|
127
|
+
commit({ ...value, mode });
|
|
128
|
+
},
|
|
129
|
+
options: [
|
|
130
|
+
{
|
|
131
|
+
value: "all",
|
|
132
|
+
label: resolvedAllLabel,
|
|
133
|
+
description: allLabel === void 0 ? t("dataEntry.branchScope.allDescription") : void 0
|
|
134
|
+
},
|
|
135
|
+
{
|
|
136
|
+
value: "selected",
|
|
137
|
+
label: resolvedSelectedLabel,
|
|
138
|
+
description: selectedLabel === void 0 ? t("dataEntry.branchScope.selectedDescription") : void 0
|
|
139
|
+
}
|
|
140
|
+
],
|
|
141
|
+
disabled,
|
|
142
|
+
name,
|
|
143
|
+
...fieldA11y,
|
|
144
|
+
"aria-invalid": invalid ? true : fieldA11y["aria-invalid"],
|
|
145
|
+
"aria-errormessage": invalid ? mergeAriaIds(errorId, fieldA11y["aria-errormessage"]) : void 0
|
|
146
|
+
}
|
|
147
|
+
),
|
|
148
|
+
value.mode === "selected" && /* @__PURE__ */ jsxs("div", { className: "border-border flex flex-col gap-2 border-s-2 ps-4", children: [
|
|
149
|
+
searchable && branches.length > 0 && /* @__PURE__ */ jsx(
|
|
150
|
+
SearchInput,
|
|
151
|
+
{
|
|
152
|
+
value: search,
|
|
153
|
+
onValueChange: setSearch,
|
|
154
|
+
debounce: 0,
|
|
155
|
+
placeholder: t("dataEntry.branchScope.searchPlaceholder"),
|
|
156
|
+
ariaLabel: t("dataEntry.branchScope.searchPlaceholder")
|
|
157
|
+
}
|
|
158
|
+
),
|
|
159
|
+
filtered.length === 0 ? /* @__PURE__ */ jsx(Text, { size: "xs", tone: "muted", "aria-live": "polite", children: t("dataEntry.branchScope.noMatches") }) : (
|
|
160
|
+
// A bounded list is a scroll container, so it MUST be reachable and scrollable
|
|
161
|
+
// with the keyboard alone even when every row is unfocusable (all checkboxes
|
|
162
|
+
// `disabled`) — WCAG 2.1.1 / axe `scrollable-region-focusable`; same contract as
|
|
163
|
+
// MasterDetail's bounded master region. It is an ordinary tab stop (no trap), and
|
|
164
|
+
// it carries the group's accessible name so the stop is announced meaningfully —
|
|
165
|
+
// the inner CheckboxGroup deliberately no longer duplicates that label.
|
|
166
|
+
/* @__PURE__ */ jsx(
|
|
167
|
+
"div",
|
|
168
|
+
{
|
|
169
|
+
role: "group",
|
|
170
|
+
"aria-label": t("dataEntry.branchScope.listLabel"),
|
|
171
|
+
tabIndex: 0,
|
|
172
|
+
className: "max-h-64 overflow-y-auto",
|
|
173
|
+
children: /* @__PURE__ */ jsx(
|
|
174
|
+
CheckboxGroup,
|
|
175
|
+
{
|
|
176
|
+
value: [...branchIds],
|
|
177
|
+
onValueChange: (next) => commit({ mode: "selected", branchIds: next }),
|
|
178
|
+
options: filtered.map((branch) => ({
|
|
179
|
+
value: branch.id,
|
|
180
|
+
label: branch.name,
|
|
181
|
+
description: branch.description,
|
|
182
|
+
disabled: branch.disabled
|
|
183
|
+
})),
|
|
184
|
+
disabled
|
|
185
|
+
}
|
|
186
|
+
)
|
|
187
|
+
}
|
|
188
|
+
)
|
|
189
|
+
),
|
|
190
|
+
/* @__PURE__ */ jsx(Text, { size: "xs", tone: "muted", "aria-live": "polite", children: t("dataEntry.branchScope.selectedCount", { count: branchIds.length }) })
|
|
191
|
+
] }),
|
|
192
|
+
invalid && /* @__PURE__ */ jsx("p", { id: errorId, role: "alert", className: "text-destructive text-xs", children: error })
|
|
193
|
+
] })
|
|
194
|
+
);
|
|
195
|
+
}
|
|
196
|
+
);
|
|
197
|
+
BranchScopePicker.displayName = "BranchScopePicker";
|
|
198
|
+
export {
|
|
199
|
+
BranchScopePicker
|
|
200
|
+
};
|
|
@@ -29,50 +29,9 @@ export type CommandPaletteProps = {
|
|
|
29
29
|
open?: boolean;
|
|
30
30
|
defaultOpen?: boolean;
|
|
31
31
|
onOpenChange?: (open: boolean) => void;
|
|
32
|
-
/**
|
|
33
|
-
* Controlled search-box query. Pairs with `onSearchChange`; leave it out for the uncontrolled
|
|
34
|
-
* palette (seeded by `defaultSearch`). Same idiom as `SearchSelect`'s `search`.
|
|
35
|
-
*/
|
|
36
|
-
search?: string;
|
|
37
|
-
/** Initial uncontrolled query, and the value the palette resets to when it closes. Default `""`. */
|
|
38
|
-
defaultSearch?: string;
|
|
39
|
-
/**
|
|
40
|
-
* Fires on every keystroke with the current query — the seam a server-backed group needs to run
|
|
41
|
-
* search-as-you-type. Also fires with `defaultSearch` when the palette closes.
|
|
42
|
-
*/
|
|
43
|
-
onSearchChange?: (query: string) => void;
|
|
44
|
-
/**
|
|
45
|
-
* Whether the palette filters `groups` itself (cmdk's client-side fuzzy match). Set `false` when
|
|
46
|
-
* the QUERY is answered by a server and `groups` already holds the matches — otherwise every row
|
|
47
|
-
* is scored a second time against the same string and late-arriving matches are dropped.
|
|
48
|
-
*
|
|
49
|
-
* It also decides who owns the empty node; see the component doc block. Default `true`.
|
|
50
|
-
*/
|
|
51
|
-
shouldFilter?: boolean;
|
|
52
32
|
loading?: boolean;
|
|
53
33
|
error?: React.ReactNode;
|
|
54
34
|
trigger?: React.ReactNode;
|
|
55
35
|
shortcut?: boolean;
|
|
56
36
|
};
|
|
57
|
-
|
|
58
|
-
* CommandPalette — the ⌘K search dialog.
|
|
59
|
-
*
|
|
60
|
-
* ## The empty-state contract (gh#412)
|
|
61
|
-
*
|
|
62
|
-
* `labels.empty` renders under exactly one rule, and which mechanism decides follows `shouldFilter`:
|
|
63
|
-
*
|
|
64
|
-
* - **`shouldFilter` (default, client-side)** — cmdk owns it: the palette holds items, the query
|
|
65
|
-
* matches none of them. Unchanged.
|
|
66
|
-
* - **`shouldFilter={false}` (server-side)** — the PALETTE owns it, derived synchronously from
|
|
67
|
-
* props: the empty node renders when `groups` carries no items, and never while `loading` or
|
|
68
|
-
* `error` is set. cmdk's own empty node cannot be trusted here, because it is driven by a
|
|
69
|
-
* scheduled count of the items that have REGISTERED in the DOM, not by what the consumer knows —
|
|
70
|
-
* so an async group that populates a frame late flips it on and off and any assertion over it
|
|
71
|
-
* races. Reading `groups` instead makes "did we render the empty state?" a pure function of the
|
|
72
|
-
* props at that render, which is what a contract test can assert.
|
|
73
|
-
*
|
|
74
|
-
* The practical consequence for search-as-you-type: hold `loading` true for the whole in-flight
|
|
75
|
-
* window. While it is true the palette shows `labels.loading` and never claims "no results" —
|
|
76
|
-
* a request that has not answered yet is not an empty result.
|
|
77
|
-
*/
|
|
78
|
-
export declare function CommandPalette({ groups, labels, onSelect, open: controlledOpen, defaultOpen, onOpenChange, search: controlledSearch, defaultSearch, onSearchChange, shouldFilter, loading, error, trigger, shortcut, }: CommandPaletteProps): React.JSX.Element;
|
|
37
|
+
export declare function CommandPalette({ groups, labels, onSelect, open: controlledOpen, defaultOpen, onOpenChange, loading, error, trigger, shortcut, }: CommandPaletteProps): React.JSX.Element;
|
|
@@ -19,20 +19,14 @@ function CommandPalette({
|
|
|
19
19
|
open: controlledOpen,
|
|
20
20
|
defaultOpen = false,
|
|
21
21
|
onOpenChange,
|
|
22
|
-
search: controlledSearch,
|
|
23
|
-
defaultSearch = "",
|
|
24
|
-
onSearchChange,
|
|
25
|
-
shouldFilter = true,
|
|
26
22
|
loading = false,
|
|
27
23
|
error,
|
|
28
24
|
trigger,
|
|
29
25
|
shortcut = true
|
|
30
26
|
}) {
|
|
31
27
|
const [uncontrolledOpen, setUncontrolledOpen] = React.useState(defaultOpen);
|
|
32
|
-
const [uncontrolledSearch, setUncontrolledSearch] = React.useState(defaultSearch);
|
|
33
28
|
const shortcutRestoreFocusRef = React.useRef(null);
|
|
34
29
|
const open = controlledOpen ?? uncontrolledOpen;
|
|
35
|
-
const search = controlledSearch ?? uncontrolledSearch;
|
|
36
30
|
const setOpen = React.useCallback(
|
|
37
31
|
(next) => {
|
|
38
32
|
if (controlledOpen === void 0) {
|
|
@@ -42,22 +36,6 @@ function CommandPalette({
|
|
|
42
36
|
},
|
|
43
37
|
[controlledOpen, onOpenChange]
|
|
44
38
|
);
|
|
45
|
-
const setSearch = React.useCallback(
|
|
46
|
-
(next) => {
|
|
47
|
-
if (controlledSearch === void 0) {
|
|
48
|
-
setUncontrolledSearch(next);
|
|
49
|
-
}
|
|
50
|
-
onSearchChange?.(next);
|
|
51
|
-
},
|
|
52
|
-
[controlledSearch, onSearchChange]
|
|
53
|
-
);
|
|
54
|
-
const previousOpenRef = React.useRef(open);
|
|
55
|
-
React.useEffect(() => {
|
|
56
|
-
const wasOpen = previousOpenRef.current;
|
|
57
|
-
previousOpenRef.current = open;
|
|
58
|
-
if (!wasOpen || open || search === defaultSearch) return;
|
|
59
|
-
setSearch(defaultSearch);
|
|
60
|
-
}, [open, search, defaultSearch, setSearch]);
|
|
61
39
|
React.useEffect(() => {
|
|
62
40
|
if (!shortcut) return;
|
|
63
41
|
const handleKeyDown = (event) => {
|
|
@@ -72,7 +50,6 @@ function CommandPalette({
|
|
|
72
50
|
document.addEventListener("keydown", handleKeyDown);
|
|
73
51
|
return () => document.removeEventListener("keydown", handleKeyDown);
|
|
74
52
|
}, [open, setOpen, shortcut]);
|
|
75
|
-
const hasItems = React.useMemo(() => groups.some((group) => group.items.length > 0), [groups]);
|
|
76
53
|
const triggerNode = trigger ?? /* @__PURE__ */ jsxs(Button, { variant: "outline", size: "sm", className: "ui-command-palette-trigger", children: [
|
|
77
54
|
/* @__PURE__ */ jsx(Search, { "aria-hidden": "true" }),
|
|
78
55
|
/* @__PURE__ */ jsx("span", { children: labels.open }),
|
|
@@ -102,23 +79,17 @@ function CommandPalette({
|
|
|
102
79
|
children: [
|
|
103
80
|
/* @__PURE__ */ jsx(Dialog.Title, { className: "sr-only", children: labels.title }),
|
|
104
81
|
/* @__PURE__ */ jsx(Dialog.Description, { id: "ui-command-palette-description", className: "sr-only", children: labels.description }),
|
|
105
|
-
/* @__PURE__ */ jsxs(Command, { label: labels.title,
|
|
82
|
+
/* @__PURE__ */ jsxs(Command, { label: labels.title, children: [
|
|
106
83
|
/* @__PURE__ */ jsx(
|
|
107
84
|
CommandInput,
|
|
108
85
|
{
|
|
109
86
|
autoFocus: true,
|
|
110
|
-
value: search,
|
|
111
|
-
onValueChange: setSearch,
|
|
112
87
|
placeholder: labels.placeholder,
|
|
113
88
|
"aria-label": labels.placeholder
|
|
114
89
|
}
|
|
115
90
|
),
|
|
116
91
|
/* @__PURE__ */ jsx(CommandList, { "aria-busy": loading, children: loading ? /* @__PURE__ */ jsx("div", { className: "ui-command-palette-state", role: "status", children: labels.loading }) : error ? /* @__PURE__ */ jsx("div", { className: "ui-command-palette-state", role: "alert", children: error }) : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
117
|
-
|
|
118
|
-
// Same node cmdk would have rendered (class + role), decided from `groups`
|
|
119
|
-
// instead of from its scheduled DOM-registration count — see the doc block.
|
|
120
|
-
/* @__PURE__ */ jsx("div", { className: "ui-command-empty", role: "presentation", children: labels.empty })
|
|
121
|
-
),
|
|
92
|
+
/* @__PURE__ */ jsx(CommandEmpty, { children: labels.empty }),
|
|
122
93
|
groups.map((group) => /* @__PURE__ */ jsx(CommandGroup, { heading: group.label, children: group.items.map((item) => /* @__PURE__ */ jsxs(
|
|
123
94
|
CommandItem,
|
|
124
95
|
{
|
|
@@ -60,3 +60,5 @@ export { Rating } from "./rating.js";
|
|
|
60
60
|
export type { RatingProps } from "./rating.js";
|
|
61
61
|
export { TagInput } from "./tag-input.js";
|
|
62
62
|
export type { TagInputProps } from "./tag-input.js";
|
|
63
|
+
export { BranchScopePicker } from "./branch-scope-picker.js";
|
|
64
|
+
export type { BranchScopeModeProp, BranchScopeOptionProp, BranchScopePickerProp, BranchScopePickerProps, BranchScopeValueProp, } from "./branch-scope-picker.js";
|
|
@@ -50,7 +50,9 @@ import { PasswordStrength, usePasswordStrength } from "./password-strength.js";
|
|
|
50
50
|
import { InputOTP, InputOTPGroup, InputOTPSlot, InputOTPSeparator } from "./input-otp.js";
|
|
51
51
|
import { Rating } from "./rating.js";
|
|
52
52
|
import { TagInput } from "./tag-input.js";
|
|
53
|
+
import { BranchScopePicker } from "./branch-scope-picker.js";
|
|
53
54
|
export {
|
|
55
|
+
BranchScopePicker,
|
|
54
56
|
Calendar,
|
|
55
57
|
Cascader,
|
|
56
58
|
Checkbox,
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
export { InputOTP, InputOTPGroup, InputOTPSlot, InputOTPSeparator } from "../ui/input-otp.js";
|
|
2
|
-
export type {
|
|
2
|
+
export type { InputOTPGroupAppearanceProp, InputOTPGroupProp, InputOTPGroupProps, } from "../ui/input-otp.js";
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
2
|
import type { ToneProp } from "../../props/vocabulary/index.js";
|
|
3
|
-
import type { AlertQueryErrorProp
|
|
4
|
-
export type {
|
|
3
|
+
import type { AlertQueryErrorProp } from "../../props/components/feedback.prop.js";
|
|
4
|
+
export type { AlertProp, AlertProp as AlertProps, AlertTitleProp, AlertTitleProp as AlertTitleProps, AlertContentProp, AlertContentProp as AlertContentProps, AlertDescriptionProp, AlertDescriptionProp as AlertDescriptionProps, AlertActionsProp, AlertActionsProp as AlertActionsProps, AlertQueryErrorProp, AlertQueryErrorProp as AlertQueryErrorProps, } from "../../props/components/feedback.prop.js";
|
|
5
5
|
declare const AlertBase: React.ForwardRefExoticComponent<React.HTMLAttributes<HTMLDivElement> & {
|
|
6
6
|
variant?: import("../../props/index.js").AlertVariantProp;
|
|
7
7
|
tone?: ToneProp;
|
|
@@ -63,22 +63,4 @@ export declare const Alert: React.ForwardRefExoticComponent<React.HTMLAttributes
|
|
|
63
63
|
} & React.RefAttributes<HTMLDivElement>>;
|
|
64
64
|
QueryError: typeof AlertQueryError;
|
|
65
65
|
};
|
|
66
|
-
export declare const Banner: React.ForwardRefExoticComponent<BannerProp & React.RefAttributes<HTMLDivElement>> & {
|
|
67
|
-
Title: React.ForwardRefExoticComponent<React.HTMLAttributes<HTMLParagraphElement> & {
|
|
68
|
-
className?: import("../../props/index.js").ClassNameProp;
|
|
69
|
-
children?: import("../../props/index.js").ChildrenProp;
|
|
70
|
-
} & React.RefAttributes<HTMLParagraphElement>>;
|
|
71
|
-
Content: React.ForwardRefExoticComponent<React.HTMLAttributes<HTMLDivElement> & {
|
|
72
|
-
className?: import("../../props/index.js").ClassNameProp;
|
|
73
|
-
children?: import("../../props/index.js").ChildrenProp;
|
|
74
|
-
} & React.RefAttributes<HTMLDivElement>>;
|
|
75
|
-
Description: React.ForwardRefExoticComponent<React.HTMLAttributes<HTMLParagraphElement> & {
|
|
76
|
-
className?: import("../../props/index.js").ClassNameProp;
|
|
77
|
-
children?: import("../../props/index.js").ChildrenProp;
|
|
78
|
-
} & React.RefAttributes<HTMLParagraphElement>>;
|
|
79
|
-
Actions: React.ForwardRefExoticComponent<React.HTMLAttributes<HTMLDivElement> & {
|
|
80
|
-
className?: import("../../props/index.js").ClassNameProp;
|
|
81
|
-
children?: import("../../props/index.js").ChildrenProp;
|
|
82
|
-
} & React.RefAttributes<HTMLDivElement>>;
|
|
83
|
-
};
|
|
84
66
|
export { AlertBase };
|
|
@@ -159,15 +159,6 @@ const Alert = Object.assign(AlertBase, {
|
|
|
159
159
|
Actions: AlertActions,
|
|
160
160
|
QueryError: AlertQueryError
|
|
161
161
|
});
|
|
162
|
-
const BannerBase = React.forwardRef(function Banner(props, ref) {
|
|
163
|
-
return /* @__PURE__ */ jsx(AlertBase, { ...props, ref, variant: "banner" });
|
|
164
|
-
});
|
|
165
|
-
const Banner2 = Object.assign(BannerBase, {
|
|
166
|
-
Title: AlertTitle,
|
|
167
|
-
Content: AlertContent,
|
|
168
|
-
Description: AlertDescription,
|
|
169
|
-
Actions: AlertActions
|
|
170
|
-
});
|
|
171
162
|
export {
|
|
172
163
|
Alert,
|
|
173
164
|
AlertActions,
|
|
@@ -175,6 +166,5 @@ export {
|
|
|
175
166
|
AlertContent,
|
|
176
167
|
AlertDescription,
|
|
177
168
|
AlertQueryError,
|
|
178
|
-
AlertTitle
|
|
179
|
-
Banner2 as Banner
|
|
169
|
+
AlertTitle
|
|
180
170
|
};
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import type { BannerProp } from "../../props/components/feedback.prop.js";
|
|
3
|
+
export type { BannerProp, BannerProp as BannerProps } from "../../props/components/feedback.prop.js";
|
|
4
|
+
export declare const Banner: React.ForwardRefExoticComponent<BannerProp & React.RefAttributes<HTMLDivElement>> & {
|
|
5
|
+
Title: React.ForwardRefExoticComponent<React.HTMLAttributes<HTMLParagraphElement> & {
|
|
6
|
+
className?: import("../../props/index.js").ClassNameProp;
|
|
7
|
+
children?: import("../../props/index.js").ChildrenProp;
|
|
8
|
+
} & React.RefAttributes<HTMLParagraphElement>>;
|
|
9
|
+
Content: React.ForwardRefExoticComponent<React.HTMLAttributes<HTMLDivElement> & {
|
|
10
|
+
className?: import("../../props/index.js").ClassNameProp;
|
|
11
|
+
children?: import("../../props/index.js").ChildrenProp;
|
|
12
|
+
} & React.RefAttributes<HTMLDivElement>>;
|
|
13
|
+
Description: React.ForwardRefExoticComponent<React.HTMLAttributes<HTMLParagraphElement> & {
|
|
14
|
+
className?: import("../../props/index.js").ClassNameProp;
|
|
15
|
+
children?: import("../../props/index.js").ChildrenProp;
|
|
16
|
+
} & React.RefAttributes<HTMLParagraphElement>>;
|
|
17
|
+
Actions: React.ForwardRefExoticComponent<React.HTMLAttributes<HTMLDivElement> & {
|
|
18
|
+
className?: import("../../props/index.js").ClassNameProp;
|
|
19
|
+
children?: import("../../props/index.js").ChildrenProp;
|
|
20
|
+
} & React.RefAttributes<HTMLDivElement>>;
|
|
21
|
+
};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx } from "react/jsx-runtime";
|
|
3
|
+
import * as React from "react";
|
|
4
|
+
import { AlertActions, AlertBase, AlertContent, AlertDescription, AlertTitle } from "./alert.js";
|
|
5
|
+
const BannerBase = React.forwardRef((props, ref) => /* @__PURE__ */ jsx(AlertBase, { ref, variant: "banner", ...props }));
|
|
6
|
+
BannerBase.displayName = "Banner";
|
|
7
|
+
const Banner = Object.assign(BannerBase, {
|
|
8
|
+
Title: AlertTitle,
|
|
9
|
+
Content: AlertContent,
|
|
10
|
+
Description: AlertDescription,
|
|
11
|
+
Actions: AlertActions
|
|
12
|
+
});
|
|
13
|
+
export {
|
|
14
|
+
Banner
|
|
15
|
+
};
|
|
@@ -8,6 +8,8 @@ export { Toaster } from "./sonner.js";
|
|
|
8
8
|
export { toast } from "./use-toast.js";
|
|
9
9
|
export { Skeleton, SkeletonRows, SkeletonTable, SkeletonDetail, SkeletonStat } from "./skeleton.js";
|
|
10
10
|
export type { SkeletonProps } from "./skeleton.js";
|
|
11
|
-
export {
|
|
12
|
-
export type { BannerProp, BannerProps
|
|
11
|
+
export { Banner } from "./banner.js";
|
|
12
|
+
export type { BannerProp, BannerProps } from "./banner.js";
|
|
13
|
+
export { Alert, AlertTitle, AlertContent, AlertDescription, AlertActions, AlertQueryError, } from "./alert.js";
|
|
14
|
+
export type { AlertProp, AlertProps, AlertTitleProp, AlertTitleProps, AlertContentProp, AlertContentProps, AlertDescriptionProp, AlertDescriptionProps, AlertActionsProp, AlertActionsProps, AlertQueryErrorProp, AlertQueryErrorProps, } from "./alert.js";
|
|
13
15
|
export { Tooltip, TooltipTrigger, TooltipContent, TooltipProvider } from "./tooltip.js";
|
|
@@ -43,14 +43,14 @@ import { TwoFactorSetup } from "./two-factor-setup.js";
|
|
|
43
43
|
import { Toaster } from "./sonner.js";
|
|
44
44
|
import { toast } from "./use-toast.js";
|
|
45
45
|
import { Skeleton, SkeletonRows, SkeletonTable, SkeletonDetail, SkeletonStat } from "./skeleton.js";
|
|
46
|
+
import { Banner } from "./banner.js";
|
|
46
47
|
import {
|
|
47
48
|
Alert,
|
|
48
49
|
AlertTitle,
|
|
49
50
|
AlertContent,
|
|
50
51
|
AlertDescription,
|
|
51
52
|
AlertActions,
|
|
52
|
-
AlertQueryError
|
|
53
|
-
Banner
|
|
53
|
+
AlertQueryError
|
|
54
54
|
} from "./alert.js";
|
|
55
55
|
import { Tooltip, TooltipTrigger, TooltipContent, TooltipProvider } from "./tooltip.js";
|
|
56
56
|
export {
|
|
@@ -13,6 +13,7 @@ export declare const Text: React.ForwardRefExoticComponent<Omit<React.HTMLAttrib
|
|
|
13
13
|
weight?: import("../../props/index.js").FontWeightProp;
|
|
14
14
|
align?: import("../../props/index.js").TextAlignProp;
|
|
15
15
|
truncate?: boolean;
|
|
16
|
+
clamp?: number;
|
|
16
17
|
tabular?: boolean;
|
|
17
18
|
mono?: boolean;
|
|
18
19
|
htmlFor?: string;
|
|
@@ -8,23 +8,42 @@ const Text = React.forwardRef(
|
|
|
8
8
|
weight = "regular",
|
|
9
9
|
align,
|
|
10
10
|
truncate,
|
|
11
|
+
clamp,
|
|
11
12
|
tabular,
|
|
12
13
|
mono,
|
|
13
14
|
className,
|
|
15
|
+
style,
|
|
14
16
|
...props
|
|
15
|
-
}, ref) =>
|
|
16
|
-
|
|
17
|
-
"
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
17
|
+
}, ref) => {
|
|
18
|
+
const clampLines = typeof clamp === "number" && Number.isFinite(clamp) && clamp >= 1 ? Math.floor(clamp) : void 0;
|
|
19
|
+
if (typeof process !== "undefined" && process.env?.NODE_ENV !== "production") {
|
|
20
|
+
if (clamp !== void 0 && clampLines === void 0) {
|
|
21
|
+
console.warn(
|
|
22
|
+
`Text: \`clamp\` must be a finite number \u2265 1 (got ${String(clamp)}); ignored.`
|
|
23
|
+
);
|
|
24
|
+
}
|
|
25
|
+
if (truncate && clampLines !== void 0) {
|
|
26
|
+
console.warn(
|
|
27
|
+
"Text: `truncate` and `clamp` are mutually exclusive \u2014 `clamp` takes precedence; drop `truncate`."
|
|
28
|
+
);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
return React.createElement(as, {
|
|
32
|
+
ref,
|
|
33
|
+
"data-slot": "text",
|
|
34
|
+
"data-size": size,
|
|
35
|
+
"data-tone": tone,
|
|
36
|
+
"data-weight": weight,
|
|
37
|
+
"data-align": align,
|
|
38
|
+
"data-truncate": truncate && clampLines === void 0 ? "" : void 0,
|
|
39
|
+
"data-clamp": clampLines !== void 0 ? "" : void 0,
|
|
40
|
+
style: clampLines !== void 0 ? { ...style, "--text-clamp": clampLines } : style,
|
|
41
|
+
"data-tabular": tabular ? "" : void 0,
|
|
42
|
+
"data-mono": mono ? "" : void 0,
|
|
43
|
+
className: cn("ui-text", className),
|
|
44
|
+
...props
|
|
45
|
+
});
|
|
46
|
+
}
|
|
28
47
|
);
|
|
29
48
|
Text.displayName = "Text";
|
|
30
49
|
const Heading = React.forwardRef(
|
|
@@ -10,8 +10,8 @@ export type { AuthShellProp, AuthShellProp as AuthShellProps, } from "../../prop
|
|
|
10
10
|
*
|
|
11
11
|
* `preset` names the flow MEASURE (card max-width + desktop/mobile page gutters) so a consumer
|
|
12
12
|
* never overrides page geometry by hand: `"login"` = SCR-001's stable identity/card/footer anchor
|
|
13
|
-
* for standalone and real requester states; `"registration"` = the 360px sign-up measure,
|
|
14
|
-
*
|
|
13
|
+
* for standalone and real requester states; `"registration"` = the 360px sign-up measure,
|
|
14
|
+
* start-aligned like login (a tall sign-up card must scroll, not clip its own top above the scroll
|
|
15
15
|
* origin) and the only one with its own footer clearance; `"device-authorization"` = 380px card
|
|
16
16
|
* with a 5px inline gutter at 390px; `"context-selection"` = 25rem card, edge-to-edge on mobile;
|
|
17
17
|
* `"account-recovery"` = the 432px SCR-008 panel measure shared by password recovery and the
|
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
export { PageContainer } from "./page-container.js";
|
|
2
2
|
export type { PageContainerProp, PageContainerProps, BreadcrumbItem, BreadcrumbItemProp, } from "./page-container.js";
|
|
3
|
-
export { PageHeader } from "./page-header.js";
|
|
4
|
-
export type { PageHeaderProp, PageHeaderProps } from "./page-header.js";
|
|
5
3
|
export { Flex } from "./flex.js";
|
|
6
4
|
export type { FlexAlignProp, FlexDirectionProp, FlexJustifyProp, FlexProp, FlexProps, } from "./flex.js";
|
|
7
5
|
export { ResizablePanel, ResizablePanelGroup, ResizableHandle } from "./resizable.js";
|
|
@@ -44,3 +42,5 @@ export { Separator } from "./separator.js";
|
|
|
44
42
|
export { AspectRatio } from "./aspect-ratio.js";
|
|
45
43
|
export { LegalDocumentShell } from "./legal-document-shell.js";
|
|
46
44
|
export type { LegalDocumentSectionProp, LegalDocumentShellProp, LegalDocumentShellProps, } from "./legal-document-shell.js";
|
|
45
|
+
export { ServiceRolePanel } from "./service-role-panel.js";
|
|
46
|
+
export type { ServiceRoleItemProp, ServiceRolePanelProp, ServiceRolePanelProps, } from "./service-role-panel.js";
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { PageContainer } from "./page-container.js";
|
|
2
|
-
import { PageHeader } from "./page-header.js";
|
|
3
2
|
import { Flex } from "./flex.js";
|
|
4
3
|
import { ResizablePanel, ResizablePanelGroup, ResizableHandle } from "./resizable.js";
|
|
5
4
|
import { AppShell } from "./app-shell.js";
|
|
@@ -21,6 +20,7 @@ import { SplitPane } from "./split-pane.js";
|
|
|
21
20
|
import { Separator } from "./separator.js";
|
|
22
21
|
import { AspectRatio } from "./aspect-ratio.js";
|
|
23
22
|
import { LegalDocumentShell } from "./legal-document-shell.js";
|
|
23
|
+
import { ServiceRolePanel } from "./service-role-panel.js";
|
|
24
24
|
export {
|
|
25
25
|
AppShell,
|
|
26
26
|
AspectRatio,
|
|
@@ -38,12 +38,12 @@ export {
|
|
|
38
38
|
MasterDetail,
|
|
39
39
|
OrgSwitcher,
|
|
40
40
|
PageContainer,
|
|
41
|
-
PageHeader,
|
|
42
41
|
ResizableHandle,
|
|
43
42
|
ResizablePanel,
|
|
44
43
|
ResizablePanelGroup,
|
|
45
44
|
ResponsiveGrid,
|
|
46
45
|
Separator,
|
|
46
|
+
ServiceRolePanel,
|
|
47
47
|
Sidebar,
|
|
48
48
|
SidebarHeader,
|
|
49
49
|
SidebarItem,
|