@seekalfred/primitives 0.2.0 → 0.4.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/README.md +975 -13
- package/dist/accordion/accordion.d.ts +107 -0
- package/dist/accordion/accordion.js +84 -0
- package/dist/accordion/accordion.js.map +1 -0
- package/dist/accordion/index.d.ts +2 -0
- package/dist/accordion/index.js +2 -0
- package/dist/alert/alert.d.ts +68 -0
- package/dist/alert/alert.js +67 -0
- package/dist/alert/alert.js.map +1 -0
- package/dist/alert/index.d.ts +2 -0
- package/dist/alert/index.js +2 -0
- package/dist/alert-dialog/alert-dialog.d.ts +53 -0
- package/dist/alert-dialog/alert-dialog.js +16 -0
- package/dist/alert-dialog/alert-dialog.js.map +1 -0
- package/dist/alert-dialog/index.d.ts +2 -0
- package/dist/alert-dialog/index.js +2 -0
- package/dist/avatar/avatar.d.ts +50 -0
- package/dist/avatar/avatar.js +91 -0
- package/dist/avatar/avatar.js.map +1 -0
- package/dist/avatar/index.d.ts +2 -0
- package/dist/avatar/index.js +2 -0
- package/dist/badge/badge.d.ts +47 -0
- package/dist/badge/badge.js +189 -0
- package/dist/badge/badge.js.map +1 -0
- package/dist/badge/index.d.ts +2 -0
- package/dist/badge/index.js +2 -0
- package/dist/breadcrumb/breadcrumb.d.ts +98 -0
- package/dist/breadcrumb/breadcrumb.js +93 -0
- package/dist/breadcrumb/breadcrumb.js.map +1 -0
- package/dist/breadcrumb/index.d.ts +2 -0
- package/dist/breadcrumb/index.js +2 -0
- package/dist/button/button.d.ts +1 -1
- package/dist/button/button.js +7 -0
- package/dist/button/button.js.map +1 -1
- package/dist/calendar/calendar.d.ts +154 -0
- package/dist/calendar/calendar.js +282 -0
- package/dist/calendar/calendar.js.map +1 -0
- package/dist/calendar/index.d.ts +2 -0
- package/dist/calendar/index.js +2 -0
- package/dist/card/card.d.ts +93 -0
- package/dist/card/card.js +105 -0
- package/dist/card/card.js.map +1 -0
- package/dist/card/index.d.ts +2 -0
- package/dist/card/index.js +2 -0
- package/dist/checkbox/checkbox.d.ts +63 -0
- package/dist/checkbox/checkbox.js +94 -0
- package/dist/checkbox/checkbox.js.map +1 -0
- package/dist/checkbox/index.d.ts +2 -0
- package/dist/checkbox/index.js +2 -0
- package/dist/dialog/dialog.d.ts +140 -0
- package/dist/dialog/dialog.js +127 -0
- package/dist/dialog/dialog.js.map +1 -0
- package/dist/dialog/index.d.ts +2 -0
- package/dist/dialog/index.js +2 -0
- package/dist/index.d.ts +30 -1
- package/dist/index.js +30 -1
- package/dist/input/index.d.ts +2 -0
- package/dist/input/index.js +2 -0
- package/dist/input/input.d.ts +80 -0
- package/dist/input/input.js +195 -0
- package/dist/input/input.js.map +1 -0
- package/dist/label/index.d.ts +2 -0
- package/dist/label/index.js +2 -0
- package/dist/label/label.d.ts +41 -0
- package/dist/label/label.js +44 -0
- package/dist/label/label.js.map +1 -0
- package/dist/lib/field-surface.js +40 -0
- package/dist/lib/field-surface.js.map +1 -0
- package/dist/lib/selection-control.js +57 -0
- package/dist/lib/selection-control.js.map +1 -0
- package/dist/menu/index.d.ts +2 -0
- package/dist/menu/index.js +2 -0
- package/dist/menu/menu.d.ts +98 -0
- package/dist/menu/menu.js +99 -0
- package/dist/menu/menu.js.map +1 -0
- package/dist/popover/index.d.ts +2 -0
- package/dist/popover/index.js +2 -0
- package/dist/popover/popover.d.ts +50 -0
- package/dist/popover/popover.js +46 -0
- package/dist/popover/popover.js.map +1 -0
- package/dist/progress/index.d.ts +2 -0
- package/dist/progress/index.js +2 -0
- package/dist/progress/progress.d.ts +82 -0
- package/dist/progress/progress.js +82 -0
- package/dist/progress/progress.js.map +1 -0
- package/dist/radio-group/index.d.ts +2 -0
- package/dist/radio-group/index.js +2 -0
- package/dist/radio-group/radio-group.d.ts +53 -0
- package/dist/radio-group/radio-group.js +65 -0
- package/dist/radio-group/radio-group.js.map +1 -0
- package/dist/scroll-area/index.d.ts +2 -0
- package/dist/scroll-area/index.js +2 -0
- package/dist/scroll-area/scroll-area.d.ts +74 -0
- package/dist/scroll-area/scroll-area.js +63 -0
- package/dist/scroll-area/scroll-area.js.map +1 -0
- package/dist/select/index.d.ts +2 -0
- package/dist/select/index.js +2 -0
- package/dist/select/select.d.ts +105 -0
- package/dist/select/select.js +149 -0
- package/dist/select/select.js.map +1 -0
- package/dist/separator/index.d.ts +2 -0
- package/dist/separator/index.js +2 -0
- package/dist/separator/separator.d.ts +42 -0
- package/dist/separator/separator.js +49 -0
- package/dist/separator/separator.js.map +1 -0
- package/dist/sheet/index.d.ts +2 -0
- package/dist/sheet/index.js +2 -0
- package/dist/sheet/sheet.d.ts +96 -0
- package/dist/sheet/sheet.js +98 -0
- package/dist/sheet/sheet.js.map +1 -0
- package/dist/skeleton/index.d.ts +2 -0
- package/dist/skeleton/index.js +2 -0
- package/dist/skeleton/skeleton.d.ts +33 -0
- package/dist/skeleton/skeleton.js +42 -0
- package/dist/skeleton/skeleton.js.map +1 -0
- package/dist/slider/index.d.ts +2 -0
- package/dist/slider/index.js +2 -0
- package/dist/slider/slider.d.ts +70 -0
- package/dist/slider/slider.js +92 -0
- package/dist/slider/slider.js.map +1 -0
- package/dist/spinner/index.d.ts +2 -0
- package/dist/spinner/index.js +2 -0
- package/dist/spinner/spinner.d.ts +75 -0
- package/dist/spinner/spinner.js +68 -0
- package/dist/spinner/spinner.js.map +1 -0
- package/dist/styles.css +1 -1
- package/dist/switch/index.d.ts +2 -0
- package/dist/switch/index.js +2 -0
- package/dist/switch/switch.d.ts +50 -0
- package/dist/switch/switch.js +66 -0
- package/dist/switch/switch.js.map +1 -0
- package/dist/table/index.d.ts +2 -0
- package/dist/table/index.js +2 -0
- package/dist/table/table.d.ts +288 -0
- package/dist/table/table.js +513 -0
- package/dist/table/table.js.map +1 -0
- package/dist/tabs/index.d.ts +2 -0
- package/dist/tabs/index.js +2 -0
- package/dist/tabs/tabs.d.ts +79 -0
- package/dist/tabs/tabs.js +103 -0
- package/dist/tabs/tabs.js.map +1 -0
- package/dist/textarea/index.d.ts +2 -0
- package/dist/textarea/index.js +2 -0
- package/dist/textarea/textarea.d.ts +27 -0
- package/dist/textarea/textarea.js +37 -0
- package/dist/textarea/textarea.js.map +1 -0
- package/dist/toast/index.d.ts +2 -0
- package/dist/toast/index.js +2 -0
- package/dist/toast/toast.d.ts +93 -0
- package/dist/toast/toast.js +145 -0
- package/dist/toast/toast.js.map +1 -0
- package/dist/tooltip/index.d.ts +2 -0
- package/dist/tooltip/index.js +2 -0
- package/dist/tooltip/tooltip.d.ts +70 -0
- package/dist/tooltip/tooltip.js +65 -0
- package/dist/tooltip/tooltip.js.map +1 -0
- package/package.json +125 -7
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import { VariantProps } from "class-variance-authority";
|
|
2
|
+
import { DisclosureGroupProps, DisclosurePanelProps, DisclosureProps } from "react-aria-components";
|
|
3
|
+
import { ReactNode } from "react";
|
|
4
|
+
//#region src/accordion/accordion.d.ts
|
|
5
|
+
/**
|
|
6
|
+
* Accordion, ported from the legacy shadcn/Radix component onto React Aria's
|
|
7
|
+
* Disclosure primitives.
|
|
8
|
+
*
|
|
9
|
+
* Every string in the cva blocks below is a STATIC literal. Tailwind scans
|
|
10
|
+
* source text, so a class assembled at runtime is invisible to it and would
|
|
11
|
+
* simply never be emitted -- the component would render unstyled with no
|
|
12
|
+
* error anywhere.
|
|
13
|
+
*
|
|
14
|
+
* State comes from React Aria data attributes (`data-expanded`,
|
|
15
|
+
* `data-focus-visible`, `data-disabled`), never from pseudo-classes.
|
|
16
|
+
*
|
|
17
|
+
* ONE BEHAVIOUR IS DELIBERATELY DROPPED. Radix moved focus between headers
|
|
18
|
+
* with Home/End and the arrow keys; React Aria's useDisclosure has no key
|
|
19
|
+
* handling, so each trigger is a button in the tab order and arrows do
|
|
20
|
+
* nothing. The ARIA APG lists arrow navigation for accordions as optional,
|
|
21
|
+
* and hand-rolling roving focus would mean owning focus management that the
|
|
22
|
+
* headless base deliberately does not. The TabReachesEveryTrigger story pins
|
|
23
|
+
* this so it stays a decision rather than becoming a surprise.
|
|
24
|
+
*/
|
|
25
|
+
export declare const accordionVariants: (props?: import("class-variance-authority/types").ClassProp | undefined) => string;
|
|
26
|
+
export declare const accordionItemVariants: (props?: import("class-variance-authority/types").ClassProp | undefined) => string;
|
|
27
|
+
export declare const accordionTriggerVariants: (props?: import("class-variance-authority/types").ClassProp | undefined) => string;
|
|
28
|
+
export declare const accordionPanelVariants: (props?: import("class-variance-authority/types").ClassProp | undefined) => string;
|
|
29
|
+
/**
|
|
30
|
+
* A grouping of collapsible sections.
|
|
31
|
+
*
|
|
32
|
+
* Expansion is KEYED, which is the sharpest break from the legacy component:
|
|
33
|
+
* `type="single" | "multiple"` becomes {@link AccordionProps.allowsMultipleExpanded},
|
|
34
|
+
* and `value` / `defaultValue` strings become `expandedKeys` /
|
|
35
|
+
* `defaultExpandedKeys` holding item ids. The change handler receives a
|
|
36
|
+
* `Set`, not a string.
|
|
37
|
+
*
|
|
38
|
+
* The legacy `collapsible` prop has no equivalent and needs none: React
|
|
39
|
+
* Aria's single-expand mode always allows collapsing the open item.
|
|
40
|
+
*
|
|
41
|
+
* @example
|
|
42
|
+
* <Accordion defaultExpandedKeys={["billing"]}>
|
|
43
|
+
* <AccordionItem id="billing">
|
|
44
|
+
* <AccordionTrigger icon={<ChevronDown aria-hidden />}>Billing</AccordionTrigger>
|
|
45
|
+
* <AccordionPanel>Invoices and payment methods.</AccordionPanel>
|
|
46
|
+
* </AccordionItem>
|
|
47
|
+
* </Accordion>
|
|
48
|
+
*/
|
|
49
|
+
export interface AccordionProps extends Omit<DisclosureGroupProps, "className" | "style">, VariantProps<typeof accordionVariants> {
|
|
50
|
+
/** Extra classes. Merged last, so they win conflicts with ours. */
|
|
51
|
+
className?: string;
|
|
52
|
+
}
|
|
53
|
+
export declare function Accordion({ className, ...props }: AccordionProps): import("react").JSX.Element;
|
|
54
|
+
/**
|
|
55
|
+
* One collapsible section.
|
|
56
|
+
*
|
|
57
|
+
* `id` replaces the legacy `value`, and is what `expandedKeys` refers to.
|
|
58
|
+
*/
|
|
59
|
+
export interface AccordionItemProps extends Omit<DisclosureProps, "className" | "style">, VariantProps<typeof accordionItemVariants> {
|
|
60
|
+
/** Extra classes. Merged last, so they win conflicts with ours. */
|
|
61
|
+
className?: string;
|
|
62
|
+
}
|
|
63
|
+
export declare function AccordionItem({ className, ...props }: AccordionItemProps): import("react").JSX.Element;
|
|
64
|
+
/**
|
|
65
|
+
* The header button that expands its item.
|
|
66
|
+
*
|
|
67
|
+
* Rendered inside a {@link Heading} because screen-reader users navigate an
|
|
68
|
+
* accordion by heading; that wrapper is what makes it usable rather than
|
|
69
|
+
* merely operable.
|
|
70
|
+
*/
|
|
71
|
+
export interface AccordionTriggerProps extends VariantProps<typeof accordionTriggerVariants> {
|
|
72
|
+
/** The header label. */
|
|
73
|
+
children?: ReactNode;
|
|
74
|
+
/**
|
|
75
|
+
* The expand/collapse glyph, rendered after the label.
|
|
76
|
+
*
|
|
77
|
+
* Required, and supplied by the caller: this library ships no icon set, so
|
|
78
|
+
* it stays icon-library agnostic. Mark the glyph `aria-hidden` -- the label
|
|
79
|
+
* is the accessible name, and a second name source makes the trigger
|
|
80
|
+
* announce twice. It is sized at `--icon-sm` unless it carries a `size-*`
|
|
81
|
+
* class of its own, and rotates on expand.
|
|
82
|
+
*/
|
|
83
|
+
icon: ReactNode;
|
|
84
|
+
/** Extra classes. Merged last, so they win conflicts with ours. */
|
|
85
|
+
className?: string;
|
|
86
|
+
/**
|
|
87
|
+
* Heading level for the wrapper. Accordions appear at different depths, and
|
|
88
|
+
* a fixed level would break the document outline wherever it is wrong.
|
|
89
|
+
*
|
|
90
|
+
* @default 3
|
|
91
|
+
*/
|
|
92
|
+
headingLevel?: number;
|
|
93
|
+
}
|
|
94
|
+
export declare function AccordionTrigger({ children, icon, className, headingLevel }: AccordionTriggerProps): import("react").JSX.Element;
|
|
95
|
+
/**
|
|
96
|
+
* The content revealed when its item expands.
|
|
97
|
+
*
|
|
98
|
+
* Named Panel rather than the legacy Content, matching React Aria and the
|
|
99
|
+
* ARIA pattern.
|
|
100
|
+
*/
|
|
101
|
+
export interface AccordionPanelProps extends Omit<DisclosurePanelProps, "className" | "style">, VariantProps<typeof accordionPanelVariants> {
|
|
102
|
+
/** Extra classes. Merged last, so they win conflicts with ours. */
|
|
103
|
+
className?: string;
|
|
104
|
+
}
|
|
105
|
+
export declare function AccordionPanel({ className, ...props }: AccordionPanelProps): import("react").JSX.Element;
|
|
106
|
+
//#endregion
|
|
107
|
+
//# sourceMappingURL=accordion.d.ts.map
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { cn } from "../lib/cn.js";
|
|
3
|
+
import { cva } from "class-variance-authority";
|
|
4
|
+
import { Button, Disclosure, DisclosureGroup, DisclosurePanel, Heading } from "react-aria-components";
|
|
5
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
6
|
+
//#region src/accordion/accordion.tsx
|
|
7
|
+
/**
|
|
8
|
+
* Accordion, ported from the legacy shadcn/Radix component onto React Aria's
|
|
9
|
+
* Disclosure primitives.
|
|
10
|
+
*
|
|
11
|
+
* Every string in the cva blocks below is a STATIC literal. Tailwind scans
|
|
12
|
+
* source text, so a class assembled at runtime is invisible to it and would
|
|
13
|
+
* simply never be emitted -- the component would render unstyled with no
|
|
14
|
+
* error anywhere.
|
|
15
|
+
*
|
|
16
|
+
* State comes from React Aria data attributes (`data-expanded`,
|
|
17
|
+
* `data-focus-visible`, `data-disabled`), never from pseudo-classes.
|
|
18
|
+
*
|
|
19
|
+
* ONE BEHAVIOUR IS DELIBERATELY DROPPED. Radix moved focus between headers
|
|
20
|
+
* with Home/End and the arrow keys; React Aria's useDisclosure has no key
|
|
21
|
+
* handling, so each trigger is a button in the tab order and arrows do
|
|
22
|
+
* nothing. The ARIA APG lists arrow navigation for accordions as optional,
|
|
23
|
+
* and hand-rolling roving focus would mean owning focus management that the
|
|
24
|
+
* headless base deliberately does not. The TabReachesEveryTrigger story pins
|
|
25
|
+
* this so it stays a decision rather than becoming a surprise.
|
|
26
|
+
*/
|
|
27
|
+
const accordionVariants = cva("w-full");
|
|
28
|
+
const accordionItemVariants = cva(["border-b-(length:--border-width) border-b-border last:border-b-0", "data-[expanded]:[&_[data-slot=accordion-trigger]_svg]:rotate-180"]);
|
|
29
|
+
const accordionTriggerVariants = cva([
|
|
30
|
+
"flex w-full items-center justify-between gap-(--density-control-gap)",
|
|
31
|
+
"text-start text-sm leading-(--leading-normal) font-sans font-medium text-foreground",
|
|
32
|
+
"rounded-md py-(--density-control-pad-md)",
|
|
33
|
+
"cursor-pointer select-none",
|
|
34
|
+
"border-(length:--border-width) border-transparent bg-transparent",
|
|
35
|
+
"outline-none",
|
|
36
|
+
"data-[focus-visible]:outline-solid",
|
|
37
|
+
"data-[focus-visible]:outline-(length:--focus-ring-width)",
|
|
38
|
+
"data-[focus-visible]:outline-offset-(--focus-ring-offset)",
|
|
39
|
+
"data-[focus-visible]:outline-(--color-ring)",
|
|
40
|
+
"motion-safe:transition-colors motion-safe:duration-(--duration-fast) motion-safe:ease-standard",
|
|
41
|
+
"data-[hovered]:underline",
|
|
42
|
+
"data-[disabled]:cursor-not-allowed data-[disabled]:opacity-(--opacity-disabled)",
|
|
43
|
+
"[&_svg]:pointer-events-none [&_svg]:shrink-0",
|
|
44
|
+
"[&_svg:not([class*='size-'])]:size-(--icon-sm)",
|
|
45
|
+
"[&_svg]:text-muted-foreground",
|
|
46
|
+
"[&_svg]:motion-safe:transition-transform [&_svg]:motion-safe:duration-(--duration-fast)"
|
|
47
|
+
]);
|
|
48
|
+
const accordionPanelVariants = cva(["pb-(--density-control-pad-md) font-sans text-sm leading-(--leading-normal) text-foreground"]);
|
|
49
|
+
function Accordion({ className, ...props }) {
|
|
50
|
+
return /* @__PURE__ */ jsx(DisclosureGroup, {
|
|
51
|
+
...props,
|
|
52
|
+
"data-slot": "accordion",
|
|
53
|
+
className: cn(accordionVariants(), className)
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
function AccordionItem({ className, ...props }) {
|
|
57
|
+
return /* @__PURE__ */ jsx(Disclosure, {
|
|
58
|
+
...props,
|
|
59
|
+
"data-slot": "accordion-item",
|
|
60
|
+
className: cn(accordionItemVariants(), className)
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
function AccordionTrigger({ children, icon, className, headingLevel = 3 }) {
|
|
64
|
+
return /* @__PURE__ */ jsx(Heading, {
|
|
65
|
+
level: headingLevel,
|
|
66
|
+
children: /* @__PURE__ */ jsxs(Button, {
|
|
67
|
+
slot: "trigger",
|
|
68
|
+
"data-slot": "accordion-trigger",
|
|
69
|
+
className: cn(accordionTriggerVariants(), className),
|
|
70
|
+
children: [children, icon]
|
|
71
|
+
})
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
function AccordionPanel({ className, ...props }) {
|
|
75
|
+
return /* @__PURE__ */ jsx(DisclosurePanel, {
|
|
76
|
+
...props,
|
|
77
|
+
"data-slot": "accordion-panel",
|
|
78
|
+
className: cn(accordionPanelVariants(), className)
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
//#endregion
|
|
82
|
+
export { Accordion, AccordionItem, AccordionPanel, AccordionTrigger, accordionItemVariants, accordionPanelVariants, accordionTriggerVariants, accordionVariants };
|
|
83
|
+
|
|
84
|
+
//# sourceMappingURL=accordion.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"accordion.js","names":["AriaDisclosureGroup","AriaDisclosure","AriaButton","AriaDisclosurePanel"],"sources":["../../src/accordion/accordion.tsx"],"sourcesContent":["\"use client\";\n\nimport { cva, type VariantProps } from \"class-variance-authority\";\nimport type { ReactNode } from \"react\";\nimport {\n Button as AriaButton,\n Disclosure as AriaDisclosure,\n DisclosureGroup as AriaDisclosureGroup,\n DisclosurePanel as AriaDisclosurePanel,\n Heading,\n type DisclosureGroupProps as AriaDisclosureGroupProps,\n type DisclosurePanelProps as AriaDisclosurePanelProps,\n type DisclosureProps as AriaDisclosureProps,\n} from \"react-aria-components\";\n\nimport { cn } from \"../lib/cn.js\";\n\n/**\n * Accordion, ported from the legacy shadcn/Radix component onto React Aria's\n * Disclosure primitives.\n *\n * Every string in the cva blocks below is a STATIC literal. Tailwind scans\n * source text, so a class assembled at runtime is invisible to it and would\n * simply never be emitted -- the component would render unstyled with no\n * error anywhere.\n *\n * State comes from React Aria data attributes (`data-expanded`,\n * `data-focus-visible`, `data-disabled`), never from pseudo-classes.\n *\n * ONE BEHAVIOUR IS DELIBERATELY DROPPED. Radix moved focus between headers\n * with Home/End and the arrow keys; React Aria's useDisclosure has no key\n * handling, so each trigger is a button in the tab order and arrows do\n * nothing. The ARIA APG lists arrow navigation for accordions as optional,\n * and hand-rolling roving focus would mean owning focus management that the\n * headless base deliberately does not. The TabReachesEveryTrigger story pins\n * this so it stays a decision rather than becoming a surprise.\n */\nexport const accordionVariants = cva(\"w-full\");\n\nexport const accordionItemVariants = cva([\n // The divider between items. border-b-0 on the last child rather than\n // border-t on siblings: it survives a single-item accordion, which the\n // sibling form does not.\n \"border-b-(length:--border-width) border-b-border last:border-b-0\",\n // The chevron rotation is authored HERE, not on the trigger: React Aria\n // puts data-expanded on the Disclosure, and CSS cannot look upward from\n // the button to its expanded ancestor.\n \"data-[expanded]:[&_[data-slot=accordion-trigger]_svg]:rotate-180\",\n]);\n\nexport const accordionTriggerVariants = cva([\n \"flex w-full items-center justify-between gap-(--density-control-gap)\",\n // text-start, never text-left. Logical properties are what make RTL work\n // without a second stylesheet (ARCHITECTURE section 5 rule 4).\n \"text-start text-sm leading-(--leading-normal) font-sans font-medium text-foreground\",\n \"rounded-md py-(--density-control-pad-md)\",\n \"cursor-pointer select-none\",\n\n // The reset in @seekalfred/styles is opt-in, so a consumer may load none.\n // A bare <button> then keeps the user-agent border, ButtonFace grey and\n // Arial -- the same defence the Button base carries, for the same reason.\n \"border-(length:--border-width) border-transparent bg-transparent\",\n\n // A real outline, not a ring. The legacy component focused with\n // ring-[3px], a box-shadow, which forced-colors discards entirely -- and\n // axe has no focus-indicator rule, so nothing would have caught it.\n // outline-solid is load-bearing: outline-none sets --tw-outline-style:none\n // and the width utility resolves its style from that same variable, so\n // without it the ring gets a width and a colour and paints nothing.\n \"outline-none\",\n \"data-[focus-visible]:outline-solid\",\n \"data-[focus-visible]:outline-(length:--focus-ring-width)\",\n \"data-[focus-visible]:outline-offset-(--focus-ring-offset)\",\n \"data-[focus-visible]:outline-(--color-ring)\",\n\n \"motion-safe:transition-colors motion-safe:duration-(--duration-fast) motion-safe:ease-standard\",\n \"data-[hovered]:underline\",\n \"data-[disabled]:cursor-not-allowed data-[disabled]:opacity-(--opacity-disabled)\",\n\n // The chevron. Sized from the icon scale unless the caller sized it, and\n // never a press target of its own.\n \"[&_svg]:pointer-events-none [&_svg]:shrink-0\",\n \"[&_svg:not([class*='size-'])]:size-(--icon-sm)\",\n \"[&_svg]:text-muted-foreground\",\n // Rotation is the whole motion story for this component -- see the panel\n // note below for why the panel itself does not animate.\n \"[&_svg]:motion-safe:transition-transform [&_svg]:motion-safe:duration-(--duration-fast)\",\n]);\n\nexport const accordionPanelVariants = cva([\n // font-sans is not decoration. The panel is a plain <div> inheriting from\n // the consumer's body, and the library deliberately does not style the\n // page -- so without this the copy renders in the browser's default serif\n // while the trigger above it renders in the brand face. Caught by eye in\n // the browser, not by any assertion, which is why NoUaLeak now covers the\n // panel too.\n \"pb-(--density-control-pad-md) font-sans text-sm leading-(--leading-normal) text-foreground\",\n // No expand/collapse animation, deliberately. React Aria hides a collapsed\n // panel with the `hidden` attribute, which is display:none, and CSS cannot\n // transition out of display:none. Overriding [hidden] would restore the\n // animation by breaking the accessibility semantics that make hidden\n // correct -- the panel would stay in the accessibility tree while\n // collapsed. @starting-style with transition-behavior:allow-discrete could\n // do this properly once the browser floor allows it.\n]);\n\n/**\n * A grouping of collapsible sections.\n *\n * Expansion is KEYED, which is the sharpest break from the legacy component:\n * `type=\"single\" | \"multiple\"` becomes {@link AccordionProps.allowsMultipleExpanded},\n * and `value` / `defaultValue` strings become `expandedKeys` /\n * `defaultExpandedKeys` holding item ids. The change handler receives a\n * `Set`, not a string.\n *\n * The legacy `collapsible` prop has no equivalent and needs none: React\n * Aria's single-expand mode always allows collapsing the open item.\n *\n * @example\n * <Accordion defaultExpandedKeys={[\"billing\"]}>\n * <AccordionItem id=\"billing\">\n * <AccordionTrigger icon={<ChevronDown aria-hidden />}>Billing</AccordionTrigger>\n * <AccordionPanel>Invoices and payment methods.</AccordionPanel>\n * </AccordionItem>\n * </Accordion>\n */\nexport interface AccordionProps\n extends\n Omit<AriaDisclosureGroupProps, \"className\" | \"style\">,\n VariantProps<typeof accordionVariants> {\n /** Extra classes. Merged last, so they win conflicts with ours. */\n className?: string;\n}\n\nexport function Accordion({ className, ...props }: AccordionProps) {\n return (\n <AriaDisclosureGroup\n {...props}\n data-slot=\"accordion\"\n className={cn(accordionVariants(), className)}\n />\n );\n}\n\n/**\n * One collapsible section.\n *\n * `id` replaces the legacy `value`, and is what `expandedKeys` refers to.\n */\nexport interface AccordionItemProps\n extends\n Omit<AriaDisclosureProps, \"className\" | \"style\">,\n VariantProps<typeof accordionItemVariants> {\n /** Extra classes. Merged last, so they win conflicts with ours. */\n className?: string;\n}\n\nexport function AccordionItem({ className, ...props }: AccordionItemProps) {\n return (\n <AriaDisclosure\n {...props}\n data-slot=\"accordion-item\"\n className={cn(accordionItemVariants(), className)}\n />\n );\n}\n\n/**\n * The header button that expands its item.\n *\n * Rendered inside a {@link Heading} because screen-reader users navigate an\n * accordion by heading; that wrapper is what makes it usable rather than\n * merely operable.\n */\nexport interface AccordionTriggerProps extends VariantProps<typeof accordionTriggerVariants> {\n /** The header label. */\n children?: ReactNode;\n /**\n * The expand/collapse glyph, rendered after the label.\n *\n * Required, and supplied by the caller: this library ships no icon set, so\n * it stays icon-library agnostic. Mark the glyph `aria-hidden` -- the label\n * is the accessible name, and a second name source makes the trigger\n * announce twice. It is sized at `--icon-sm` unless it carries a `size-*`\n * class of its own, and rotates on expand.\n */\n icon: ReactNode;\n /** Extra classes. Merged last, so they win conflicts with ours. */\n className?: string;\n /**\n * Heading level for the wrapper. Accordions appear at different depths, and\n * a fixed level would break the document outline wherever it is wrong.\n *\n * @default 3\n */\n headingLevel?: number;\n}\n\nexport function AccordionTrigger({\n children,\n icon,\n className,\n headingLevel = 3,\n}: AccordionTriggerProps) {\n return (\n <Heading level={headingLevel}>\n <AriaButton\n slot=\"trigger\"\n data-slot=\"accordion-trigger\"\n className={cn(accordionTriggerVariants(), className)}\n >\n {children}\n {icon}\n </AriaButton>\n </Heading>\n );\n}\n\n/**\n * The content revealed when its item expands.\n *\n * Named Panel rather than the legacy Content, matching React Aria and the\n * ARIA pattern.\n */\nexport interface AccordionPanelProps\n extends\n Omit<AriaDisclosurePanelProps, \"className\" | \"style\">,\n VariantProps<typeof accordionPanelVariants> {\n /** Extra classes. Merged last, so they win conflicts with ours. */\n className?: string;\n}\n\nexport function AccordionPanel({ className, ...props }: AccordionPanelProps) {\n return (\n <AriaDisclosurePanel\n {...props}\n data-slot=\"accordion-panel\"\n className={cn(accordionPanelVariants(), className)}\n />\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;AAqCA,MAAa,oBAAoB,IAAI,QAAQ;AAE7C,MAAa,wBAAwB,IAAI,CAIvC,oEAIA,kEACF,CAAC;AAED,MAAa,2BAA2B,IAAI;CAC1C;CAGA;CACA;CACA;CAKA;CAQA;CACA;CACA;CACA;CACA;CAEA;CACA;CACA;CAIA;CACA;CACA;CAGA;AACF,CAAC;AAED,MAAa,yBAAyB,IAAI,CAOxC,4FAQF,CAAC;AA8BD,SAAgB,UAAU,EAAE,WAAW,GAAG,SAAyB;CACjE,OACE,oBAACA,iBAAD;EACE,GAAI;EACJ,aAAU;EACV,WAAW,GAAG,kBAAkB,GAAG,SAAS;CAC7C,CAAA;AAEL;AAeA,SAAgB,cAAc,EAAE,WAAW,GAAG,SAA6B;CACzE,OACE,oBAACC,YAAD;EACE,GAAI;EACJ,aAAU;EACV,WAAW,GAAG,sBAAsB,GAAG,SAAS;CACjD,CAAA;AAEL;AAiCA,SAAgB,iBAAiB,EAC/B,UACA,MACA,WACA,eAAe,KACS;CACxB,OACE,oBAAC,SAAD;EAAS,OAAO;EACd,UAAA,qBAACC,QAAD;GACE,MAAK;GACL,aAAU;GACV,WAAW,GAAG,yBAAyB,GAAG,SAAS;GAHrD,UAAA,CAKG,UACA,IACS;;CACL,CAAA;AAEb;AAgBA,SAAgB,eAAe,EAAE,WAAW,GAAG,SAA8B;CAC3E,OACE,oBAACC,iBAAD;EACE,GAAI;EACJ,aAAU;EACV,WAAW,GAAG,uBAAuB,GAAG,SAAS;CAClD,CAAA;AAEL"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import { Accordion, AccordionItem, AccordionItemProps, AccordionPanel, AccordionPanelProps, AccordionProps, AccordionTrigger, AccordionTriggerProps } from "./accordion.js";
|
|
2
|
+
export { Accordion, AccordionItem, type AccordionItemProps, AccordionPanel, type AccordionPanelProps, type AccordionProps, AccordionTrigger, type AccordionTriggerProps };
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { VariantProps } from "class-variance-authority";
|
|
2
|
+
import { ComponentPropsWithoutRef, ReactNode } from "react";
|
|
3
|
+
//#region src/alert/alert.d.ts
|
|
4
|
+
/**
|
|
5
|
+
* Alert, ported from the legacy shadcn component.
|
|
6
|
+
*
|
|
7
|
+
* There is no React Aria base: RAC ships no static inline alert (its Toast
|
|
8
|
+
* API is transient and queue-driven), so this is a styled div with
|
|
9
|
+
* role="alert". Because it is not RAC-backed, its props follow
|
|
10
|
+
* ARCHITECTURE section 7 rule 1 -- VariantProps & ComponentPropsWithoutRef --
|
|
11
|
+
* rather than the Button's Omit-from-React-Aria departure, which exists only
|
|
12
|
+
* to stop RAC-ignored props being advertised.
|
|
13
|
+
*
|
|
14
|
+
* Every string below is a STATIC literal. Tailwind scans source text, so a
|
|
15
|
+
* class assembled at runtime is invisible to it and would never be emitted.
|
|
16
|
+
*
|
|
17
|
+
* THE LAYOUT IS THE BIGGEST CHANGE. The legacy component positioned its icon
|
|
18
|
+
* with `[&>svg]:absolute [&>svg]:left-4 [&>svg]:top-4`, pushed the text over
|
|
19
|
+
* with `[&>svg~*]:pl-7`, and nudged it back with `[&>svg+div]:translate-y-[-3px]`.
|
|
20
|
+
* All three are physical properties or magic numbers: `left` and `pl` do not
|
|
21
|
+
* mirror in RTL, so the icon stayed left while the text indented the wrong
|
|
22
|
+
* side, and `translate-y-[-3px]` is a bracket value that `check:hardcoding`
|
|
23
|
+
* rejects outright. Flex with an explicit `icon` prop deletes all three
|
|
24
|
+
* problems rather than porting them.
|
|
25
|
+
*/
|
|
26
|
+
export declare const alertVariants: (props?: ({
|
|
27
|
+
variant?: "default" | "destructive" | null | undefined;
|
|
28
|
+
} & import("class-variance-authority/types").ClassProp) | undefined) => string;
|
|
29
|
+
/**
|
|
30
|
+
* An inline status message.
|
|
31
|
+
*
|
|
32
|
+
* Announced by assistive technology the moment it renders, via `role="alert"`.
|
|
33
|
+
* That makes it the wrong component for content that is present on load and
|
|
34
|
+
* merely styled as a notice -- use a plain region for those.
|
|
35
|
+
*
|
|
36
|
+
* @example
|
|
37
|
+
* <Alert variant="destructive" icon={<WarningIcon aria-hidden />} title="Save failed">
|
|
38
|
+
* Your changes were not saved.
|
|
39
|
+
* </Alert>
|
|
40
|
+
*/
|
|
41
|
+
export interface AlertProps extends Omit<ComponentPropsWithoutRef<"div">, "title">, VariantProps<typeof alertVariants> {
|
|
42
|
+
/**
|
|
43
|
+
* Leading glyph. Mark it `aria-hidden` -- the message text is the
|
|
44
|
+
* announcement, and an unhidden graphic makes the alert announce twice.
|
|
45
|
+
*
|
|
46
|
+
* A prop rather than a positioned child: the legacy `[&>svg]` selectors
|
|
47
|
+
* only worked when the icon was the first element, and broke in RTL.
|
|
48
|
+
*/
|
|
49
|
+
icon?: ReactNode;
|
|
50
|
+
/**
|
|
51
|
+
* Optional heading. Replaces the legacy `AlertTitle` part.
|
|
52
|
+
*
|
|
53
|
+
* Omit it for a single-line alert; most call sites do.
|
|
54
|
+
*/
|
|
55
|
+
title?: ReactNode;
|
|
56
|
+
/**
|
|
57
|
+
* Heading level for {@link AlertProps.title}.
|
|
58
|
+
*
|
|
59
|
+
* The legacy `AlertTitle` was always an `<h5>`, which breaks the document
|
|
60
|
+
* outline anywhere the alert is not nested five deep.
|
|
61
|
+
*
|
|
62
|
+
* @default 3
|
|
63
|
+
*/
|
|
64
|
+
headingLevel?: 2 | 3 | 4 | 5 | 6;
|
|
65
|
+
}
|
|
66
|
+
export declare function Alert({ className, variant, icon, title, headingLevel, children, ...props }: AlertProps): import("react").JSX.Element;
|
|
67
|
+
//#endregion
|
|
68
|
+
//# sourceMappingURL=alert.d.ts.map
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { cn } from "../lib/cn.js";
|
|
3
|
+
import { cva } from "class-variance-authority";
|
|
4
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
5
|
+
//#region src/alert/alert.tsx
|
|
6
|
+
/**
|
|
7
|
+
* Alert, ported from the legacy shadcn component.
|
|
8
|
+
*
|
|
9
|
+
* There is no React Aria base: RAC ships no static inline alert (its Toast
|
|
10
|
+
* API is transient and queue-driven), so this is a styled div with
|
|
11
|
+
* role="alert". Because it is not RAC-backed, its props follow
|
|
12
|
+
* ARCHITECTURE section 7 rule 1 -- VariantProps & ComponentPropsWithoutRef --
|
|
13
|
+
* rather than the Button's Omit-from-React-Aria departure, which exists only
|
|
14
|
+
* to stop RAC-ignored props being advertised.
|
|
15
|
+
*
|
|
16
|
+
* Every string below is a STATIC literal. Tailwind scans source text, so a
|
|
17
|
+
* class assembled at runtime is invisible to it and would never be emitted.
|
|
18
|
+
*
|
|
19
|
+
* THE LAYOUT IS THE BIGGEST CHANGE. The legacy component positioned its icon
|
|
20
|
+
* with `[&>svg]:absolute [&>svg]:left-4 [&>svg]:top-4`, pushed the text over
|
|
21
|
+
* with `[&>svg~*]:pl-7`, and nudged it back with `[&>svg+div]:translate-y-[-3px]`.
|
|
22
|
+
* All three are physical properties or magic numbers: `left` and `pl` do not
|
|
23
|
+
* mirror in RTL, so the icon stayed left while the text indented the wrong
|
|
24
|
+
* side, and `translate-y-[-3px]` is a bracket value that `check:hardcoding`
|
|
25
|
+
* rejects outright. Flex with an explicit `icon` prop deletes all three
|
|
26
|
+
* problems rather than porting them.
|
|
27
|
+
*/
|
|
28
|
+
const alertVariants = cva([
|
|
29
|
+
"box-border flex w-full items-start gap-(--density-control-gap)",
|
|
30
|
+
"rounded-lg border-(length:--border-width) p-(--density-control-pad-md)",
|
|
31
|
+
"font-sans text-sm leading-(--leading-normal)"
|
|
32
|
+
], {
|
|
33
|
+
variants: { variant: {
|
|
34
|
+
default: "bg-background text-foreground border-border",
|
|
35
|
+
destructive: "bg-background text-destructive-strong border-destructive-strong"
|
|
36
|
+
} },
|
|
37
|
+
defaultVariants: { variant: "default" }
|
|
38
|
+
});
|
|
39
|
+
function Alert({ className, variant, icon, title, headingLevel = 3, children, ...props }) {
|
|
40
|
+
const Title = `h${headingLevel}`;
|
|
41
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
42
|
+
...props,
|
|
43
|
+
role: "alert",
|
|
44
|
+
"data-slot": "alert",
|
|
45
|
+
className: cn(alertVariants({ variant }), className),
|
|
46
|
+
children: [icon === void 0 ? null : /* @__PURE__ */ jsx("span", {
|
|
47
|
+
"data-slot": "alert-icon",
|
|
48
|
+
className: "shrink-0 [&>svg]:pointer-events-none [&>svg:not([class*='size-'])]:size-(--icon-sm)",
|
|
49
|
+
children: icon
|
|
50
|
+
}), /* @__PURE__ */ jsxs("div", {
|
|
51
|
+
"data-slot": "alert-body",
|
|
52
|
+
className: "min-w-0 flex-1",
|
|
53
|
+
children: [title === void 0 ? null : /* @__PURE__ */ jsx(Title, {
|
|
54
|
+
"data-slot": "alert-title",
|
|
55
|
+
className: "mb-1 text-sm leading-(--leading-tight) font-medium",
|
|
56
|
+
children: title
|
|
57
|
+
}), children === void 0 ? null : /* @__PURE__ */ jsx("div", {
|
|
58
|
+
"data-slot": "alert-description",
|
|
59
|
+
children
|
|
60
|
+
})]
|
|
61
|
+
})]
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
//#endregion
|
|
65
|
+
export { Alert, alertVariants };
|
|
66
|
+
|
|
67
|
+
//# sourceMappingURL=alert.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"alert.js","names":[],"sources":["../../src/alert/alert.tsx"],"sourcesContent":["\"use client\";\n\nimport { cva, type VariantProps } from \"class-variance-authority\";\nimport type { ComponentPropsWithoutRef, ReactNode } from \"react\";\n\nimport { cn } from \"../lib/cn.js\";\n\n/**\n * Alert, ported from the legacy shadcn component.\n *\n * There is no React Aria base: RAC ships no static inline alert (its Toast\n * API is transient and queue-driven), so this is a styled div with\n * role=\"alert\". Because it is not RAC-backed, its props follow\n * ARCHITECTURE section 7 rule 1 -- VariantProps & ComponentPropsWithoutRef --\n * rather than the Button's Omit-from-React-Aria departure, which exists only\n * to stop RAC-ignored props being advertised.\n *\n * Every string below is a STATIC literal. Tailwind scans source text, so a\n * class assembled at runtime is invisible to it and would never be emitted.\n *\n * THE LAYOUT IS THE BIGGEST CHANGE. The legacy component positioned its icon\n * with `[&>svg]:absolute [&>svg]:left-4 [&>svg]:top-4`, pushed the text over\n * with `[&>svg~*]:pl-7`, and nudged it back with `[&>svg+div]:translate-y-[-3px]`.\n * All three are physical properties or magic numbers: `left` and `pl` do not\n * mirror in RTL, so the icon stayed left while the text indented the wrong\n * side, and `translate-y-[-3px]` is a bracket value that `check:hardcoding`\n * rejects outright. Flex with an explicit `icon` prop deletes all three\n * problems rather than porting them.\n */\nexport const alertVariants = cva(\n [\n // box-border is not boilerplate. Tailwind Preflight sets box-sizing\n // globally and the legacy app had it; this library's reset is OPT-IN, so\n // a consumer may load none and the browser default content-box applies.\n // w-full is width:100%, so the padding and border are then ADDED to it\n // and the alert overflows its container by exactly 46px at comfortable\n // density. Measured, not theorised: 346px inside a 300px parent.\n \"box-border flex w-full items-start gap-(--density-control-gap)\",\n \"rounded-lg border-(length:--border-width) p-(--density-control-pad-md)\",\n // font-sans is load-bearing. The library does not style the consumer's\n // page, so anything that does not set its own face inherits the host's\n // default -- which is a serif in an unstyled document. The accordion\n // panel shipped exactly that way and it was caught by eye, not by a test.\n \"font-sans text-sm leading-(--leading-normal)\",\n ],\n {\n variants: {\n variant: {\n default: \"bg-background text-foreground border-border\",\n // destructive-STRONG, not destructive. The fill token is 4.04:1 on\n // the dark page; this role exists so the text and border clear the\n // 4.5 floor in both themes. The legacy `border-destructive/50` was\n // also an opacity modifier, which cannot be contrast-checked at all\n // because the result depends on whatever sits behind it.\n destructive: \"bg-background text-destructive-strong border-destructive-strong\",\n },\n },\n defaultVariants: { variant: \"default\" },\n },\n);\n\n/**\n * An inline status message.\n *\n * Announced by assistive technology the moment it renders, via `role=\"alert\"`.\n * That makes it the wrong component for content that is present on load and\n * merely styled as a notice -- use a plain region for those.\n *\n * @example\n * <Alert variant=\"destructive\" icon={<WarningIcon aria-hidden />} title=\"Save failed\">\n * Your changes were not saved.\n * </Alert>\n */\nexport interface AlertProps\n // The native `title` attribute is omitted so this component can use the\n // name for its heading. That attribute renders a browser tooltip, which is\n // not keyboard reachable and is not announced reliably -- on a role=\"alert\"\n // it is worth nothing, and silently shadowing it with a ReactNode would be\n // a type error waiting for the first consumer who tried both.\n extends Omit<ComponentPropsWithoutRef<\"div\">, \"title\">, VariantProps<typeof alertVariants> {\n /**\n * Leading glyph. Mark it `aria-hidden` -- the message text is the\n * announcement, and an unhidden graphic makes the alert announce twice.\n *\n * A prop rather than a positioned child: the legacy `[&>svg]` selectors\n * only worked when the icon was the first element, and broke in RTL.\n */\n icon?: ReactNode;\n /**\n * Optional heading. Replaces the legacy `AlertTitle` part.\n *\n * Omit it for a single-line alert; most call sites do.\n */\n title?: ReactNode;\n /**\n * Heading level for {@link AlertProps.title}.\n *\n * The legacy `AlertTitle` was always an `<h5>`, which breaks the document\n * outline anywhere the alert is not nested five deep.\n *\n * @default 3\n */\n headingLevel?: 2 | 3 | 4 | 5 | 6;\n}\n\nexport function Alert({\n className,\n variant,\n icon,\n title,\n headingLevel = 3,\n children,\n ...props\n}: AlertProps) {\n const Title = `h${headingLevel}` as const;\n\n return (\n <div\n {...props}\n role=\"alert\"\n data-slot=\"alert\"\n className={cn(alertVariants({ variant }), className)}\n >\n {/*\n * The glyph is sized from the icon scale unless the caller sized it,\n * and never becomes a press target. shrink-0 keeps it square when the\n * message wraps.\n */}\n {icon === undefined ? null : (\n <span\n data-slot=\"alert-icon\"\n className=\"shrink-0 [&>svg]:pointer-events-none [&>svg:not([class*='size-'])]:size-(--icon-sm)\"\n >\n {icon}\n </span>\n )}\n <div data-slot=\"alert-body\" className=\"min-w-0 flex-1\">\n {title === undefined ? null : (\n // leading-* AFTER text-*, always: tailwind-merge treats a later\n // text-* as owning line-height and silently strips a leading-*\n // that precedes it.\n <Title\n data-slot=\"alert-title\"\n className=\"mb-1 text-sm leading-(--leading-tight) font-medium\"\n >\n {title}\n </Title>\n )}\n {children === undefined ? null : <div data-slot=\"alert-description\">{children}</div>}\n </div>\n </div>\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;AA6BA,MAAa,gBAAgB,IAC3B;CAOE;CACA;CAKA;AACF,GACA;CACE,UAAU,EACR,SAAS;EACP,SAAS;EAMT,aAAa;CACf,EACF;CACA,iBAAiB,EAAE,SAAS,UAAU;AACxC,CACF;AA8CA,SAAgB,MAAM,EACpB,WACA,SACA,MACA,OACA,eAAe,GACf,UACA,GAAG,SACU;CACb,MAAM,QAAQ,IAAI;CAElB,OACE,qBAAC,OAAD;EACE,GAAI;EACJ,MAAK;EACL,aAAU;EACV,WAAW,GAAG,cAAc,EAAE,QAAQ,CAAC,GAAG,SAAS;EAJrD,UAAA,CAWG,SAAS,KAAA,IAAY,OACpB,oBAAC,QAAD;GACE,aAAU;GACV,WAAU;GAET,UAAA;EACG,CAAA,GAER,qBAAC,OAAD;GAAK,aAAU;GAAa,WAAU;GAAtC,UAAA,CACG,UAAU,KAAA,IAAY,OAIrB,oBAAC,OAAD;IACE,aAAU;IACV,WAAU;IAET,UAAA;GACI,CAAA,GAER,aAAa,KAAA,IAAY,OAAO,oBAAC,OAAD;IAAK,aAAU;IAAqB;GAAc,CAAA,CAChF;EACF,CAAA,CAAA;;AAET"}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { DialogProps } from "../dialog/dialog.js";
|
|
2
|
+
import { ReactNode } from "react";
|
|
3
|
+
//#region src/alert-dialog/alert-dialog.d.ts
|
|
4
|
+
/**
|
|
5
|
+
* AlertDialog: a confirmation that must be answered.
|
|
6
|
+
*
|
|
7
|
+
* A PRESET over `Dialog`, not a second implementation. The legacy
|
|
8
|
+
* `alert-dialog.tsx` is a 157-line clone of `dialog.tsx` with three
|
|
9
|
+
* differences, and keeping two copies is how they drift -- the legacy pair
|
|
10
|
+
* already disagree about `leading-none` on their titles for no stated
|
|
11
|
+
* reason.
|
|
12
|
+
*
|
|
13
|
+
* Census: 2 files, all eight parts used twice each, `AlertDialogPortal`,
|
|
14
|
+
* `AlertDialogOverlay` and `AlertDialogTrigger` never rendered externally.
|
|
15
|
+
*
|
|
16
|
+
* What the preset forces, and why each one is a defect if forgotten:
|
|
17
|
+
*
|
|
18
|
+
* - `role="alertdialog"`. React Aria associates the description with
|
|
19
|
+
* `aria-describedby` ONLY for this role (useDialog.mjs:29), so a
|
|
20
|
+
* confirmation built from a plain Dialog loses the sentence explaining
|
|
21
|
+
* what is about to happen.
|
|
22
|
+
* - `closeButton={false}`. An X in the corner is a third answer to a
|
|
23
|
+
* two-answer question, and it is ambiguous: it reads as "cancel" but
|
|
24
|
+
* looks like "dismiss".
|
|
25
|
+
* - `isDismissable={false}`. Clicking the page must not resolve a
|
|
26
|
+
* destructive confirmation. Escape still cancels, which is the APG
|
|
27
|
+
* behaviour and what Radix does.
|
|
28
|
+
* - `description` is REQUIRED. A confirmation with no explanation is the
|
|
29
|
+
* thing this component exists to prevent, and the role only associates it
|
|
30
|
+
* when it is there.
|
|
31
|
+
*
|
|
32
|
+
* NO `AlertDialogAction` OR `AlertDialogCancel`. The legacy shipped both,
|
|
33
|
+
* with `AlertDialogAction` defaulting to the gradient primary button -- and
|
|
34
|
+
* BOTH call sites override it back to destructive by hand
|
|
35
|
+
* (`data-table.tsx:146`, `calendar-view.tsx:638`). A default that every
|
|
36
|
+
* caller fights is not a default. Use a `Button` and say which one it is:
|
|
37
|
+
* `slot="close"` cancels, and the confirm button picks its own variant.
|
|
38
|
+
*/
|
|
39
|
+
export interface AlertDialogProps extends Omit<DialogProps, "role" | "closeButton" | "closeLabel" | "isDismissable"> {
|
|
40
|
+
/**
|
|
41
|
+
* What is about to happen, and whether it can be undone.
|
|
42
|
+
*
|
|
43
|
+
* **Required**, unlike on `Dialog`. `role="alertdialog"` is what makes
|
|
44
|
+
* React Aria wire this to `aria-describedby`, so it is both the sentence
|
|
45
|
+
* the user needs and the one the screen reader announces with the name.
|
|
46
|
+
*/
|
|
47
|
+
description: ReactNode;
|
|
48
|
+
/** The actions. Give the cancel button `slot="close"`. */
|
|
49
|
+
children?: ReactNode;
|
|
50
|
+
}
|
|
51
|
+
export declare function AlertDialog(props: AlertDialogProps): import("react").JSX.Element;
|
|
52
|
+
//#endregion
|
|
53
|
+
//# sourceMappingURL=alert-dialog.d.ts.map
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { Dialog } from "../dialog/dialog.js";
|
|
3
|
+
import { jsx } from "react/jsx-runtime";
|
|
4
|
+
//#region src/alert-dialog/alert-dialog.tsx
|
|
5
|
+
function AlertDialog(props) {
|
|
6
|
+
return /* @__PURE__ */ jsx(Dialog, {
|
|
7
|
+
...props,
|
|
8
|
+
role: "alertdialog",
|
|
9
|
+
closeButton: false,
|
|
10
|
+
isDismissable: false
|
|
11
|
+
});
|
|
12
|
+
}
|
|
13
|
+
//#endregion
|
|
14
|
+
export { AlertDialog };
|
|
15
|
+
|
|
16
|
+
//# sourceMappingURL=alert-dialog.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"alert-dialog.js","names":[],"sources":["../../src/alert-dialog/alert-dialog.tsx"],"sourcesContent":["\"use client\";\n\nimport type { ReactNode } from \"react\";\n\nimport { Dialog, type DialogProps } from \"../dialog/dialog.js\";\n\n/**\n * AlertDialog: a confirmation that must be answered.\n *\n * A PRESET over `Dialog`, not a second implementation. The legacy\n * `alert-dialog.tsx` is a 157-line clone of `dialog.tsx` with three\n * differences, and keeping two copies is how they drift -- the legacy pair\n * already disagree about `leading-none` on their titles for no stated\n * reason.\n *\n * Census: 2 files, all eight parts used twice each, `AlertDialogPortal`,\n * `AlertDialogOverlay` and `AlertDialogTrigger` never rendered externally.\n *\n * What the preset forces, and why each one is a defect if forgotten:\n *\n * - `role=\"alertdialog\"`. React Aria associates the description with\n * `aria-describedby` ONLY for this role (useDialog.mjs:29), so a\n * confirmation built from a plain Dialog loses the sentence explaining\n * what is about to happen.\n * - `closeButton={false}`. An X in the corner is a third answer to a\n * two-answer question, and it is ambiguous: it reads as \"cancel\" but\n * looks like \"dismiss\".\n * - `isDismissable={false}`. Clicking the page must not resolve a\n * destructive confirmation. Escape still cancels, which is the APG\n * behaviour and what Radix does.\n * - `description` is REQUIRED. A confirmation with no explanation is the\n * thing this component exists to prevent, and the role only associates it\n * when it is there.\n *\n * NO `AlertDialogAction` OR `AlertDialogCancel`. The legacy shipped both,\n * with `AlertDialogAction` defaulting to the gradient primary button -- and\n * BOTH call sites override it back to destructive by hand\n * (`data-table.tsx:146`, `calendar-view.tsx:638`). A default that every\n * caller fights is not a default. Use a `Button` and say which one it is:\n * `slot=\"close\"` cancels, and the confirm button picks its own variant.\n */\nexport interface AlertDialogProps\n extends Omit<DialogProps, \"role\" | \"closeButton\" | \"closeLabel\" | \"isDismissable\"> {\n /**\n * What is about to happen, and whether it can be undone.\n *\n * **Required**, unlike on `Dialog`. `role=\"alertdialog\"` is what makes\n * React Aria wire this to `aria-describedby`, so it is both the sentence\n * the user needs and the one the screen reader announces with the name.\n */\n description: ReactNode;\n /** The actions. Give the cancel button `slot=\"close\"`. */\n children?: ReactNode;\n}\n\nexport function AlertDialog(props: AlertDialogProps) {\n return <Dialog {...props} role=\"alertdialog\" closeButton={false} isDismissable={false} />;\n}\n"],"mappings":";;;;AAuDA,SAAgB,YAAY,OAAyB;CACnD,OAAO,oBAAC,QAAD;EAAQ,GAAI;EAAO,MAAK;EAAc,aAAa;EAAO,eAAe;CAAQ,CAAA;AAC1F"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { VariantProps } from "class-variance-authority";
|
|
2
|
+
import { ComponentPropsWithoutRef, ReactNode } from "react";
|
|
3
|
+
//#region src/avatar/avatar.d.ts
|
|
4
|
+
/**
|
|
5
|
+
* Avatar, ported from the legacy shadcn/Radix component.
|
|
6
|
+
*
|
|
7
|
+
* React Aria ships no avatar, so the image load/error state machine is
|
|
8
|
+
* re-implemented here -- see the status handling below, which is the part
|
|
9
|
+
* Radix was actually providing.
|
|
10
|
+
*
|
|
11
|
+
* The three legacy parts (Avatar / AvatarImage / AvatarFallback) collapse
|
|
12
|
+
* into one props-driven component. The census is unambiguous: 36 / 35 / 35
|
|
13
|
+
* uses, always as the same triple, so the compound API bought nothing but
|
|
14
|
+
* three imports and the chance to forget one.
|
|
15
|
+
*
|
|
16
|
+
* Every string below is a STATIC literal. Tailwind scans source text, so a
|
|
17
|
+
* class assembled at runtime is invisible to it and would never be emitted.
|
|
18
|
+
*/
|
|
19
|
+
export declare const avatarVariants: (props?: ({
|
|
20
|
+
size?: "sm" | "md" | "lg" | "xs" | "xl" | null | undefined;
|
|
21
|
+
} & import("class-variance-authority/types").ClassProp) | undefined) => string;
|
|
22
|
+
/**
|
|
23
|
+
* A user avatar.
|
|
24
|
+
*
|
|
25
|
+
* @example
|
|
26
|
+
* <Avatar src={user.photoUrl} alt={user.name} fallback={initials(user.name)} />
|
|
27
|
+
* <Avatar alt="" fallback="JD" />
|
|
28
|
+
*/
|
|
29
|
+
export interface AvatarProps extends Omit<ComponentPropsWithoutRef<"span">, "children">, VariantProps<typeof avatarVariants> {
|
|
30
|
+
/** Image URL. Omit it to render the fallback alone. */
|
|
31
|
+
src?: string;
|
|
32
|
+
/**
|
|
33
|
+
* Alternative text. **Required**, and `""` is the right value when the
|
|
34
|
+
* person's name already appears next to the avatar.
|
|
35
|
+
*
|
|
36
|
+
* Required on purpose: the census found 15 of 38 legacy `AvatarImage` uses
|
|
37
|
+
* with no `alt` at all, which renders an `<img>` that fails axe's
|
|
38
|
+
* `image-alt` rule. Making it required turns that into a decision the
|
|
39
|
+
* caller makes rather than a default they fall into.
|
|
40
|
+
*/
|
|
41
|
+
alt: string;
|
|
42
|
+
/**
|
|
43
|
+
* Shown until the image loads, and permanently if it fails. Usually
|
|
44
|
+
* initials.
|
|
45
|
+
*/
|
|
46
|
+
fallback?: ReactNode;
|
|
47
|
+
}
|
|
48
|
+
export declare function Avatar({ className, size, src, alt, fallback, ...props }: AvatarProps): import("react").JSX.Element;
|
|
49
|
+
//#endregion
|
|
50
|
+
//# sourceMappingURL=avatar.d.ts.map
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { cn } from "../lib/cn.js";
|
|
3
|
+
import { cva } from "class-variance-authority";
|
|
4
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
5
|
+
import { useCallback, useState } from "react";
|
|
6
|
+
//#region src/avatar/avatar.tsx
|
|
7
|
+
/**
|
|
8
|
+
* Avatar, ported from the legacy shadcn/Radix component.
|
|
9
|
+
*
|
|
10
|
+
* React Aria ships no avatar, so the image load/error state machine is
|
|
11
|
+
* re-implemented here -- see the status handling below, which is the part
|
|
12
|
+
* Radix was actually providing.
|
|
13
|
+
*
|
|
14
|
+
* The three legacy parts (Avatar / AvatarImage / AvatarFallback) collapse
|
|
15
|
+
* into one props-driven component. The census is unambiguous: 36 / 35 / 35
|
|
16
|
+
* uses, always as the same triple, so the compound API bought nothing but
|
|
17
|
+
* three imports and the chance to forget one.
|
|
18
|
+
*
|
|
19
|
+
* Every string below is a STATIC literal. Tailwind scans source text, so a
|
|
20
|
+
* class assembled at runtime is invisible to it and would never be emitted.
|
|
21
|
+
*/
|
|
22
|
+
const avatarVariants = cva([
|
|
23
|
+
"relative inline-flex shrink-0 items-center justify-center overflow-hidden",
|
|
24
|
+
"rounded-full",
|
|
25
|
+
"box-border",
|
|
26
|
+
"font-sans font-medium",
|
|
27
|
+
"bg-muted text-foreground"
|
|
28
|
+
], {
|
|
29
|
+
variants: { size: {
|
|
30
|
+
xs: "size-5 text-2xs leading-(--leading-none)",
|
|
31
|
+
sm: "size-6 text-2xs leading-(--leading-none)",
|
|
32
|
+
md: "size-8 text-sm leading-(--leading-none)",
|
|
33
|
+
lg: "size-10 text-sm leading-(--leading-none)",
|
|
34
|
+
xl: "size-16 text-base leading-(--leading-none)"
|
|
35
|
+
} },
|
|
36
|
+
defaultVariants: { size: "md" }
|
|
37
|
+
});
|
|
38
|
+
function Avatar({ className, size, src, alt, fallback, ...props }) {
|
|
39
|
+
const [status, setStatus] = useState(src === void 0 ? "idle" : "loading");
|
|
40
|
+
/**
|
|
41
|
+
* Reset when src changes, during RENDER rather than in an effect.
|
|
42
|
+
*
|
|
43
|
+
* React's documented "adjusting state when a prop changes" pattern. An
|
|
44
|
+
* effect that called setState here would be flagged by
|
|
45
|
+
* react-hooks/set-state-in-effect, and rightly: it renders once with the
|
|
46
|
+
* stale status before correcting itself.
|
|
47
|
+
*/
|
|
48
|
+
const [renderedSrc, setRenderedSrc] = useState(src);
|
|
49
|
+
if (src !== renderedSrc) {
|
|
50
|
+
setRenderedSrc(src);
|
|
51
|
+
setStatus(src === void 0 ? "idle" : "loading");
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Resolve the status from the DOM, not only from events.
|
|
55
|
+
*
|
|
56
|
+
* A cached or data-URL image is already decoded by the time React attaches
|
|
57
|
+
* its handlers, so `onLoad` fires BEFORE any effect could run -- and an
|
|
58
|
+
* effect that set "loading" would then clobber it and leave the avatar on
|
|
59
|
+
* its fallback forever. A ref callback runs when the node attaches, which
|
|
60
|
+
* is early enough to read `complete` and late enough to have a node. The
|
|
61
|
+
* handlers below still cover the asynchronous case.
|
|
62
|
+
*/
|
|
63
|
+
const measure = useCallback((node) => {
|
|
64
|
+
if (node?.complete) setStatus(node.naturalWidth > 0 ? "loaded" : "error");
|
|
65
|
+
}, []);
|
|
66
|
+
const showImage = src !== void 0 && status !== "error";
|
|
67
|
+
return /* @__PURE__ */ jsxs("span", {
|
|
68
|
+
...props,
|
|
69
|
+
"data-slot": "avatar",
|
|
70
|
+
"data-status": status,
|
|
71
|
+
className: cn(avatarVariants({ size }), className),
|
|
72
|
+
children: [showImage ? /* @__PURE__ */ jsx("img", {
|
|
73
|
+
ref: measure,
|
|
74
|
+
"data-slot": "avatar-image",
|
|
75
|
+
className: "size-full object-cover",
|
|
76
|
+
src,
|
|
77
|
+
alt,
|
|
78
|
+
onLoad: () => setStatus("loaded"),
|
|
79
|
+
onError: () => setStatus("error")
|
|
80
|
+
}) : null, status === "loaded" ? null : /* @__PURE__ */ jsx("span", {
|
|
81
|
+
"data-slot": "avatar-fallback",
|
|
82
|
+
"aria-hidden": "true",
|
|
83
|
+
className: "select-none",
|
|
84
|
+
children: fallback
|
|
85
|
+
})]
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
//#endregion
|
|
89
|
+
export { Avatar, avatarVariants };
|
|
90
|
+
|
|
91
|
+
//# sourceMappingURL=avatar.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"avatar.js","names":[],"sources":["../../src/avatar/avatar.tsx"],"sourcesContent":["\"use client\";\n\nimport { cva, type VariantProps } from \"class-variance-authority\";\nimport { useCallback, useState, type ComponentPropsWithoutRef, type ReactNode } from \"react\";\n\nimport { cn } from \"../lib/cn.js\";\n\n/**\n * Avatar, ported from the legacy shadcn/Radix component.\n *\n * React Aria ships no avatar, so the image load/error state machine is\n * re-implemented here -- see the status handling below, which is the part\n * Radix was actually providing.\n *\n * The three legacy parts (Avatar / AvatarImage / AvatarFallback) collapse\n * into one props-driven component. The census is unambiguous: 36 / 35 / 35\n * uses, always as the same triple, so the compound API bought nothing but\n * three imports and the chance to forget one.\n *\n * Every string below is a STATIC literal. Tailwind scans source text, so a\n * class assembled at runtime is invisible to it and would never be emitted.\n */\nexport const avatarVariants = cva(\n [\n \"relative inline-flex shrink-0 items-center justify-center overflow-hidden\",\n \"rounded-full\",\n // box-border: this library's reset is OPT-IN, so a consumer may load\n // none and the browser default content-box applies. The Alert shipped\n // overflowing its container by 46px for exactly this reason.\n \"box-border\",\n // font-sans: initials are text, and an unstyled document renders text in\n // a serif. The accordion panel shipped that way.\n \"font-sans font-medium\",\n \"bg-muted text-foreground\",\n ],\n {\n variants: {\n // Sizes come from the census, not from taste: call sites reach for\n // h-5 / h-6 / h-8 / h-10 / h-16 through className because the legacy\n // component has no size prop. size-7 (2 uses) has no variant; those\n // sites pick sm or md.\n //\n // Deliberately NOT on the density scale. An avatar is content, not a\n // control -- it does not shrink when a table is compacted, and putting\n // it on --density-control-* would couple a portrait to a button's\n // rhythm. If that turns out wrong it becomes an --avatar-* scale.\n size: {\n xs: \"size-5 text-2xs leading-(--leading-none)\",\n sm: \"size-6 text-2xs leading-(--leading-none)\",\n md: \"size-8 text-sm leading-(--leading-none)\",\n lg: \"size-10 text-sm leading-(--leading-none)\",\n xl: \"size-16 text-base leading-(--leading-none)\",\n },\n },\n defaultVariants: { size: \"md\" },\n },\n);\n\ntype Status = \"idle\" | \"loading\" | \"loaded\" | \"error\";\n\n/**\n * A user avatar.\n *\n * @example\n * <Avatar src={user.photoUrl} alt={user.name} fallback={initials(user.name)} />\n * <Avatar alt=\"\" fallback=\"JD\" />\n */\nexport interface AvatarProps\n extends Omit<ComponentPropsWithoutRef<\"span\">, \"children\">, VariantProps<typeof avatarVariants> {\n /** Image URL. Omit it to render the fallback alone. */\n src?: string;\n /**\n * Alternative text. **Required**, and `\"\"` is the right value when the\n * person's name already appears next to the avatar.\n *\n * Required on purpose: the census found 15 of 38 legacy `AvatarImage` uses\n * with no `alt` at all, which renders an `<img>` that fails axe's\n * `image-alt` rule. Making it required turns that into a decision the\n * caller makes rather than a default they fall into.\n */\n alt: string;\n /**\n * Shown until the image loads, and permanently if it fails. Usually\n * initials.\n */\n fallback?: ReactNode;\n}\n\nexport function Avatar({ className, size, src, alt, fallback, ...props }: AvatarProps) {\n const [status, setStatus] = useState<Status>(src === undefined ? \"idle\" : \"loading\");\n\n /**\n * Reset when src changes, during RENDER rather than in an effect.\n *\n * React's documented \"adjusting state when a prop changes\" pattern. An\n * effect that called setState here would be flagged by\n * react-hooks/set-state-in-effect, and rightly: it renders once with the\n * stale status before correcting itself.\n */\n const [renderedSrc, setRenderedSrc] = useState(src);\n if (src !== renderedSrc) {\n setRenderedSrc(src);\n setStatus(src === undefined ? \"idle\" : \"loading\");\n }\n\n /**\n * Resolve the status from the DOM, not only from events.\n *\n * A cached or data-URL image is already decoded by the time React attaches\n * its handlers, so `onLoad` fires BEFORE any effect could run -- and an\n * effect that set \"loading\" would then clobber it and leave the avatar on\n * its fallback forever. A ref callback runs when the node attaches, which\n * is early enough to read `complete` and late enough to have a node. The\n * handlers below still cover the asynchronous case.\n */\n const measure = useCallback((node: HTMLImageElement | null) => {\n if (node?.complete) {\n setStatus(node.naturalWidth > 0 ? \"loaded\" : \"error\");\n }\n }, []);\n\n const showImage = src !== undefined && status !== \"error\";\n\n return (\n <span\n {...props}\n data-slot=\"avatar\"\n data-status={status}\n className={cn(avatarVariants({ size }), className)}\n >\n {showImage ? (\n <img\n ref={measure}\n data-slot=\"avatar-image\"\n className=\"size-full object-cover\"\n src={src}\n alt={alt}\n onLoad={() => setStatus(\"loaded\")}\n onError={() => setStatus(\"error\")}\n />\n ) : null}\n {status === \"loaded\" ? null : (\n // aria-hidden: when the image is present the img carries the\n // accessible name, and when it is not the initials are decorative\n // shorthand for a name the surrounding UI already states.\n <span data-slot=\"avatar-fallback\" aria-hidden=\"true\" className=\"select-none\">\n {fallback}\n </span>\n )}\n </span>\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;AAsBA,MAAa,iBAAiB,IAC5B;CACE;CACA;CAIA;CAGA;CACA;AACF,GACA;CACE,UAAU,EAUR,MAAM;EACJ,IAAI;EACJ,IAAI;EACJ,IAAI;EACJ,IAAI;EACJ,IAAI;CACN,EACF;CACA,iBAAiB,EAAE,MAAM,KAAK;AAChC,CACF;AAgCA,SAAgB,OAAO,EAAE,WAAW,MAAM,KAAK,KAAK,UAAU,GAAG,SAAsB;CACrF,MAAM,CAAC,QAAQ,aAAa,SAAiB,QAAQ,KAAA,IAAY,SAAS,SAAS;;;;;;;;;CAUnF,MAAM,CAAC,aAAa,kBAAkB,SAAS,GAAG;CAClD,IAAI,QAAQ,aAAa;EACvB,eAAe,GAAG;EAClB,UAAU,QAAQ,KAAA,IAAY,SAAS,SAAS;CAClD;;;;;;;;;;;CAYA,MAAM,UAAU,aAAa,SAAkC;EAC7D,IAAI,MAAM,UACR,UAAU,KAAK,eAAe,IAAI,WAAW,OAAO;CAExD,GAAG,CAAC,CAAC;CAEL,MAAM,YAAY,QAAQ,KAAA,KAAa,WAAW;CAElD,OACE,qBAAC,QAAD;EACE,GAAI;EACJ,aAAU;EACV,eAAa;EACb,WAAW,GAAG,eAAe,EAAE,KAAK,CAAC,GAAG,SAAS;EAJnD,UAAA,CAMG,YACC,oBAAC,OAAD;GACE,KAAK;GACL,aAAU;GACV,WAAU;GACL;GACA;GACL,cAAc,UAAU,QAAQ;GAChC,eAAe,UAAU,OAAO;EACjC,CAAA,IACC,MACH,WAAW,WAAW,OAIrB,oBAAC,QAAD;GAAM,aAAU;GAAkB,eAAY;GAAO,WAAU;GAC5D,UAAA;EACG,CAAA,CAEJ;;AAEV"}
|