@graundtech/fluent2-react-kit 0.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (98) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +69 -0
  3. package/dist/components/ui/accordion.d.ts +133 -0
  4. package/dist/components/ui/accordion.js +80 -0
  5. package/dist/components/ui/accordion.js.map +1 -0
  6. package/dist/components/ui/alert.d.ts +106 -0
  7. package/dist/components/ui/alert.js +73 -0
  8. package/dist/components/ui/alert.js.map +1 -0
  9. package/dist/components/ui/avatar.d.ts +42 -0
  10. package/dist/components/ui/avatar.js +55 -0
  11. package/dist/components/ui/avatar.js.map +1 -0
  12. package/dist/components/ui/badge.d.ts +36 -0
  13. package/dist/components/ui/badge.js +81 -0
  14. package/dist/components/ui/badge.js.map +1 -0
  15. package/dist/components/ui/breadcrumb.d.ts +53 -0
  16. package/dist/components/ui/breadcrumb.js +149 -0
  17. package/dist/components/ui/breadcrumb.js.map +1 -0
  18. package/dist/components/ui/button.d.ts +24 -0
  19. package/dist/components/ui/button.js +86 -0
  20. package/dist/components/ui/button.js.map +1 -0
  21. package/dist/components/ui/card.d.ts +51 -0
  22. package/dist/components/ui/card.js +97 -0
  23. package/dist/components/ui/card.js.map +1 -0
  24. package/dist/components/ui/checkbox.d.ts +101 -0
  25. package/dist/components/ui/checkbox.js +57 -0
  26. package/dist/components/ui/checkbox.js.map +1 -0
  27. package/dist/components/ui/combobox.d.ts +212 -0
  28. package/dist/components/ui/combobox.js +236 -0
  29. package/dist/components/ui/combobox.js.map +1 -0
  30. package/dist/components/ui/command.d.ts +187 -0
  31. package/dist/components/ui/command.js +225 -0
  32. package/dist/components/ui/command.js.map +1 -0
  33. package/dist/components/ui/dialog.d.ts +117 -0
  34. package/dist/components/ui/dialog.js +165 -0
  35. package/dist/components/ui/dialog.js.map +1 -0
  36. package/dist/components/ui/dropdown-menu.d.ts +155 -0
  37. package/dist/components/ui/dropdown-menu.js +295 -0
  38. package/dist/components/ui/dropdown-menu.js.map +1 -0
  39. package/dist/components/ui/input.d.ts +44 -0
  40. package/dist/components/ui/input.js +43 -0
  41. package/dist/components/ui/input.js.map +1 -0
  42. package/dist/components/ui/label.d.ts +39 -0
  43. package/dist/components/ui/label.js +30 -0
  44. package/dist/components/ui/label.js.map +1 -0
  45. package/dist/components/ui/link.d.ts +62 -0
  46. package/dist/components/ui/link.js +61 -0
  47. package/dist/components/ui/link.js.map +1 -0
  48. package/dist/components/ui/multi-select.d.ts +115 -0
  49. package/dist/components/ui/multi-select.js +133 -0
  50. package/dist/components/ui/multi-select.js.map +1 -0
  51. package/dist/components/ui/pagination.d.ts +46 -0
  52. package/dist/components/ui/pagination.js +164 -0
  53. package/dist/components/ui/pagination.js.map +1 -0
  54. package/dist/components/ui/popover.d.ts +117 -0
  55. package/dist/components/ui/popover.js +62 -0
  56. package/dist/components/ui/popover.js.map +1 -0
  57. package/dist/components/ui/progress.d.ts +98 -0
  58. package/dist/components/ui/progress.js +67 -0
  59. package/dist/components/ui/progress.js.map +1 -0
  60. package/dist/components/ui/radio-group.d.ts +94 -0
  61. package/dist/components/ui/radio-group.js +65 -0
  62. package/dist/components/ui/radio-group.js.map +1 -0
  63. package/dist/components/ui/select.d.ts +145 -0
  64. package/dist/components/ui/select.js +240 -0
  65. package/dist/components/ui/select.js.map +1 -0
  66. package/dist/components/ui/separator.d.ts +43 -0
  67. package/dist/components/ui/separator.js +27 -0
  68. package/dist/components/ui/separator.js.map +1 -0
  69. package/dist/components/ui/skeleton.d.ts +81 -0
  70. package/dist/components/ui/skeleton.js +24 -0
  71. package/dist/components/ui/skeleton.js.map +1 -0
  72. package/dist/components/ui/spinner.d.ts +56 -0
  73. package/dist/components/ui/spinner.js +83 -0
  74. package/dist/components/ui/spinner.js.map +1 -0
  75. package/dist/components/ui/switch.d.ts +60 -0
  76. package/dist/components/ui/switch.js +63 -0
  77. package/dist/components/ui/switch.js.map +1 -0
  78. package/dist/components/ui/tabs.d.ts +107 -0
  79. package/dist/components/ui/tabs.js +102 -0
  80. package/dist/components/ui/tabs.js.map +1 -0
  81. package/dist/components/ui/textarea.d.ts +28 -0
  82. package/dist/components/ui/textarea.js +36 -0
  83. package/dist/components/ui/textarea.js.map +1 -0
  84. package/dist/components/ui/toast.d.ts +185 -0
  85. package/dist/components/ui/toast.js +181 -0
  86. package/dist/components/ui/toast.js.map +1 -0
  87. package/dist/components/ui/tooltip.d.ts +115 -0
  88. package/dist/components/ui/tooltip.js +72 -0
  89. package/dist/components/ui/tooltip.js.map +1 -0
  90. package/dist/index.d.ts +55 -0
  91. package/dist/index.js +284 -0
  92. package/dist/index.js.map +1 -0
  93. package/dist/lib/utils.d.ts +9 -0
  94. package/dist/lib/utils.js +9 -0
  95. package/dist/lib/utils.js.map +1 -0
  96. package/package.json +77 -0
  97. package/src/styles/tokens.css +596 -0
  98. package/src/styles/tokens.test.ts +216 -0
@@ -0,0 +1,102 @@
1
+ "use client";
2
+ import { jsx, jsxs } from "react/jsx-runtime";
3
+ import { Tabs as TabsPrimitive } from "@base-ui/react/tabs";
4
+ import { cn } from "../../lib/utils.js";
5
+ function Tabs({
6
+ className,
7
+ ...props
8
+ }) {
9
+ return /* @__PURE__ */ jsx(
10
+ TabsPrimitive.Root,
11
+ {
12
+ "data-slot": "tabs",
13
+ className: cn("flex flex-col gap-2", className),
14
+ ...props
15
+ }
16
+ );
17
+ }
18
+ function TabsList({
19
+ className,
20
+ children,
21
+ ...props
22
+ }) {
23
+ return /* @__PURE__ */ jsxs(
24
+ TabsPrimitive.List,
25
+ {
26
+ "data-slot": "tabs-list",
27
+ className: cn(
28
+ "relative flex items-center gap-1 border-b border-border",
29
+ className
30
+ ),
31
+ ...props,
32
+ children: [
33
+ children,
34
+ /* @__PURE__ */ jsx(
35
+ TabsPrimitive.Indicator,
36
+ {
37
+ "data-slot": "tabs-indicator",
38
+ className: "absolute bottom-0 left-[calc(var(--active-tab-left)+12px)] h-[3px] w-[calc(var(--active-tab-width)-24px)] rounded-full bg-primary transition-[left,width] duration-normal ease-ease"
39
+ }
40
+ )
41
+ ]
42
+ }
43
+ );
44
+ }
45
+ function TabsTrigger({
46
+ className,
47
+ ...props
48
+ }) {
49
+ return /* @__PURE__ */ jsx(
50
+ TabsPrimitive.Tab,
51
+ {
52
+ "data-slot": "tabs-trigger",
53
+ className: cn(
54
+ // layout
55
+ // py-3 + 20px line-height = Fluent's 44px Medium tab height (Figma
56
+ // validation pass 2, node 9116:18471).
57
+ "cursor-pointer px-3 py-3 text-sm font-medium whitespace-nowrap select-none",
58
+ // motion
59
+ "outline-none transition-colors duration-fast ease-ease",
60
+ // rest / hover — muted until active
61
+ "text-muted-foreground hover:text-foreground",
62
+ // active — Fluent foreground + semibold (divergence 2)
63
+ "data-[active]:text-foreground data-[active]:font-semibold",
64
+ // focus — generic offset-ring recipe (conventions §4)
65
+ "focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background",
66
+ // disabled — opacity-based (conventions §4). Unlike `SelectTrigger`,
67
+ // Base UI's `Tabs.Tab` never sets the native `disabled` attribute —
68
+ // it stays a focusable `<button>` per the WAI-ARIA "disabled but
69
+ // reachable" tab pattern and only exposes `aria-disabled`/
70
+ // `data-disabled` (see `TabsTab.js`), so this is `data-[disabled]:`
71
+ // only; a plain `disabled:` selector would never match.
72
+ "data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
73
+ className
74
+ ),
75
+ ...props
76
+ }
77
+ );
78
+ }
79
+ function TabsContent({
80
+ className,
81
+ ...props
82
+ }) {
83
+ return /* @__PURE__ */ jsx(
84
+ TabsPrimitive.Panel,
85
+ {
86
+ "data-slot": "tabs-content",
87
+ className: cn(
88
+ "pt-4 outline-none",
89
+ "focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background",
90
+ className
91
+ ),
92
+ ...props
93
+ }
94
+ );
95
+ }
96
+ export {
97
+ Tabs,
98
+ TabsContent,
99
+ TabsList,
100
+ TabsTrigger
101
+ };
102
+ //# sourceMappingURL=tabs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/components/ui/tabs.tsx"],"sourcesContent":["\"use client\";\n\nimport { Tabs as TabsPrimitive } from \"@base-ui/react/tabs\";\nimport type { ComponentProps } from \"react\";\n\nimport { cn } from \"../../lib/utils\";\n\n/**\n * Tabs — Fluent 2-styled, shadcn-API tabs.\n *\n * ## Base UI mapping (conventions §9)\n * Roving-tabindex focus, arrow-key navigation, and (per divergence 3 below)\n * the sliding active-tab indicator are genuine behavior/layout-measurement\n * that plain markup can't express, so the four parts wrap `@base-ui/react/tabs`\n * (namespace import as `TabsPrimitive`, matching the actual\n * `export * as Tabs from \"./index.parts.js\"` shape in node_modules — the same\n * pattern `select.tsx`/`radio-group.tsx` use):\n *\n * | Exported (shadcn name) | Base UI primitive |\n * | ----------------------- | --------------------- |\n * | `Tabs` | `Tabs.Root` |\n * | `TabsList` | `Tabs.List` (+ `Tabs.Indicator` appended) |\n * | `TabsTrigger` | `Tabs.Tab` |\n * | `TabsContent` | `Tabs.Panel` |\n *\n * `\"use client\"` is required here — unlike `radio-group.tsx`, this wrapper\n * itself needs it, not just the primitive parts. `Tabs.Indicator` measures the\n * active tab's DOM layout (`getBoundingClientRect`/`offsetLeft`) inside a\n * `React.useEffect` to drive the sliding-underline CSS vars (divergence 3), so\n * the component genuinely participates in client-side behavior beyond just\n * rendering a client-boundary child — matching the reasoning that already\n * governs `select.tsx`/`checkbox.tsx` for a different trigger (icons there;\n * layout measurement here).\n *\n * ## Divergences from the shadcn/Radix Tabs API (all deliberate)\n * 1. **`TabsList` is a transparent underline bar, not a muted pill.** shadcn's\n * reference `TabsList` is a segmented control: `bg-muted` rounded box with\n * each `TabsTrigger` becoming a filled `bg-background` pill when active.\n * Fluent 2's `TabList` has no pill — it's a transparent row of labels over a\n * hairline `border-b`, with a 2px brand bar that slides under the active\n * label. This implementation follows Fluent, not shadcn's segmented look:\n * `TabsList` carries `border-b border-border` (the resting hairline) and no\n * background; `TabsTrigger` is unstyled at rest beyond text color (muted →\n * foreground on hover, foreground + semibold when active via\n * `data-[active]:`), never a filled pill.\n * 2. **Active state uses Base UI's `data-active`, not shadcn's `data-state`\n * value pair.** Radix's `Tabs.Trigger` exposes `data-state=\"active\"|\n * \"inactive\"`; Base UI's `Tabs.Tab` instead exposes `data-active` as a plain\n * presence attribute (see `TabsTabDataAttributes` in node_modules — boolean\n * presence, not a value pair, the same model `radio-group.tsx`'s\n * `data-checked` uses). Styled here via the bracketed\n * `data-[active]:` form per conventions §4.\n * 3. **The sliding indicator uses `Tabs.Indicator`'s CSS-var position API**\n * (`--active-tab-left`/`--active-tab-width`, from `TabsIndicatorCssVars` in\n * node_modules), not a custom `ref`-measured span. `Tabs.Indicator` renders\n * a `<span>` inside `TabsList` with those vars set as inline custom\n * properties (re-measured via a `ResizeObserver`-backed listener whenever\n * the active tab or list layout changes) and `hidden` until a non-zero size\n * is available. This wrapper positions the span with\n * `left-[var(--active-tab-left)] w-[var(--active-tab-width)]` and animates\n * moves with `transition-[left,width] duration-normal ease-ease` — the\n * Fluent sliding-underline motion, confirmed working. **jsdom caveat:**\n * jsdom has no layout engine, so `offsetWidth`/`getBoundingClientRect` are\n * always `0`; `Tabs.Indicator` treats that as \"not yet measured\" and stays\n * `hidden`, so the indicator element exists in the test DOM\n * (`data-slot=\"tabs-indicator\"`) but the sliding motion itself is only\n * observable in a real browser (see the Select/Dialog popup-motion note in\n * conventions §3.5 for the same class of jsdom limitation applied to\n * motion). The component test asserts the indicator renders and tracks\n * `data-activation-direction`, not the pixel position.\n * 4. **Default activation is manual (Enter/Space), not automatic-on-arrow.**\n * Radix/shadcn Tabs activates on arrow-key focus move (`automatic`). Base\n * UI's `Tabs.List` defaults `activateOnFocus` to `false` — the\n * WAI-ARIA-recommended \"manual activation\" pattern: arrow keys move focus\n * among tabs, and the focused tab is only selected on `Enter`/`Space` (or\n * click). This wrapper does not override that default, so the kit ships\n * Base UI's more accessible default rather than papering over it to match\n * Radix bit-for-bit; callers who want automatic activation can pass\n * `activateOnFocus` to `TabsList` themselves (it's forwarded straight\n * through as an ordinary prop).\n *\n * ## data-slot note\n * Every part renders a real DOM element, so every part gets a `data-slot`:\n * `tabs`, `tabs-list`, `tabs-indicator`, `tabs-trigger`, `tabs-content`.\n */\n\nfunction Tabs({\n className,\n ...props\n}: ComponentProps<typeof TabsPrimitive.Root>) {\n return (\n <TabsPrimitive.Root\n data-slot=\"tabs\"\n className={cn(\"flex flex-col gap-2\", className)}\n {...props}\n />\n );\n}\n\n/**\n * List — transparent row of tab labels over a hairline bottom border, with\n * the brand sliding indicator (divergence 3) appended as the last child so it\n * paints above the hairline.\n */\nfunction TabsList({\n className,\n children,\n ...props\n}: ComponentProps<typeof TabsPrimitive.List>) {\n return (\n <TabsPrimitive.List\n data-slot=\"tabs-list\"\n className={cn(\n \"relative flex items-center gap-1 border-b border-border\",\n className\n )}\n {...props}\n >\n {children}\n <TabsPrimitive.Indicator\n data-slot=\"tabs-indicator\"\n // Fluent's Medium indicator is a 3px rounded pill inset 12px from\n // each edge of the active tab — not an edge-to-edge bar (Figma\n // validation pass 2, node 9116:18476).\n className=\"absolute bottom-0 left-[calc(var(--active-tab-left)+12px)] h-[3px] w-[calc(var(--active-tab-width)-24px)] rounded-full bg-primary transition-[left,width] duration-normal ease-ease\"\n />\n </TabsPrimitive.List>\n );\n}\n\n/**\n * Trigger — muted label at rest, brand-adjacent foreground + semibold when\n * active (divergence 2: `data-[active]:`, not shadcn's filled pill). Focus\n * uses the generic offset-ring recipe (conventions §4) — a tab is a\n * selectable control, not a typed-into field, so it doesn't get the bottom\n * brand-accent treatment `Input`/`Select` use.\n */\nfunction TabsTrigger({\n className,\n ...props\n}: ComponentProps<typeof TabsPrimitive.Tab>) {\n return (\n <TabsPrimitive.Tab\n data-slot=\"tabs-trigger\"\n className={cn(\n // layout\n // py-3 + 20px line-height = Fluent's 44px Medium tab height (Figma\n // validation pass 2, node 9116:18471).\n \"cursor-pointer px-3 py-3 text-sm font-medium whitespace-nowrap select-none\",\n // motion\n \"outline-none transition-colors duration-fast ease-ease\",\n // rest / hover — muted until active\n \"text-muted-foreground hover:text-foreground\",\n // active — Fluent foreground + semibold (divergence 2)\n \"data-[active]:text-foreground data-[active]:font-semibold\",\n // focus — generic offset-ring recipe (conventions §4)\n \"focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background\",\n // disabled — opacity-based (conventions §4). Unlike `SelectTrigger`,\n // Base UI's `Tabs.Tab` never sets the native `disabled` attribute —\n // it stays a focusable `<button>` per the WAI-ARIA \"disabled but\n // reachable\" tab pattern and only exposes `aria-disabled`/\n // `data-disabled` (see `TabsTab.js`), so this is `data-[disabled]:`\n // only; a plain `disabled:` selector would never match.\n \"data-[disabled]:pointer-events-none data-[disabled]:opacity-50\",\n className\n )}\n {...props}\n />\n );\n}\n\n/**\n * Content — the panel shown for the active tab. Base UI's `Tabs.Panel`\n * unmounts inactive panels from the accessibility tree (`hidden`) and only\n * the active one is focusable/rendered visible, so this wrapper is just\n * spacing + a focus ring for when a panel itself receives focus (e.g. no\n * focusable content inside it).\n */\nfunction TabsContent({\n className,\n ...props\n}: ComponentProps<typeof TabsPrimitive.Panel>) {\n return (\n <TabsPrimitive.Panel\n data-slot=\"tabs-content\"\n className={cn(\n \"pt-4 outline-none\",\n \"focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background\",\n className\n )}\n {...props}\n />\n );\n}\n\nexport { Tabs, TabsList, TabsTrigger, TabsContent };\n"],"mappings":";AA2FI,cAmBA,YAnBA;AAzFJ,SAAS,QAAQ,qBAAqB;AAGtC,SAAS,UAAU;AAiFnB,SAAS,KAAK;AAAA,EACZ;AAAA,EACA,GAAG;AACL,GAA8C;AAC5C,SACE;AAAA,IAAC,cAAc;AAAA,IAAd;AAAA,MACC,aAAU;AAAA,MACV,WAAW,GAAG,uBAAuB,SAAS;AAAA,MAC7C,GAAG;AAAA;AAAA,EACN;AAEJ;AAOA,SAAS,SAAS;AAAA,EAChB;AAAA,EACA;AAAA,EACA,GAAG;AACL,GAA8C;AAC5C,SACE;AAAA,IAAC,cAAc;AAAA,IAAd;AAAA,MACC,aAAU;AAAA,MACV,WAAW;AAAA,QACT;AAAA,QACA;AAAA,MACF;AAAA,MACC,GAAG;AAAA,MAEH;AAAA;AAAA,QACD;AAAA,UAAC,cAAc;AAAA,UAAd;AAAA,YACC,aAAU;AAAA,YAIV,WAAU;AAAA;AAAA,QACZ;AAAA;AAAA;AAAA,EACF;AAEJ;AASA,SAAS,YAAY;AAAA,EACnB;AAAA,EACA,GAAG;AACL,GAA6C;AAC3C,SACE;AAAA,IAAC,cAAc;AAAA,IAAd;AAAA,MACC,aAAU;AAAA,MACV,WAAW;AAAA;AAAA;AAAA;AAAA,QAIT;AAAA;AAAA,QAEA;AAAA;AAAA,QAEA;AAAA;AAAA,QAEA;AAAA;AAAA,QAEA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,QAOA;AAAA,QACA;AAAA,MACF;AAAA,MACC,GAAG;AAAA;AAAA,EACN;AAEJ;AASA,SAAS,YAAY;AAAA,EACnB;AAAA,EACA,GAAG;AACL,GAA+C;AAC7C,SACE;AAAA,IAAC,cAAc;AAAA,IAAd;AAAA,MACC,aAAU;AAAA,MACV,WAAW;AAAA,QACT;AAAA,QACA;AAAA,QACA;AAAA,MACF;AAAA,MACC,GAAG;AAAA;AAAA,EACN;AAEJ;","names":[]}
@@ -0,0 +1,28 @@
1
+ import * as react from 'react';
2
+ import { ComponentProps } from 'react';
3
+
4
+ /**
5
+ * Textarea — Fluent 2-styled, shadcn-API multi-line text field.
6
+ *
7
+ * Aesthetics follow Fluent 2 (flat at rest, `rounded-md` = 4px); the prop
8
+ * surface is a bare `ComponentProps<"textarea">` — shadcn parity, no size
9
+ * variants. No `cva`/variants export: there is only one visual treatment,
10
+ * same reasoning as `Input`/`Separator`.
11
+ *
12
+ * Server-safe: no `"use client"`, no hooks — the React import is type-only,
13
+ * so the file can be dropped straight into an RSC tree.
14
+ *
15
+ * `field-sizing-content` (current shadcn/ui baseline) lets the field grow
16
+ * with its content up to `min-h-16`, instead of being permanently boxed to a
17
+ * fixed row count; the browser's native corner-drag resize handle still
18
+ * applies on top of that since no `resize-*` utility overrides it.
19
+ *
20
+ * Focus/invalid: identical Fluent bottom-accent recipe as `Input` (see that
21
+ * file for the full rationale) — an inset box-shadow underline plus
22
+ * `border-primary` on focus, swapping to `--destructive` when the field is
23
+ * both invalid and focused. Copied verbatim from `input.tsx` per
24
+ * conventions §4 so every field-like control in the kit behaves identically.
25
+ */
26
+ declare function Textarea({ className, ...props }: ComponentProps<"textarea">): react.JSX.Element;
27
+
28
+ export { Textarea };
@@ -0,0 +1,36 @@
1
+ import { jsx } from "react/jsx-runtime";
2
+ import { cn } from "../../lib/utils.js";
3
+ function Textarea({ className, ...props }) {
4
+ return /* @__PURE__ */ jsx(
5
+ "textarea",
6
+ {
7
+ "data-slot": "textarea",
8
+ className: cn(
9
+ // layout — grows with content (field-sizing-content), Fluent flat field
10
+ "flex field-sizing-content min-h-16 w-full min-w-0 rounded-md border border-input bg-background px-3 py-2 text-sm",
11
+ // placeholder / text selection
12
+ "placeholder:text-muted-foreground selection:bg-primary selection:text-primary-foreground",
13
+ // motion — color transitions plus the focus box-shadow accent below
14
+ "outline-none transition-[color,box-shadow] duration-fast ease-ease",
15
+ // disabled — opacity-based, matches conventions §4 exactly
16
+ "disabled:pointer-events-none disabled:opacity-50",
17
+ // focus — Fluent bottom brand accent via inset box-shadow, no reflow.
18
+ // Replaces the generic ring recipe for this component (documented
19
+ // deviation, conventions §4).
20
+ "focus-visible:border-primary focus-visible:shadow-[inset_0_-2px_0_0_var(--brand-80)] dark:focus-visible:shadow-[inset_0_-2px_0_0_var(--brand-100)]",
21
+ // invalid — shadcn aria-invalid treatment, conventions §4. Declared
22
+ // after focus-visible so it wins the border tie when both apply; the
23
+ // compound aria-invalid+focus-visible rule swaps the underline accent
24
+ // to destructive too, so an invalid+focused field reads consistently.
25
+ "aria-invalid:border-destructive aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40",
26
+ "aria-invalid:focus-visible:shadow-[inset_0_-2px_0_0_var(--destructive)]",
27
+ className
28
+ ),
29
+ ...props
30
+ }
31
+ );
32
+ }
33
+ export {
34
+ Textarea
35
+ };
36
+ //# sourceMappingURL=textarea.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/components/ui/textarea.tsx"],"sourcesContent":["import type { ComponentProps } from \"react\";\n\nimport { cn } from \"../../lib/utils\";\n\n/**\n * Textarea — Fluent 2-styled, shadcn-API multi-line text field.\n *\n * Aesthetics follow Fluent 2 (flat at rest, `rounded-md` = 4px); the prop\n * surface is a bare `ComponentProps<\"textarea\">` — shadcn parity, no size\n * variants. No `cva`/variants export: there is only one visual treatment,\n * same reasoning as `Input`/`Separator`.\n *\n * Server-safe: no `\"use client\"`, no hooks — the React import is type-only,\n * so the file can be dropped straight into an RSC tree.\n *\n * `field-sizing-content` (current shadcn/ui baseline) lets the field grow\n * with its content up to `min-h-16`, instead of being permanently boxed to a\n * fixed row count; the browser's native corner-drag resize handle still\n * applies on top of that since no `resize-*` utility overrides it.\n *\n * Focus/invalid: identical Fluent bottom-accent recipe as `Input` (see that\n * file for the full rationale) — an inset box-shadow underline plus\n * `border-primary` on focus, swapping to `--destructive` when the field is\n * both invalid and focused. Copied verbatim from `input.tsx` per\n * conventions §4 so every field-like control in the kit behaves identically.\n */\nfunction Textarea({ className, ...props }: ComponentProps<\"textarea\">) {\n return (\n <textarea\n data-slot=\"textarea\"\n className={cn(\n // layout — grows with content (field-sizing-content), Fluent flat field\n \"flex field-sizing-content min-h-16 w-full min-w-0 rounded-md border border-input bg-background px-3 py-2 text-sm\",\n // placeholder / text selection\n \"placeholder:text-muted-foreground selection:bg-primary selection:text-primary-foreground\",\n // motion — color transitions plus the focus box-shadow accent below\n \"outline-none transition-[color,box-shadow] duration-fast ease-ease\",\n // disabled — opacity-based, matches conventions §4 exactly\n \"disabled:pointer-events-none disabled:opacity-50\",\n // focus — Fluent bottom brand accent via inset box-shadow, no reflow.\n // Replaces the generic ring recipe for this component (documented\n // deviation, conventions §4).\n \"focus-visible:border-primary focus-visible:shadow-[inset_0_-2px_0_0_var(--brand-80)] dark:focus-visible:shadow-[inset_0_-2px_0_0_var(--brand-100)]\",\n // invalid — shadcn aria-invalid treatment, conventions §4. Declared\n // after focus-visible so it wins the border tie when both apply; the\n // compound aria-invalid+focus-visible rule swaps the underline accent\n // to destructive too, so an invalid+focused field reads consistently.\n \"aria-invalid:border-destructive aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40\",\n \"aria-invalid:focus-visible:shadow-[inset_0_-2px_0_0_var(--destructive)]\",\n className\n )}\n {...props}\n />\n );\n}\n\nexport { Textarea };\n"],"mappings":"AA4BI;AA1BJ,SAAS,UAAU;AAwBnB,SAAS,SAAS,EAAE,WAAW,GAAG,MAAM,GAA+B;AACrE,SACE;AAAA,IAAC;AAAA;AAAA,MACC,aAAU;AAAA,MACV,WAAW;AAAA;AAAA,QAET;AAAA;AAAA,QAEA;AAAA;AAAA,QAEA;AAAA;AAAA,QAEA;AAAA;AAAA;AAAA;AAAA,QAIA;AAAA;AAAA;AAAA;AAAA;AAAA,QAKA;AAAA,QACA;AAAA,QACA;AAAA,MACF;AAAA,MACC,GAAG;AAAA;AAAA,EACN;AAEJ;","names":[]}
@@ -0,0 +1,185 @@
1
+ import * as class_variance_authority_types from 'class-variance-authority/types';
2
+ import * as react from 'react';
3
+ import { ComponentProps } from 'react';
4
+ import { Toast as Toast$1 } from '@base-ui/react/toast';
5
+ import { VariantProps } from 'class-variance-authority';
6
+
7
+ /**
8
+ * Toast — Fluent 2-styled, shadcn-API toast notifications.
9
+ *
10
+ * Follows the overlay patterns set by `select.tsx`/`dialog.tsx` (portal + a
11
+ * floating surface, Base UI `data-starting-style`/`data-ending-style` transition
12
+ * hooks) and is the designated next consumer of the status-extension tokens the
13
+ * `alert.tsx` variants introduced: the `variant` cva mirrors Alert's treatment
14
+ * (`*-subtle` fills, `*-border` borders, `*-text`/status accents on the title),
15
+ * so a toast reads as the transient sibling of the inline Alert.
16
+ *
17
+ * ## Base UI mapping (conventions §9)
18
+ * Behavior — the toast queue/manager, auto-dismiss timers, priority-based
19
+ * live-region announcement, F6 viewport landmark, portalling, swipe-to-dismiss,
20
+ * and the stacking/offset CSS variables — genuinely needs a primitive, so the
21
+ * parts wrap `@base-ui/react/toast` (namespace import, matching the actual
22
+ * export shape in node_modules, exactly like `select.tsx`/`dialog.tsx`). shadcn
23
+ * part names are mapped onto Base UI's model:
24
+ *
25
+ * | Exported (shadcn name) | Base UI primitive |
26
+ * | ---------------------- | ---------------------------------------------------- |
27
+ * | `ToastProvider` | `Toast.Provider` |
28
+ * | `ToastViewport` | `Toast.Portal` + `Toast.Viewport` ← see divergence 1 |
29
+ * | `Toast` | `Toast.Root` + `Toast.Content` ← see divergence 2 |
30
+ * | `ToastTitle` | `Toast.Title` (renders `<h2>`) |
31
+ * | `ToastDescription` | `Toast.Description` (renders `<p>`) |
32
+ * | `ToastAction` | `Toast.Action` (renders `<button>`) |
33
+ * | `ToastClose` | `Toast.Close` (renders `<button>`, ✕ via `DismissRegular`) |
34
+ * | `useToast` | `Toast.useToastManager` ← see divergence 3 |
35
+ *
36
+ * ## Firing a toast — how the wrapper maps to Base UI's manager (the API)
37
+ * Unlike shadcn's sonner-based `toast()` global, Base UI has no
38
+ * render-anywhere singleton: toasts live in a manager scoped to the nearest
39
+ * `ToastProvider`, and each visible toast is rendered by a caller-owned map over
40
+ * `useToast().toasts`. The kit keeps that model honest (same call as `select.tsx`
41
+ * did with `SelectValue`) rather than papering a fake global over it:
42
+ *
43
+ * ```tsx
44
+ * function ToastList() {
45
+ * const { toasts } = useToast();
46
+ * return toasts.map((toast) => (
47
+ * <Toast key={toast.id} toast={toast} variant={toast.data?.variant}>
48
+ * <ToastTitle />
49
+ * <ToastDescription />
50
+ * <ToastClose />
51
+ * </Toast>
52
+ * ));
53
+ * }
54
+ *
55
+ * function Fire() {
56
+ * const { add } = useToast();
57
+ * return (
58
+ * <button onClick={() => add({
59
+ * title: "Saved",
60
+ * description: "Your changes were saved.",
61
+ * data: { variant: "success" },
62
+ * })}>Save</button>
63
+ * );
64
+ * }
65
+ * ```
66
+ *
67
+ * `useToast()` returns Base UI's `{ toasts, add, close, update, promise }`.
68
+ * `add(options)` enqueues a toast and returns its id; `options.timeout` (ms,
69
+ * default 5000 via the Provider, `0` disables) drives auto-dismiss;
70
+ * `options.priority` (`'low'` polite / `'high'` assertive) drives the live-region
71
+ * urgency; `options.data` carries arbitrary payload — the kit's convention is to
72
+ * stash the visual `variant` there and read it back in the map (`toast.data?.
73
+ * variant`). Empty `<ToastTitle />`/`<ToastDescription />` fall back to the
74
+ * toast's `title`/`description` strings automatically (Base UI behavior), so the
75
+ * list rarely needs children. `Toast.createToastManager()` (re-exported as
76
+ * `createToastManager`) builds a manager usable outside React — pass it to
77
+ * `<ToastProvider toastManager={…}>` to fire toasts from non-component code.
78
+ *
79
+ * ## Divergences from the shadcn/Radix Toast API (all deliberate)
80
+ * 1. **`ToastViewport` folds `Toast.Portal` + `Toast.Viewport`.** shadcn's
81
+ * viewport is a bare positioned list; Base UI portals the viewport to
82
+ * `document.body` (so it escapes overflow/transform ancestors) and exposes it
83
+ * as a separate `Portal` part. The kit composes both, matching how
84
+ * `SelectContent` folds `Portal` + `Positioner` + `Popup`. Render it once,
85
+ * inside `ToastProvider`, with your `ToastList` map as its children.
86
+ * 2. **`Toast` composes `Toast.Root` + `Toast.Content`; children render into the
87
+ * Content.** Base UI splits an individual toast into `Root` (the stacked,
88
+ * swipeable, height-animated box that carries the `toast` prop) and `Content`
89
+ * (the inner layout whose `data-behind`/`data-expanded` opacity fades the
90
+ * stacked-behind toasts back). Folding them keeps the shadcn-flat inner API —
91
+ * `<Toast><ToastTitle/><ToastDescription/><ToastClose/></Toast>` — while
92
+ * preserving the fade. `ToastClose` is absolutely positioned (shadcn parity),
93
+ * so it can be a direct child. The **required** `toast` prop is Base UI's per-
94
+ * toast object from the `useToast().toasts` map.
95
+ * 3. **`useToast` is Base UI's `useToastManager`, not shadcn's `useToast()`.**
96
+ * shadcn's hook returns `{ toast, dismiss, toasts }` where `toast()` is a
97
+ * global fire-and-forget; Base UI's returns `{ toasts, add, close, update,
98
+ * promise }` scoped to the Provider. The kit re-exports it under the familiar
99
+ * `useToast` name but keeps Base UI's shape — call `add()` (not `toast()`) to
100
+ * fire, and render the `toasts` array yourself (divergence 2). See the firing
101
+ * recipe above.
102
+ *
103
+ * ## Motion note — the toast stack animates `transform`, NOT the popup `scale`
104
+ * The kit's other overlays (`select`/`dialog`) forbid `transition-[transform,
105
+ * opacity]` and require `transition-[opacity,scale]` (conventions §3.5): their
106
+ * zoom rides Tailwind's `scale-*`/`translate-*` utilities, which v4 compiles to
107
+ * the independent `scale:`/`translate:` CSS properties, so a `transform`-based
108
+ * transition list would leave the zoom snapping. Toast is the **sanctioned
109
+ * exception**: Base UI drives the entire stack — index offset, peek, scale-back,
110
+ * swipe displacement, and enter/exit slide — through the `transform` *shorthand*
111
+ * built from its `--toast-*` CSS variables (`--toast-index`, `--toast-offset-y`,
112
+ * `--toast-height`, `--toast-swipe-movement-x/y`), so the recipe here is an
113
+ * explicit `[transform:…]` arbitrary value with a matching `[transition:transform
114
+ * …]` — Base UI's documented styling recipe, adapted to kit tokens. This is not
115
+ * a §3.5 violation: no Tailwind `scale-*`/`translate-*` utility is used, so there
116
+ * is no independent-property split to break. Opacity/height animate alongside in
117
+ * the same explicit transition list because Base UI needs three coordinated
118
+ * durations the token utilities can't express.
119
+ *
120
+ * ## `"use client"` — required
121
+ * Two reasons, same as `dialog.tsx`. The Base UI Toast parts manage client
122
+ * state (the manager context, timers, swipe listeners — each part module carries
123
+ * its own `'use client'`), and — decisively — `DismissRegular` from
124
+ * `@fluentui/react-icons` must stay inside a client boundary: the package's
125
+ * shared icon-sizing module calls `@griffel/react`'s client-only `__styles()` at
126
+ * module scope without its own directive, so importing an icon from a Server
127
+ * Component breaks `next build`. See conventions §9; `select.tsx`/`checkbox.tsx`
128
+ * are the precedents.
129
+ *
130
+ * ## data-slot note
131
+ * `ToastProvider` renders no DOM element of its own (context only), so it
132
+ * carries no `data-slot`. Every part that renders an element does —
133
+ * `toast-viewport`, `toast` (Root), `toast-content`, `toast-title`, etc.
134
+ */
135
+ declare function ToastProvider(props: ComponentProps<typeof Toast$1.Provider>): react.JSX.Element;
136
+ /**
137
+ * Viewport — the fixed bottom-right stack region, portalled to `document.body`.
138
+ * `w-[22.5rem]` (matching Base UI's demo) on a comfortable viewport, collapsing
139
+ * to `calc(100vw-2rem)` on narrow screens; `z-50` over app content. The stacked
140
+ * toasts inside position themselves absolutely against this box (see `Toast`).
141
+ */
142
+ declare function ToastViewport({ className, ...props }: ComponentProps<typeof Toast$1.Viewport>): react.JSX.Element;
143
+ /**
144
+ * Toast surface variants — mirror `alert.tsx`'s token usage exactly. `default`
145
+ * is the neutral floating popover surface (`bg-popover`); the four status
146
+ * variants reuse the status-extension tokens (`*-subtle` fill, `*-border`
147
+ * border) with the intent color carried by the *title* (`ToastTitle`) and the
148
+ * body left as `text-muted-foreground`, so status is never conveyed by
149
+ * body-text color alone (conventions §5). See `alert.tsx`'s doc comment for the
150
+ * per-variant contrast math against these same token pairs. The title accent is
151
+ * targeted with a descendant selector (`[&_[data-slot=toast-title]]`) because
152
+ * the title sits inside the folded `Content`, not as a direct Root child.
153
+ */
154
+ declare const toastVariants: (props?: ({
155
+ variant?: "default" | "destructive" | "success" | "warning" | "info" | null | undefined;
156
+ } & class_variance_authority_types.ClassProp) | undefined) => string;
157
+ /**
158
+ * Toast — one notification. Wraps `Toast.Root` (the stacked/swipeable/height-
159
+ * animated box carrying the required `toast` prop and the `variant` surface) and
160
+ * folds a `Toast.Content` inside (the inner flex layout whose
161
+ * `data-behind`/`data-expanded` opacity fades stacked-behind toasts). `children`
162
+ * (ToastTitle/Description/Action/Close) render into the Content; `ToastClose` is
163
+ * absolutely positioned, so `pr-10` reserves room for it.
164
+ */
165
+ declare function Toast({ className, variant, children, ...props }: ComponentProps<typeof Toast$1.Root> & VariantProps<typeof toastVariants>): react.JSX.Element;
166
+ declare function ToastTitle({ className, ...props }: ComponentProps<typeof Toast$1.Title>): react.JSX.Element;
167
+ declare function ToastDescription({ className, ...props }: ComponentProps<typeof Toast$1.Description>): react.JSX.Element;
168
+ /**
169
+ * Action — an optional in-toast button (e.g. "Undo"). Styled as the kit's
170
+ * neutral outline button in miniature (conventions §4 neutral ramp), sitting
171
+ * left-aligned under the message. Base UI closes the toast after the action
172
+ * fires unless the handler prevents it.
173
+ */
174
+ declare function ToastAction({ className, ...props }: ComponentProps<typeof Toast$1.Action>): react.JSX.Element;
175
+ /**
176
+ * Close — the icon-only ✕ dismiss button, absolutely positioned top-right (like
177
+ * `dialog.tsx`'s built-in close). Accessible name comes from the `sr-only` span;
178
+ * ✕ glyph is `DismissRegular` (which is what forces `"use client"`, §9). Base UI
179
+ * marks it non-swipe-triggering automatically.
180
+ */
181
+ declare function ToastClose({ className, ...props }: ComponentProps<typeof Toast$1.Close>): react.JSX.Element;
182
+ declare const useToast: typeof Toast$1.useToastManager;
183
+ declare const createToastManager: typeof Toast$1.createToastManager;
184
+
185
+ export { Toast, ToastAction, ToastClose, ToastDescription, ToastProvider, ToastTitle, ToastViewport, createToastManager, toastVariants, useToast };
@@ -0,0 +1,181 @@
1
+ "use client";
2
+ import { jsx, jsxs } from "react/jsx-runtime";
3
+ import { Toast as ToastPrimitive } from "@base-ui/react/toast";
4
+ import { DismissRegular } from "@fluentui/react-icons";
5
+ import { cva } from "class-variance-authority";
6
+ import { cn } from "../../lib/utils.js";
7
+ function ToastProvider(props) {
8
+ return /* @__PURE__ */ jsx(ToastPrimitive.Provider, { ...props });
9
+ }
10
+ function ToastViewport({
11
+ className,
12
+ ...props
13
+ }) {
14
+ return /* @__PURE__ */ jsx(ToastPrimitive.Portal, { children: /* @__PURE__ */ jsx(
15
+ ToastPrimitive.Viewport,
16
+ {
17
+ "data-slot": "toast-viewport",
18
+ className: cn(
19
+ "fixed right-4 bottom-4 z-50 mx-auto flex w-[calc(100vw-2rem)] sm:right-6 sm:bottom-6 sm:w-[22.5rem]",
20
+ className
21
+ ),
22
+ ...props
23
+ }
24
+ ) });
25
+ }
26
+ const toastVariants = cva(
27
+ [
28
+ // --- Base UI stacking / swipe / enter-exit recipe (adapted from the Base UI
29
+ // Toast docs' bottom-right demo; the --toast-* vars are Base UI's contract).
30
+ // See the "Motion note" above for why this uses the `transform` shorthand.
31
+ "[--gap:0.75rem] [--peek:0.75rem] [--scale:calc(max(0,1-(var(--toast-index)*0.1)))] [--shrink:calc(1-var(--scale))] [--height:var(--toast-frontmost-height,var(--toast-height))] [--offset-y:calc(var(--toast-offset-y)*-1+calc(var(--toast-index)*var(--gap)*-1)+var(--toast-swipe-movement-y))]",
32
+ "absolute right-0 bottom-0 left-auto z-[calc(1000-var(--toast-index))] mr-0 w-full origin-bottom",
33
+ "[transform:translateX(var(--toast-swipe-movement-x))_translateY(calc(var(--toast-swipe-movement-y)-(var(--toast-index)*var(--peek))-(var(--shrink)*var(--height))))_scale(var(--scale))]",
34
+ // an invisible bridge below the toast so the pointer can move between stacked
35
+ // toasts without leaving the hover (Base UI recipe)
36
+ "after:absolute after:top-full after:left-0 after:h-[calc(var(--gap)+1px)] after:w-full after:content-['']",
37
+ "h-[var(--height)] data-expanded:h-[var(--toast-height)]",
38
+ "data-expanded:[transform:translateX(var(--toast-swipe-movement-x))_translateY(calc(var(--offset-y)))]",
39
+ // enter (starting) / exit (ending) slide + fade, plus the swipe-out offsets
40
+ "data-starting-style:[transform:translateY(150%)]",
41
+ "data-ending-style:opacity-0 data-limited:opacity-0",
42
+ "[&[data-ending-style]:not([data-limited]):not([data-swipe-direction])]:[transform:translateY(150%)]",
43
+ "data-ending-style:data-[swipe-direction=down]:[transform:translateY(calc(var(--toast-swipe-movement-y)+150%))] data-expanded:data-ending-style:data-[swipe-direction=down]:[transform:translateY(calc(var(--toast-swipe-movement-y)+150%))]",
44
+ "data-ending-style:data-[swipe-direction=up]:[transform:translateY(calc(var(--toast-swipe-movement-y)-150%))] data-expanded:data-ending-style:data-[swipe-direction=up]:[transform:translateY(calc(var(--toast-swipe-movement-y)-150%))]",
45
+ "data-ending-style:data-[swipe-direction=left]:[transform:translateX(calc(var(--toast-swipe-movement-x)-150%))_translateY(var(--offset-y))] data-expanded:data-ending-style:data-[swipe-direction=left]:[transform:translateX(calc(var(--toast-swipe-movement-x)-150%))_translateY(var(--offset-y))]",
46
+ "data-ending-style:data-[swipe-direction=right]:[transform:translateX(calc(var(--toast-swipe-movement-x)+150%))_translateY(var(--offset-y))] data-expanded:data-ending-style:data-[swipe-direction=right]:[transform:translateX(calc(var(--toast-swipe-movement-x)+150%))_translateY(var(--offset-y))]",
47
+ "[transition:transform_0.5s_cubic-bezier(0.22,1,0.36,1),opacity_0.5s,height_0.15s]",
48
+ // --- Fluent surface: flat floating card, medium radius, flyout elevation.
49
+ "rounded-md border shadow-16 select-none",
50
+ // F6-navigable; keyboard focus ring (conventions §4)
51
+ "outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background"
52
+ ],
53
+ {
54
+ variants: {
55
+ variant: {
56
+ default: "border-border bg-popover text-popover-foreground",
57
+ destructive: "border-destructive-border bg-destructive-subtle text-foreground [&_[data-slot=toast-title]]:text-destructive-text",
58
+ success: "border-success-border bg-success-subtle text-foreground [&_[data-slot=toast-title]]:text-success",
59
+ warning: "border-warning-border bg-warning-subtle text-foreground [&_[data-slot=toast-title]]:text-warning-text",
60
+ info: "border-brand-140 bg-brand-160 text-foreground [&_[data-slot=toast-title]]:text-brand-80 dark:border-brand-70 dark:bg-brand-30 dark:[&_[data-slot=toast-title]]:text-brand-100"
61
+ }
62
+ },
63
+ defaultVariants: {
64
+ variant: "default"
65
+ }
66
+ }
67
+ );
68
+ function Toast({
69
+ className,
70
+ variant = "default",
71
+ children,
72
+ ...props
73
+ }) {
74
+ return /* @__PURE__ */ jsx(
75
+ ToastPrimitive.Root,
76
+ {
77
+ "data-slot": "toast",
78
+ "data-variant": variant,
79
+ className: cn(toastVariants({ variant, className })),
80
+ ...props,
81
+ children: /* @__PURE__ */ jsx(
82
+ ToastPrimitive.Content,
83
+ {
84
+ "data-slot": "toast-content",
85
+ className: cn(
86
+ "relative flex h-full flex-col gap-1 overflow-hidden p-4 pr-10",
87
+ // fade the stacked-behind content back in only when the viewport expands
88
+ "transition-opacity duration-normal ease-decelerate-mid data-behind:opacity-0 data-expanded:opacity-100"
89
+ ),
90
+ children
91
+ }
92
+ )
93
+ }
94
+ );
95
+ }
96
+ function ToastTitle({
97
+ className,
98
+ ...props
99
+ }) {
100
+ return /* @__PURE__ */ jsx(
101
+ ToastPrimitive.Title,
102
+ {
103
+ "data-slot": "toast-title",
104
+ className: cn("text-sm font-semibold", className),
105
+ ...props
106
+ }
107
+ );
108
+ }
109
+ function ToastDescription({
110
+ className,
111
+ ...props
112
+ }) {
113
+ return /* @__PURE__ */ jsx(
114
+ ToastPrimitive.Description,
115
+ {
116
+ "data-slot": "toast-description",
117
+ className: cn("text-sm text-muted-foreground", className),
118
+ ...props
119
+ }
120
+ );
121
+ }
122
+ function ToastAction({
123
+ className,
124
+ ...props
125
+ }) {
126
+ return /* @__PURE__ */ jsx(
127
+ ToastPrimitive.Action,
128
+ {
129
+ "data-slot": "toast-action",
130
+ className: cn(
131
+ "mt-1 inline-flex h-8 w-fit shrink-0 items-center justify-center rounded-md border border-input bg-transparent px-3 text-sm font-medium",
132
+ "cursor-pointer outline-none transition-colors duration-fast ease-ease",
133
+ "hover:bg-accent hover:text-accent-foreground active:bg-accent/80 dark:bg-input/30 dark:hover:bg-input/50 dark:active:bg-input/70",
134
+ "focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background",
135
+ "disabled:pointer-events-none disabled:opacity-50 data-disabled:pointer-events-none data-disabled:opacity-50",
136
+ className
137
+ ),
138
+ ...props
139
+ }
140
+ );
141
+ }
142
+ function ToastClose({
143
+ className,
144
+ ...props
145
+ }) {
146
+ return /* @__PURE__ */ jsxs(
147
+ ToastPrimitive.Close,
148
+ {
149
+ "data-slot": "toast-close",
150
+ className: cn(
151
+ "absolute top-3 right-3 flex size-7 items-center justify-center rounded-md text-muted-foreground",
152
+ "cursor-pointer outline-none transition-colors duration-fast ease-ease",
153
+ "hover:bg-accent hover:text-accent-foreground active:bg-accent/80 dark:hover:bg-accent/50 dark:active:bg-accent/70",
154
+ "focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background",
155
+ "disabled:pointer-events-none disabled:opacity-50",
156
+ "[&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4",
157
+ className
158
+ ),
159
+ ...props,
160
+ children: [
161
+ /* @__PURE__ */ jsx(DismissRegular, {}),
162
+ /* @__PURE__ */ jsx("span", { className: "sr-only", children: "Close" })
163
+ ]
164
+ }
165
+ );
166
+ }
167
+ const useToast = ToastPrimitive.useToastManager;
168
+ const createToastManager = ToastPrimitive.createToastManager;
169
+ export {
170
+ Toast,
171
+ ToastAction,
172
+ ToastClose,
173
+ ToastDescription,
174
+ ToastProvider,
175
+ ToastTitle,
176
+ ToastViewport,
177
+ createToastManager,
178
+ toastVariants,
179
+ useToast
180
+ };
181
+ //# sourceMappingURL=toast.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/components/ui/toast.tsx"],"sourcesContent":["\"use client\";\n\nimport { Toast as ToastPrimitive } from \"@base-ui/react/toast\";\nimport { DismissRegular } from \"@fluentui/react-icons\";\nimport { cva, type VariantProps } from \"class-variance-authority\";\nimport type { ComponentProps } from \"react\";\n\nimport { cn } from \"../../lib/utils\";\n\n/**\n * Toast — Fluent 2-styled, shadcn-API toast notifications.\n *\n * Follows the overlay patterns set by `select.tsx`/`dialog.tsx` (portal + a\n * floating surface, Base UI `data-starting-style`/`data-ending-style` transition\n * hooks) and is the designated next consumer of the status-extension tokens the\n * `alert.tsx` variants introduced: the `variant` cva mirrors Alert's treatment\n * (`*-subtle` fills, `*-border` borders, `*-text`/status accents on the title),\n * so a toast reads as the transient sibling of the inline Alert.\n *\n * ## Base UI mapping (conventions §9)\n * Behavior — the toast queue/manager, auto-dismiss timers, priority-based\n * live-region announcement, F6 viewport landmark, portalling, swipe-to-dismiss,\n * and the stacking/offset CSS variables — genuinely needs a primitive, so the\n * parts wrap `@base-ui/react/toast` (namespace import, matching the actual\n * export shape in node_modules, exactly like `select.tsx`/`dialog.tsx`). shadcn\n * part names are mapped onto Base UI's model:\n *\n * | Exported (shadcn name) | Base UI primitive |\n * | ---------------------- | ---------------------------------------------------- |\n * | `ToastProvider` | `Toast.Provider` |\n * | `ToastViewport` | `Toast.Portal` + `Toast.Viewport` ← see divergence 1 |\n * | `Toast` | `Toast.Root` + `Toast.Content` ← see divergence 2 |\n * | `ToastTitle` | `Toast.Title` (renders `<h2>`) |\n * | `ToastDescription` | `Toast.Description` (renders `<p>`) |\n * | `ToastAction` | `Toast.Action` (renders `<button>`) |\n * | `ToastClose` | `Toast.Close` (renders `<button>`, ✕ via `DismissRegular`) |\n * | `useToast` | `Toast.useToastManager` ← see divergence 3 |\n *\n * ## Firing a toast — how the wrapper maps to Base UI's manager (the API)\n * Unlike shadcn's sonner-based `toast()` global, Base UI has no\n * render-anywhere singleton: toasts live in a manager scoped to the nearest\n * `ToastProvider`, and each visible toast is rendered by a caller-owned map over\n * `useToast().toasts`. The kit keeps that model honest (same call as `select.tsx`\n * did with `SelectValue`) rather than papering a fake global over it:\n *\n * ```tsx\n * function ToastList() {\n * const { toasts } = useToast();\n * return toasts.map((toast) => (\n * <Toast key={toast.id} toast={toast} variant={toast.data?.variant}>\n * <ToastTitle />\n * <ToastDescription />\n * <ToastClose />\n * </Toast>\n * ));\n * }\n *\n * function Fire() {\n * const { add } = useToast();\n * return (\n * <button onClick={() => add({\n * title: \"Saved\",\n * description: \"Your changes were saved.\",\n * data: { variant: \"success\" },\n * })}>Save</button>\n * );\n * }\n * ```\n *\n * `useToast()` returns Base UI's `{ toasts, add, close, update, promise }`.\n * `add(options)` enqueues a toast and returns its id; `options.timeout` (ms,\n * default 5000 via the Provider, `0` disables) drives auto-dismiss;\n * `options.priority` (`'low'` polite / `'high'` assertive) drives the live-region\n * urgency; `options.data` carries arbitrary payload — the kit's convention is to\n * stash the visual `variant` there and read it back in the map (`toast.data?.\n * variant`). Empty `<ToastTitle />`/`<ToastDescription />` fall back to the\n * toast's `title`/`description` strings automatically (Base UI behavior), so the\n * list rarely needs children. `Toast.createToastManager()` (re-exported as\n * `createToastManager`) builds a manager usable outside React — pass it to\n * `<ToastProvider toastManager={…}>` to fire toasts from non-component code.\n *\n * ## Divergences from the shadcn/Radix Toast API (all deliberate)\n * 1. **`ToastViewport` folds `Toast.Portal` + `Toast.Viewport`.** shadcn's\n * viewport is a bare positioned list; Base UI portals the viewport to\n * `document.body` (so it escapes overflow/transform ancestors) and exposes it\n * as a separate `Portal` part. The kit composes both, matching how\n * `SelectContent` folds `Portal` + `Positioner` + `Popup`. Render it once,\n * inside `ToastProvider`, with your `ToastList` map as its children.\n * 2. **`Toast` composes `Toast.Root` + `Toast.Content`; children render into the\n * Content.** Base UI splits an individual toast into `Root` (the stacked,\n * swipeable, height-animated box that carries the `toast` prop) and `Content`\n * (the inner layout whose `data-behind`/`data-expanded` opacity fades the\n * stacked-behind toasts back). Folding them keeps the shadcn-flat inner API —\n * `<Toast><ToastTitle/><ToastDescription/><ToastClose/></Toast>` — while\n * preserving the fade. `ToastClose` is absolutely positioned (shadcn parity),\n * so it can be a direct child. The **required** `toast` prop is Base UI's per-\n * toast object from the `useToast().toasts` map.\n * 3. **`useToast` is Base UI's `useToastManager`, not shadcn's `useToast()`.**\n * shadcn's hook returns `{ toast, dismiss, toasts }` where `toast()` is a\n * global fire-and-forget; Base UI's returns `{ toasts, add, close, update,\n * promise }` scoped to the Provider. The kit re-exports it under the familiar\n * `useToast` name but keeps Base UI's shape — call `add()` (not `toast()`) to\n * fire, and render the `toasts` array yourself (divergence 2). See the firing\n * recipe above.\n *\n * ## Motion note — the toast stack animates `transform`, NOT the popup `scale`\n * The kit's other overlays (`select`/`dialog`) forbid `transition-[transform,\n * opacity]` and require `transition-[opacity,scale]` (conventions §3.5): their\n * zoom rides Tailwind's `scale-*`/`translate-*` utilities, which v4 compiles to\n * the independent `scale:`/`translate:` CSS properties, so a `transform`-based\n * transition list would leave the zoom snapping. Toast is the **sanctioned\n * exception**: Base UI drives the entire stack — index offset, peek, scale-back,\n * swipe displacement, and enter/exit slide — through the `transform` *shorthand*\n * built from its `--toast-*` CSS variables (`--toast-index`, `--toast-offset-y`,\n * `--toast-height`, `--toast-swipe-movement-x/y`), so the recipe here is an\n * explicit `[transform:…]` arbitrary value with a matching `[transition:transform\n * …]` — Base UI's documented styling recipe, adapted to kit tokens. This is not\n * a §3.5 violation: no Tailwind `scale-*`/`translate-*` utility is used, so there\n * is no independent-property split to break. Opacity/height animate alongside in\n * the same explicit transition list because Base UI needs three coordinated\n * durations the token utilities can't express.\n *\n * ## `\"use client\"` — required\n * Two reasons, same as `dialog.tsx`. The Base UI Toast parts manage client\n * state (the manager context, timers, swipe listeners — each part module carries\n * its own `'use client'`), and — decisively — `DismissRegular` from\n * `@fluentui/react-icons` must stay inside a client boundary: the package's\n * shared icon-sizing module calls `@griffel/react`'s client-only `__styles()` at\n * module scope without its own directive, so importing an icon from a Server\n * Component breaks `next build`. See conventions §9; `select.tsx`/`checkbox.tsx`\n * are the precedents.\n *\n * ## data-slot note\n * `ToastProvider` renders no DOM element of its own (context only), so it\n * carries no `data-slot`. Every part that renders an element does —\n * `toast-viewport`, `toast` (Root), `toast-content`, `toast-title`, etc.\n */\n\nfunction ToastProvider(props: ComponentProps<typeof ToastPrimitive.Provider>) {\n return <ToastPrimitive.Provider {...props} />;\n}\n\n/**\n * Viewport — the fixed bottom-right stack region, portalled to `document.body`.\n * `w-[22.5rem]` (matching Base UI's demo) on a comfortable viewport, collapsing\n * to `calc(100vw-2rem)` on narrow screens; `z-50` over app content. The stacked\n * toasts inside position themselves absolutely against this box (see `Toast`).\n */\nfunction ToastViewport({\n className,\n ...props\n}: ComponentProps<typeof ToastPrimitive.Viewport>) {\n return (\n <ToastPrimitive.Portal>\n <ToastPrimitive.Viewport\n data-slot=\"toast-viewport\"\n className={cn(\n \"fixed right-4 bottom-4 z-50 mx-auto flex w-[calc(100vw-2rem)] sm:right-6 sm:bottom-6 sm:w-[22.5rem]\",\n className\n )}\n {...props}\n />\n </ToastPrimitive.Portal>\n );\n}\n\n/**\n * Toast surface variants — mirror `alert.tsx`'s token usage exactly. `default`\n * is the neutral floating popover surface (`bg-popover`); the four status\n * variants reuse the status-extension tokens (`*-subtle` fill, `*-border`\n * border) with the intent color carried by the *title* (`ToastTitle`) and the\n * body left as `text-muted-foreground`, so status is never conveyed by\n * body-text color alone (conventions §5). See `alert.tsx`'s doc comment for the\n * per-variant contrast math against these same token pairs. The title accent is\n * targeted with a descendant selector (`[&_[data-slot=toast-title]]`) because\n * the title sits inside the folded `Content`, not as a direct Root child.\n */\nconst toastVariants = cva(\n [\n // --- Base UI stacking / swipe / enter-exit recipe (adapted from the Base UI\n // Toast docs' bottom-right demo; the --toast-* vars are Base UI's contract).\n // See the \"Motion note\" above for why this uses the `transform` shorthand.\n \"[--gap:0.75rem] [--peek:0.75rem] [--scale:calc(max(0,1-(var(--toast-index)*0.1)))] [--shrink:calc(1-var(--scale))] [--height:var(--toast-frontmost-height,var(--toast-height))] [--offset-y:calc(var(--toast-offset-y)*-1+calc(var(--toast-index)*var(--gap)*-1)+var(--toast-swipe-movement-y))]\",\n \"absolute right-0 bottom-0 left-auto z-[calc(1000-var(--toast-index))] mr-0 w-full origin-bottom\",\n \"[transform:translateX(var(--toast-swipe-movement-x))_translateY(calc(var(--toast-swipe-movement-y)-(var(--toast-index)*var(--peek))-(var(--shrink)*var(--height))))_scale(var(--scale))]\",\n // an invisible bridge below the toast so the pointer can move between stacked\n // toasts without leaving the hover (Base UI recipe)\n \"after:absolute after:top-full after:left-0 after:h-[calc(var(--gap)+1px)] after:w-full after:content-['']\",\n \"h-[var(--height)] data-expanded:h-[var(--toast-height)]\",\n \"data-expanded:[transform:translateX(var(--toast-swipe-movement-x))_translateY(calc(var(--offset-y)))]\",\n // enter (starting) / exit (ending) slide + fade, plus the swipe-out offsets\n \"data-starting-style:[transform:translateY(150%)]\",\n \"data-ending-style:opacity-0 data-limited:opacity-0\",\n \"[&[data-ending-style]:not([data-limited]):not([data-swipe-direction])]:[transform:translateY(150%)]\",\n \"data-ending-style:data-[swipe-direction=down]:[transform:translateY(calc(var(--toast-swipe-movement-y)+150%))] data-expanded:data-ending-style:data-[swipe-direction=down]:[transform:translateY(calc(var(--toast-swipe-movement-y)+150%))]\",\n \"data-ending-style:data-[swipe-direction=up]:[transform:translateY(calc(var(--toast-swipe-movement-y)-150%))] data-expanded:data-ending-style:data-[swipe-direction=up]:[transform:translateY(calc(var(--toast-swipe-movement-y)-150%))]\",\n \"data-ending-style:data-[swipe-direction=left]:[transform:translateX(calc(var(--toast-swipe-movement-x)-150%))_translateY(var(--offset-y))] data-expanded:data-ending-style:data-[swipe-direction=left]:[transform:translateX(calc(var(--toast-swipe-movement-x)-150%))_translateY(var(--offset-y))]\",\n \"data-ending-style:data-[swipe-direction=right]:[transform:translateX(calc(var(--toast-swipe-movement-x)+150%))_translateY(var(--offset-y))] data-expanded:data-ending-style:data-[swipe-direction=right]:[transform:translateX(calc(var(--toast-swipe-movement-x)+150%))_translateY(var(--offset-y))]\",\n \"[transition:transform_0.5s_cubic-bezier(0.22,1,0.36,1),opacity_0.5s,height_0.15s]\",\n // --- Fluent surface: flat floating card, medium radius, flyout elevation.\n \"rounded-md border shadow-16 select-none\",\n // F6-navigable; keyboard focus ring (conventions §4)\n \"outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background\",\n ],\n {\n variants: {\n variant: {\n default: \"border-border bg-popover text-popover-foreground\",\n destructive:\n \"border-destructive-border bg-destructive-subtle text-foreground [&_[data-slot=toast-title]]:text-destructive-text\",\n success:\n \"border-success-border bg-success-subtle text-foreground [&_[data-slot=toast-title]]:text-success\",\n warning:\n \"border-warning-border bg-warning-subtle text-foreground [&_[data-slot=toast-title]]:text-warning-text\",\n info: \"border-brand-140 bg-brand-160 text-foreground [&_[data-slot=toast-title]]:text-brand-80 dark:border-brand-70 dark:bg-brand-30 dark:[&_[data-slot=toast-title]]:text-brand-100\",\n },\n },\n defaultVariants: {\n variant: \"default\",\n },\n }\n);\n\n/**\n * Toast — one notification. Wraps `Toast.Root` (the stacked/swipeable/height-\n * animated box carrying the required `toast` prop and the `variant` surface) and\n * folds a `Toast.Content` inside (the inner flex layout whose\n * `data-behind`/`data-expanded` opacity fades stacked-behind toasts). `children`\n * (ToastTitle/Description/Action/Close) render into the Content; `ToastClose` is\n * absolutely positioned, so `pr-10` reserves room for it.\n */\nfunction Toast({\n className,\n variant = \"default\",\n children,\n ...props\n}: ComponentProps<typeof ToastPrimitive.Root> &\n VariantProps<typeof toastVariants>) {\n return (\n <ToastPrimitive.Root\n data-slot=\"toast\"\n data-variant={variant}\n className={cn(toastVariants({ variant, className }))}\n {...props}\n >\n <ToastPrimitive.Content\n data-slot=\"toast-content\"\n className={cn(\n \"relative flex h-full flex-col gap-1 overflow-hidden p-4 pr-10\",\n // fade the stacked-behind content back in only when the viewport expands\n \"transition-opacity duration-normal ease-decelerate-mid data-behind:opacity-0 data-expanded:opacity-100\"\n )}\n >\n {children}\n </ToastPrimitive.Content>\n </ToastPrimitive.Root>\n );\n}\n\nfunction ToastTitle({\n className,\n ...props\n}: ComponentProps<typeof ToastPrimitive.Title>) {\n return (\n <ToastPrimitive.Title\n data-slot=\"toast-title\"\n className={cn(\"text-sm font-semibold\", className)}\n {...props}\n />\n );\n}\n\nfunction ToastDescription({\n className,\n ...props\n}: ComponentProps<typeof ToastPrimitive.Description>) {\n return (\n <ToastPrimitive.Description\n data-slot=\"toast-description\"\n className={cn(\"text-sm text-muted-foreground\", className)}\n {...props}\n />\n );\n}\n\n/**\n * Action — an optional in-toast button (e.g. \"Undo\"). Styled as the kit's\n * neutral outline button in miniature (conventions §4 neutral ramp), sitting\n * left-aligned under the message. Base UI closes the toast after the action\n * fires unless the handler prevents it.\n */\nfunction ToastAction({\n className,\n ...props\n}: ComponentProps<typeof ToastPrimitive.Action>) {\n return (\n <ToastPrimitive.Action\n data-slot=\"toast-action\"\n className={cn(\n \"mt-1 inline-flex h-8 w-fit shrink-0 items-center justify-center rounded-md border border-input bg-transparent px-3 text-sm font-medium\",\n \"cursor-pointer outline-none transition-colors duration-fast ease-ease\",\n \"hover:bg-accent hover:text-accent-foreground active:bg-accent/80 dark:bg-input/30 dark:hover:bg-input/50 dark:active:bg-input/70\",\n \"focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background\",\n \"disabled:pointer-events-none disabled:opacity-50 data-disabled:pointer-events-none data-disabled:opacity-50\",\n className\n )}\n {...props}\n />\n );\n}\n\n/**\n * Close — the icon-only ✕ dismiss button, absolutely positioned top-right (like\n * `dialog.tsx`'s built-in close). Accessible name comes from the `sr-only` span;\n * ✕ glyph is `DismissRegular` (which is what forces `\"use client\"`, §9). Base UI\n * marks it non-swipe-triggering automatically.\n */\nfunction ToastClose({\n className,\n ...props\n}: ComponentProps<typeof ToastPrimitive.Close>) {\n return (\n <ToastPrimitive.Close\n data-slot=\"toast-close\"\n className={cn(\n \"absolute top-3 right-3 flex size-7 items-center justify-center rounded-md text-muted-foreground\",\n \"cursor-pointer outline-none transition-colors duration-fast ease-ease\",\n \"hover:bg-accent hover:text-accent-foreground active:bg-accent/80 dark:hover:bg-accent/50 dark:active:bg-accent/70\",\n \"focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background\",\n \"disabled:pointer-events-none disabled:opacity-50\",\n \"[&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4\",\n className\n )}\n {...props}\n >\n <DismissRegular />\n <span className=\"sr-only\">Close</span>\n </ToastPrimitive.Close>\n );\n}\n\nconst useToast = ToastPrimitive.useToastManager;\nconst createToastManager = ToastPrimitive.createToastManager;\n\nexport {\n Toast,\n ToastProvider,\n ToastViewport,\n ToastTitle,\n ToastDescription,\n ToastAction,\n ToastClose,\n useToast,\n createToastManager,\n toastVariants,\n};\n"],"mappings":";AA2IS,cAuLL,YAvLK;AAzIT,SAAS,SAAS,sBAAsB;AACxC,SAAS,sBAAsB;AAC/B,SAAS,WAA8B;AAGvC,SAAS,UAAU;AAmInB,SAAS,cAAc,OAAuD;AAC5E,SAAO,oBAAC,eAAe,UAAf,EAAyB,GAAG,OAAO;AAC7C;AAQA,SAAS,cAAc;AAAA,EACrB;AAAA,EACA,GAAG;AACL,GAAmD;AACjD,SACE,oBAAC,eAAe,QAAf,EACC;AAAA,IAAC,eAAe;AAAA,IAAf;AAAA,MACC,aAAU;AAAA,MACV,WAAW;AAAA,QACT;AAAA,QACA;AAAA,MACF;AAAA,MACC,GAAG;AAAA;AAAA,EACN,GACF;AAEJ;AAaA,MAAM,gBAAgB;AAAA,EACpB;AAAA;AAAA;AAAA;AAAA,IAIE;AAAA,IACA;AAAA,IACA;AAAA;AAAA;AAAA,IAGA;AAAA,IACA;AAAA,IACA;AAAA;AAAA,IAEA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA;AAAA,IAEA;AAAA;AAAA,IAEA;AAAA,EACF;AAAA,EACA;AAAA,IACE,UAAU;AAAA,MACR,SAAS;AAAA,QACP,SAAS;AAAA,QACT,aACE;AAAA,QACF,SACE;AAAA,QACF,SACE;AAAA,QACF,MAAM;AAAA,MACR;AAAA,IACF;AAAA,IACA,iBAAiB;AAAA,MACf,SAAS;AAAA,IACX;AAAA,EACF;AACF;AAUA,SAAS,MAAM;AAAA,EACb;AAAA,EACA,UAAU;AAAA,EACV;AAAA,EACA,GAAG;AACL,GACsC;AACpC,SACE;AAAA,IAAC,eAAe;AAAA,IAAf;AAAA,MACC,aAAU;AAAA,MACV,gBAAc;AAAA,MACd,WAAW,GAAG,cAAc,EAAE,SAAS,UAAU,CAAC,CAAC;AAAA,MAClD,GAAG;AAAA,MAEJ;AAAA,QAAC,eAAe;AAAA,QAAf;AAAA,UACC,aAAU;AAAA,UACV,WAAW;AAAA,YACT;AAAA;AAAA,YAEA;AAAA,UACF;AAAA,UAEC;AAAA;AAAA,MACH;AAAA;AAAA,EACF;AAEJ;AAEA,SAAS,WAAW;AAAA,EAClB;AAAA,EACA,GAAG;AACL,GAAgD;AAC9C,SACE;AAAA,IAAC,eAAe;AAAA,IAAf;AAAA,MACC,aAAU;AAAA,MACV,WAAW,GAAG,yBAAyB,SAAS;AAAA,MAC/C,GAAG;AAAA;AAAA,EACN;AAEJ;AAEA,SAAS,iBAAiB;AAAA,EACxB;AAAA,EACA,GAAG;AACL,GAAsD;AACpD,SACE;AAAA,IAAC,eAAe;AAAA,IAAf;AAAA,MACC,aAAU;AAAA,MACV,WAAW,GAAG,iCAAiC,SAAS;AAAA,MACvD,GAAG;AAAA;AAAA,EACN;AAEJ;AAQA,SAAS,YAAY;AAAA,EACnB;AAAA,EACA,GAAG;AACL,GAAiD;AAC/C,SACE;AAAA,IAAC,eAAe;AAAA,IAAf;AAAA,MACC,aAAU;AAAA,MACV,WAAW;AAAA,QACT;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,MACF;AAAA,MACC,GAAG;AAAA;AAAA,EACN;AAEJ;AAQA,SAAS,WAAW;AAAA,EAClB;AAAA,EACA,GAAG;AACL,GAAgD;AAC9C,SACE;AAAA,IAAC,eAAe;AAAA,IAAf;AAAA,MACC,aAAU;AAAA,MACV,WAAW;AAAA,QACT;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,MACF;AAAA,MACC,GAAG;AAAA,MAEJ;AAAA,4BAAC,kBAAe;AAAA,QAChB,oBAAC,UAAK,WAAU,WAAU,mBAAK;AAAA;AAAA;AAAA,EACjC;AAEJ;AAEA,MAAM,WAAW,eAAe;AAChC,MAAM,qBAAqB,eAAe;","names":[]}