@godxjp/ui 18.8.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 +2 -2
- 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.js +8 -1
- 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 +273 -72
- package/dist/props/registry.js +361 -92
- 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/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 -2
- 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 -1
- 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
|
+
};
|
|
@@ -80,7 +80,14 @@ function CommandPalette({
|
|
|
80
80
|
/* @__PURE__ */ jsx(Dialog.Title, { className: "sr-only", children: labels.title }),
|
|
81
81
|
/* @__PURE__ */ jsx(Dialog.Description, { id: "ui-command-palette-description", className: "sr-only", children: labels.description }),
|
|
82
82
|
/* @__PURE__ */ jsxs(Command, { label: labels.title, children: [
|
|
83
|
-
/* @__PURE__ */ jsx(
|
|
83
|
+
/* @__PURE__ */ jsx(
|
|
84
|
+
CommandInput,
|
|
85
|
+
{
|
|
86
|
+
autoFocus: true,
|
|
87
|
+
placeholder: labels.placeholder,
|
|
88
|
+
"aria-label": labels.placeholder
|
|
89
|
+
}
|
|
90
|
+
),
|
|
84
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: [
|
|
85
92
|
/* @__PURE__ */ jsx(CommandEmpty, { children: labels.empty }),
|
|
86
93
|
groups.map((group) => /* @__PURE__ */ jsx(CommandGroup, { heading: group.label, children: group.items.map((item) => /* @__PURE__ */ jsxs(
|
|
@@ -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,
|
|
@@ -2,7 +2,7 @@ import type { PageContainerProp, PageInsetProp } from "../../props/components/la
|
|
|
2
2
|
export type { PageContainerProp, PageContainerProp as PageContainerProps, } from "../../props/components/layout.prop.js";
|
|
3
3
|
export type { BreadcrumbItemProp, BreadcrumbItemProp as BreadcrumbItem, } from "../../props/vocabulary/navigation.prop.js";
|
|
4
4
|
export declare function PageContainerInset({ className, children, ...props }: PageInsetProp): import("react").JSX.Element;
|
|
5
|
-
declare function PageContainerRoot({ title, subtitle,
|
|
5
|
+
declare function PageContainerRoot({ title, subtitle, status, extra, footer, breadcrumb, breadcrumbLabel, breadcrumbAriaLabel, linkComponent: LinkComponent, density, variant, preset, headerLayout, measure, stickyFooter, footerReveal, fill, children, className, }: PageContainerProp): import("react").JSX.Element;
|
|
6
6
|
export declare const PageContainer: typeof PageContainerRoot & {
|
|
7
7
|
Inset: typeof PageContainerInset;
|
|
8
8
|
};
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
3
3
|
import { useEffect, useRef, useState } from "react";
|
|
4
|
+
import { ChevronRight } from "lucide-react";
|
|
5
|
+
import { useTranslation } from "../../i18n/use-translation.js";
|
|
4
6
|
import { cn } from "../../lib/utils.js";
|
|
5
7
|
import { densityClass, pageContainerVariantClass } from "../../lib/variants.js";
|
|
6
|
-
import { PageHeader } from "./page-header.js";
|
|
7
8
|
function scrollParent(el) {
|
|
8
9
|
let node = el?.parentElement ?? null;
|
|
9
10
|
while (node) {
|
|
@@ -35,8 +36,7 @@ function PageContainerInset({ className, children, ...props }) {
|
|
|
35
36
|
function PageContainerRoot({
|
|
36
37
|
title,
|
|
37
38
|
subtitle,
|
|
38
|
-
|
|
39
|
-
headerLoading,
|
|
39
|
+
status,
|
|
40
40
|
extra,
|
|
41
41
|
footer,
|
|
42
42
|
breadcrumb,
|
|
@@ -56,6 +56,7 @@ function PageContainerRoot({
|
|
|
56
56
|
}) {
|
|
57
57
|
const reveal = stickyFooter && footer != null && footerReveal === "onScroll";
|
|
58
58
|
const { headerRef, revealed } = useFooterReveal(reveal);
|
|
59
|
+
const { t } = useTranslation();
|
|
59
60
|
return /* @__PURE__ */ jsxs(
|
|
60
61
|
"div",
|
|
61
62
|
{
|
|
@@ -74,22 +75,47 @@ function PageContainerRoot({
|
|
|
74
75
|
className
|
|
75
76
|
),
|
|
76
77
|
children: [
|
|
77
|
-
/* @__PURE__ */
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
78
|
+
/* @__PURE__ */ jsxs("header", { ref: headerRef, className: "ui-page-header", "data-layout": headerLayout, children: [
|
|
79
|
+
breadcrumb && breadcrumb.length > 0 && /* @__PURE__ */ jsx(
|
|
80
|
+
"nav",
|
|
81
|
+
{
|
|
82
|
+
"aria-label": breadcrumbLabel ?? breadcrumbAriaLabel ?? t("navigation.breadcrumb.ariaLabel"),
|
|
83
|
+
className: "ui-breadcrumb",
|
|
84
|
+
children: /* @__PURE__ */ jsx("ol", { className: "ui-breadcrumb-list", children: breadcrumb.map((item, i) => {
|
|
85
|
+
const isLast = i === breadcrumb.length - 1;
|
|
86
|
+
return /* @__PURE__ */ jsxs("li", { className: "ui-inline-xs", children: [
|
|
87
|
+
item.to && !isLast ? /* @__PURE__ */ jsx(
|
|
88
|
+
LinkComponent,
|
|
89
|
+
{
|
|
90
|
+
href: item.to,
|
|
91
|
+
to: item.to,
|
|
92
|
+
className: "hover:text-foreground hover:underline",
|
|
93
|
+
children: item.label
|
|
94
|
+
}
|
|
95
|
+
) : /* @__PURE__ */ jsx(
|
|
96
|
+
"span",
|
|
97
|
+
{
|
|
98
|
+
className: isLast ? "text-foreground" : "",
|
|
99
|
+
"aria-current": isLast ? "page" : void 0,
|
|
100
|
+
children: item.label
|
|
101
|
+
}
|
|
102
|
+
),
|
|
103
|
+
!isLast && /* @__PURE__ */ jsx(ChevronRight, { className: "size-3", "aria-hidden": "true" })
|
|
104
|
+
] }, i);
|
|
105
|
+
}) })
|
|
106
|
+
}
|
|
107
|
+
),
|
|
108
|
+
/* @__PURE__ */ jsxs("div", { className: "ui-page-header-row", children: [
|
|
109
|
+
/* @__PURE__ */ jsxs("div", { className: "ui-page-header-heading min-w-0", children: [
|
|
110
|
+
status != null ? /* @__PURE__ */ jsxs("div", { className: "ui-page-header-title-row", children: [
|
|
111
|
+
/* @__PURE__ */ jsx("h1", { className: "ui-page-title", children: title }),
|
|
112
|
+
/* @__PURE__ */ jsx("div", { className: "ui-page-header-status", children: status })
|
|
113
|
+
] }) : /* @__PURE__ */ jsx("h1", { className: "ui-page-title", children: title }),
|
|
114
|
+
subtitle && /* @__PURE__ */ jsx("p", { className: "ui-page-subtitle", children: subtitle })
|
|
115
|
+
] }),
|
|
116
|
+
extra && /* @__PURE__ */ jsx("div", { className: "ui-page-header-extra", children: extra })
|
|
117
|
+
] })
|
|
118
|
+
] }),
|
|
93
119
|
children != null && /* @__PURE__ */ jsx("div", { className: "ui-page-body", children }),
|
|
94
120
|
footer && /* @__PURE__ */ jsx("footer", { className: "ui-page-footer", children: footer })
|
|
95
121
|
]
|