@vaam-apps/ui 0.1.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/CHANGELOG.md +104 -0
- package/LICENSE +21 -0
- package/README.md +286 -0
- package/dist/components/data/code.d.ts +37 -0
- package/dist/components/data/code.d.ts.map +1 -0
- package/dist/components/data/code.js +37 -0
- package/dist/components/data/code.js.map +1 -0
- package/dist/components/data/copy-button.d.ts +39 -0
- package/dist/components/data/copy-button.d.ts.map +1 -0
- package/dist/components/data/copy-button.js +50 -0
- package/dist/components/data/copy-button.js.map +1 -0
- package/dist/components/data/detail-row.d.ts +69 -0
- package/dist/components/data/detail-row.d.ts.map +1 -0
- package/dist/components/data/detail-row.js +27 -0
- package/dist/components/data/detail-row.js.map +1 -0
- package/dist/components/data/id-display.d.ts +33 -0
- package/dist/components/data/id-display.d.ts.map +1 -0
- package/dist/components/data/id-display.js +25 -0
- package/dist/components/data/id-display.js.map +1 -0
- package/dist/components/data/masked-value.d.ts +47 -0
- package/dist/components/data/masked-value.d.ts.map +1 -0
- package/dist/components/data/masked-value.js +46 -0
- package/dist/components/data/masked-value.js.map +1 -0
- package/dist/components/data/money.d.ts +28 -0
- package/dist/components/data/money.d.ts.map +1 -0
- package/dist/components/data/money.js +22 -0
- package/dist/components/data/money.js.map +1 -0
- package/dist/components/data/phone-display.d.ts +45 -0
- package/dist/components/data/phone-display.d.ts.map +1 -0
- package/dist/components/data/phone-display.js +23 -0
- package/dist/components/data/phone-display.js.map +1 -0
- package/dist/components/data/stat-tile.d.ts +33 -0
- package/dist/components/data/stat-tile.d.ts.map +1 -0
- package/dist/components/data/stat-tile.js +18 -0
- package/dist/components/data/stat-tile.js.map +1 -0
- package/dist/components/data/timestamp-display.d.ts +14 -0
- package/dist/components/data/timestamp-display.d.ts.map +1 -0
- package/dist/components/data/timestamp-display.js +77 -0
- package/dist/components/data/timestamp-display.js.map +1 -0
- package/dist/components/patterns/inline-banner.d.ts +22 -0
- package/dist/components/patterns/inline-banner.d.ts.map +1 -0
- package/dist/components/patterns/inline-banner.js +11 -0
- package/dist/components/patterns/inline-banner.js.map +1 -0
- package/dist/components/patterns/inline-empty-state.d.ts +20 -0
- package/dist/components/patterns/inline-empty-state.d.ts.map +1 -0
- package/dist/components/patterns/inline-empty-state.js +11 -0
- package/dist/components/patterns/inline-empty-state.js.map +1 -0
- package/dist/components/patterns/live-row.d.ts +23 -0
- package/dist/components/patterns/live-row.d.ts.map +1 -0
- package/dist/components/patterns/live-row.js +48 -0
- package/dist/components/patterns/live-row.js.map +1 -0
- package/dist/components/patterns/payload-inspector.d.ts +25 -0
- package/dist/components/patterns/payload-inspector.d.ts.map +1 -0
- package/dist/components/patterns/payload-inspector.js +33 -0
- package/dist/components/patterns/payload-inspector.js.map +1 -0
- package/dist/components/patterns/route-skeleton.d.ts +15 -0
- package/dist/components/patterns/route-skeleton.d.ts.map +1 -0
- package/dist/components/patterns/route-skeleton.js +7 -0
- package/dist/components/patterns/route-skeleton.js.map +1 -0
- package/dist/components/patterns/screen-layout.d.ts +14 -0
- package/dist/components/patterns/screen-layout.d.ts.map +1 -0
- package/dist/components/patterns/screen-layout.js +11 -0
- package/dist/components/patterns/screen-layout.js.map +1 -0
- package/dist/components/patterns/stale-write-banner.d.ts +26 -0
- package/dist/components/patterns/stale-write-banner.d.ts.map +1 -0
- package/dist/components/patterns/stale-write-banner.js +28 -0
- package/dist/components/patterns/stale-write-banner.js.map +1 -0
- package/dist/components/patterns/state-timeline.d.ts +58 -0
- package/dist/components/patterns/state-timeline.d.ts.map +1 -0
- package/dist/components/patterns/state-timeline.js +103 -0
- package/dist/components/patterns/state-timeline.js.map +1 -0
- package/dist/components/primitives/badge.d.ts +27 -0
- package/dist/components/primitives/badge.d.ts.map +1 -0
- package/dist/components/primitives/badge.js +33 -0
- package/dist/components/primitives/badge.js.map +1 -0
- package/dist/components/primitives/button.d.ts +12 -0
- package/dist/components/primitives/button.d.ts.map +1 -0
- package/dist/components/primitives/button.js +42 -0
- package/dist/components/primitives/button.js.map +1 -0
- package/dist/components/primitives/calendar.d.ts +39 -0
- package/dist/components/primitives/calendar.d.ts.map +1 -0
- package/dist/components/primitives/calendar.js +102 -0
- package/dist/components/primitives/calendar.js.map +1 -0
- package/dist/components/primitives/card.d.ts +24 -0
- package/dist/components/primitives/card.d.ts.map +1 -0
- package/dist/components/primitives/card.js +28 -0
- package/dist/components/primitives/card.js.map +1 -0
- package/dist/components/primitives/checkbox.d.ts +42 -0
- package/dist/components/primitives/checkbox.d.ts.map +1 -0
- package/dist/components/primitives/checkbox.js +31 -0
- package/dist/components/primitives/checkbox.js.map +1 -0
- package/dist/components/primitives/chip-select.d.ts +38 -0
- package/dist/components/primitives/chip-select.d.ts.map +1 -0
- package/dist/components/primitives/chip-select.js +25 -0
- package/dist/components/primitives/chip-select.js.map +1 -0
- package/dist/components/primitives/command-menu.d.ts +54 -0
- package/dist/components/primitives/command-menu.d.ts.map +1 -0
- package/dist/components/primitives/command-menu.js +24 -0
- package/dist/components/primitives/command-menu.js.map +1 -0
- package/dist/components/primitives/confirm-dialog.d.ts +52 -0
- package/dist/components/primitives/confirm-dialog.d.ts.map +1 -0
- package/dist/components/primitives/confirm-dialog.js +30 -0
- package/dist/components/primitives/confirm-dialog.js.map +1 -0
- package/dist/components/primitives/date-picker.d.ts +68 -0
- package/dist/components/primitives/date-picker.d.ts.map +1 -0
- package/dist/components/primitives/date-picker.js +107 -0
- package/dist/components/primitives/date-picker.js.map +1 -0
- package/dist/components/primitives/dialog.d.ts +50 -0
- package/dist/components/primitives/dialog.d.ts.map +1 -0
- package/dist/components/primitives/dialog.js +90 -0
- package/dist/components/primitives/dialog.js.map +1 -0
- package/dist/components/primitives/drawer.d.ts +71 -0
- package/dist/components/primitives/drawer.d.ts.map +1 -0
- package/dist/components/primitives/drawer.js +93 -0
- package/dist/components/primitives/drawer.js.map +1 -0
- package/dist/components/primitives/dropdown-menu.d.ts +40 -0
- package/dist/components/primitives/dropdown-menu.d.ts.map +1 -0
- package/dist/components/primitives/dropdown-menu.js +53 -0
- package/dist/components/primitives/dropdown-menu.js.map +1 -0
- package/dist/components/primitives/form-field.d.ts +94 -0
- package/dist/components/primitives/form-field.d.ts.map +1 -0
- package/dist/components/primitives/form-field.js +27 -0
- package/dist/components/primitives/form-field.js.map +1 -0
- package/dist/components/primitives/inline-confirm.d.ts +62 -0
- package/dist/components/primitives/inline-confirm.d.ts.map +1 -0
- package/dist/components/primitives/inline-confirm.js +11 -0
- package/dist/components/primitives/inline-confirm.js.map +1 -0
- package/dist/components/primitives/input.d.ts +4 -0
- package/dist/components/primitives/input.d.ts.map +1 -0
- package/dist/components/primitives/input.js +13 -0
- package/dist/components/primitives/input.js.map +1 -0
- package/dist/components/primitives/label.d.ts +26 -0
- package/dist/components/primitives/label.d.ts.map +1 -0
- package/dist/components/primitives/label.js +33 -0
- package/dist/components/primitives/label.js.map +1 -0
- package/dist/components/primitives/pagination.d.ts +54 -0
- package/dist/components/primitives/pagination.d.ts.map +1 -0
- package/dist/components/primitives/pagination.js +31 -0
- package/dist/components/primitives/pagination.js.map +1 -0
- package/dist/components/primitives/popover.d.ts +12 -0
- package/dist/components/primitives/popover.d.ts.map +1 -0
- package/dist/components/primitives/popover.js +22 -0
- package/dist/components/primitives/popover.js.map +1 -0
- package/dist/components/primitives/progress.d.ts +25 -0
- package/dist/components/primitives/progress.d.ts.map +1 -0
- package/dist/components/primitives/progress.js +25 -0
- package/dist/components/primitives/progress.js.map +1 -0
- package/dist/components/primitives/radio-group.d.ts +47 -0
- package/dist/components/primitives/radio-group.d.ts.map +1 -0
- package/dist/components/primitives/radio-group.js +11 -0
- package/dist/components/primitives/radio-group.js.map +1 -0
- package/dist/components/primitives/select.d.ts +39 -0
- package/dist/components/primitives/select.d.ts.map +1 -0
- package/dist/components/primitives/select.js +142 -0
- package/dist/components/primitives/select.js.map +1 -0
- package/dist/components/primitives/separator.d.ts +9 -0
- package/dist/components/primitives/separator.d.ts.map +1 -0
- package/dist/components/primitives/separator.js +16 -0
- package/dist/components/primitives/separator.js.map +1 -0
- package/dist/components/primitives/side-nav.d.ts +65 -0
- package/dist/components/primitives/side-nav.d.ts.map +1 -0
- package/dist/components/primitives/side-nav.js +100 -0
- package/dist/components/primitives/side-nav.js.map +1 -0
- package/dist/components/primitives/skeleton.d.ts +22 -0
- package/dist/components/primitives/skeleton.d.ts.map +1 -0
- package/dist/components/primitives/skeleton.js +25 -0
- package/dist/components/primitives/skeleton.js.map +1 -0
- package/dist/components/primitives/spinner.d.ts +20 -0
- package/dist/components/primitives/spinner.d.ts.map +1 -0
- package/dist/components/primitives/spinner.js +21 -0
- package/dist/components/primitives/spinner.js.map +1 -0
- package/dist/components/primitives/switch.d.ts +29 -0
- package/dist/components/primitives/switch.d.ts.map +1 -0
- package/dist/components/primitives/switch.js +24 -0
- package/dist/components/primitives/switch.js.map +1 -0
- package/dist/components/primitives/table.d.ts +23 -0
- package/dist/components/primitives/table.d.ts.map +1 -0
- package/dist/components/primitives/table.js +81 -0
- package/dist/components/primitives/table.js.map +1 -0
- package/dist/components/primitives/tabs.d.ts +38 -0
- package/dist/components/primitives/tabs.d.ts.map +1 -0
- package/dist/components/primitives/tabs.js +84 -0
- package/dist/components/primitives/tabs.js.map +1 -0
- package/dist/components/primitives/textarea.d.ts +4 -0
- package/dist/components/primitives/textarea.d.ts.map +1 -0
- package/dist/components/primitives/textarea.js +11 -0
- package/dist/components/primitives/textarea.js.map +1 -0
- package/dist/components/primitives/toast.d.ts +24 -0
- package/dist/components/primitives/toast.d.ts.map +1 -0
- package/dist/components/primitives/toast.js +58 -0
- package/dist/components/primitives/toast.js.map +1 -0
- package/dist/components/primitives/tooltip.d.ts +30 -0
- package/dist/components/primitives/tooltip.d.ts.map +1 -0
- package/dist/components/primitives/tooltip.js +6 -0
- package/dist/components/primitives/tooltip.js.map +1 -0
- package/dist/components/status/state-chip.d.ts +53 -0
- package/dist/components/status/state-chip.d.ts.map +1 -0
- package/dist/components/status/state-chip.js +8 -0
- package/dist/components/status/state-chip.js.map +1 -0
- package/dist/components/status/state-mark.d.ts +21 -0
- package/dist/components/status/state-mark.d.ts.map +1 -0
- package/dist/components/status/state-mark.js +90 -0
- package/dist/components/status/state-mark.js.map +1 -0
- package/dist/components/status/status-pill.d.ts +62 -0
- package/dist/components/status/status-pill.d.ts.map +1 -0
- package/dist/components/status/status-pill.js +65 -0
- package/dist/components/status/status-pill.js.map +1 -0
- package/dist/components/status/status-tokens.d.ts +110 -0
- package/dist/components/status/status-tokens.d.ts.map +1 -0
- package/dist/components/status/status-tokens.js +102 -0
- package/dist/components/status/status-tokens.js.map +1 -0
- package/dist/index.d.ts +76 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +95 -0
- package/dist/index.js.map +1 -0
- package/dist/lib/cn.d.ts +11 -0
- package/dist/lib/cn.d.ts.map +1 -0
- package/dist/lib/cn.js +78 -0
- package/dist/lib/cn.js.map +1 -0
- package/dist/lib/money.d.ts +73 -0
- package/dist/lib/money.d.ts.map +1 -0
- package/dist/lib/money.js +123 -0
- package/dist/lib/money.js.map +1 -0
- package/dist/lib/omit-undefined.d.ts +17 -0
- package/dist/lib/omit-undefined.d.ts.map +1 -0
- package/dist/lib/omit-undefined.js +24 -0
- package/dist/lib/omit-undefined.js.map +1 -0
- package/package.json +100 -0
- package/src/components/data/code.tsx +43 -0
- package/src/components/data/copy-button.tsx +97 -0
- package/src/components/data/detail-row.tsx +113 -0
- package/src/components/data/id-display.tsx +49 -0
- package/src/components/data/masked-value.tsx +96 -0
- package/src/components/data/money.tsx +46 -0
- package/src/components/data/phone-display.tsx +60 -0
- package/src/components/data/stat-tile.tsx +68 -0
- package/src/components/data/timestamp-display.tsx +106 -0
- package/src/components/patterns/inline-banner.tsx +60 -0
- package/src/components/patterns/inline-empty-state.tsx +45 -0
- package/src/components/patterns/live-row.tsx +75 -0
- package/src/components/patterns/payload-inspector.tsx +157 -0
- package/src/components/patterns/route-skeleton.tsx +77 -0
- package/src/components/patterns/screen-layout.tsx +44 -0
- package/src/components/patterns/stale-write-banner.tsx +44 -0
- package/src/components/patterns/state-timeline.tsx +229 -0
- package/src/components/primitives/badge.tsx +40 -0
- package/src/components/primitives/button.tsx +54 -0
- package/src/components/primitives/calendar.tsx +136 -0
- package/src/components/primitives/card.tsx +70 -0
- package/src/components/primitives/checkbox.tsx +101 -0
- package/src/components/primitives/chip-select.tsx +105 -0
- package/src/components/primitives/command-menu.tsx +92 -0
- package/src/components/primitives/confirm-dialog.tsx +109 -0
- package/src/components/primitives/date-picker.tsx +271 -0
- package/src/components/primitives/dialog.tsx +195 -0
- package/src/components/primitives/drawer.tsx +326 -0
- package/src/components/primitives/dropdown-menu.tsx +128 -0
- package/src/components/primitives/form-field.tsx +136 -0
- package/src/components/primitives/inline-confirm.tsx +118 -0
- package/src/components/primitives/input.tsx +21 -0
- package/src/components/primitives/label.tsx +43 -0
- package/src/components/primitives/pagination.tsx +110 -0
- package/src/components/primitives/popover.tsx +41 -0
- package/src/components/primitives/progress.tsx +66 -0
- package/src/components/primitives/radio-group.tsx +90 -0
- package/src/components/primitives/select.tsx +254 -0
- package/src/components/primitives/separator.tsx +49 -0
- package/src/components/primitives/side-nav.tsx +253 -0
- package/src/components/primitives/skeleton.tsx +25 -0
- package/src/components/primitives/spinner.tsx +39 -0
- package/src/components/primitives/switch.tsx +74 -0
- package/src/components/primitives/table.tsx +157 -0
- package/src/components/primitives/tabs.tsx +163 -0
- package/src/components/primitives/textarea.tsx +21 -0
- package/src/components/primitives/toast.tsx +117 -0
- package/src/components/primitives/tooltip.tsx +38 -0
- package/src/components/status/state-chip.tsx +70 -0
- package/src/components/status/state-mark.tsx +154 -0
- package/src/components/status/status-pill.tsx +153 -0
- package/src/components/status/status-tokens.ts +173 -0
- package/src/index.ts +96 -0
- package/src/lib/cn.ts +168 -0
- package/src/lib/money.ts +164 -0
- package/src/lib/omit-undefined.ts +25 -0
- package/src/styles/theme.css +381 -0
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import type { ReactNode } from "react";
|
|
2
|
+
/**
|
|
3
|
+
* A single-choice control over a small, fixed vocabulary.
|
|
4
|
+
*
|
|
5
|
+
* # Why this exists rather than reaching for `Select`
|
|
6
|
+
*
|
|
7
|
+
* Two reasons, and the second is a correctness one.
|
|
8
|
+
*
|
|
9
|
+
* The first is the one that prompted it: for a handful of options, a
|
|
10
|
+
* `Select` makes the reader click once to discover what the choices even
|
|
11
|
+
* are, and again to pick. A radio group shows the whole vocabulary and
|
|
12
|
+
* costs one click. `SenderIdRegistrationStatus` has four values and lives
|
|
13
|
+
* in a review drawer where seeing the other three *is* the decision.
|
|
14
|
+
*
|
|
15
|
+
* The second: this cannot hit the bug that made `Select` unusable inside a
|
|
16
|
+
* drawer for its entire existence (#315). Headless UI's `Listbox` portals
|
|
17
|
+
* its options to a top-level sibling of `<body>`, which lands outside
|
|
18
|
+
* vaul's Radix focus trap and stalls the enter transition —
|
|
19
|
+
* `opacity: 0`, `pointer-events: none`, measured live. `RadioGroup`
|
|
20
|
+
* renders inline with no portal and no transition, so there is no
|
|
21
|
+
* equivalent failure available to it. For a small vocabulary inside a
|
|
22
|
+
* drawer, that makes radio the *safer* control, not merely the friendlier
|
|
23
|
+
* one.
|
|
24
|
+
*
|
|
25
|
+
* Deliberately not built on `Select`'s CVA table: there are no visual
|
|
26
|
+
* variants to parameterise, and every option renders identically apart
|
|
27
|
+
* from its checked state.
|
|
28
|
+
*/
|
|
29
|
+
export interface RadioGroupOption<T extends string> {
|
|
30
|
+
value: T;
|
|
31
|
+
label: ReactNode;
|
|
32
|
+
/** Optional one-line explanation rendered under the label. */
|
|
33
|
+
description?: ReactNode;
|
|
34
|
+
}
|
|
35
|
+
export interface RadioGroupProps<T extends string> {
|
|
36
|
+
value: T | undefined;
|
|
37
|
+
onValueChange: (value: T) => void;
|
|
38
|
+
options: readonly RadioGroupOption<T>[];
|
|
39
|
+
/** Accessible name. Pair with `FormField`'s label via `aria-labelledby`
|
|
40
|
+
* where one exists; supplied directly when the group stands alone. */
|
|
41
|
+
"aria-label"?: string | undefined;
|
|
42
|
+
"aria-labelledby"?: string | undefined;
|
|
43
|
+
disabled?: boolean | undefined;
|
|
44
|
+
className?: string | undefined;
|
|
45
|
+
}
|
|
46
|
+
export declare function RadioGroup<T extends string>({ value, onValueChange, options, disabled, className, ...aria }: RadioGroupProps<T>): import("react").JSX.Element;
|
|
47
|
+
//# sourceMappingURL=radio-group.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"radio-group.d.ts","sourceRoot":"","sources":["../../../src/components/primitives/radio-group.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAGvC;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,MAAM,WAAW,gBAAgB,CAAC,CAAC,SAAS,MAAM;IAChD,KAAK,EAAE,CAAC,CAAC;IACT,KAAK,EAAE,SAAS,CAAC;IACjB,8DAA8D;IAC9D,WAAW,CAAC,EAAE,SAAS,CAAC;CACzB;AAED,MAAM,WAAW,eAAe,CAAC,CAAC,SAAS,MAAM;IAC/C,KAAK,EAAE,CAAC,GAAG,SAAS,CAAC;IACrB,aAAa,EAAE,CAAC,KAAK,EAAE,CAAC,KAAK,IAAI,CAAC;IAClC,OAAO,EAAE,SAAS,gBAAgB,CAAC,CAAC,CAAC,EAAE,CAAC;IACxC;0EACsE;IACtE,YAAY,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAClC,iBAAiB,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACvC,QAAQ,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IAC/B,SAAS,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CAChC;AAED,wBAAgB,UAAU,CAAC,CAAC,SAAS,MAAM,EAAE,EAC3C,KAAK,EACL,aAAa,EACb,OAAO,EACP,QAAQ,EACR,SAAS,EACT,GAAG,IAAI,EACR,EAAE,eAAe,CAAC,CAAC,CAAC,+BA8BpB"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { RadioGroup as HeadlessRadioGroup, Radio } from "@headlessui/react";
|
|
4
|
+
import { cn } from "../../lib/cn.js";
|
|
5
|
+
export function RadioGroup({ value, onValueChange, options, disabled, className, ...aria }) {
|
|
6
|
+
return (_jsx(HeadlessRadioGroup, { value: value ?? null, onChange: (next) => {
|
|
7
|
+
if (next !== null)
|
|
8
|
+
onValueChange(next);
|
|
9
|
+
}, disabled: disabled ?? false, className: cn("flex flex-wrap gap-2", className), ...aria, children: options.map((option) => (_jsxs(Radio, { value: option.value, className: cn("flex cursor-pointer flex-col gap-0.5 rounded-sm border border-edge bg-surface-2 px-3 py-2 text-body text-muted-foreground", "data-checked:border-state-success-border data-checked:bg-state-success-bg data-checked:text-state-success-fg", "data-focus:outline-none data-focus:ring-1 data-focus:ring-state-success-border", "data-disabled:cursor-not-allowed data-disabled:opacity-50"), children: [_jsx("span", { className: "font-medium", children: option.label }), option.description !== undefined && (_jsx("span", { className: "text-caption text-subtle-foreground", children: option.description }))] }, option.value))) }));
|
|
10
|
+
}
|
|
11
|
+
//# sourceMappingURL=radio-group.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"radio-group.js","sourceRoot":"","sources":["../../../src/components/primitives/radio-group.tsx"],"names":[],"mappings":"AAAA,YAAY,CAAC;;AAEb,OAAO,EAAE,UAAU,IAAI,kBAAkB,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAC;AAE5E,OAAO,EAAE,EAAE,EAAE,MAAM,cAAc,CAAC;AAgDlC,MAAM,UAAU,UAAU,CAAmB,EAC3C,KAAK,EACL,aAAa,EACb,OAAO,EACP,QAAQ,EACR,SAAS,EACT,GAAG,IAAI,EACY;IACnB,OAAO,CACL,KAAC,kBAAkB,IACjB,KAAK,EAAE,KAAK,IAAI,IAAI,EACpB,QAAQ,EAAE,CAAC,IAAc,EAAE,EAAE;YAC3B,IAAI,IAAI,KAAK,IAAI;gBAAE,aAAa,CAAC,IAAI,CAAC,CAAC;QACzC,CAAC,EACD,QAAQ,EAAE,QAAQ,IAAI,KAAK,EAC3B,SAAS,EAAE,EAAE,CAAC,sBAAsB,EAAE,SAAS,CAAC,KAC5C,IAAI,YAEP,OAAO,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,CACvB,MAAC,KAAK,IAEJ,KAAK,EAAE,MAAM,CAAC,KAAK,EACnB,SAAS,EAAE,EAAE,CACX,2HAA2H,EAC3H,8GAA8G,EAC9G,gFAAgF,EAChF,2DAA2D,CAC5D,aAED,eAAM,SAAS,EAAC,aAAa,YAAE,MAAM,CAAC,KAAK,GAAQ,EAClD,MAAM,CAAC,WAAW,KAAK,SAAS,IAAI,CACnC,eAAM,SAAS,EAAC,qCAAqC,YAAE,MAAM,CAAC,WAAW,GAAQ,CAClF,KAZI,MAAM,CAAC,KAAK,CAaX,CACT,CAAC,GACiB,CACtB,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { type ReactNode } from "react";
|
|
2
|
+
/**
|
|
3
|
+
* Note the `| undefined` on the optional props below. This package
|
|
4
|
+
* compiles under `exactOptionalPropertyTypes`, where a bare `value?:
|
|
5
|
+
* string` means "you may omit this key" and NOT "you may pass
|
|
6
|
+
* `undefined`" — so the ordinary controlled pattern,
|
|
7
|
+
* `const [v, setV] = useState<string>()` followed by `value={v}`, is a
|
|
8
|
+
* type error. Found writing this component's own story, which is the
|
|
9
|
+
* first code outside the original application to use it.
|
|
10
|
+
*/
|
|
11
|
+
export interface SelectProps {
|
|
12
|
+
value?: string | undefined;
|
|
13
|
+
defaultValue?: string | undefined;
|
|
14
|
+
onValueChange?: ((value: string) => void) | undefined;
|
|
15
|
+
disabled?: boolean | undefined;
|
|
16
|
+
children: ReactNode;
|
|
17
|
+
}
|
|
18
|
+
export declare function Select({ value, defaultValue, onValueChange, disabled, children }: SelectProps): import("react").JSX.Element;
|
|
19
|
+
export declare function SelectGroup({ children }: {
|
|
20
|
+
children: ReactNode;
|
|
21
|
+
}): import("react").JSX.Element;
|
|
22
|
+
export declare function SelectTrigger({ id, className, children, }: {
|
|
23
|
+
id?: string;
|
|
24
|
+
className?: string;
|
|
25
|
+
children: ReactNode;
|
|
26
|
+
}): import("react").JSX.Element;
|
|
27
|
+
export declare function SelectValue({ placeholder }: {
|
|
28
|
+
placeholder?: string;
|
|
29
|
+
}): import("react").JSX.Element;
|
|
30
|
+
export declare function SelectContent({ className, children, }: {
|
|
31
|
+
className?: string;
|
|
32
|
+
children: ReactNode;
|
|
33
|
+
}): import("react").JSX.Element;
|
|
34
|
+
export declare function SelectItem({ value, className, children, }: {
|
|
35
|
+
value: string;
|
|
36
|
+
className?: string;
|
|
37
|
+
children: ReactNode;
|
|
38
|
+
}): import("react").JSX.Element;
|
|
39
|
+
//# sourceMappingURL=select.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"select.d.ts","sourceRoot":"","sources":["../../../src/components/primitives/select.tsx"],"names":[],"mappings":"AAIA,OAAO,EAKL,KAAK,SAAS,EAIf,MAAM,OAAO,CAAC;AAuDf;;;;;;;;GAQG;AACH,MAAM,WAAW,WAAW;IAC1B,KAAK,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC3B,YAAY,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAClC,aAAa,CAAC,EAAE,CAAC,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC,GAAG,SAAS,CAAC;IACtD,QAAQ,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IAC/B,QAAQ,EAAE,SAAS,CAAC;CACrB;AAED,wBAAgB,MAAM,CAAC,EAAE,KAAK,EAAE,YAAY,EAAE,aAAa,EAAE,QAAQ,EAAE,QAAQ,EAAE,EAAE,WAAW,+BA+B7F;AAOD,wBAAgB,WAAW,CAAC,EAAE,QAAQ,EAAE,EAAE;IAAE,QAAQ,EAAE,SAAS,CAAA;CAAE,+BAEhE;AAED,wBAAgB,aAAa,CAAC,EAC5B,EAAE,EACF,SAAS,EACT,QAAQ,GACT,EAAE;IACD,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,SAAS,CAAC;CACrB,+BAmBA;AAED,wBAAgB,WAAW,CAAC,EAAE,WAAW,EAAE,EAAE;IAAE,WAAW,CAAC,EAAE,MAAM,CAAA;CAAE,+BAMpE;AAED,wBAAgB,aAAa,CAAC,EAC5B,SAAS,EACT,QAAQ,GACT,EAAE;IACD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,SAAS,CAAC;CACrB,+BAqDA;AAED,wBAAgB,UAAU,CAAC,EACzB,KAAK,EACL,SAAS,EACT,QAAQ,GACT,EAAE;IACD,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,SAAS,CAAC;CACrB,+BAoBA"}
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { Listbox, ListboxButton, ListboxOption, ListboxOptions } from "@headlessui/react";
|
|
4
|
+
import { Check, ChevronDown } from "lucide-react";
|
|
5
|
+
import { Children, createContext, isValidElement, useContext, useMemo, useState, } from "react";
|
|
6
|
+
import { cn } from "../../lib/cn.js";
|
|
7
|
+
import { omitUndefined } from "../../lib/omit-undefined.js";
|
|
8
|
+
const SelectContext = createContext(null);
|
|
9
|
+
function useSelectContext(component) {
|
|
10
|
+
const ctx = useContext(SelectContext);
|
|
11
|
+
if (ctx === null) {
|
|
12
|
+
throw new Error(`<${component} /> must be rendered inside <Select>.`);
|
|
13
|
+
}
|
|
14
|
+
return ctx;
|
|
15
|
+
}
|
|
16
|
+
function findItemLabel(node, value) {
|
|
17
|
+
let found;
|
|
18
|
+
Children.forEach(node, (child) => {
|
|
19
|
+
if (found !== undefined || !isValidElement(child))
|
|
20
|
+
return;
|
|
21
|
+
const el = child;
|
|
22
|
+
if (el.type === SelectItem) {
|
|
23
|
+
if (el.props.value === value)
|
|
24
|
+
found = el.props.children;
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
if (el.props?.children != null) {
|
|
28
|
+
found = findItemLabel(el.props.children, value);
|
|
29
|
+
}
|
|
30
|
+
});
|
|
31
|
+
return found;
|
|
32
|
+
}
|
|
33
|
+
export function Select({ value, defaultValue, onValueChange, disabled, children }) {
|
|
34
|
+
const [internalValue, setInternalValue] = useState(defaultValue);
|
|
35
|
+
const isControlled = value !== undefined;
|
|
36
|
+
const currentValue = isControlled ? value : internalValue;
|
|
37
|
+
function handleChange(next) {
|
|
38
|
+
if (!isControlled)
|
|
39
|
+
setInternalValue(next);
|
|
40
|
+
onValueChange?.(next);
|
|
41
|
+
}
|
|
42
|
+
const itemLabel = useMemo(() => (v) => findItemLabel(children, v), [children]);
|
|
43
|
+
return (_jsx(Listbox, { as: "div", className: "relative", value: currentValue ?? "", onChange: handleChange, ...omitUndefined({ disabled }), children: _jsx(SelectContext.Provider, { value: { value: currentValue, itemLabel }, children: children }) }));
|
|
44
|
+
}
|
|
45
|
+
// Unconsumed today (grepped across `admin/`) — kept for API parity. Radix's
|
|
46
|
+
// `SelectGroup` had no visual treatment of its own beyond semantic
|
|
47
|
+
// grouping; Headless UI's `Listbox` has no equivalent, so this stays a
|
|
48
|
+
// plain wrapper rather than reaching for `Menu`'s `MenuSection` (a
|
|
49
|
+
// different component family).
|
|
50
|
+
export function SelectGroup({ children }) {
|
|
51
|
+
return _jsx("fieldset", { className: "contents border-0 p-0 m-0 min-w-0", children: children });
|
|
52
|
+
}
|
|
53
|
+
export function SelectTrigger({ id, className, children, }) {
|
|
54
|
+
useSelectContext("SelectTrigger");
|
|
55
|
+
return (_jsxs(ListboxButton, { id: id, className: cn("select select-bordered flex w-full items-center justify-between font-sans text-prose", className), children: [children, _jsx(ChevronDown, { size: 14, strokeWidth: 1.5, className: "text-muted-foreground", "aria-hidden": "true" })] }));
|
|
56
|
+
}
|
|
57
|
+
export function SelectValue({ placeholder }) {
|
|
58
|
+
const { value, itemLabel } = useSelectContext("SelectValue");
|
|
59
|
+
if (value === undefined || value === "") {
|
|
60
|
+
return _jsx("span", { className: "text-subtle-foreground", children: placeholder });
|
|
61
|
+
}
|
|
62
|
+
return _jsx(_Fragment, { children: itemLabel(value) ?? value });
|
|
63
|
+
}
|
|
64
|
+
export function SelectContent({ className, children, }) {
|
|
65
|
+
useSelectContext("SelectContent");
|
|
66
|
+
return (_jsx(ListboxOptions
|
|
67
|
+
// `portal={false}` is a correctness fix, not a preference.
|
|
68
|
+
//
|
|
69
|
+
// Headless UI's `anchor` prop portals the options into
|
|
70
|
+
// `#headlessui-portal-root`, a top-level sibling of `<body>`. Inside a
|
|
71
|
+
// `vaul` drawer that is fatal: vaul's `Content` mounts a Radix
|
|
72
|
+
// `FocusScope` with `trapped: true`, a document-level `focusin`
|
|
73
|
+
// listener that force-refocuses back into the drawer the instant
|
|
74
|
+
// focus lands outside it. The portaled listbox is outside, so its
|
|
75
|
+
// enter transition stalls mid-flight and it never becomes usable.
|
|
76
|
+
//
|
|
77
|
+
// Measured on the live console rather than inferred — opening the
|
|
78
|
+
// registration status select inside its stacked drawer gave:
|
|
79
|
+
//
|
|
80
|
+
// parentChain [..., DIV#headlessui-portal-root, BODY]
|
|
81
|
+
// insideAnyDrawer false
|
|
82
|
+
// opacity "0"
|
|
83
|
+
// pointerEvents "none"
|
|
84
|
+
// rect [122, 10] (collapsed, not four options tall)
|
|
85
|
+
//
|
|
86
|
+
// — byte-for-byte the signature #274 recorded for a nested Dialog.
|
|
87
|
+
// #282 fixed that class for `Dialog` and never covered `Select`, so
|
|
88
|
+
// every select inside a drawer has been silently unusable since.
|
|
89
|
+
//
|
|
90
|
+
// Rendering inline keeps the options inside the drawer's own subtree,
|
|
91
|
+
// so the focus trap contains them instead of fighting them. The cost
|
|
92
|
+
// is losing `anchor`'s collision detection; `top-full` + `w-full`
|
|
93
|
+
// below reproduces the same "directly under the trigger, matching its
|
|
94
|
+
// width" placement, which is what every call site here wants anyway.
|
|
95
|
+
, {
|
|
96
|
+
// `portal={false}` is a correctness fix, not a preference.
|
|
97
|
+
//
|
|
98
|
+
// Headless UI's `anchor` prop portals the options into
|
|
99
|
+
// `#headlessui-portal-root`, a top-level sibling of `<body>`. Inside a
|
|
100
|
+
// `vaul` drawer that is fatal: vaul's `Content` mounts a Radix
|
|
101
|
+
// `FocusScope` with `trapped: true`, a document-level `focusin`
|
|
102
|
+
// listener that force-refocuses back into the drawer the instant
|
|
103
|
+
// focus lands outside it. The portaled listbox is outside, so its
|
|
104
|
+
// enter transition stalls mid-flight and it never becomes usable.
|
|
105
|
+
//
|
|
106
|
+
// Measured on the live console rather than inferred — opening the
|
|
107
|
+
// registration status select inside its stacked drawer gave:
|
|
108
|
+
//
|
|
109
|
+
// parentChain [..., DIV#headlessui-portal-root, BODY]
|
|
110
|
+
// insideAnyDrawer false
|
|
111
|
+
// opacity "0"
|
|
112
|
+
// pointerEvents "none"
|
|
113
|
+
// rect [122, 10] (collapsed, not four options tall)
|
|
114
|
+
//
|
|
115
|
+
// — byte-for-byte the signature #274 recorded for a nested Dialog.
|
|
116
|
+
// #282 fixed that class for `Dialog` and never covered `Select`, so
|
|
117
|
+
// every select inside a drawer has been silently unusable since.
|
|
118
|
+
//
|
|
119
|
+
// Rendering inline keeps the options inside the drawer's own subtree,
|
|
120
|
+
// so the focus trap contains them instead of fighting them. The cost
|
|
121
|
+
// is losing `anchor`'s collision detection; `top-full` + `w-full`
|
|
122
|
+
// below reproduces the same "directly under the trigger, matching its
|
|
123
|
+
// width" placement, which is what every call site here wants anyway.
|
|
124
|
+
portal: false,
|
|
125
|
+
// No `transition`, and no `data-closed:*` classes. Headless UI's
|
|
126
|
+
// transition machinery holds `data-closed` until it observes the
|
|
127
|
+
// enter transition finish; inside a drawer it never does. Measured
|
|
128
|
+
// after the portal fix, 1.4s after opening: `data-closed` and
|
|
129
|
+
// `data-enter` both still present, `opacity: 0`, on an element that
|
|
130
|
+
// was otherwise correct (inside the drawer, `pointer-events: auto`,
|
|
131
|
+
// full 146px height, all four options present).
|
|
132
|
+
//
|
|
133
|
+
// That is the same failure mode twice now — #274's nested Dialog was
|
|
134
|
+
// also a stalled enter transition, not a mispositioned element. A
|
|
135
|
+
// 100ms fade on a select dropdown is not worth a second component
|
|
136
|
+
// that silently does not open, so it is gone rather than debugged.
|
|
137
|
+
className: cn("absolute top-full left-0 z-50 mt-1 max-h-80 w-full min-w-[8rem] overflow-y-auto rounded-md border border-edge bg-surface-2 p-1 shadow-[var(--shadow-popover)] focus:outline-none", className), children: children }));
|
|
138
|
+
}
|
|
139
|
+
export function SelectItem({ value, className, children, }) {
|
|
140
|
+
return (_jsx(ListboxOption, { value: value, className: cn("relative flex cursor-pointer items-center rounded-sm py-1.5 pr-2 pl-7 text-body text-foreground outline-none", "data-focus:bg-surface-3", className), children: ({ selected }) => (_jsxs(_Fragment, { children: [_jsx("span", { className: "absolute left-2 flex h-3.5 w-3.5 items-center justify-center", children: selected && _jsx(Check, { size: 14, strokeWidth: 1.5, "aria-hidden": "true" }) }), children] })) }));
|
|
141
|
+
}
|
|
142
|
+
//# sourceMappingURL=select.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"select.js","sourceRoot":"","sources":["../../../src/components/primitives/select.tsx"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export interface SeparatorProps extends React.HTMLAttributes<HTMLDivElement> {
|
|
2
|
+
orientation?: "horizontal" | "vertical";
|
|
3
|
+
/** Matches Radix's own default: `true` renders a purely visual rule with
|
|
4
|
+
* no `separator` semantics exposed to assistive tech (`role="none"` on a
|
|
5
|
+
* `<div>`); `false` renders a native `<hr>` with `aria-orientation`. */
|
|
6
|
+
decorative?: boolean;
|
|
7
|
+
}
|
|
8
|
+
export declare const Separator: import("react").ForwardRefExoticComponent<SeparatorProps & import("react").RefAttributes<HTMLDivElement>>;
|
|
9
|
+
//# sourceMappingURL=separator.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"separator.d.ts","sourceRoot":"","sources":["../../../src/components/primitives/separator.tsx"],"names":[],"mappings":"AAgBA,MAAM,WAAW,cAAe,SAAQ,KAAK,CAAC,cAAc,CAAC,cAAc,CAAC;IAC1E,WAAW,CAAC,EAAE,YAAY,GAAG,UAAU,CAAC;IACxC;;4EAEwE;IACxE,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB;AAED,eAAO,MAAM,SAAS,2GAuBrB,CAAC"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { forwardRef } from "react";
|
|
3
|
+
import { cn } from "../../lib/cn.js";
|
|
4
|
+
export const Separator = forwardRef(({ className, orientation = "horizontal", decorative = true, ...props }, ref) => {
|
|
5
|
+
const sharedClassName = cn("shrink-0 border-0 bg-edge", orientation === "horizontal" ? "h-px w-full" : "h-full w-px", className);
|
|
6
|
+
if (decorative) {
|
|
7
|
+
return _jsx("div", { ref: ref, role: "none", className: sharedClassName, ...props });
|
|
8
|
+
}
|
|
9
|
+
// No consumer forwards a ref through the non-decorative branch today
|
|
10
|
+
// (grepped across `admin/`) — the cast is a documented, zero-risk
|
|
11
|
+
// approximation rather than widening `Separator`'s public ref type to
|
|
12
|
+
// `HTMLDivElement | HTMLHRElement` for a case nothing exercises.
|
|
13
|
+
return (_jsx("hr", { ref: ref, "aria-orientation": orientation, className: sharedClassName, ...props }));
|
|
14
|
+
});
|
|
15
|
+
Separator.displayName = "Separator";
|
|
16
|
+
//# sourceMappingURL=separator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"separator.js","sourceRoot":"","sources":["../../../src/components/primitives/separator.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,OAAO,CAAC;AACnC,OAAO,EAAE,EAAE,EAAE,MAAM,cAAc,CAAC;AAuBlC,MAAM,CAAC,MAAM,SAAS,GAAG,UAAU,CACjC,CAAC,EAAE,SAAS,EAAE,WAAW,GAAG,YAAY,EAAE,UAAU,GAAG,IAAI,EAAE,GAAG,KAAK,EAAE,EAAE,GAAG,EAAE,EAAE;IAC9E,MAAM,eAAe,GAAG,EAAE,CACxB,2BAA2B,EAC3B,WAAW,KAAK,YAAY,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,aAAa,EAC5D,SAAS,CACV,CAAC;IACF,IAAI,UAAU,EAAE,CAAC;QACf,OAAO,cAAK,GAAG,EAAE,GAAG,EAAE,IAAI,EAAC,MAAM,EAAC,SAAS,EAAE,eAAe,KAAM,KAAK,GAAI,CAAC;IAC9E,CAAC;IACD,qEAAqE;IACrE,kEAAkE;IAClE,sEAAsE;IACtE,iEAAiE;IACjE,OAAO,CACL,aACE,GAAG,EAAE,GAA0C,sBAC7B,WAAW,EAC7B,SAAS,EAAE,eAAe,KACtB,KAAK,GACT,CACH,CAAC;AACJ,CAAC,CACF,CAAC;AACF,SAAS,CAAC,WAAW,GAAG,WAAW,CAAC"}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import type { ComponentType, ReactNode } from "react";
|
|
2
|
+
/**
|
|
3
|
+
* The console's information architecture (console-redesign.md §4), as data.
|
|
4
|
+
* `@vaam-apps/ui` owns the shape; `frontends/apps/admin/app/nav-groups.ts` owns the actual
|
|
5
|
+
* content (routes, groupings, icons) — this file never hardcodes a route.
|
|
6
|
+
*/
|
|
7
|
+
export interface NavItem {
|
|
8
|
+
label: string;
|
|
9
|
+
href: string;
|
|
10
|
+
/** Any lucide-react icon component. Typed structurally so this file
|
|
11
|
+
* doesn't need to depend on `lucide-react`'s own exported icon type name. */
|
|
12
|
+
icon: ComponentType<{
|
|
13
|
+
size?: number;
|
|
14
|
+
className?: string;
|
|
15
|
+
"aria-hidden"?: boolean | "true";
|
|
16
|
+
}>;
|
|
17
|
+
}
|
|
18
|
+
export interface NavGroup {
|
|
19
|
+
/** Small-caps section header, e.g. "Messaging" (console-redesign.md §4). */
|
|
20
|
+
label: string;
|
|
21
|
+
items: NavItem[];
|
|
22
|
+
}
|
|
23
|
+
export interface SideNavProps {
|
|
24
|
+
/** Flat, ungrouped, always first — §4 ("Dashboard"). */
|
|
25
|
+
topItem: NavItem;
|
|
26
|
+
groups: NavGroup[];
|
|
27
|
+
/** De-emphasized footer utility rows (§1.1: "administrivia, not content"). */
|
|
28
|
+
footerItems: NavItem[];
|
|
29
|
+
/** Current pathname, for active-row highlighting. Plain string, not a
|
|
30
|
+
* `next/navigation` call — this package has no dependency on Next.js, so
|
|
31
|
+
* the caller (`frontends/apps/admin/app/console-shell.tsx`) resolves it via
|
|
32
|
+
* `usePathname()` and passes it down. */
|
|
33
|
+
currentPath: string;
|
|
34
|
+
/** App-specific account/sign-out markup (§4's footer "Signed in as
|
|
35
|
+
* <email> · Sign out" row) — rendered as-is, never built here, so this
|
|
36
|
+
* component stays free of any auth-specific knowledge. */
|
|
37
|
+
accountSlot?: ReactNode;
|
|
38
|
+
className?: string;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* The console's side navigation (console-redesign.md §4, §6.2). A pure
|
|
42
|
+
* structural/layout component — routing, session data, and the drawer's
|
|
43
|
+
* own off-canvas/persistent CSS split all live at the call site
|
|
44
|
+
* (`frontends/apps/admin/app/console-shell.tsx`, D7): this component only ever decides
|
|
45
|
+
* "flat top item → grouped middle → de-emphasized footer" composition and
|
|
46
|
+
* the label/icon-only/accordion treatment per breakpoint.
|
|
47
|
+
*
|
|
48
|
+
* Breakpoint behaviour (§6.1 is the authoritative table here — see that
|
|
49
|
+
* section's own reasoning for why it supersedes §4's looser "Tablet
|
|
50
|
+
* (768–1024px)" prose, which pre-dates that table and was never updated to
|
|
51
|
+
* match it) — entirely CSS-driven (`lg:`/`xl:` Tailwind variants), never a
|
|
52
|
+
* JS breakpoint read:
|
|
53
|
+
* - `<1024px` (phone and tablet alike): off-canvas, full labels,
|
|
54
|
+
* collapsible accordion groups.
|
|
55
|
+
* - `1024–1279px`: persistent icon-only rail, tooltip on hover/focus.
|
|
56
|
+
* - `≥1280px`: persistent full sidebar with labels.
|
|
57
|
+
*
|
|
58
|
+
* This means the whole nav — every row, every group, every breakpoint's
|
|
59
|
+
* shape — is present in the server-rendered HTML on first paint. No
|
|
60
|
+
* `next/dynamic({ ssr: false })`, no client-only mount flash. Verify that
|
|
61
|
+
* claim directly, not by trusting this comment: `curl` a page and grep the
|
|
62
|
+
* raw HTML for a nav item's label.
|
|
63
|
+
*/
|
|
64
|
+
export declare function SideNav({ topItem, groups, footerItems, currentPath, accountSlot, className, }: SideNavProps): import("react").JSX.Element;
|
|
65
|
+
//# sourceMappingURL=side-nav.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"side-nav.d.ts","sourceRoot":"","sources":["../../../src/components/primitives/side-nav.tsx"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAGtD;;;;GAIG;AACH,MAAM,WAAW,OAAO;IACtB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb;iFAC6E;IAC7E,IAAI,EAAE,aAAa,CAAC;QAAE,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,SAAS,CAAC,EAAE,MAAM,CAAC;QAAC,aAAa,CAAC,EAAE,OAAO,GAAG,MAAM,CAAA;KAAE,CAAC,CAAC;CAC9F;AAED,MAAM,WAAW,QAAQ;IACvB,4EAA4E;IAC5E,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,OAAO,EAAE,CAAC;CAClB;AAED,MAAM,WAAW,YAAY;IAC3B,wDAAwD;IACxD,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,EAAE,QAAQ,EAAE,CAAC;IACnB,8EAA8E;IAC9E,WAAW,EAAE,OAAO,EAAE,CAAC;IACvB;;;6CAGyC;IACzC,WAAW,EAAE,MAAM,CAAC;IACpB;;8DAE0D;IAC1D,WAAW,CAAC,EAAE,SAAS,CAAC;IACxB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AA+ID;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAgB,OAAO,CAAC,EACtB,OAAO,EACP,MAAM,EACN,WAAW,EACX,WAAW,EACX,WAAW,EACX,SAAS,GACV,EAAE,YAAY,+BAoCd"}
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { Disclosure, DisclosureButton, DisclosurePanel } from "@headlessui/react";
|
|
4
|
+
import { ChevronDown } from "lucide-react";
|
|
5
|
+
import { cn } from "../../lib/cn.js";
|
|
6
|
+
function isActive(href, currentPath) {
|
|
7
|
+
if (href === "/")
|
|
8
|
+
return currentPath === "/";
|
|
9
|
+
return currentPath === href || currentPath.startsWith(`${href}/`);
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* One nav row.
|
|
13
|
+
*
|
|
14
|
+
* **CSS-driven, not `useMediaQuery`-driven — found live, corrected after
|
|
15
|
+
* an earlier revision of this file used `@uidotdev/usehooks`' hook here
|
|
16
|
+
* and wrapped `SideNav` in `next/dynamic({ ssr: false })` to work around
|
|
17
|
+
* its SSR crash (see `console-shell.tsx`'s own history / this file's own
|
|
18
|
+
* git log for the full finding).** That fix traded a real cost — the
|
|
19
|
+
* sidebar never appeared in the server-rendered HTML, so every full page
|
|
20
|
+
* load painted an empty slab and popped the real nav in after hydration —
|
|
21
|
+
* for a problem the breakpoint switch itself never needed JS to solve:
|
|
22
|
+
* `variant="responsive"` below expresses "full label off-canvas and at
|
|
23
|
+
* `xl`, `sr-only` at the `lg` icon-rail band" purely with `lg:sr-only
|
|
24
|
+
* xl:not-sr-only`, no hook, no client-only state, no hydration boundary.
|
|
25
|
+
*
|
|
26
|
+
* - **`"responsive"`**: the label is visible off-canvas (`<1024px`, where
|
|
27
|
+
* this row is never reached without the group around it already being
|
|
28
|
+
* fully expanded) and at `≥1280px`, `sr-only` in the `1024–1279px` icon
|
|
29
|
+
* rail band — a daisyUI `.tooltip`/`data-tip` (D5) carries the label
|
|
30
|
+
* back on hover/focus there. Used for every row that can appear in the
|
|
31
|
+
* *persistent* sidebar: `topItem`, `footerItems`, and each group's own
|
|
32
|
+
* "always expanded" desktop rows (`GroupSection` below).
|
|
33
|
+
* - **`"always"`**: the label is always visible, no responsive classes at
|
|
34
|
+
* all. Used only inside the off-canvas accordion tree, which is itself
|
|
35
|
+
* gated to `<1024px` by its own `lg:hidden` wrapper — a per-row
|
|
36
|
+
* breakpoint switch would be redundant there, since that whole tree
|
|
37
|
+
* never renders at any width where a switch could matter.
|
|
38
|
+
*/
|
|
39
|
+
function NavLink({ item, active, variant, dim = false, }) {
|
|
40
|
+
const Icon = item.icon;
|
|
41
|
+
const responsive = variant === "responsive";
|
|
42
|
+
return (_jsxs("a", { href: item.href, "aria-current": active ? "page" : undefined, "data-tip": item.label, className: cn("flex items-center gap-3 rounded-field px-3 py-2 transition-colors", dim ? "text-caption" : "text-body", responsive && "tooltip tooltip-right lg:justify-center lg:px-0 xl:justify-start xl:px-3", active && !dim && "bg-base-300 font-medium text-foreground", active && dim && "text-foreground", !active && "text-muted-foreground hover:bg-base-300/60 hover:text-foreground"), children: [_jsx(Icon, { size: 16, className: "shrink-0", "aria-hidden": "true" }), _jsx("span", { className: cn(responsive && "lg:sr-only xl:not-sr-only"), children: item.label })] }));
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* One group's worth of rows, rendered as **two parallel trees**, one per
|
|
46
|
+
* §6.1 regime, each visible only at its own breakpoint via a plain
|
|
47
|
+
* `hidden`/`lg:hidden` toggle — not one tree whose *content* changes based
|
|
48
|
+
* on a JS-read viewport width. The two regimes genuinely need different
|
|
49
|
+
* DOM, not just different visibility, because the off-canvas tree is
|
|
50
|
+
* interactive (a collapsible `Disclosure`) and the persistent tree is not
|
|
51
|
+
* (every group is always fully expanded there, matching §1.1's LottieFiles
|
|
52
|
+
* reference, which shows no user-collapsible groups on desktop at all) —
|
|
53
|
+
* duplicating ~4 rows per group across two trees is a irrelevant DOM cost
|
|
54
|
+
* next to the alternative (a client-only nav that never appears in the
|
|
55
|
+
* first paint).
|
|
56
|
+
*
|
|
57
|
+
* - **Off-canvas** (`lg:hidden`, so effectively `<1024px` — both the phone
|
|
58
|
+
* band and the tablet band §6.1 explicitly keeps behind the hamburger):
|
|
59
|
+
* a Headless UI `Disclosure`, collapsed by default, expanded only if it
|
|
60
|
+
* contains the current route — "roughly 6–8 tappable rows on open, not
|
|
61
|
+
* 18" (§4). `defaultOpen` is computed from `currentPath`, which is
|
|
62
|
+
* available identically on the server and the client, so this renders
|
|
63
|
+
* correctly on first paint with no hydration mismatch.
|
|
64
|
+
* - **Persistent** (`hidden lg:flex`, so `≥1024px`): always fully
|
|
65
|
+
* expanded. The header/rail-divider split (small-caps text at `≥1280px`,
|
|
66
|
+
* a hairline divider instead in the `1024–1279px` icon rail band) is the
|
|
67
|
+
* same CSS-toggle technique `NavLink`'s own `"responsive"` variant uses.
|
|
68
|
+
*/
|
|
69
|
+
function GroupSection({ group, currentPath }) {
|
|
70
|
+
const hasActiveItem = group.items.some((item) => isActive(item.href, currentPath));
|
|
71
|
+
return (_jsxs(_Fragment, { children: [_jsx("div", { className: "lg:hidden", children: _jsx(Disclosure, { defaultOpen: hasActiveItem, children: ({ open }) => (_jsxs("div", { className: "flex flex-col gap-0.5", children: [_jsxs(DisclosureButton, { className: "flex items-center justify-between rounded-field px-3 py-1.5 text-left text-caption text-subtle-foreground uppercase tracking-wide hover:text-foreground", children: [group.label, _jsx(ChevronDown, { size: 14, "aria-hidden": "true", className: cn("transition-transform", open && "rotate-180") })] }), _jsx(DisclosurePanel, { className: "flex flex-col gap-0.5", children: group.items.map((item) => (_jsx(NavLink, { item: item, active: isActive(item.href, currentPath), variant: "always" }, item.href))) })] })) }) }), _jsxs("div", { className: "hidden lg:flex lg:flex-col lg:gap-0.5", children: [_jsx("p", { className: "hidden px-3 py-1.5 text-caption text-subtle-foreground uppercase tracking-wide xl:block", children: group.label }), _jsx("div", { className: "mx-3 my-1 border-edge-subtle border-t xl:hidden", "aria-hidden": "true" }), group.items.map((item) => (_jsx(NavLink, { item: item, active: isActive(item.href, currentPath), variant: "responsive" }, item.href)))] })] }));
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* The console's side navigation (console-redesign.md §4, §6.2). A pure
|
|
75
|
+
* structural/layout component — routing, session data, and the drawer's
|
|
76
|
+
* own off-canvas/persistent CSS split all live at the call site
|
|
77
|
+
* (`frontends/apps/admin/app/console-shell.tsx`, D7): this component only ever decides
|
|
78
|
+
* "flat top item → grouped middle → de-emphasized footer" composition and
|
|
79
|
+
* the label/icon-only/accordion treatment per breakpoint.
|
|
80
|
+
*
|
|
81
|
+
* Breakpoint behaviour (§6.1 is the authoritative table here — see that
|
|
82
|
+
* section's own reasoning for why it supersedes §4's looser "Tablet
|
|
83
|
+
* (768–1024px)" prose, which pre-dates that table and was never updated to
|
|
84
|
+
* match it) — entirely CSS-driven (`lg:`/`xl:` Tailwind variants), never a
|
|
85
|
+
* JS breakpoint read:
|
|
86
|
+
* - `<1024px` (phone and tablet alike): off-canvas, full labels,
|
|
87
|
+
* collapsible accordion groups.
|
|
88
|
+
* - `1024–1279px`: persistent icon-only rail, tooltip on hover/focus.
|
|
89
|
+
* - `≥1280px`: persistent full sidebar with labels.
|
|
90
|
+
*
|
|
91
|
+
* This means the whole nav — every row, every group, every breakpoint's
|
|
92
|
+
* shape — is present in the server-rendered HTML on first paint. No
|
|
93
|
+
* `next/dynamic({ ssr: false })`, no client-only mount flash. Verify that
|
|
94
|
+
* claim directly, not by trusting this comment: `curl` a page and grep the
|
|
95
|
+
* raw HTML for a nav item's label.
|
|
96
|
+
*/
|
|
97
|
+
export function SideNav({ topItem, groups, footerItems, currentPath, accountSlot, className, }) {
|
|
98
|
+
return (_jsxs("nav", { "aria-label": "Primary", className: cn("flex h-full flex-col gap-4 overflow-y-auto bg-base-200 py-4", className), children: [_jsx("div", { className: "flex flex-col gap-0.5 px-2", children: _jsx(NavLink, { item: topItem, active: isActive(topItem.href, currentPath), variant: "responsive" }) }), _jsx("div", { className: "flex flex-1 flex-col gap-4 px-2", children: groups.map((group) => (_jsx(GroupSection, { group: group, currentPath: currentPath }, group.label))) }), _jsxs("div", { className: "flex flex-col gap-2 border-edge-subtle border-t px-2 pt-3", children: [_jsx("div", { className: "flex flex-col gap-0.5", children: footerItems.map((item) => (_jsx(NavLink, { item: item, active: isActive(item.href, currentPath), variant: "responsive", dim: true }, item.href))) }), accountSlot != null && _jsx("div", { className: "px-3 lg:hidden xl:block", children: accountSlot })] })] }));
|
|
99
|
+
}
|
|
100
|
+
//# sourceMappingURL=side-nav.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"side-nav.js","sourceRoot":"","sources":["../../../src/components/primitives/side-nav.tsx"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { HTMLAttributes } from "react";
|
|
2
|
+
/**
|
|
3
|
+
* Static — never shimmering (design doc §3.8 rule 2: "no skeleton
|
|
4
|
+
* shimmer"; §5.2: skeleton rows must match the real row height exactly so
|
|
5
|
+
* nothing shifts on load). House rule, not negotiable — see this repo's
|
|
6
|
+
* own AGENTS.md-lineage note; do not add animation here.
|
|
7
|
+
*
|
|
8
|
+
* Deliberately hand-rolled `<div>`, not daisyUI's own `.skeleton` class:
|
|
9
|
+
* read `daisyui/components/skeleton.css` directly before deciding this —
|
|
10
|
+
* daisyUI's `.skeleton` ships a `background-position` shimmer under
|
|
11
|
+
* `animation:1.8s ease-in-out infinite skeleton` (guarded only by
|
|
12
|
+
* `prefers-reduced-motion`, which is not the same thing as "off by
|
|
13
|
+
* default"), which is exactly the animation this house rule forbids.
|
|
14
|
+
* Radius stays `rounded-sm` (now `--radius-field`, 12px, via Phase 0's
|
|
15
|
+
* token rewrite) rather than moving to `--radius-box` — this component
|
|
16
|
+
* stands in for table cells and text lines across every screen, all
|
|
17
|
+
* field-scale content, not card-scale surfaces, so the token that already
|
|
18
|
+
* existed here is also the correct D8 tier, not a value left untouched by
|
|
19
|
+
* omission.
|
|
20
|
+
*/
|
|
21
|
+
export declare function Skeleton({ className, ...props }: HTMLAttributes<HTMLDivElement>): import("react").JSX.Element;
|
|
22
|
+
//# sourceMappingURL=skeleton.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"skeleton.d.ts","sourceRoot":"","sources":["../../../src/components/primitives/skeleton.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,OAAO,CAAC;AAG5C;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,QAAQ,CAAC,EAAE,SAAS,EAAE,GAAG,KAAK,EAAE,EAAE,cAAc,CAAC,cAAc,CAAC,+BAE/E"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { cn } from "../../lib/cn.js";
|
|
3
|
+
/**
|
|
4
|
+
* Static — never shimmering (design doc §3.8 rule 2: "no skeleton
|
|
5
|
+
* shimmer"; §5.2: skeleton rows must match the real row height exactly so
|
|
6
|
+
* nothing shifts on load). House rule, not negotiable — see this repo's
|
|
7
|
+
* own AGENTS.md-lineage note; do not add animation here.
|
|
8
|
+
*
|
|
9
|
+
* Deliberately hand-rolled `<div>`, not daisyUI's own `.skeleton` class:
|
|
10
|
+
* read `daisyui/components/skeleton.css` directly before deciding this —
|
|
11
|
+
* daisyUI's `.skeleton` ships a `background-position` shimmer under
|
|
12
|
+
* `animation:1.8s ease-in-out infinite skeleton` (guarded only by
|
|
13
|
+
* `prefers-reduced-motion`, which is not the same thing as "off by
|
|
14
|
+
* default"), which is exactly the animation this house rule forbids.
|
|
15
|
+
* Radius stays `rounded-sm` (now `--radius-field`, 12px, via Phase 0's
|
|
16
|
+
* token rewrite) rather than moving to `--radius-box` — this component
|
|
17
|
+
* stands in for table cells and text lines across every screen, all
|
|
18
|
+
* field-scale content, not card-scale surfaces, so the token that already
|
|
19
|
+
* existed here is also the correct D8 tier, not a value left untouched by
|
|
20
|
+
* omission.
|
|
21
|
+
*/
|
|
22
|
+
export function Skeleton({ className, ...props }) {
|
|
23
|
+
return _jsx("div", { className: cn("rounded-sm bg-surface-3", className), ...props });
|
|
24
|
+
}
|
|
25
|
+
//# sourceMappingURL=skeleton.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"skeleton.js","sourceRoot":"","sources":["../../../src/components/primitives/skeleton.tsx"],"names":[],"mappings":";AACA,OAAO,EAAE,EAAE,EAAE,MAAM,cAAc,CAAC;AAElC;;;;;;;;;;;;;;;;;;GAkBG;AACH,MAAM,UAAU,QAAQ,CAAC,EAAE,SAAS,EAAE,GAAG,KAAK,EAAkC;IAC9E,OAAO,cAAK,SAAS,EAAE,EAAE,CAAC,yBAAyB,EAAE,SAAS,CAAC,KAAM,KAAK,GAAI,CAAC;AACjF,CAAC"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
export interface SpinnerProps {
|
|
2
|
+
size?: "xs" | "sm" | "md" | "lg";
|
|
3
|
+
/** Announced to assistive technology. `undefined` renders the spinner
|
|
4
|
+
* `aria-hidden`, which is correct when a visible sibling already says
|
|
5
|
+
* what is loading — two announcements of the same wait is worse than
|
|
6
|
+
* one. */
|
|
7
|
+
label?: string | undefined;
|
|
8
|
+
className?: string | undefined;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* An indeterminate busy indicator, for a wait whose *shape* is unknown.
|
|
12
|
+
*
|
|
13
|
+
* Prefer `Skeleton` wherever the shape of what is arriving is known —
|
|
14
|
+
* a table, a card, a detail pane. A skeleton keeps the layout from
|
|
15
|
+
* jumping when content lands and tells the reader what to expect; a
|
|
16
|
+
* spinner tells them only that something is happening. This is for the
|
|
17
|
+
* rest: a button mid-submit, a poll with no placeholder to draw.
|
|
18
|
+
*/
|
|
19
|
+
export declare function Spinner({ size, label, className }: SpinnerProps): import("react").JSX.Element;
|
|
20
|
+
//# sourceMappingURL=spinner.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"spinner.d.ts","sourceRoot":"","sources":["../../../src/components/primitives/spinner.tsx"],"names":[],"mappings":"AAEA,MAAM,WAAW,YAAY;IAC3B,IAAI,CAAC,EAAE,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,CAAC;IACjC;;;cAGU;IACV,KAAK,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC3B,SAAS,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CAChC;AASD;;;;;;;;GAQG;AACH,wBAAgB,OAAO,CAAC,EAAE,IAAW,EAAE,KAAK,EAAE,SAAS,EAAE,EAAE,YAAY,+BAUtE"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { cn } from "../../lib/cn.js";
|
|
3
|
+
const SIZE_CLASS = {
|
|
4
|
+
xs: "loading-xs",
|
|
5
|
+
sm: "loading-sm",
|
|
6
|
+
md: "loading-md",
|
|
7
|
+
lg: "loading-lg",
|
|
8
|
+
};
|
|
9
|
+
/**
|
|
10
|
+
* An indeterminate busy indicator, for a wait whose *shape* is unknown.
|
|
11
|
+
*
|
|
12
|
+
* Prefer `Skeleton` wherever the shape of what is arriving is known —
|
|
13
|
+
* a table, a card, a detail pane. A skeleton keeps the layout from
|
|
14
|
+
* jumping when content lands and tells the reader what to expect; a
|
|
15
|
+
* spinner tells them only that something is happening. This is for the
|
|
16
|
+
* rest: a button mid-submit, a poll with no placeholder to draw.
|
|
17
|
+
*/
|
|
18
|
+
export function Spinner({ size = "sm", label, className }) {
|
|
19
|
+
return (_jsx("span", { className: cn("loading loading-spinner", SIZE_CLASS[size], className), role: label === undefined ? undefined : "status", "aria-hidden": label === undefined ? true : undefined, children: label !== undefined && _jsx("span", { className: "sr-only", children: label }) }));
|
|
20
|
+
}
|
|
21
|
+
//# sourceMappingURL=spinner.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"spinner.js","sourceRoot":"","sources":["../../../src/components/primitives/spinner.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,EAAE,EAAE,MAAM,cAAc,CAAC;AAYlC,MAAM,UAAU,GAAG;IACjB,EAAE,EAAE,YAAY;IAChB,EAAE,EAAE,YAAY;IAChB,EAAE,EAAE,YAAY;IAChB,EAAE,EAAE,YAAY;CACR,CAAC;AAEX;;;;;;;;GAQG;AACH,MAAM,UAAU,OAAO,CAAC,EAAE,IAAI,GAAG,IAAI,EAAE,KAAK,EAAE,SAAS,EAAgB;IACrE,OAAO,CACL,eACE,SAAS,EAAE,EAAE,CAAC,yBAAyB,EAAE,UAAU,CAAC,IAAI,CAAC,EAAE,SAAS,CAAC,EACrE,IAAI,EAAE,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,QAAQ,iBACnC,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS,YAElD,KAAK,KAAK,SAAS,IAAI,eAAM,SAAS,EAAC,SAAS,YAAE,KAAK,GAAQ,GAC3D,CACR,CAAC;AACJ,CAAC"}
|