@seekalfred/primitives 0.2.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (157) hide show
  1. package/README.md +950 -13
  2. package/dist/accordion/accordion.d.ts +107 -0
  3. package/dist/accordion/accordion.js +84 -0
  4. package/dist/accordion/accordion.js.map +1 -0
  5. package/dist/accordion/index.d.ts +2 -0
  6. package/dist/accordion/index.js +2 -0
  7. package/dist/alert/alert.d.ts +68 -0
  8. package/dist/alert/alert.js +67 -0
  9. package/dist/alert/alert.js.map +1 -0
  10. package/dist/alert/index.d.ts +2 -0
  11. package/dist/alert/index.js +2 -0
  12. package/dist/alert-dialog/alert-dialog.d.ts +53 -0
  13. package/dist/alert-dialog/alert-dialog.js +16 -0
  14. package/dist/alert-dialog/alert-dialog.js.map +1 -0
  15. package/dist/alert-dialog/index.d.ts +2 -0
  16. package/dist/alert-dialog/index.js +2 -0
  17. package/dist/avatar/avatar.d.ts +50 -0
  18. package/dist/avatar/avatar.js +91 -0
  19. package/dist/avatar/avatar.js.map +1 -0
  20. package/dist/avatar/index.d.ts +2 -0
  21. package/dist/avatar/index.js +2 -0
  22. package/dist/badge/badge.d.ts +47 -0
  23. package/dist/badge/badge.js +189 -0
  24. package/dist/badge/badge.js.map +1 -0
  25. package/dist/badge/index.d.ts +2 -0
  26. package/dist/badge/index.js +2 -0
  27. package/dist/breadcrumb/breadcrumb.d.ts +98 -0
  28. package/dist/breadcrumb/breadcrumb.js +93 -0
  29. package/dist/breadcrumb/breadcrumb.js.map +1 -0
  30. package/dist/breadcrumb/index.d.ts +2 -0
  31. package/dist/breadcrumb/index.js +2 -0
  32. package/dist/button/button.d.ts +1 -1
  33. package/dist/button/button.js +7 -0
  34. package/dist/button/button.js.map +1 -1
  35. package/dist/calendar/calendar.d.ts +154 -0
  36. package/dist/calendar/calendar.js +282 -0
  37. package/dist/calendar/calendar.js.map +1 -0
  38. package/dist/calendar/index.d.ts +2 -0
  39. package/dist/calendar/index.js +2 -0
  40. package/dist/card/card.d.ts +93 -0
  41. package/dist/card/card.js +105 -0
  42. package/dist/card/card.js.map +1 -0
  43. package/dist/card/index.d.ts +2 -0
  44. package/dist/card/index.js +2 -0
  45. package/dist/checkbox/checkbox.d.ts +63 -0
  46. package/dist/checkbox/checkbox.js +94 -0
  47. package/dist/checkbox/checkbox.js.map +1 -0
  48. package/dist/checkbox/index.d.ts +2 -0
  49. package/dist/checkbox/index.js +2 -0
  50. package/dist/dialog/dialog.d.ts +140 -0
  51. package/dist/dialog/dialog.js +127 -0
  52. package/dist/dialog/dialog.js.map +1 -0
  53. package/dist/dialog/index.d.ts +2 -0
  54. package/dist/dialog/index.js +2 -0
  55. package/dist/index.d.ts +30 -1
  56. package/dist/index.js +30 -1
  57. package/dist/input/index.d.ts +2 -0
  58. package/dist/input/index.js +2 -0
  59. package/dist/input/input.d.ts +64 -0
  60. package/dist/input/input.js +94 -0
  61. package/dist/input/input.js.map +1 -0
  62. package/dist/label/index.d.ts +2 -0
  63. package/dist/label/index.js +2 -0
  64. package/dist/label/label.d.ts +41 -0
  65. package/dist/label/label.js +44 -0
  66. package/dist/label/label.js.map +1 -0
  67. package/dist/lib/field-surface.js +40 -0
  68. package/dist/lib/field-surface.js.map +1 -0
  69. package/dist/lib/selection-control.js +57 -0
  70. package/dist/lib/selection-control.js.map +1 -0
  71. package/dist/menu/index.d.ts +2 -0
  72. package/dist/menu/index.js +2 -0
  73. package/dist/menu/menu.d.ts +98 -0
  74. package/dist/menu/menu.js +99 -0
  75. package/dist/menu/menu.js.map +1 -0
  76. package/dist/popover/index.d.ts +2 -0
  77. package/dist/popover/index.js +2 -0
  78. package/dist/popover/popover.d.ts +50 -0
  79. package/dist/popover/popover.js +46 -0
  80. package/dist/popover/popover.js.map +1 -0
  81. package/dist/progress/index.d.ts +2 -0
  82. package/dist/progress/index.js +2 -0
  83. package/dist/progress/progress.d.ts +82 -0
  84. package/dist/progress/progress.js +82 -0
  85. package/dist/progress/progress.js.map +1 -0
  86. package/dist/radio-group/index.d.ts +2 -0
  87. package/dist/radio-group/index.js +2 -0
  88. package/dist/radio-group/radio-group.d.ts +53 -0
  89. package/dist/radio-group/radio-group.js +65 -0
  90. package/dist/radio-group/radio-group.js.map +1 -0
  91. package/dist/scroll-area/index.d.ts +2 -0
  92. package/dist/scroll-area/index.js +2 -0
  93. package/dist/scroll-area/scroll-area.d.ts +74 -0
  94. package/dist/scroll-area/scroll-area.js +63 -0
  95. package/dist/scroll-area/scroll-area.js.map +1 -0
  96. package/dist/select/index.d.ts +2 -0
  97. package/dist/select/index.js +2 -0
  98. package/dist/select/select.d.ts +93 -0
  99. package/dist/select/select.js +132 -0
  100. package/dist/select/select.js.map +1 -0
  101. package/dist/separator/index.d.ts +2 -0
  102. package/dist/separator/index.js +2 -0
  103. package/dist/separator/separator.d.ts +42 -0
  104. package/dist/separator/separator.js +49 -0
  105. package/dist/separator/separator.js.map +1 -0
  106. package/dist/sheet/index.d.ts +2 -0
  107. package/dist/sheet/index.js +2 -0
  108. package/dist/sheet/sheet.d.ts +96 -0
  109. package/dist/sheet/sheet.js +98 -0
  110. package/dist/sheet/sheet.js.map +1 -0
  111. package/dist/skeleton/index.d.ts +2 -0
  112. package/dist/skeleton/index.js +2 -0
  113. package/dist/skeleton/skeleton.d.ts +33 -0
  114. package/dist/skeleton/skeleton.js +42 -0
  115. package/dist/skeleton/skeleton.js.map +1 -0
  116. package/dist/slider/index.d.ts +2 -0
  117. package/dist/slider/index.js +2 -0
  118. package/dist/slider/slider.d.ts +70 -0
  119. package/dist/slider/slider.js +92 -0
  120. package/dist/slider/slider.js.map +1 -0
  121. package/dist/spinner/index.d.ts +2 -0
  122. package/dist/spinner/index.js +2 -0
  123. package/dist/spinner/spinner.d.ts +75 -0
  124. package/dist/spinner/spinner.js +68 -0
  125. package/dist/spinner/spinner.js.map +1 -0
  126. package/dist/styles.css +1 -1
  127. package/dist/switch/index.d.ts +2 -0
  128. package/dist/switch/index.js +2 -0
  129. package/dist/switch/switch.d.ts +50 -0
  130. package/dist/switch/switch.js +66 -0
  131. package/dist/switch/switch.js.map +1 -0
  132. package/dist/table/index.d.ts +2 -0
  133. package/dist/table/index.js +2 -0
  134. package/dist/table/table.d.ts +288 -0
  135. package/dist/table/table.js +513 -0
  136. package/dist/table/table.js.map +1 -0
  137. package/dist/tabs/index.d.ts +2 -0
  138. package/dist/tabs/index.js +2 -0
  139. package/dist/tabs/tabs.d.ts +79 -0
  140. package/dist/tabs/tabs.js +103 -0
  141. package/dist/tabs/tabs.js.map +1 -0
  142. package/dist/textarea/index.d.ts +2 -0
  143. package/dist/textarea/index.js +2 -0
  144. package/dist/textarea/textarea.d.ts +27 -0
  145. package/dist/textarea/textarea.js +37 -0
  146. package/dist/textarea/textarea.js.map +1 -0
  147. package/dist/toast/index.d.ts +2 -0
  148. package/dist/toast/index.js +2 -0
  149. package/dist/toast/toast.d.ts +93 -0
  150. package/dist/toast/toast.js +145 -0
  151. package/dist/toast/toast.js.map +1 -0
  152. package/dist/tooltip/index.d.ts +2 -0
  153. package/dist/tooltip/index.js +2 -0
  154. package/dist/tooltip/tooltip.d.ts +70 -0
  155. package/dist/tooltip/tooltip.js +65 -0
  156. package/dist/tooltip/tooltip.js.map +1 -0
  157. package/package.json +125 -7
@@ -0,0 +1,79 @@
1
+ import { TabListProps, TabPanelProps, TabProps, TabsProps } from "react-aria-components";
2
+ //#region src/tabs/tabs.d.ts
3
+ /**
4
+ * Tabs, ported from the legacy shadcn/Radix component.
5
+ *
6
+ * The largest legacy surface in this migration: 18 files, `TabsTrigger`
7
+ * 51, `TabsContent` 31, `Tabs` 17, `TabsList` 17. Props: `value` 88,
8
+ * `className` 76, `defaultValue` 12, `onValueChange` 10, `disabled` 6.
9
+ *
10
+ * The rename is mechanical but it touches every one of those:
11
+ * `value` -> `selectedKey`, `defaultValue` -> `defaultSelectedKey`,
12
+ * `onValueChange` -> `onSelectionChange`, and the `value` on each trigger
13
+ * and panel becomes `id`. React Aria pairs a Tab to its TabPanel by that
14
+ * id, exactly as Radix paired them by value.
15
+ *
16
+ * THE SELECTED TAB GAINS A BORDER, and that is a contrast fix rather than
17
+ * a decoration. The legacy marks the selected tab with `bg-background` on
18
+ * a `bg-muted` list -- 1.13:1, which is not a boundary anybody can see --
19
+ * and leans on `shadow-sm` to carry the rest. Under WCAG 1.4.11 the thing
20
+ * telling you which tab is active has to clear 3:1. `border-border` on
21
+ * `muted` is 4.65:1 and is already in the contrast contract.
22
+ *
23
+ * Two bracket values are gone because check:hardcoding rejects them:
24
+ * `p-[3px]` on the list and `h-[calc(100%-1px)]` on the trigger. The list
25
+ * is `p-1` and the trigger sizes to the list rather than to a value one
26
+ * pixel short of it.
27
+ *
28
+ * ONE BEHAVIOUR DIFFERS AND IS WORTH KNOWING. Radix keeps every mounted
29
+ * TabsContent in the DOM and hides the inactive ones; React Aria renders
30
+ * ONLY the selected panel. A panel that holds uncommitted form state, a
31
+ * running video or a scroll position will lose it on tab change. React
32
+ * Aria's `shouldForceMount` on TabPanel restores the old behaviour where
33
+ * a call site needs it.
34
+ */
35
+ export declare const tabsVariants: (props?: import("class-variance-authority/types").ClassProp | undefined) => string;
36
+ export declare const tabListVariants: (props?: import("class-variance-authority/types").ClassProp | undefined) => string;
37
+ export declare const tabVariants: (props?: import("class-variance-authority/types").ClassProp | undefined) => string;
38
+ export declare const tabPanelVariants: (props?: import("class-variance-authority/types").ClassProp | undefined) => string;
39
+ /**
40
+ * A set of panels, one visible at a time.
41
+ *
42
+ * @example
43
+ * <Tabs defaultSelectedKey="overview">
44
+ * <TabList aria-label="Sections">
45
+ * <Tab id="overview">Overview</Tab>
46
+ * <Tab id="activity">Activity</Tab>
47
+ * </TabList>
48
+ * <TabPanel id="overview">...</TabPanel>
49
+ * <TabPanel id="activity">...</TabPanel>
50
+ * </Tabs>
51
+ */
52
+ interface TabsProps$1 extends Omit<TabsProps, "className" | "style"> {
53
+ /** Extra classes. Merged last, so they win conflicts with ours. */
54
+ className?: string;
55
+ }
56
+ declare function Tabs$1({ className, ...props }: TabsProps$1): import("react").JSX.Element;
57
+ /**
58
+ * The row of tabs.
59
+ *
60
+ * `aria-label` is worth passing: a tablist is a landmark-ish grouping and
61
+ * a page with two of them is ambiguous without one.
62
+ */
63
+ interface TabListProps$1 extends Omit<TabListProps<object>, "className" | "style"> {
64
+ className?: string;
65
+ }
66
+ declare function TabList$1({ className, ...props }: TabListProps$1): import("react").JSX.Element;
67
+ /** One tab. Its `id` pairs it with the panel of the same `id`. */
68
+ interface TabProps$1 extends Omit<TabProps, "className" | "style"> {
69
+ className?: string;
70
+ }
71
+ declare function Tab$1({ className, ...props }: TabProps$1): import("react").JSX.Element;
72
+ /** One panel. Its `id` pairs it with the tab of the same `id`. */
73
+ interface TabPanelProps$1 extends Omit<TabPanelProps, "className" | "style"> {
74
+ className?: string;
75
+ }
76
+ declare function TabPanel$1({ className, ...props }: TabPanelProps$1): import("react").JSX.Element;
77
+ //#endregion
78
+ export { Tab$1 as Tab, TabList$1 as TabList, TabListProps$1 as TabListProps, TabPanel$1 as TabPanel, TabPanelProps$1 as TabPanelProps, TabProps$1 as TabProps, Tabs$1 as Tabs, TabsProps$1 as TabsProps };
79
+ //# sourceMappingURL=tabs.d.ts.map
@@ -0,0 +1,103 @@
1
+ "use client";
2
+ import { cn } from "../lib/cn.js";
3
+ import { cva } from "class-variance-authority";
4
+ import { Tab, TabList, TabPanel, Tabs } from "react-aria-components";
5
+ import { jsx } from "react/jsx-runtime";
6
+ //#region src/tabs/tabs.tsx
7
+ /**
8
+ * Tabs, ported from the legacy shadcn/Radix component.
9
+ *
10
+ * The largest legacy surface in this migration: 18 files, `TabsTrigger`
11
+ * 51, `TabsContent` 31, `Tabs` 17, `TabsList` 17. Props: `value` 88,
12
+ * `className` 76, `defaultValue` 12, `onValueChange` 10, `disabled` 6.
13
+ *
14
+ * The rename is mechanical but it touches every one of those:
15
+ * `value` -> `selectedKey`, `defaultValue` -> `defaultSelectedKey`,
16
+ * `onValueChange` -> `onSelectionChange`, and the `value` on each trigger
17
+ * and panel becomes `id`. React Aria pairs a Tab to its TabPanel by that
18
+ * id, exactly as Radix paired them by value.
19
+ *
20
+ * THE SELECTED TAB GAINS A BORDER, and that is a contrast fix rather than
21
+ * a decoration. The legacy marks the selected tab with `bg-background` on
22
+ * a `bg-muted` list -- 1.13:1, which is not a boundary anybody can see --
23
+ * and leans on `shadow-sm` to carry the rest. Under WCAG 1.4.11 the thing
24
+ * telling you which tab is active has to clear 3:1. `border-border` on
25
+ * `muted` is 4.65:1 and is already in the contrast contract.
26
+ *
27
+ * Two bracket values are gone because check:hardcoding rejects them:
28
+ * `p-[3px]` on the list and `h-[calc(100%-1px)]` on the trigger. The list
29
+ * is `p-1` and the trigger sizes to the list rather than to a value one
30
+ * pixel short of it.
31
+ *
32
+ * ONE BEHAVIOUR DIFFERS AND IS WORTH KNOWING. Radix keeps every mounted
33
+ * TabsContent in the DOM and hides the inactive ones; React Aria renders
34
+ * ONLY the selected panel. A panel that holds uncommitted form state, a
35
+ * running video or a scroll position will lose it on tab change. React
36
+ * Aria's `shouldForceMount` on TabPanel restores the old behaviour where
37
+ * a call site needs it.
38
+ */
39
+ const tabsVariants = cva(["flex flex-col gap-2 box-border font-sans"]);
40
+ const tabListVariants = cva([
41
+ "inline-flex w-fit items-center justify-center gap-1",
42
+ "rounded-lg p-1",
43
+ "bg-muted text-muted-foreground",
44
+ "box-border"
45
+ ]);
46
+ const tabVariants = cva([
47
+ "inline-flex flex-1 items-center justify-center gap-1.5 whitespace-nowrap",
48
+ "rounded-md px-2 py-1",
49
+ "text-sm leading-(--leading-normal) font-medium text-foreground",
50
+ "cursor-pointer select-none box-border",
51
+ "border-(length:--border-width) border-transparent",
52
+ "motion-safe:transition-colors motion-safe:duration-(--duration-fast) motion-safe:ease-standard",
53
+ "data-[selected]:bg-background data-[selected]:border-border",
54
+ "data-[selected]:shadow-surface",
55
+ "outline-none",
56
+ "data-[focus-visible]:outline-solid",
57
+ "data-[focus-visible]:outline-(length:--focus-ring-width)",
58
+ "data-[focus-visible]:outline-offset-(--focus-ring-offset)",
59
+ "data-[focus-visible]:outline-(--color-ring)",
60
+ "data-[disabled]:cursor-not-allowed data-[disabled]:opacity-(--opacity-disabled)",
61
+ "[&_svg]:pointer-events-none [&_svg]:shrink-0",
62
+ "[&_svg:not([class*='size-'])]:size-(--icon-sm)"
63
+ ]);
64
+ const tabPanelVariants = cva([
65
+ "flex-1 box-border font-sans text-foreground",
66
+ "outline-none",
67
+ "data-[focus-visible]:outline-solid",
68
+ "data-[focus-visible]:outline-(length:--focus-ring-width)",
69
+ "data-[focus-visible]:outline-offset-(--focus-ring-offset)",
70
+ "data-[focus-visible]:outline-(--color-ring)"
71
+ ]);
72
+ function Tabs$1({ className, ...props }) {
73
+ return /* @__PURE__ */ jsx(Tabs, {
74
+ ...props,
75
+ "data-slot": "tabs",
76
+ className: cn(tabsVariants(), className)
77
+ });
78
+ }
79
+ function TabList$1({ className, ...props }) {
80
+ return /* @__PURE__ */ jsx(TabList, {
81
+ ...props,
82
+ "data-slot": "tab-list",
83
+ className: cn(tabListVariants(), className)
84
+ });
85
+ }
86
+ function Tab$1({ className, ...props }) {
87
+ return /* @__PURE__ */ jsx(Tab, {
88
+ ...props,
89
+ "data-slot": "tab",
90
+ className: cn(tabVariants(), className)
91
+ });
92
+ }
93
+ function TabPanel$1({ className, ...props }) {
94
+ return /* @__PURE__ */ jsx(TabPanel, {
95
+ ...props,
96
+ "data-slot": "tab-panel",
97
+ className: cn(tabPanelVariants(), className)
98
+ });
99
+ }
100
+ //#endregion
101
+ export { Tab$1 as Tab, TabList$1 as TabList, TabPanel$1 as TabPanel, Tabs$1 as Tabs, tabListVariants, tabPanelVariants, tabVariants, tabsVariants };
102
+
103
+ //# sourceMappingURL=tabs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tabs.js","names":["Tabs","AriaTabs","TabList","AriaTabList","Tab","AriaTab","TabPanel","AriaTabPanel"],"sources":["../../src/tabs/tabs.tsx"],"sourcesContent":["\"use client\";\n\nimport { cva } from \"class-variance-authority\";\nimport {\n Tab as AriaTab,\n TabList as AriaTabList,\n TabPanel as AriaTabPanel,\n Tabs as AriaTabs,\n type TabListProps as AriaTabListProps,\n type TabPanelProps as AriaTabPanelProps,\n type TabProps as AriaTabProps,\n type TabsProps as AriaTabsProps,\n} from \"react-aria-components\";\n\nimport { cn } from \"../lib/cn.js\";\n\n/**\n * Tabs, ported from the legacy shadcn/Radix component.\n *\n * The largest legacy surface in this migration: 18 files, `TabsTrigger`\n * 51, `TabsContent` 31, `Tabs` 17, `TabsList` 17. Props: `value` 88,\n * `className` 76, `defaultValue` 12, `onValueChange` 10, `disabled` 6.\n *\n * The rename is mechanical but it touches every one of those:\n * `value` -> `selectedKey`, `defaultValue` -> `defaultSelectedKey`,\n * `onValueChange` -> `onSelectionChange`, and the `value` on each trigger\n * and panel becomes `id`. React Aria pairs a Tab to its TabPanel by that\n * id, exactly as Radix paired them by value.\n *\n * THE SELECTED TAB GAINS A BORDER, and that is a contrast fix rather than\n * a decoration. The legacy marks the selected tab with `bg-background` on\n * a `bg-muted` list -- 1.13:1, which is not a boundary anybody can see --\n * and leans on `shadow-sm` to carry the rest. Under WCAG 1.4.11 the thing\n * telling you which tab is active has to clear 3:1. `border-border` on\n * `muted` is 4.65:1 and is already in the contrast contract.\n *\n * Two bracket values are gone because check:hardcoding rejects them:\n * `p-[3px]` on the list and `h-[calc(100%-1px)]` on the trigger. The list\n * is `p-1` and the trigger sizes to the list rather than to a value one\n * pixel short of it.\n *\n * ONE BEHAVIOUR DIFFERS AND IS WORTH KNOWING. Radix keeps every mounted\n * TabsContent in the DOM and hides the inactive ones; React Aria renders\n * ONLY the selected panel. A panel that holds uncommitted form state, a\n * running video or a scroll position will lose it on tab change. React\n * Aria's `shouldForceMount` on TabPanel restores the old behaviour where\n * a call site needs it.\n */\nexport const tabsVariants = cva([\"flex flex-col gap-2 box-border font-sans\"]);\n\nexport const tabListVariants = cva([\n \"inline-flex w-fit items-center justify-center gap-1\",\n // p-1, not the legacy p-[3px]: a bracket value check:hardcoding rejects.\n \"rounded-lg p-1\",\n \"bg-muted text-muted-foreground\",\n \"box-border\",\n]);\n\nexport const tabVariants = cva([\n \"inline-flex flex-1 items-center justify-center gap-1.5 whitespace-nowrap\",\n \"rounded-md px-2 py-1\",\n \"text-sm leading-(--leading-normal) font-medium text-foreground\",\n \"cursor-pointer select-none box-border\",\n // A transparent border at rest so selecting one does not move the text.\n \"border-(length:--border-width) border-transparent\",\n \"motion-safe:transition-colors motion-safe:duration-(--duration-fast) motion-safe:ease-standard\",\n\n // The selected tab. bg-background on a muted list is 1.13:1 -- invisible\n // as a boundary -- so the border is what satisfies WCAG 1.4.11 at\n // 4.65:1. The fill and the shadow are the polish on top of it.\n \"data-[selected]:bg-background data-[selected]:border-border\",\n \"data-[selected]:shadow-surface\",\n\n // outline-solid is load-bearing: outline-none sets --tw-outline-style to\n // none and the width utility resolves its style from that same variable,\n // so a focus rule can apply a width and a colour and paint 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 \"data-[disabled]:cursor-not-allowed data-[disabled]:opacity-(--opacity-disabled)\",\n \"[&_svg]:pointer-events-none [&_svg]:shrink-0\",\n \"[&_svg:not([class*='size-'])]:size-(--icon-sm)\",\n]);\n\nexport const tabPanelVariants = cva([\n \"flex-1 box-border font-sans text-foreground\",\n // React Aria gives the panel tabindex=0 when it holds no focusable\n // child, so it can take a ring it does not want at rest.\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\n/**\n * A set of panels, one visible at a time.\n *\n * @example\n * <Tabs defaultSelectedKey=\"overview\">\n * <TabList aria-label=\"Sections\">\n * <Tab id=\"overview\">Overview</Tab>\n * <Tab id=\"activity\">Activity</Tab>\n * </TabList>\n * <TabPanel id=\"overview\">...</TabPanel>\n * <TabPanel id=\"activity\">...</TabPanel>\n * </Tabs>\n */\nexport interface TabsProps extends Omit<AriaTabsProps, \"className\" | \"style\"> {\n /** Extra classes. Merged last, so they win conflicts with ours. */\n className?: string;\n}\n\nexport function Tabs({ className, ...props }: TabsProps) {\n return <AriaTabs {...props} data-slot=\"tabs\" className={cn(tabsVariants(), className)} />;\n}\n\n/**\n * The row of tabs.\n *\n * `aria-label` is worth passing: a tablist is a landmark-ish grouping and\n * a page with two of them is ambiguous without one.\n */\nexport interface TabListProps extends Omit<AriaTabListProps<object>, \"className\" | \"style\"> {\n className?: string;\n}\n\nexport function TabList({ className, ...props }: TabListProps) {\n return (\n <AriaTabList {...props} data-slot=\"tab-list\" className={cn(tabListVariants(), className)} />\n );\n}\n\n/** One tab. Its `id` pairs it with the panel of the same `id`. */\nexport interface TabProps extends Omit<AriaTabProps, \"className\" | \"style\"> {\n className?: string;\n}\n\nexport function Tab({ className, ...props }: TabProps) {\n return <AriaTab {...props} data-slot=\"tab\" className={cn(tabVariants(), className)} />;\n}\n\n/** One panel. Its `id` pairs it with the tab of the same `id`. */\nexport interface TabPanelProps extends Omit<AriaTabPanelProps, \"className\" | \"style\"> {\n className?: string;\n}\n\nexport function TabPanel({ className, ...props }: TabPanelProps) {\n return (\n <AriaTabPanel {...props} data-slot=\"tab-panel\" className={cn(tabPanelVariants(), className)} />\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAgDA,MAAa,eAAe,IAAI,CAAC,0CAA0C,CAAC;AAE5E,MAAa,kBAAkB,IAAI;CACjC;CAEA;CACA;CACA;AACF,CAAC;AAED,MAAa,cAAc,IAAI;CAC7B;CACA;CACA;CACA;CAEA;CACA;CAKA;CACA;CAKA;CACA;CACA;CACA;CACA;CAEA;CACA;CACA;AACF,CAAC;AAED,MAAa,mBAAmB,IAAI;CAClC;CAGA;CACA;CACA;CACA;CACA;AACF,CAAC;AAoBD,SAAgBA,OAAK,EAAE,WAAW,GAAG,SAAoB;CACvD,OAAO,oBAACC,MAAD;EAAU,GAAI;EAAO,aAAU;EAAO,WAAW,GAAG,aAAa,GAAG,SAAS;CAAI,CAAA;AAC1F;AAYA,SAAgBC,UAAQ,EAAE,WAAW,GAAG,SAAuB;CAC7D,OACE,oBAACC,SAAD;EAAa,GAAI;EAAO,aAAU;EAAW,WAAW,GAAG,gBAAgB,GAAG,SAAS;CAAI,CAAA;AAE/F;AAOA,SAAgBC,MAAI,EAAE,WAAW,GAAG,SAAmB;CACrD,OAAO,oBAACC,KAAD;EAAS,GAAI;EAAO,aAAU;EAAM,WAAW,GAAG,YAAY,GAAG,SAAS;CAAI,CAAA;AACvF;AAOA,SAAgBC,WAAS,EAAE,WAAW,GAAG,SAAwB;CAC/D,OACE,oBAACC,UAAD;EAAc,GAAI;EAAO,aAAU;EAAY,WAAW,GAAG,iBAAiB,GAAG,SAAS;CAAI,CAAA;AAElG"}
@@ -0,0 +1,2 @@
1
+ import { Textarea, TextareaProps, textareaVariants } from "./textarea.js";
2
+ export { Textarea, type TextareaProps, textareaVariants };
@@ -0,0 +1,2 @@
1
+ import { Textarea, textareaVariants } from "./textarea.js";
2
+ export { Textarea, textareaVariants };
@@ -0,0 +1,27 @@
1
+ import { TextAreaProps } from "react-aria-components";
2
+ //#region src/textarea/textarea.d.ts
3
+ /**
4
+ * Textarea, ported from the legacy component onto React Aria's TextArea.
5
+ *
6
+ * Census: 3 files, 3 uses -- `value`, `onChange`, `placeholder`, `id`,
7
+ * `ref`. All native props, all still native here.
8
+ *
9
+ * The surface comes from `fieldSurfaceVariants`, shared with Input. The two
10
+ * legacy files styled it separately and had already drifted -- different
11
+ * background, different focus ring, invalid styling on one and not the
12
+ * other -- and none of those differences was a decision anyone made.
13
+ */
14
+ export declare const textareaVariants: (props?: import("class-variance-authority/types").ClassProp | undefined) => string;
15
+ /**
16
+ * A multi-line text field.
17
+ *
18
+ * @example
19
+ * <Textarea placeholder="Tell us more" value={v} onChange={e => set(e.target.value)} />
20
+ */
21
+ export interface TextareaProps extends Omit<TextAreaProps, "className" | "style"> {
22
+ /** Extra classes. Merged last, so they win conflicts with ours. */
23
+ className?: string;
24
+ }
25
+ export declare function Textarea({ className, ...props }: TextareaProps): import("react").JSX.Element;
26
+ //#endregion
27
+ //# sourceMappingURL=textarea.d.ts.map
@@ -0,0 +1,37 @@
1
+ "use client";
2
+ import { cn } from "../lib/cn.js";
3
+ import { fieldSurfaceVariants } from "../lib/field-surface.js";
4
+ import { cva } from "class-variance-authority";
5
+ import { TextArea } from "react-aria-components";
6
+ import { jsx } from "react/jsx-runtime";
7
+ //#region src/textarea/textarea.tsx
8
+ /**
9
+ * Textarea, ported from the legacy component onto React Aria's TextArea.
10
+ *
11
+ * Census: 3 files, 3 uses -- `value`, `onChange`, `placeholder`, `id`,
12
+ * `ref`. All native props, all still native here.
13
+ *
14
+ * The surface comes from `fieldSurfaceVariants`, shared with Input. The two
15
+ * legacy files styled it separately and had already drifted -- different
16
+ * background, different focus ring, invalid styling on one and not the
17
+ * other -- and none of those differences was a decision anyone made.
18
+ */
19
+ const textareaVariants = cva([
20
+ fieldSurfaceVariants(),
21
+ "min-h-20",
22
+ "px-(--density-control-pad-md) py-(--density-control-pad-sm)",
23
+ "text-base",
24
+ "resize-y",
25
+ "leading-(--leading-normal)"
26
+ ]);
27
+ function Textarea({ className, ...props }) {
28
+ return /* @__PURE__ */ jsx(TextArea, {
29
+ ...props,
30
+ "data-slot": "textarea",
31
+ className: cn(textareaVariants(), className)
32
+ });
33
+ }
34
+ //#endregion
35
+ export { Textarea, textareaVariants };
36
+
37
+ //# sourceMappingURL=textarea.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"textarea.js","names":["AriaTextArea"],"sources":["../../src/textarea/textarea.tsx"],"sourcesContent":["\"use client\";\n\nimport { cva } from \"class-variance-authority\";\nimport {\n TextArea as AriaTextArea,\n type TextAreaProps as AriaTextAreaProps,\n} from \"react-aria-components\";\n\nimport { cn } from \"../lib/cn.js\";\nimport { fieldSurfaceVariants } from \"../lib/field-surface.js\";\n\n/**\n * Textarea, ported from the legacy component onto React Aria's TextArea.\n *\n * Census: 3 files, 3 uses -- `value`, `onChange`, `placeholder`, `id`,\n * `ref`. All native props, all still native here.\n *\n * The surface comes from `fieldSurfaceVariants`, shared with Input. The two\n * legacy files styled it separately and had already drifted -- different\n * background, different focus ring, invalid styling on one and not the\n * other -- and none of those differences was a decision anyone made.\n */\nexport const textareaVariants = cva([\n fieldSurfaceVariants(),\n\n // min-h-20 is 80px, the legacy min-h-[80px] -- but as a spacing-scale step\n // rather than a bracket value, which check:hardcoding rejects.\n \"min-h-20\",\n \"px-(--density-control-pad-md) py-(--density-control-pad-sm)\",\n \"text-base\",\n\n // A textarea is resizable by the user agent, and horizontal resize breaks\n // any layout it sits in. Vertical only.\n \"resize-y\",\n // Height is content, not a control slot, so the line-height has to be set\n // explicitly -- unset it computes to `normal`, which varies with the\n // font's own metrics.\n \"leading-(--leading-normal)\",\n]);\n\n/**\n * A multi-line text field.\n *\n * @example\n * <Textarea placeholder=\"Tell us more\" value={v} onChange={e => set(e.target.value)} />\n */\nexport interface TextareaProps extends Omit<AriaTextAreaProps, \"className\" | \"style\"> {\n /** Extra classes. Merged last, so they win conflicts with ours. */\n className?: string;\n}\n\nexport function Textarea({ className, ...props }: TextareaProps) {\n return (\n <AriaTextArea {...props} data-slot=\"textarea\" className={cn(textareaVariants(), className)} />\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AAsBA,MAAa,mBAAmB,IAAI;CAClC,qBAAqB;CAIrB;CACA;CACA;CAIA;CAIA;AACF,CAAC;AAaD,SAAgB,SAAS,EAAE,WAAW,GAAG,SAAwB;CAC/D,OACE,oBAACA,UAAD;EAAc,GAAI;EAAO,aAAU;EAAW,WAAW,GAAG,iBAAiB,GAAG,SAAS;CAAI,CAAA;AAEjG"}
@@ -0,0 +1,2 @@
1
+ import { ToastContent, ToastRegion, ToastRegionProps, toast, toastCloseVariants, toastQueue, toastRegionVariants, toastVariants } from "./toast.js";
2
+ export { type ToastContent, ToastRegion, type ToastRegionProps, toast, toastCloseVariants, toastQueue, toastRegionVariants, toastVariants };
@@ -0,0 +1,2 @@
1
+ import { ToastRegion, toast, toastCloseVariants, toastQueue, toastRegionVariants, toastVariants } from "./toast.js";
2
+ export { ToastRegion, toast, toastCloseVariants, toastQueue, toastRegionVariants, toastVariants };
@@ -0,0 +1,93 @@
1
+ import { VariantProps } from "class-variance-authority";
2
+ import { UNSTABLE_ToastQueue } from "react-aria-components";
3
+ import { ReactNode } from "react";
4
+ //#region src/toast/toast.d.ts
5
+ /**
6
+ * Toast: a transient message, announced without stealing focus.
7
+ *
8
+ * Maturity: **experimental**, and the reason is upstream rather than here.
9
+ * React Aria ships this API as `UNSTABLE_Toast*` in 1.21.1, so a RAC minor
10
+ * bump can rename or reshape it. The alternative was hand-rolling the live
11
+ * region, the queue, the timers and the focus behaviour, which is how every
12
+ * toast implementation acquires its accessibility bugs -- so this takes the
13
+ * upstream one and labels the risk instead of hiding it.
14
+ *
15
+ * THE PRODUCT HAS 30 FILES CALLING `useToast` AND 67 `toast(...)` CALLS, and
16
+ * its implementation is the shadcn reducer with both of its known defects
17
+ * still in place:
18
+ *
19
+ * TOAST_LIMIT = 1 -- a second toast REPLACES the first, so a
20
+ * burst of results shows only the last one.
21
+ * TOAST_REMOVE_DELAY = 1e6 -- sixteen minutes. Nothing auto-dismisses;
22
+ * every toast waits to be closed by hand.
23
+ *
24
+ * Neither is ported. `maxVisibleToasts` defaults to 3 and `timeout` to 5s,
25
+ * which is the WCAG 2.2.1 floor React Aria enforces -- it REFUSES a timeout
26
+ * under 5000ms, because a message that vanishes faster cannot be read by
27
+ * someone using a screen magnifier.
28
+ *
29
+ * The queue is a module singleton on purpose. The product's `toast()` is
30
+ * importable from anywhere and called from API error handlers and effects
31
+ * that have no component to hang a hook off, and a context-based queue would
32
+ * have made those 67 call sites into 67 refactors.
33
+ */
34
+ /** Where the region sits. Fixed, above everything, out of the way of content. */
35
+ export declare const toastRegionVariants: (props?: import("class-variance-authority/types").ClassProp | undefined) => string;
36
+ export declare const toastVariants: (props?: ({
37
+ tone?: "neutral" | "success" | "warning" | "danger" | "info" | null | undefined;
38
+ } & import("class-variance-authority/types").ClassProp) | undefined) => string;
39
+ export declare const toastCloseVariants: (props?: import("class-variance-authority/types").ClassProp | undefined) => string;
40
+ /** What a toast carries. `title` is required: an unnamed toast announces nothing. */
41
+ export interface ToastContent extends VariantProps<typeof toastVariants> {
42
+ /** The message. Required -- a toast with only a description announces as loose text. */
43
+ title: ReactNode;
44
+ /** Secondary detail, beneath the title. */
45
+ description?: ReactNode;
46
+ }
47
+ /**
48
+ * The queue every `toast()` call feeds.
49
+ *
50
+ * Exported so a consumer can read `visibleToasts` in a test, or dismiss them
51
+ * on a route change -- there is no `clear()` upstream, so that is
52
+ * `[...toastQueue.visibleToasts].forEach((t) => toastQueue.close(t.key))`.
53
+ * Not something to touch in normal use.
54
+ */
55
+ export declare const toastQueue: UNSTABLE_ToastQueue<ToastContent>;
56
+ /**
57
+ * Show a toast.
58
+ *
59
+ * @example
60
+ * toast({ title: "Report saved" });
61
+ * toast({ title: "Upload failed", description: err.message, tone: "danger" });
62
+ *
63
+ * @param timeout - ms before it dismisses itself. React Aria REFUSES anything
64
+ * under 5000 and anything at all while the region is focused, because a
65
+ * message that disappears before it can be read fails WCAG 2.2.1. Pass 0 to
66
+ * require a manual dismiss, which is right for an error a user must act on.
67
+ */
68
+ export declare function toast(content: ToastContent, timeout?: number): string;
69
+ export interface ToastRegionProps {
70
+ /**
71
+ * Names the region for assistive tech.
72
+ *
73
+ * **Required.** React Aria renders the region as a labelled landmark, and
74
+ * an unnamed one is announced as "region" with no indication of what just
75
+ * arrived. It is a prop rather than a default string because
76
+ * ARCHITECTURE section 7 rule 9 routes user-visible copy through the
77
+ * consumer until `useMessages()` exists.
78
+ */
79
+ label: string;
80
+ /** Accessible name for each toast's dismiss control. */
81
+ closeLabel?: string;
82
+ /** Extra classes for the region. Merged last. */
83
+ className?: string;
84
+ }
85
+ /**
86
+ * Renders the queue. Mount ONCE, near the root.
87
+ *
88
+ * React Aria only renders the landmark while something is queued, so this
89
+ * costs nothing on a quiet screen.
90
+ */
91
+ export declare function ToastRegion({ label, closeLabel, className }: ToastRegionProps): import("react").JSX.Element;
92
+ //#endregion
93
+ //# sourceMappingURL=toast.d.ts.map
@@ -0,0 +1,145 @@
1
+ "use client";
2
+ import { cn } from "../lib/cn.js";
3
+ import { cva } from "class-variance-authority";
4
+ import { Button, Text, UNSTABLE_Toast, UNSTABLE_ToastContent, UNSTABLE_ToastQueue, UNSTABLE_ToastRegion } from "react-aria-components";
5
+ import { jsx, jsxs } from "react/jsx-runtime";
6
+ //#region src/toast/toast.tsx
7
+ /**
8
+ * Toast: a transient message, announced without stealing focus.
9
+ *
10
+ * Maturity: **experimental**, and the reason is upstream rather than here.
11
+ * React Aria ships this API as `UNSTABLE_Toast*` in 1.21.1, so a RAC minor
12
+ * bump can rename or reshape it. The alternative was hand-rolling the live
13
+ * region, the queue, the timers and the focus behaviour, which is how every
14
+ * toast implementation acquires its accessibility bugs -- so this takes the
15
+ * upstream one and labels the risk instead of hiding it.
16
+ *
17
+ * THE PRODUCT HAS 30 FILES CALLING `useToast` AND 67 `toast(...)` CALLS, and
18
+ * its implementation is the shadcn reducer with both of its known defects
19
+ * still in place:
20
+ *
21
+ * TOAST_LIMIT = 1 -- a second toast REPLACES the first, so a
22
+ * burst of results shows only the last one.
23
+ * TOAST_REMOVE_DELAY = 1e6 -- sixteen minutes. Nothing auto-dismisses;
24
+ * every toast waits to be closed by hand.
25
+ *
26
+ * Neither is ported. `maxVisibleToasts` defaults to 3 and `timeout` to 5s,
27
+ * which is the WCAG 2.2.1 floor React Aria enforces -- it REFUSES a timeout
28
+ * under 5000ms, because a message that vanishes faster cannot be read by
29
+ * someone using a screen magnifier.
30
+ *
31
+ * The queue is a module singleton on purpose. The product's `toast()` is
32
+ * importable from anywhere and called from API error handlers and effects
33
+ * that have no component to hang a hook off, and a context-based queue would
34
+ * have made those 67 call sites into 67 refactors.
35
+ */
36
+ /** Where the region sits. Fixed, above everything, out of the way of content. */
37
+ const toastRegionVariants = cva([
38
+ "fixed z-50 flex flex-col gap-2 box-border",
39
+ "bottom-(--density-bar-pad-y) end-(--density-bar-pad-x)",
40
+ "w-[min(24rem,calc(100vw-2rem))]",
41
+ "outline-none"
42
+ ]);
43
+ const toastVariants = cva([
44
+ "flex items-start gap-3 box-border w-full",
45
+ "rounded-md border-(length:--border-width) p-(--density-bar-pad-x)",
46
+ "font-sans shadow-surface",
47
+ "motion-safe:transition-opacity motion-safe:duration-(--duration-fast) motion-safe:ease-standard",
48
+ "data-[animation=exiting]:opacity-0"
49
+ ], {
50
+ variants: { tone: {
51
+ neutral: "bg-background border-separator text-foreground",
52
+ success: "bg-success-subtle border-success-strong text-success-foreground",
53
+ warning: "bg-warning-subtle border-warning-strong text-warning-foreground",
54
+ danger: "bg-destructive-subtle border-destructive-strong text-destructive-subtle-foreground",
55
+ info: "bg-info-subtle border-info-strong text-info-foreground"
56
+ } },
57
+ defaultVariants: { tone: "neutral" }
58
+ });
59
+ const toastCloseVariants = cva([
60
+ "ms-auto shrink-0 rounded-sm cursor-pointer",
61
+ "text-current opacity-70 data-[hovered]:opacity-100",
62
+ "outline-none",
63
+ "data-[focus-visible]:outline-solid",
64
+ "data-[focus-visible]:outline-(length:--focus-ring-width)",
65
+ "data-[focus-visible]:outline-offset-(--focus-ring-offset)",
66
+ "data-[focus-visible]:outline-(--color-ring)"
67
+ ]);
68
+ /**
69
+ * The queue every `toast()` call feeds.
70
+ *
71
+ * Exported so a consumer can read `visibleToasts` in a test, or dismiss them
72
+ * on a route change -- there is no `clear()` upstream, so that is
73
+ * `[...toastQueue.visibleToasts].forEach((t) => toastQueue.close(t.key))`.
74
+ * Not something to touch in normal use.
75
+ */
76
+ const toastQueue = new UNSTABLE_ToastQueue({ maxVisibleToasts: 3 });
77
+ /**
78
+ * Show a toast.
79
+ *
80
+ * @example
81
+ * toast({ title: "Report saved" });
82
+ * toast({ title: "Upload failed", description: err.message, tone: "danger" });
83
+ *
84
+ * @param timeout - ms before it dismisses itself. React Aria REFUSES anything
85
+ * under 5000 and anything at all while the region is focused, because a
86
+ * message that disappears before it can be read fails WCAG 2.2.1. Pass 0 to
87
+ * require a manual dismiss, which is right for an error a user must act on.
88
+ */
89
+ function toast(content, timeout = 5e3) {
90
+ return toastQueue.add(content, timeout === 0 ? void 0 : { timeout });
91
+ }
92
+ /**
93
+ * Renders the queue. Mount ONCE, near the root.
94
+ *
95
+ * React Aria only renders the landmark while something is queued, so this
96
+ * costs nothing on a quiet screen.
97
+ */
98
+ function ToastRegion({ label, closeLabel = "Dismiss", className }) {
99
+ return /* @__PURE__ */ jsx(UNSTABLE_ToastRegion, {
100
+ queue: toastQueue,
101
+ "aria-label": label,
102
+ "data-slot": "toast-region",
103
+ className: cn(toastRegionVariants(), className),
104
+ children: ({ toast: queued }) => /* @__PURE__ */ jsxs(UNSTABLE_Toast, {
105
+ toast: queued,
106
+ "data-slot": "toast",
107
+ "data-tone": queued.content.tone ?? "neutral",
108
+ className: toastVariants({ tone: queued.content.tone }),
109
+ children: [/* @__PURE__ */ jsxs(UNSTABLE_ToastContent, {
110
+ "data-slot": "toast-content",
111
+ className: "flex min-w-0 flex-col gap-1",
112
+ children: [/* @__PURE__ */ jsx(Text, {
113
+ slot: "title",
114
+ "data-slot": "toast-title",
115
+ className: "text-sm leading-(--leading-snug) font-medium",
116
+ children: queued.content.title
117
+ }), queued.content.description == null ? null : /* @__PURE__ */ jsx(Text, {
118
+ slot: "description",
119
+ "data-slot": "toast-description",
120
+ className: "text-sm leading-(--leading-normal) opacity-90",
121
+ children: queued.content.description
122
+ })]
123
+ }), /* @__PURE__ */ jsx(Button, {
124
+ slot: "close",
125
+ "aria-label": closeLabel,
126
+ "data-slot": "toast-close",
127
+ className: toastCloseVariants(),
128
+ children: /* @__PURE__ */ jsx("svg", {
129
+ "aria-hidden": "true",
130
+ viewBox: "0 0 16 16",
131
+ fill: "none",
132
+ stroke: "currentColor",
133
+ strokeWidth: "1.75",
134
+ strokeLinecap: "round",
135
+ className: "size-(--icon-sm)",
136
+ children: /* @__PURE__ */ jsx("path", { d: "m4 4 8 8M12 4l-8 8" })
137
+ })
138
+ })]
139
+ })
140
+ });
141
+ }
142
+ //#endregion
143
+ export { ToastRegion, toast, toastCloseVariants, toastQueue, toastRegionVariants, toastVariants };
144
+
145
+ //# sourceMappingURL=toast.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"toast.js","names":["AriaToastQueue","AriaToastRegion","AriaToast","AriaToastContent","AriaText","AriaButton"],"sources":["../../src/toast/toast.tsx"],"sourcesContent":["\"use client\";\n\nimport { cva, type VariantProps } from \"class-variance-authority\";\nimport type { ReactNode } from \"react\";\nimport {\n Button as AriaButton,\n Text as AriaText,\n UNSTABLE_Toast as AriaToast,\n UNSTABLE_ToastContent as AriaToastContent,\n UNSTABLE_ToastQueue as AriaToastQueue,\n UNSTABLE_ToastRegion as AriaToastRegion,\n} from \"react-aria-components\";\n\nimport { cn } from \"../lib/cn.js\";\n\n/**\n * Toast: a transient message, announced without stealing focus.\n *\n * Maturity: **experimental**, and the reason is upstream rather than here.\n * React Aria ships this API as `UNSTABLE_Toast*` in 1.21.1, so a RAC minor\n * bump can rename or reshape it. The alternative was hand-rolling the live\n * region, the queue, the timers and the focus behaviour, which is how every\n * toast implementation acquires its accessibility bugs -- so this takes the\n * upstream one and labels the risk instead of hiding it.\n *\n * THE PRODUCT HAS 30 FILES CALLING `useToast` AND 67 `toast(...)` CALLS, and\n * its implementation is the shadcn reducer with both of its known defects\n * still in place:\n *\n * TOAST_LIMIT = 1 -- a second toast REPLACES the first, so a\n * burst of results shows only the last one.\n * TOAST_REMOVE_DELAY = 1e6 -- sixteen minutes. Nothing auto-dismisses;\n * every toast waits to be closed by hand.\n *\n * Neither is ported. `maxVisibleToasts` defaults to 3 and `timeout` to 5s,\n * which is the WCAG 2.2.1 floor React Aria enforces -- it REFUSES a timeout\n * under 5000ms, because a message that vanishes faster cannot be read by\n * someone using a screen magnifier.\n *\n * The queue is a module singleton on purpose. The product's `toast()` is\n * importable from anywhere and called from API error handlers and effects\n * that have no component to hang a hook off, and a context-based queue would\n * have made those 67 call sites into 67 refactors.\n */\n\n/** Where the region sits. Fixed, above everything, out of the way of content. */\nexport const toastRegionVariants = cva([\n \"fixed z-50 flex flex-col gap-2 box-border\",\n // Logical insets so the stack follows the writing direction.\n \"bottom-(--density-bar-pad-y) end-(--density-bar-pad-x)\",\n \"w-[min(24rem,calc(100vw-2rem))]\",\n \"outline-none\",\n]);\n\nexport const toastVariants = cva(\n [\n \"flex items-start gap-3 box-border w-full\",\n \"rounded-md border-(length:--border-width) p-(--density-bar-pad-x)\",\n \"font-sans shadow-surface\",\n \"motion-safe:transition-opacity motion-safe:duration-(--duration-fast) motion-safe:ease-standard\",\n // Not colour alone: an exiting toast fades AND the region reflows.\n \"data-[animation=exiting]:opacity-0\",\n ],\n {\n variants: {\n /*\n * The same vocabulary as Badge, deliberately. The product's toast had\n * `default` and `destructive` only, so 38 of its 67 calls pass a variant\n * that cannot say \"this worked\" -- and a save confirmation styled\n * identically to a failure is the most common thing a toast gets wrong.\n */\n tone: {\n neutral: \"bg-background border-separator text-foreground\",\n success: \"bg-success-subtle border-success-strong text-success-foreground\",\n warning: \"bg-warning-subtle border-warning-strong text-warning-foreground\",\n danger:\n \"bg-destructive-subtle border-destructive-strong text-destructive-subtle-foreground\",\n info: \"bg-info-subtle border-info-strong text-info-foreground\",\n },\n },\n defaultVariants: { tone: \"neutral\" },\n },\n);\n\nexport const toastCloseVariants = cva([\n \"ms-auto shrink-0 rounded-sm cursor-pointer\",\n \"text-current opacity-70 data-[hovered]:opacity-100\",\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\n/** What a toast carries. `title` is required: an unnamed toast announces nothing. */\nexport interface ToastContent extends VariantProps<typeof toastVariants> {\n /** The message. Required -- a toast with only a description announces as loose text. */\n title: ReactNode;\n /** Secondary detail, beneath the title. */\n description?: ReactNode;\n}\n\n/**\n * The queue every `toast()` call feeds.\n *\n * Exported so a consumer can read `visibleToasts` in a test, or dismiss them\n * on a route change -- there is no `clear()` upstream, so that is\n * `[...toastQueue.visibleToasts].forEach((t) => toastQueue.close(t.key))`.\n * Not something to touch in normal use.\n */\nexport const toastQueue = new AriaToastQueue<ToastContent>({\n /*\n * Three, against the product's one. Its TOAST_LIMIT of 1 means a second\n * toast REPLACES the first -- so a page that reports three failed uploads\n * shows one and silently drops the rest.\n */\n maxVisibleToasts: 3,\n});\n\n/**\n * Show a toast.\n *\n * @example\n * toast({ title: \"Report saved\" });\n * toast({ title: \"Upload failed\", description: err.message, tone: \"danger\" });\n *\n * @param timeout - ms before it dismisses itself. React Aria REFUSES anything\n * under 5000 and anything at all while the region is focused, because a\n * message that disappears before it can be read fails WCAG 2.2.1. Pass 0 to\n * require a manual dismiss, which is right for an error a user must act on.\n */\nexport function toast(content: ToastContent, timeout = 5000) {\n return toastQueue.add(content, timeout === 0 ? undefined : { timeout });\n}\n\nexport interface ToastRegionProps {\n /**\n * Names the region for assistive tech.\n *\n * **Required.** React Aria renders the region as a labelled landmark, and\n * an unnamed one is announced as \"region\" with no indication of what just\n * arrived. It is a prop rather than a default string because\n * ARCHITECTURE section 7 rule 9 routes user-visible copy through the\n * consumer until `useMessages()` exists.\n */\n label: string;\n /** Accessible name for each toast's dismiss control. */\n closeLabel?: string;\n /** Extra classes for the region. Merged last. */\n className?: string;\n}\n\n/**\n * Renders the queue. Mount ONCE, near the root.\n *\n * React Aria only renders the landmark while something is queued, so this\n * costs nothing on a quiet screen.\n */\nexport function ToastRegion({ label, closeLabel = \"Dismiss\", className }: ToastRegionProps) {\n return (\n <AriaToastRegion\n queue={toastQueue}\n aria-label={label}\n data-slot=\"toast-region\"\n className={cn(toastRegionVariants(), className)}\n >\n {({ toast: queued }) => (\n <AriaToast\n toast={queued}\n data-slot=\"toast\"\n data-tone={queued.content.tone ?? \"neutral\"}\n className={toastVariants({ tone: queued.content.tone })}\n >\n <AriaToastContent data-slot=\"toast-content\" className=\"flex min-w-0 flex-col gap-1\">\n {/*\n slot=\"title\" is what React Aria announces. A plain div here\n renders identically and leaves the toast unnamed.\n */}\n <AriaText\n slot=\"title\"\n data-slot=\"toast-title\"\n className=\"text-sm leading-(--leading-snug) font-medium\"\n >\n {queued.content.title}\n </AriaText>\n {queued.content.description == null ? null : (\n <AriaText\n slot=\"description\"\n data-slot=\"toast-description\"\n className=\"text-sm leading-(--leading-normal) opacity-90\"\n >\n {queued.content.description}\n </AriaText>\n )}\n </AriaToastContent>\n <AriaButton\n slot=\"close\"\n aria-label={closeLabel}\n data-slot=\"toast-close\"\n className={toastCloseVariants()}\n >\n <svg\n aria-hidden=\"true\"\n viewBox=\"0 0 16 16\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"1.75\"\n strokeLinecap=\"round\"\n className=\"size-(--icon-sm)\"\n >\n <path d=\"m4 4 8 8M12 4l-8 8\" />\n </svg>\n </AriaButton>\n </AriaToast>\n )}\n </AriaToastRegion>\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA8CA,MAAa,sBAAsB,IAAI;CACrC;CAEA;CACA;CACA;AACF,CAAC;AAED,MAAa,gBAAgB,IAC3B;CACE;CACA;CACA;CACA;CAEA;AACF,GACA;CACE,UAAU,EAOR,MAAM;EACJ,SAAS;EACT,SAAS;EACT,SAAS;EACT,QACE;EACF,MAAM;CACR,EACF;CACA,iBAAiB,EAAE,MAAM,UAAU;AACrC,CACF;AAEA,MAAa,qBAAqB,IAAI;CACpC;CACA;CACA;CACA;CACA;CACA;CACA;AACF,CAAC;;;;;;;;;AAkBD,MAAa,aAAa,IAAIA,oBAA6B,EAMzD,kBAAkB,EACpB,CAAC;;;;;;;;;;;;;AAcD,SAAgB,MAAM,SAAuB,UAAU,KAAM;CAC3D,OAAO,WAAW,IAAI,SAAS,YAAY,IAAI,KAAA,IAAY,EAAE,QAAQ,CAAC;AACxE;;;;;;;AAyBA,SAAgB,YAAY,EAAE,OAAO,aAAa,WAAW,aAA+B;CAC1F,OACE,oBAACC,sBAAD;EACE,OAAO;EACP,cAAY;EACZ,aAAU;EACV,WAAW,GAAG,oBAAoB,GAAG,SAAS;EAE5C,WAAA,EAAE,OAAO,aACT,qBAACC,gBAAD;GACE,OAAO;GACP,aAAU;GACV,aAAW,OAAO,QAAQ,QAAQ;GAClC,WAAW,cAAc,EAAE,MAAM,OAAO,QAAQ,KAAK,CAAC;GAJxD,UAAA,CAME,qBAACC,uBAAD;IAAkB,aAAU;IAAgB,WAAU;IAAtD,UAAA,CAKE,oBAACC,MAAD;KACE,MAAK;KACL,aAAU;KACV,WAAU;KAET,UAAA,OAAO,QAAQ;IACR,CAAA,GACT,OAAO,QAAQ,eAAe,OAAO,OACpC,oBAACA,MAAD;KACE,MAAK;KACL,aAAU;KACV,WAAU;KAET,UAAA,OAAO,QAAQ;IACR,CAAA,CAEI;GAClB,CAAA,GAAA,oBAACC,QAAD;IACE,MAAK;IACL,cAAY;IACZ,aAAU;IACV,WAAW,mBAAmB;IAE9B,UAAA,oBAAC,OAAD;KACE,eAAY;KACZ,SAAQ;KACR,MAAK;KACL,QAAO;KACP,aAAY;KACZ,eAAc;KACd,WAAU;KAEV,UAAA,oBAAC,QAAD,EAAM,GAAE,qBAAsB,CAAA;IAC3B,CAAA;GACK,CAAA,CACH;;CAEE,CAAA;AAErB"}
@@ -0,0 +1,2 @@
1
+ import { Tooltip, TooltipProps, TooltipTrigger, TooltipTriggerProps, tooltipVariants } from "./tooltip.js";
2
+ export { Tooltip, type TooltipProps, TooltipTrigger, type TooltipTriggerProps, tooltipVariants };
@@ -0,0 +1,2 @@
1
+ import { Tooltip, TooltipTrigger, tooltipVariants } from "./tooltip.js";
2
+ export { Tooltip, TooltipTrigger, tooltipVariants };
@@ -0,0 +1,70 @@
1
+ import { TooltipProps, TooltipTriggerComponentProps } from "react-aria-components";
2
+ import { ReactNode } from "react";
3
+ //#region src/tooltip/tooltip.d.ts
4
+ /**
5
+ * Tooltip, ported from the legacy shadcn/Radix component.
6
+ *
7
+ * Census: ten files import it but only SEVEN render anything -- three
8
+ * import the parts and use none. Across those seven: `Tooltip` 34,
9
+ * `TooltipTrigger` 34, `TooltipContent` 34, `TooltipProvider` 23. `side`
10
+ * is passed 12 times: `"top"` 11, `"bottom"` once.
11
+ *
12
+ * `TooltipProvider` IS NOT PORTED, and that removes 23 call sites rather
13
+ * than renaming them. The legacy `Tooltip` already wraps itself in a
14
+ * provider, so every explicit `<TooltipProvider>` in app code nested a
15
+ * second one inside the first -- harmless, but it also meant the
16
+ * `skipDelayDuration` grouping the provider exists for never spanned two
17
+ * tooltips. React Aria has no provider at all; that grouping is
18
+ * module-global.
19
+ *
20
+ * THE DELAY IS THE ONE THING THAT WOULD HAVE CHANGED SILENTLY. The legacy
21
+ * provider hardcodes `delayDuration = 0`, so all 34 tooltips appear
22
+ * instantly on hover. React Aria's default is 1500ms. Porting without
23
+ * noticing would have put a 1.5-second warm-up on every tooltip in the
24
+ * app, and neither the type system nor the test suite would have said a
25
+ * word -- so `delay` defaults to 0 here, and a story pins the default.
26
+ */
27
+ export declare const tooltipVariants: (props?: import("class-variance-authority/types").ClassProp | undefined) => string;
28
+ /**
29
+ * A hover and focus hint.
30
+ *
31
+ * @example
32
+ * <TooltipTrigger>
33
+ * <Button aria-label="Mute"><MicOff /></Button>
34
+ * <Tooltip>Mute</Tooltip>
35
+ * </TooltipTrigger>
36
+ */
37
+ interface TooltipProps$1 extends Omit<TooltipProps, "className" | "style" | "children"> {
38
+ children?: ReactNode;
39
+ /** Extra classes. Merged last, so they win conflicts with ours. */
40
+ className?: string;
41
+ /**
42
+ * Where it opens. The legacy `side` prop: `"top"` 11 times, `"bottom"`
43
+ * once, and the default for the other 22.
44
+ *
45
+ * @default "top"
46
+ */
47
+ placement?: TooltipProps["placement"];
48
+ }
49
+ declare function Tooltip$1({ children, className, placement, ...props }: TooltipProps$1): import("react").JSX.Element;
50
+ /**
51
+ * Pairs a trigger with a tooltip.
52
+ *
53
+ * React Aria's `TooltipTrigger`, EXCEPT that `delay` and `closeDelay`
54
+ * default to 0 to match the legacy provider. React Aria ships 1500ms and
55
+ * 500ms; taking those defaults would have changed all 34 call sites
56
+ * without a word.
57
+ *
58
+ * Focus opens it immediately whatever `delay` says -- React Aria passes
59
+ * `immediate` on focus -- which is the behaviour a keyboard user needs.
60
+ */
61
+ export interface TooltipTriggerProps extends TooltipTriggerComponentProps {
62
+ /** Hover warm-up in ms. @default 0 */
63
+ delay?: number;
64
+ /** Hover cool-down in ms. @default 0 */
65
+ closeDelay?: number;
66
+ }
67
+ declare function TooltipTrigger$1({ delay, closeDelay, ...props }: TooltipTriggerProps): import("react").JSX.Element;
68
+ //#endregion
69
+ export { Tooltip$1 as Tooltip, TooltipProps$1 as TooltipProps, TooltipTrigger$1 as TooltipTrigger };
70
+ //# sourceMappingURL=tooltip.d.ts.map