@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.
Files changed (85) hide show
  1. package/LICENSE +202 -0
  2. package/dist/components/data-display/badge.d.ts +7 -0
  3. package/dist/components/data-display/badge.js +1 -1
  4. package/dist/components/data-display/card.d.ts +3 -27
  5. package/dist/components/data-display/card.js +1 -4
  6. package/dist/components/data-display/data-table.js +5 -4
  7. package/dist/components/data-display/index.d.ts +2 -0
  8. package/dist/components/data-display/index.js +2 -0
  9. package/dist/components/data-display/permission-matrix.d.ts +26 -0
  10. package/dist/components/data-display/permission-matrix.js +219 -0
  11. package/dist/components/data-display/table.d.ts +12 -0
  12. package/dist/components/data-entry/branch-scope-picker.d.ts +43 -0
  13. package/dist/components/data-entry/branch-scope-picker.js +200 -0
  14. package/dist/components/data-entry/command-palette.d.ts +1 -42
  15. package/dist/components/data-entry/command-palette.js +2 -31
  16. package/dist/components/data-entry/index.d.ts +2 -0
  17. package/dist/components/data-entry/index.js +2 -0
  18. package/dist/components/data-entry/input-otp.d.ts +1 -1
  19. package/dist/components/feedback/alert.d.ts +2 -20
  20. package/dist/components/feedback/alert.js +1 -11
  21. package/dist/components/feedback/banner.d.ts +21 -0
  22. package/dist/components/feedback/banner.js +15 -0
  23. package/dist/components/feedback/index.d.ts +4 -2
  24. package/dist/components/feedback/index.js +2 -2
  25. package/dist/components/general/typography.d.ts +1 -0
  26. package/dist/components/general/typography.js +32 -13
  27. package/dist/components/layout/auth-shell.d.ts +2 -2
  28. package/dist/components/layout/index.d.ts +2 -2
  29. package/dist/components/layout/index.js +2 -2
  30. package/dist/components/layout/page-container.d.ts +1 -1
  31. package/dist/components/layout/page-container.js +45 -19
  32. package/dist/components/layout/service-role-panel.d.ts +25 -0
  33. package/dist/components/layout/service-role-panel.js +206 -0
  34. package/dist/components/navigation/filter-bar.d.ts +2 -2
  35. package/dist/components/navigation/filter-bar.js +113 -34
  36. package/dist/components/navigation/index.d.ts +1 -1
  37. package/dist/components/navigation/steps.d.ts +2 -2
  38. package/dist/components/navigation/steps.js +2 -4
  39. package/dist/components/ui/avatar.d.ts +1 -1
  40. package/dist/components/ui/avatar.js +1 -2
  41. package/dist/components/ui/input-otp.d.ts +3 -15
  42. package/dist/components/ui/input-otp.js +1 -2
  43. package/dist/email/tokens.generated.d.ts +2 -2
  44. package/dist/email/tokens.generated.js +2 -2
  45. package/dist/i18n/messages/en.json +56 -4
  46. package/dist/i18n/messages/ja.json +51 -5
  47. package/dist/i18n/messages/vi.json +50 -4
  48. package/dist/props/components/data-display.prop.d.ts +66 -16
  49. package/dist/props/components/data-entry.prop.d.ts +54 -7
  50. package/dist/props/components/feedback.prop.d.ts +3 -3
  51. package/dist/props/components/general.prop.d.ts +8 -1
  52. package/dist/props/components/layout.prop.d.ts +75 -54
  53. package/dist/props/components/navigation.prop.d.ts +77 -59
  54. package/dist/props/registry.d.ts +274 -73
  55. package/dist/props/registry.js +362 -93
  56. package/dist/props/vocabulary/content.prop.d.ts +5 -0
  57. package/dist/props/vocabulary/index.d.ts +1 -1
  58. package/dist/props/vocabulary/interaction.prop.d.ts +4 -7
  59. package/dist/props/vocabulary/layout.prop.d.ts +2 -2
  60. package/dist/styles/alert-layout.css +15 -32
  61. package/dist/styles/badge-layout.css +5 -0
  62. package/dist/styles/base.css +0 -28
  63. package/dist/styles/card-layout.css +13 -49
  64. package/dist/styles/control.css +2 -12
  65. package/dist/styles/data-display-layout.css +0 -16
  66. package/dist/styles/layout.css +102 -108
  67. package/dist/styles/navigation-layout.css +3 -8
  68. package/dist/styles/shell-layout.css +17 -17
  69. package/dist/styles/table-layout.css +77 -29
  70. package/dist/styles/text-layout.css +13 -0
  71. package/dist/tokens/base.css +1 -0
  72. package/dist/tokens/components/badge.css +5 -0
  73. package/dist/tokens/components/banner.css +16 -0
  74. package/dist/tokens/components/card.css +0 -12
  75. package/dist/tokens/components/control.css +0 -16
  76. package/dist/tokens/components/data-display.css +0 -12
  77. package/dist/tokens/components/email.css +2 -8
  78. package/dist/tokens/components/feedback.css +0 -20
  79. package/dist/tokens/components/navigation.css +10 -34
  80. package/dist/tokens/components/shell.css +24 -36
  81. package/dist/tokens/components/table.css +41 -22
  82. package/dist/tokens/semantic/layout.css +5 -12
  83. package/package.json +15 -2
  84. package/dist/components/layout/page-header.d.ts +0 -22
  85. 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, shouldFilter, children: [
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
- shouldFilter ? /* @__PURE__ */ jsx(CommandEmpty, { children: labels.empty }) : hasItems ? null : (
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 { InputOTPAlignProp, InputOTPGroupAppearanceProp, InputOTPGroupProp, InputOTPGroupProps, } from "../ui/input-otp.js";
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, BannerProp } from "../../props/components/feedback.prop.js";
4
- export type { BannerProp, BannerProp as BannerProps, 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";
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 { Alert, AlertTitle, AlertContent, AlertDescription, AlertActions, AlertQueryError, Banner, } from "./alert.js";
12
- export type { BannerProp, BannerProps, AlertProp, AlertProps, AlertTitleProp, AlertTitleProps, AlertContentProp, AlertContentProps, AlertDescriptionProp, AlertDescriptionProps, AlertActionsProp, AlertActionsProps, AlertQueryErrorProp, AlertQueryErrorProps, } from "./alert.js";
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) => React.createElement(as, {
16
- ref,
17
- "data-slot": "text",
18
- "data-size": size,
19
- "data-tone": tone,
20
- "data-weight": weight,
21
- "data-align": align,
22
- "data-truncate": truncate ? "" : void 0,
23
- "data-tabular": tabular ? "" : void 0,
24
- "data-mono": mono ? "" : void 0,
25
- className: cn("ui-text", className),
26
- ...props
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, the only
14
- * START-aligned preset (a tall sign-up card must scroll, not clip its own top above the scroll
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,