@waveso/ui 0.0.10 → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (288) hide show
  1. package/dist/accordion.d.ts +24 -8
  2. package/dist/accordion.d.ts.map +1 -0
  3. package/dist/accordion.js +50 -73
  4. package/dist/accordion.js.map +1 -1
  5. package/dist/action-bar.d.ts +83 -0
  6. package/dist/action-bar.d.ts.map +1 -0
  7. package/dist/action-bar.js +264 -0
  8. package/dist/action-bar.js.map +1 -0
  9. package/dist/alert-dialog.d.ts +56 -21
  10. package/dist/alert-dialog.d.ts.map +1 -0
  11. package/dist/alert-dialog.js +75 -127
  12. package/dist/alert-dialog.js.map +1 -1
  13. package/dist/alert.d.ts +26 -11
  14. package/dist/alert.d.ts.map +1 -0
  15. package/dist/alert.js +37 -68
  16. package/dist/alert.js.map +1 -1
  17. package/dist/animate.d.ts +117 -75
  18. package/dist/animate.d.ts.map +1 -0
  19. package/dist/animate.js +259 -223
  20. package/dist/animate.js.map +1 -1
  21. package/dist/aspect-ratio.d.ts +11 -6
  22. package/dist/aspect-ratio.d.ts.map +1 -0
  23. package/dist/aspect-ratio.js +12 -14
  24. package/dist/aspect-ratio.js.map +1 -1
  25. package/dist/autocomplete.d.ts +91 -25
  26. package/dist/autocomplete.d.ts.map +1 -0
  27. package/dist/autocomplete.js +119 -181
  28. package/dist/autocomplete.js.map +1 -1
  29. package/dist/avatar.d.ts +32 -11
  30. package/dist/avatar.d.ts.map +1 -0
  31. package/dist/avatar.js +42 -89
  32. package/dist/avatar.js.map +1 -1
  33. package/dist/badge.d.ts +15 -8
  34. package/dist/badge.d.ts.map +1 -0
  35. package/dist/badge.js +34 -48
  36. package/dist/badge.js.map +1 -1
  37. package/dist/breadcrumb.d.ts +35 -11
  38. package/dist/breadcrumb.d.ts.map +1 -0
  39. package/dist/breadcrumb.js +60 -110
  40. package/dist/breadcrumb.js.map +1 -1
  41. package/dist/button-group.d.ts +26 -13
  42. package/dist/button-group.d.ts.map +1 -0
  43. package/dist/button-group.js +38 -76
  44. package/dist/button-group.js.map +1 -1
  45. package/dist/button.d.ts +17 -10
  46. package/dist/button.d.ts.map +1 -0
  47. package/dist/button.js +50 -3
  48. package/dist/button.js.map +1 -1
  49. package/dist/card.d.ts +35 -11
  50. package/dist/card.d.ts.map +1 -0
  51. package/dist/card.js +43 -82
  52. package/dist/card.js.map +1 -1
  53. package/dist/checkbox.d.ts +6 -4
  54. package/dist/checkbox.d.ts.map +1 -0
  55. package/dist/checkbox.js +21 -29
  56. package/dist/checkbox.js.map +1 -1
  57. package/dist/collapsible.d.ts +15 -7
  58. package/dist/collapsible.d.ts.map +1 -0
  59. package/dist/collapsible.js +19 -8
  60. package/dist/collapsible.js.map +1 -1
  61. package/dist/combobox.d.ts +83 -23
  62. package/dist/combobox.d.ts.map +1 -0
  63. package/dist/combobox.js +149 -247
  64. package/dist/combobox.js.map +1 -1
  65. package/dist/context-menu.d.ts +80 -26
  66. package/dist/context-menu.d.ts.map +1 -0
  67. package/dist/context-menu.js +108 -164
  68. package/dist/context-menu.js.map +1 -1
  69. package/dist/count.d.ts +45 -31
  70. package/dist/count.d.ts.map +1 -0
  71. package/dist/count.js +170 -165
  72. package/dist/count.js.map +1 -1
  73. package/dist/dialog.d.ts +61 -28
  74. package/dist/dialog.d.ts.map +1 -0
  75. package/dist/dialog.js +77 -120
  76. package/dist/dialog.js.map +1 -1
  77. package/dist/direction.d.ts +2 -1
  78. package/dist/direction.js +3 -3
  79. package/dist/drawer.d.ts +45 -15
  80. package/dist/drawer.d.ts.map +1 -0
  81. package/dist/drawer.js +93 -5
  82. package/dist/drawer.js.map +1 -1
  83. package/dist/encrypted-text.d.ts +25 -12
  84. package/dist/encrypted-text.d.ts.map +1 -0
  85. package/dist/encrypted-text.js +102 -134
  86. package/dist/encrypted-text.js.map +1 -1
  87. package/dist/field.d.ts +37 -21
  88. package/dist/field.d.ts.map +1 -0
  89. package/dist/field.js +52 -3
  90. package/dist/field.js.map +1 -1
  91. package/dist/film-grain-shader.d.ts +6 -0
  92. package/dist/film-grain-shader.d.ts.map +1 -0
  93. package/dist/film-grain-shader.js +88 -0
  94. package/dist/film-grain-shader.js.map +1 -0
  95. package/dist/film-grain-webgl.d.ts +20 -0
  96. package/dist/film-grain-webgl.d.ts.map +1 -0
  97. package/dist/film-grain-webgl.js +306 -0
  98. package/dist/film-grain-webgl.js.map +1 -0
  99. package/dist/film-grain.d.ts +21 -11
  100. package/dist/film-grain.d.ts.map +1 -0
  101. package/dist/film-grain.js +28 -420
  102. package/dist/film-grain.js.map +1 -1
  103. package/dist/form.d.ts +64 -49
  104. package/dist/form.d.ts.map +1 -0
  105. package/dist/form.js +112 -91
  106. package/dist/form.js.map +1 -1
  107. package/dist/gradient-reveal-text.d.ts +35 -22
  108. package/dist/gradient-reveal-text.d.ts.map +1 -0
  109. package/dist/gradient-reveal-text.js +238 -205
  110. package/dist/gradient-reveal-text.js.map +1 -1
  111. package/dist/hooks/use-mobile.d.ts +3 -1
  112. package/dist/hooks/use-mobile.d.ts.map +1 -0
  113. package/dist/hooks/use-mobile.js +28 -2
  114. package/dist/hooks/use-mobile.js.map +1 -1
  115. package/dist/infinite-scroll.d.ts +29 -15
  116. package/dist/infinite-scroll.d.ts.map +1 -0
  117. package/dist/infinite-scroll.js +69 -99
  118. package/dist/infinite-scroll.js.map +1 -1
  119. package/dist/input-group.d.ts +41 -18
  120. package/dist/input-group.d.ts.map +1 -0
  121. package/dist/input-group.js +80 -6
  122. package/dist/input-group.js.map +1 -1
  123. package/dist/input-otp.d.ts +26 -10
  124. package/dist/input-otp.d.ts.map +1 -0
  125. package/dist/input-otp.js +40 -70
  126. package/dist/input-otp.js.map +1 -1
  127. package/dist/input.d.ts +10 -4
  128. package/dist/input.d.ts.map +1 -0
  129. package/dist/input.js +16 -3
  130. package/dist/input.js.map +1 -1
  131. package/dist/item.d.ts +58 -23
  132. package/dist/item.d.ts.map +1 -0
  133. package/dist/item.js +102 -160
  134. package/dist/item.js.map +1 -1
  135. package/dist/kbd.d.ts +12 -4
  136. package/dist/kbd.d.ts.map +1 -0
  137. package/dist/kbd.js +15 -24
  138. package/dist/kbd.js.map +1 -1
  139. package/dist/label.d.ts +9 -4
  140. package/dist/label.d.ts.map +1 -0
  141. package/dist/label.js +12 -16
  142. package/dist/label.js.map +1 -1
  143. package/dist/lib/focus.d.ts +42 -0
  144. package/dist/lib/focus.d.ts.map +1 -0
  145. package/dist/lib/focus.js +21 -0
  146. package/dist/lib/focus.js.map +1 -0
  147. package/dist/lib/internal-icons.d.ts +32 -0
  148. package/dist/lib/internal-icons.d.ts.map +1 -0
  149. package/dist/lib/internal-icons.js +222 -0
  150. package/dist/lib/internal-icons.js.map +1 -0
  151. package/dist/lib/utils.d.ts +4 -2
  152. package/dist/lib/utils.d.ts.map +1 -0
  153. package/dist/lib/utils.js +12 -2
  154. package/dist/lib/utils.js.map +1 -1
  155. package/dist/masonry.d.ts +25 -11
  156. package/dist/masonry.d.ts.map +1 -0
  157. package/dist/masonry.js +188 -229
  158. package/dist/masonry.js.map +1 -1
  159. package/dist/menu.d.ts +84 -26
  160. package/dist/menu.d.ts.map +1 -0
  161. package/dist/menu.js +141 -4
  162. package/dist/menu.js.map +1 -1
  163. package/dist/menubar.d.ts +60 -22
  164. package/dist/menubar.d.ts.map +1 -0
  165. package/dist/menubar.js +80 -52
  166. package/dist/menubar.js.map +1 -1
  167. package/dist/pagination.d.ts +38 -17
  168. package/dist/pagination.d.ts.map +1 -0
  169. package/dist/pagination.js +68 -107
  170. package/dist/pagination.js.map +1 -1
  171. package/dist/popover.d.ts +56 -14
  172. package/dist/popover.d.ts.map +1 -0
  173. package/dist/popover.js +62 -87
  174. package/dist/popover.js.map +1 -1
  175. package/dist/preview-card.d.ts +28 -9
  176. package/dist/preview-card.d.ts.map +1 -0
  177. package/dist/preview-card.js +40 -60
  178. package/dist/preview-card.js.map +1 -1
  179. package/dist/progress.d.ts +28 -9
  180. package/dist/progress.d.ts.map +1 -0
  181. package/dist/progress.js +35 -60
  182. package/dist/progress.js.map +1 -1
  183. package/dist/radio-group.d.ts +14 -8
  184. package/dist/radio-group.d.ts.map +1 -0
  185. package/dist/radio-group.js +18 -22
  186. package/dist/radio-group.js.map +1 -1
  187. package/dist/radio.d.ts +14 -6
  188. package/dist/radio.d.ts.map +1 -0
  189. package/dist/radio.js +24 -3
  190. package/dist/radio.js.map +1 -1
  191. package/dist/scroll-area.d.ts +16 -6
  192. package/dist/scroll-area.d.ts.map +1 -0
  193. package/dist/scroll-area.js +34 -55
  194. package/dist/scroll-area.js.map +1 -1
  195. package/dist/select.d.ts +66 -18
  196. package/dist/select.d.ts.map +1 -0
  197. package/dist/select.js +105 -185
  198. package/dist/select.js.map +1 -1
  199. package/dist/separator.d.ts +11 -5
  200. package/dist/separator.d.ts.map +1 -0
  201. package/dist/separator.js +17 -3
  202. package/dist/separator.js.map +1 -1
  203. package/dist/sidebar.d.ts +172 -79
  204. package/dist/sidebar.d.ts.map +1 -0
  205. package/dist/sidebar.js +363 -585
  206. package/dist/sidebar.js.map +1 -1
  207. package/dist/skeleton.d.ts +8 -3
  208. package/dist/skeleton.d.ts.map +1 -0
  209. package/dist/skeleton.js +13 -3
  210. package/dist/skeleton.js.map +1 -1
  211. package/dist/slider.d.ts +16 -6
  212. package/dist/slider.d.ts.map +1 -0
  213. package/dist/slider.js +40 -67
  214. package/dist/slider.js.map +1 -1
  215. package/dist/spinner.d.ts +8 -3
  216. package/dist/spinner.d.ts.map +1 -0
  217. package/dist/spinner.js +15 -4
  218. package/dist/spinner.js.map +1 -1
  219. package/dist/switch.d.ts +12 -6
  220. package/dist/switch.d.ts.map +1 -0
  221. package/dist/switch.js +18 -25
  222. package/dist/switch.js.map +1 -1
  223. package/dist/table.d.ts +37 -11
  224. package/dist/table.d.ts.map +1 -0
  225. package/dist/table.js +51 -88
  226. package/dist/table.js.map +1 -1
  227. package/dist/tabs.d.ts +28 -12
  228. package/dist/tabs.d.ts.map +1 -0
  229. package/dist/tabs.js +40 -74
  230. package/dist/tabs.js.map +1 -1
  231. package/dist/textarea.d.ts +13 -6
  232. package/dist/textarea.d.ts.map +1 -0
  233. package/dist/textarea.js +19 -3
  234. package/dist/textarea.js.map +1 -1
  235. package/dist/toast.d.ts +63 -39
  236. package/dist/toast.d.ts.map +1 -0
  237. package/dist/toast.js +177 -215
  238. package/dist/toast.js.map +1 -1
  239. package/dist/toggle-group.d.ts +26 -12
  240. package/dist/toggle-group.d.ts.map +1 -0
  241. package/dist/toggle-group.js +49 -73
  242. package/dist/toggle-group.js.map +1 -1
  243. package/dist/toggle.d.ts +17 -10
  244. package/dist/toggle.d.ts.map +1 -0
  245. package/dist/toggle.js +38 -3
  246. package/dist/toggle.js.map +1 -1
  247. package/dist/tooltip.d.ts +35 -14
  248. package/dist/tooltip.d.ts.map +1 -0
  249. package/dist/tooltip.js +52 -3
  250. package/dist/tooltip.js.map +1 -1
  251. package/dist/typewriter.d.ts +44 -31
  252. package/dist/typewriter.d.ts.map +1 -0
  253. package/dist/typewriter.js +185 -185
  254. package/dist/typewriter.js.map +1 -1
  255. package/package.json +6 -6
  256. package/dist/chunk-45VQAWIM.js +0 -228
  257. package/dist/chunk-45VQAWIM.js.map +0 -1
  258. package/dist/chunk-6Y7LPQMO.js +0 -11
  259. package/dist/chunk-6Y7LPQMO.js.map +0 -1
  260. package/dist/chunk-76UQO56T.js +0 -19
  261. package/dist/chunk-76UQO56T.js.map +0 -1
  262. package/dist/chunk-7F4MPMLJ.js +0 -17
  263. package/dist/chunk-7F4MPMLJ.js.map +0 -1
  264. package/dist/chunk-BKTJYX4M.js +0 -143
  265. package/dist/chunk-BKTJYX4M.js.map +0 -1
  266. package/dist/chunk-D5XPEJ6T.js +0 -36
  267. package/dist/chunk-D5XPEJ6T.js.map +0 -1
  268. package/dist/chunk-DIGOLJIR.js +0 -105
  269. package/dist/chunk-DIGOLJIR.js.map +0 -1
  270. package/dist/chunk-IQ7YQ5XA.js +0 -141
  271. package/dist/chunk-IQ7YQ5XA.js.map +0 -1
  272. package/dist/chunk-NCHHHWTB.js +0 -85
  273. package/dist/chunk-NCHHHWTB.js.map +0 -1
  274. package/dist/chunk-OUFYQLVN.js +0 -56
  275. package/dist/chunk-OUFYQLVN.js.map +0 -1
  276. package/dist/chunk-QFSEK4M6.js +0 -22
  277. package/dist/chunk-QFSEK4M6.js.map +0 -1
  278. package/dist/chunk-QRW37LRP.js +0 -25
  279. package/dist/chunk-QRW37LRP.js.map +0 -1
  280. package/dist/chunk-RPQHL6C5.js +0 -26
  281. package/dist/chunk-RPQHL6C5.js.map +0 -1
  282. package/dist/chunk-V4ZX4YCP.js +0 -66
  283. package/dist/chunk-V4ZX4YCP.js.map +0 -1
  284. package/dist/chunk-YTSQQTSF.js +0 -44
  285. package/dist/chunk-YTSQQTSF.js.map +0 -1
  286. package/dist/chunk-ZZZH3JGW.js +0 -23
  287. package/dist/chunk-ZZZH3JGW.js.map +0 -1
  288. package/dist/direction.js.map +0 -1
@@ -1,14 +1,30 @@
1
- import * as react_jsx_runtime from 'react/jsx-runtime';
2
- import * as React from 'react';
3
- import { Accordion as Accordion$1 } from '@base-ui/react/accordion';
1
+ import * as React from "react";
2
+ import { Accordion as Accordion$1 } from "@base-ui/react/accordion";
3
+ import * as _$react_jsx_runtime0 from "react/jsx-runtime";
4
4
 
5
+ //#region src/accordion.d.ts
5
6
  type AccordionProps = React.ComponentProps<typeof Accordion$1.Root>;
6
7
  type AccordionItemProps = React.ComponentProps<typeof Accordion$1.Item>;
7
8
  type AccordionTriggerProps = React.ComponentProps<typeof Accordion$1.Trigger>;
8
9
  type AccordionContentProps = React.ComponentProps<typeof Accordion$1.Panel>;
9
- declare function Accordion({ className, ...props }: AccordionProps): react_jsx_runtime.JSX.Element;
10
- declare function AccordionItem({ className, ...props }: AccordionItemProps): react_jsx_runtime.JSX.Element;
11
- declare function AccordionTrigger({ className, children, ...props }: AccordionTriggerProps): react_jsx_runtime.JSX.Element;
12
- declare function AccordionContent({ className, children, ...props }: AccordionContentProps): react_jsx_runtime.JSX.Element;
13
-
10
+ declare function Accordion({
11
+ className,
12
+ ...props
13
+ }: AccordionProps): _$react_jsx_runtime0.JSX.Element;
14
+ declare function AccordionItem({
15
+ className,
16
+ ...props
17
+ }: AccordionItemProps): _$react_jsx_runtime0.JSX.Element;
18
+ declare function AccordionTrigger({
19
+ className,
20
+ children,
21
+ ...props
22
+ }: AccordionTriggerProps): _$react_jsx_runtime0.JSX.Element;
23
+ declare function AccordionContent({
24
+ className,
25
+ children,
26
+ ...props
27
+ }: AccordionContentProps): _$react_jsx_runtime0.JSX.Element;
28
+ //#endregion
14
29
  export { Accordion, AccordionContent, AccordionItem, AccordionTrigger };
30
+ //# sourceMappingURL=accordion.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"accordion.d.ts","names":[],"sources":["../src/accordion.tsx"],"mappings":";;;;;KAUK,cAAA,GAAiB,KAAA,CAAM,cAAA,QAAsB,WAAA,CAAmB,IAAA;AAAA,KAChE,kBAAA,GAAqB,KAAA,CAAM,cAAA,QAAsB,WAAA,CAAmB,IAAA;AAAA,KACpE,qBAAA,GAAwB,KAAA,CAAM,cAAA,QAAsB,WAAA,CAAmB,OAAA;AAAA,KACvE,qBAAA,GAAwB,KAAA,CAAM,cAAA,QAAsB,WAAA,CAAmB,KAAA;AAAA,iBAEnE,SAAA,CAAA;EAAY,SAAA;EAAA,GAAc;AAAA,GAAS,cAAA,GAAc,oBAAA,CAAA,GAAA,CAAA,OAAA;AAAA,iBAajD,aAAA,CAAA;EAAgB,SAAA;EAAA,GAAc;AAAA,GAAS,kBAAA,GAAkB,oBAAA,CAAA,GAAA,CAAA,OAAA;AAAA,iBAazD,gBAAA,CAAA;EACP,SAAA;EACA,QAAA;EAAA,GACG;AAAA,GACF,qBAAA,GAAqB,oBAAA,CAAA,GAAA,CAAA,OAAA;AAAA,iBAmBf,gBAAA,CAAA;EACP,SAAA;EACA,QAAA;EAAA,GACG;AAAA,GACF,qBAAA,GAAqB,oBAAA,CAAA,GAAA,CAAA,OAAA"}
package/dist/accordion.js CHANGED
@@ -1,81 +1,58 @@
1
- import { ChevronDownIcon, ChevronUpIcon } from './chunk-DIGOLJIR.js';
2
- import { cn } from './chunk-76UQO56T.js';
3
- import { Accordion as Accordion$1 } from '@base-ui/react/accordion';
4
- import { jsx, jsxs } from 'react/jsx-runtime';
5
-
1
+ "use client";
2
+ import { cn } from "./lib/utils.js";
3
+ import { ChevronDownIcon, ChevronUpIcon } from "./lib/internal-icons.js";
4
+ import "react";
5
+ import { Accordion as Accordion$1 } from "@base-ui/react/accordion";
6
+ import { jsx, jsxs } from "react/jsx-runtime";
7
+ //#region src/accordion.tsx
6
8
  function Accordion({ className, ...props }) {
7
- return /* @__PURE__ */ jsx(
8
- Accordion$1.Root,
9
- {
10
- "data-slot": "accordion",
11
- className: cn(
12
- "overflow-hidden flex w-full flex-col",
13
- className
14
- ),
15
- ...props
16
- }
17
- );
9
+ return /* @__PURE__ */ jsx(Accordion$1.Root, {
10
+ "data-slot": "accordion",
11
+ className: cn("overflow-hidden flex w-full flex-col", className),
12
+ ...props
13
+ });
18
14
  }
19
15
  function AccordionItem({ className, ...props }) {
20
- return /* @__PURE__ */ jsx(
21
- Accordion$1.Item,
22
- {
23
- "data-slot": "accordion-item",
24
- className: cn(
25
- "not-last:border-b",
26
- className
27
- ),
28
- ...props
29
- }
30
- );
16
+ return /* @__PURE__ */ jsx(Accordion$1.Item, {
17
+ "data-slot": "accordion-item",
18
+ className: cn("not-last:border-b", className),
19
+ ...props
20
+ });
31
21
  }
32
- function AccordionTrigger({
33
- className,
34
- children,
35
- ...props
36
- }) {
37
- return /* @__PURE__ */ jsx(Accordion$1.Header, { "data-slot": "accordion-header", className: "flex", children: /* @__PURE__ */ jsxs(
38
- Accordion$1.Trigger,
39
- {
40
- "data-slot": "accordion-trigger",
41
- className: cn(
42
- "focus-visible:ring-ring/50 focus-visible:border-ring focus-visible:after:border-ring **:data-[slot=accordion-trigger-icon]:text-muted-foreground group/accordion-trigger relative flex flex-1 items-start justify-between rounded-lg border border-transparent py-2.5 text-left text-sm font-medium transition-all outline-none hover:underline focus-visible:ring-3 aria-disabled:pointer-events-none aria-disabled:opacity-50 **:data-[slot=accordion-trigger-icon]:ml-auto **:data-[slot=accordion-trigger-icon]:size-4",
43
- className
44
- ),
45
- ...props,
46
- children: [
47
- children,
48
- /* @__PURE__ */ jsx(ChevronDownIcon, { "data-slot": "accordion-trigger-icon", className: "pointer-events-none shrink-0 group-aria-expanded/accordion-trigger:hidden" }),
49
- /* @__PURE__ */ jsx(ChevronUpIcon, { "data-slot": "accordion-trigger-icon", className: "pointer-events-none hidden shrink-0 group-aria-expanded/accordion-trigger:inline" })
50
- ]
51
- }
52
- ) });
22
+ function AccordionTrigger({ className, children, ...props }) {
23
+ return /* @__PURE__ */ jsx(Accordion$1.Header, {
24
+ "data-slot": "accordion-header",
25
+ className: "flex",
26
+ children: /* @__PURE__ */ jsxs(Accordion$1.Trigger, {
27
+ "data-slot": "accordion-trigger",
28
+ className: cn("focus-visible:ring-ring/50 focus-visible:border-ring focus-visible:after:border-ring **:data-[slot=accordion-trigger-icon]:text-muted-foreground group/accordion-trigger relative flex flex-1 items-start justify-between rounded-lg border border-transparent py-2.5 text-left text-sm font-medium transition-all outline-none hover:underline focus-visible:ring-3 aria-disabled:pointer-events-none aria-disabled:opacity-50 **:data-[slot=accordion-trigger-icon]:ml-auto **:data-[slot=accordion-trigger-icon]:size-4", className),
29
+ ...props,
30
+ children: [
31
+ children,
32
+ /* @__PURE__ */ jsx(ChevronDownIcon, {
33
+ "data-slot": "accordion-trigger-icon",
34
+ className: "pointer-events-none shrink-0 group-aria-expanded/accordion-trigger:hidden"
35
+ }),
36
+ /* @__PURE__ */ jsx(ChevronUpIcon, {
37
+ "data-slot": "accordion-trigger-icon",
38
+ className: "pointer-events-none hidden shrink-0 group-aria-expanded/accordion-trigger:inline"
39
+ })
40
+ ]
41
+ })
42
+ });
53
43
  }
54
- function AccordionContent({
55
- className,
56
- children,
57
- ...props
58
- }) {
59
- return /* @__PURE__ */ jsx(
60
- Accordion$1.Panel,
61
- {
62
- "data-slot": "accordion-content",
63
- className: "data-open:animate-accordion-down data-closed:animate-accordion-up overflow-hidden text-sm",
64
- ...props,
65
- children: /* @__PURE__ */ jsx(
66
- "div",
67
- {
68
- className: cn(
69
- "[&_a]:hover:text-foreground h-(--accordion-panel-height) pt-0 pb-2.5 data-ending-style:h-0 data-starting-style:h-0 [&_a]:underline [&_a]:underline-offset-3 [&_p:not(:last-child)]:mb-4",
70
- className
71
- ),
72
- children
73
- }
74
- )
75
- }
76
- );
44
+ function AccordionContent({ className, children, ...props }) {
45
+ return /* @__PURE__ */ jsx(Accordion$1.Panel, {
46
+ "data-slot": "accordion-content",
47
+ className: "data-open:animate-accordion-down data-closed:animate-accordion-up overflow-hidden text-sm",
48
+ ...props,
49
+ children: /* @__PURE__ */ jsx("div", {
50
+ className: cn("[&_a]:hover:text-foreground h-(--accordion-panel-height) pt-0 pb-2.5 data-ending-style:h-0 data-starting-style:h-0 [&_a]:underline [&_a]:underline-offset-3 [&_p:not(:last-child)]:mb-4", className),
51
+ children
52
+ })
53
+ });
77
54
  }
78
-
55
+ //#endregion
79
56
  export { Accordion, AccordionContent, AccordionItem, AccordionTrigger };
80
- //# sourceMappingURL=accordion.js.map
57
+
81
58
  //# sourceMappingURL=accordion.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/accordion.tsx"],"names":["AccordionPrimitive"],"mappings":";;;;;AAeA,SAAS,SAAA,CAAU,EAAE,SAAA,EAAW,GAAG,OAAM,EAAmB;AAC1D,EAAA,uBACE,GAAA;AAAA,IAACA,WAAA,CAAmB,IAAA;AAAA,IAAnB;AAAA,MACC,WAAA,EAAU,WAAA;AAAA,MACV,SAAA,EAAW,EAAA;AAAA,QACT,sCAAA;AAAA,QACA;AAAA,OACF;AAAA,MACC,GAAG;AAAA;AAAA,GACN;AAEJ;AAEA,SAAS,aAAA,CAAc,EAAE,SAAA,EAAW,GAAG,OAAM,EAAuB;AAClE,EAAA,uBACE,GAAA;AAAA,IAACA,WAAA,CAAmB,IAAA;AAAA,IAAnB;AAAA,MACC,WAAA,EAAU,gBAAA;AAAA,MACV,SAAA,EAAW,EAAA;AAAA,QACT,mBAAA;AAAA,QACA;AAAA,OACF;AAAA,MACC,GAAG;AAAA;AAAA,GACN;AAEJ;AAEA,SAAS,gBAAA,CAAiB;AAAA,EACxB,SAAA;AAAA,EACA,QAAA;AAAA,EACA,GAAG;AACL,CAAA,EAA0B;AACxB,EAAA,2BACGA,WAAA,CAAmB,MAAA,EAAnB,EAA0B,WAAA,EAAU,kBAAA,EAAmB,WAAU,MAAA,EAChE,QAAA,kBAAA,IAAA;AAAA,IAACA,WAAA,CAAmB,OAAA;AAAA,IAAnB;AAAA,MACC,WAAA,EAAU,mBAAA;AAAA,MACV,SAAA,EAAW,EAAA;AAAA,QACT,4fAAA;AAAA,QACA;AAAA,OACF;AAAA,MACC,GAAG,KAAA;AAAA,MAEH,QAAA,EAAA;AAAA,QAAA,QAAA;AAAA,wBACD,GAAA,CAAC,eAAA,EAAA,EAAgB,WAAA,EAAU,wBAAA,EAAyB,WAAU,2EAAA,EAA4E,CAAA;AAAA,wBAC1I,GAAA,CAAC,aAAA,EAAA,EAAc,WAAA,EAAU,wBAAA,EAAyB,WAAU,kFAAA,EAAmF;AAAA;AAAA;AAAA,GACjJ,EACF,CAAA;AAEJ;AAEA,SAAS,gBAAA,CAAiB;AAAA,EACxB,SAAA;AAAA,EACA,QAAA;AAAA,EACA,GAAG;AACL,CAAA,EAA0B;AACxB,EAAA,uBACE,GAAA;AAAA,IAACA,WAAA,CAAmB,KAAA;AAAA,IAAnB;AAAA,MACC,WAAA,EAAU,mBAAA;AAAA,MACV,SAAA,EAAU,2FAAA;AAAA,MACT,GAAG,KAAA;AAAA,MAEJ,QAAA,kBAAA,GAAA;AAAA,QAAC,KAAA;AAAA,QAAA;AAAA,UACC,SAAA,EAAW,EAAA;AAAA,YACT,yLAAA;AAAA,YACA;AAAA,WACF;AAAA,UAEC;AAAA;AAAA;AACH;AAAA,GACF;AAEJ","file":"accordion.js","sourcesContent":["\"use client\"\n\nimport * as React from \"react\"\n\nimport { Accordion as AccordionPrimitive } from \"@base-ui/react/accordion\"\n\nimport { cn } from \"./lib/utils\"\n\nimport { ChevronDownIcon, ChevronUpIcon } from \"./lib/internal-icons\"\n\ntype AccordionProps = React.ComponentProps<typeof AccordionPrimitive.Root>\ntype AccordionItemProps = React.ComponentProps<typeof AccordionPrimitive.Item>\ntype AccordionTriggerProps = React.ComponentProps<typeof AccordionPrimitive.Trigger>\ntype AccordionContentProps = React.ComponentProps<typeof AccordionPrimitive.Panel>\n\nfunction Accordion({ className, ...props }: AccordionProps) {\n return (\n <AccordionPrimitive.Root\n data-slot=\"accordion\"\n className={cn(\n \"overflow-hidden flex w-full flex-col\",\n className\n )}\n {...props}\n />\n )\n}\n\nfunction AccordionItem({ className, ...props }: AccordionItemProps) {\n return (\n <AccordionPrimitive.Item\n data-slot=\"accordion-item\"\n className={cn(\n \"not-last:border-b\",\n className\n )}\n {...props}\n />\n )\n}\n\nfunction AccordionTrigger({\n className,\n children,\n ...props\n}: AccordionTriggerProps) {\n return (\n <AccordionPrimitive.Header data-slot=\"accordion-header\" className=\"flex\">\n <AccordionPrimitive.Trigger\n data-slot=\"accordion-trigger\"\n className={cn(\n \"focus-visible:ring-ring/50 focus-visible:border-ring focus-visible:after:border-ring **:data-[slot=accordion-trigger-icon]:text-muted-foreground group/accordion-trigger relative flex flex-1 items-start justify-between rounded-lg border border-transparent py-2.5 text-left text-sm font-medium transition-all outline-none hover:underline focus-visible:ring-3 aria-disabled:pointer-events-none aria-disabled:opacity-50 **:data-[slot=accordion-trigger-icon]:ml-auto **:data-[slot=accordion-trigger-icon]:size-4\",\n className\n )}\n {...props}\n >\n {children}\n <ChevronDownIcon data-slot=\"accordion-trigger-icon\" className=\"pointer-events-none shrink-0 group-aria-expanded/accordion-trigger:hidden\" />\n <ChevronUpIcon data-slot=\"accordion-trigger-icon\" className=\"pointer-events-none hidden shrink-0 group-aria-expanded/accordion-trigger:inline\" />\n </AccordionPrimitive.Trigger>\n </AccordionPrimitive.Header>\n )\n}\n\nfunction AccordionContent({\n className,\n children,\n ...props\n}: AccordionContentProps) {\n return (\n <AccordionPrimitive.Panel\n data-slot=\"accordion-content\"\n className=\"data-open:animate-accordion-down data-closed:animate-accordion-up overflow-hidden text-sm\"\n {...props}\n >\n <div\n className={cn(\n \"[&_a]:hover:text-foreground h-(--accordion-panel-height) pt-0 pb-2.5 data-ending-style:h-0 data-starting-style:h-0 [&_a]:underline [&_a]:underline-offset-3 [&_p:not(:last-child)]:mb-4\",\n className\n )}\n >\n {children}\n </div>\n </AccordionPrimitive.Panel>\n )\n}\n\nexport {\n Accordion,\n AccordionItem,\n AccordionTrigger,\n AccordionContent,\n}\n"]}
1
+ {"version":3,"file":"accordion.js","names":["AccordionPrimitive"],"sources":["../src/accordion.tsx"],"sourcesContent":["\"use client\"\n\nimport * as React from \"react\"\n\nimport { Accordion as AccordionPrimitive } from \"@base-ui/react/accordion\"\n\nimport { cn } from \"./lib/utils\"\n\nimport { ChevronDownIcon, ChevronUpIcon } from \"./lib/internal-icons\"\n\ntype AccordionProps = React.ComponentProps<typeof AccordionPrimitive.Root>\ntype AccordionItemProps = React.ComponentProps<typeof AccordionPrimitive.Item>\ntype AccordionTriggerProps = React.ComponentProps<typeof AccordionPrimitive.Trigger>\ntype AccordionContentProps = React.ComponentProps<typeof AccordionPrimitive.Panel>\n\nfunction Accordion({ className, ...props }: AccordionProps) {\n return (\n <AccordionPrimitive.Root\n data-slot=\"accordion\"\n className={cn(\n \"overflow-hidden flex w-full flex-col\",\n className\n )}\n {...props}\n />\n )\n}\n\nfunction AccordionItem({ className, ...props }: AccordionItemProps) {\n return (\n <AccordionPrimitive.Item\n data-slot=\"accordion-item\"\n className={cn(\n \"not-last:border-b\",\n className\n )}\n {...props}\n />\n )\n}\n\nfunction AccordionTrigger({\n className,\n children,\n ...props\n}: AccordionTriggerProps) {\n return (\n <AccordionPrimitive.Header data-slot=\"accordion-header\" className=\"flex\">\n <AccordionPrimitive.Trigger\n data-slot=\"accordion-trigger\"\n className={cn(\n \"focus-visible:ring-ring/50 focus-visible:border-ring focus-visible:after:border-ring **:data-[slot=accordion-trigger-icon]:text-muted-foreground group/accordion-trigger relative flex flex-1 items-start justify-between rounded-lg border border-transparent py-2.5 text-left text-sm font-medium transition-all outline-none hover:underline focus-visible:ring-3 aria-disabled:pointer-events-none aria-disabled:opacity-50 **:data-[slot=accordion-trigger-icon]:ml-auto **:data-[slot=accordion-trigger-icon]:size-4\",\n className\n )}\n {...props}\n >\n {children}\n <ChevronDownIcon data-slot=\"accordion-trigger-icon\" className=\"pointer-events-none shrink-0 group-aria-expanded/accordion-trigger:hidden\" />\n <ChevronUpIcon data-slot=\"accordion-trigger-icon\" className=\"pointer-events-none hidden shrink-0 group-aria-expanded/accordion-trigger:inline\" />\n </AccordionPrimitive.Trigger>\n </AccordionPrimitive.Header>\n )\n}\n\nfunction AccordionContent({\n className,\n children,\n ...props\n}: AccordionContentProps) {\n return (\n <AccordionPrimitive.Panel\n data-slot=\"accordion-content\"\n className=\"data-open:animate-accordion-down data-closed:animate-accordion-up overflow-hidden text-sm\"\n {...props}\n >\n <div\n className={cn(\n \"[&_a]:hover:text-foreground h-(--accordion-panel-height) pt-0 pb-2.5 data-ending-style:h-0 data-starting-style:h-0 [&_a]:underline [&_a]:underline-offset-3 [&_p:not(:last-child)]:mb-4\",\n className\n )}\n >\n {children}\n </div>\n </AccordionPrimitive.Panel>\n )\n}\n\nexport {\n Accordion,\n AccordionItem,\n AccordionTrigger,\n AccordionContent,\n}\n"],"mappings":";;;;;;;AAeA,SAAS,UAAU,EAAE,WAAW,GAAG,SAAyB;AAC1D,QACE,oBAACA,YAAmB,MAApB;EACE,aAAU;EACV,WAAW,GACT,wCACA,UACD;EACD,GAAI;EACJ,CAAA;;AAIN,SAAS,cAAc,EAAE,WAAW,GAAG,SAA6B;AAClE,QACE,oBAACA,YAAmB,MAApB;EACE,aAAU;EACV,WAAW,GACT,qBACA,UACD;EACD,GAAI;EACJ,CAAA;;AAIN,SAAS,iBAAiB,EACxB,WACA,UACA,GAAG,SACqB;AACxB,QACE,oBAACA,YAAmB,QAApB;EAA2B,aAAU;EAAmB,WAAU;YAChE,qBAACA,YAAmB,SAApB;GACE,aAAU;GACV,WAAW,GACT,8fACA,UACD;GACD,GAAI;aANN;IAQG;IACD,oBAAC,iBAAD;KAAiB,aAAU;KAAyB,WAAU;KAA8E,CAAA;IAC5I,oBAAC,eAAD;KAAe,aAAU;KAAyB,WAAU;KAAqF,CAAA;IACtH;;EACH,CAAA;;AAIhC,SAAS,iBAAiB,EACxB,WACA,UACA,GAAG,SACqB;AACxB,QACE,oBAACA,YAAmB,OAApB;EACE,aAAU;EACV,WAAU;EACV,GAAI;YAEJ,oBAAC,OAAD;GACE,WAAW,GACT,2LACA,UACD;GAEA;GACG,CAAA;EACmB,CAAA"}
@@ -0,0 +1,83 @@
1
+ import * as React from "react";
2
+ import * as _$react_jsx_runtime0 from "react/jsx-runtime";
3
+
4
+ //#region src/action-bar.d.ts
5
+ /** State a form registers with the ActionBar. */
6
+ interface ActionBarEntry {
7
+ /** Whether this form has unsaved changes. */
8
+ hasChanges: boolean;
9
+ /** Whether this form is currently saving. */
10
+ saving: boolean;
11
+ /** Save this form's changes. */
12
+ onSave: () => void | Promise<void>;
13
+ /** Discard this form's changes. */
14
+ onReset: () => void;
15
+ }
16
+ interface ActionBarProviderProps {
17
+ children: React.ReactNode;
18
+ /** Message when one form has changes. */
19
+ message?: string;
20
+ /** Message template for multiple dirty forms. */
21
+ pluralMessage?: (count: number) => string;
22
+ /**
23
+ * Announced to assistive tech (and the only feedback reduced-motion
24
+ * users get) when guarded navigation is blocked.
25
+ */
26
+ blockedMessage?: string;
27
+ /** Additional className for the bar's outer wrapper. */
28
+ className?: string;
29
+ }
30
+ /**
31
+ * Global action bar for unsaved changes.
32
+ *
33
+ * Place once at the root layout. Forms register via `useActionBar()`.
34
+ *
35
+ * Features:
36
+ * - Multi-form aggregation (Save All / Reset All)
37
+ * - ⌘S / Ctrl+S keyboard shortcut
38
+ * - Navigation guard with Discord-style page jiggle
39
+ * - `beforeunload` guard for browser close/refresh
40
+ *
41
+ * @example
42
+ * ```tsx
43
+ * // Root layout — once
44
+ * <ActionBarProvider>{children}</ActionBarProvider>
45
+ *
46
+ * // Any form component
47
+ * useActionBar('profile', { hasChanges, saving, onSave, onReset });
48
+ * ```
49
+ */
50
+ declare function ActionBarProvider({
51
+ children,
52
+ message,
53
+ pluralMessage,
54
+ blockedMessage,
55
+ className
56
+ }: ActionBarProviderProps): _$react_jsx_runtime0.JSX.Element;
57
+ /**
58
+ * Register a form's unsaved state with the global ActionBar.
59
+ *
60
+ * Unregisters automatically on unmount.
61
+ *
62
+ * @param id — Unique key (e.g., 'profile', 'notifications')
63
+ * @param entry — Current form state
64
+ */
65
+ declare function useActionBar(id: string, entry: ActionBarEntry): void;
66
+ /**
67
+ * Returns a function that guards navigation.
68
+ * If unsaved changes exist, triggers the jiggle and blocks navigation.
69
+ * Otherwise navigates normally via the provided callback.
70
+ *
71
+ * @param navigate — Your navigation function (e.g., `router.push`)
72
+ *
73
+ * @example
74
+ * ```tsx
75
+ * const router = useRouter();
76
+ * const guardedPush = useActionBarGuard(router.push);
77
+ * <button onClick={() => guardedPush('/settings')}>Settings</button>
78
+ * ```
79
+ */
80
+ declare function useActionBarGuard(navigate: (href: string) => void): (href: string) => boolean;
81
+ //#endregion
82
+ export { ActionBarEntry, ActionBarProvider, ActionBarProviderProps, useActionBar, useActionBarGuard };
83
+ //# sourceMappingURL=action-bar.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"action-bar.d.ts","names":[],"sources":["../src/action-bar.tsx"],"mappings":";;;;;UAeiB,cAAA;;EAEf,UAAA;EAF6B;EAI7B,MAAA;EAE4B;EAA5B,MAAA,eAAqB,OAAA;EAFrB;EAIA,OAAA;AAAA;AAAA,UA4Ce,sBAAA;EACf,QAAA,EAAU,KAAA,CAAM,SAAA;EA7CT;EA+CP,OAAA;EAHqC;EAKrC,aAAA,IAAiB,KAAA;EAJQ;;;;EASzB,cAAA;EALA;EAOA,SAAA;AAAA;;;;AACD;;;;;;;;;;;;;;;;;iBAsBQ,iBAAA,CAAA;EACP,QAAA;EACA,OAAA;EACA,aAAA;EACA,cAAA;EACA;AAAA,GACC,sBAAA,GAAsB,oBAAA,CAAA,GAAA,CAAA,OAAA;;;;;;;;;iBAuQhB,YAAA,CAAa,EAAA,UAAY,KAAA,EAAO,cAAA;AAvQhB;;;;;;;;;AAuQ8B;;;;;AAvQ9B,iBA8ShB,iBAAA,CAAkB,QAAA,GAAW,IAAA,qBAAqB,IAAA"}
@@ -0,0 +1,264 @@
1
+ "use client";
2
+ import { cn } from "./lib/utils.js";
3
+ import { Button } from "./button.js";
4
+ import { Spinner } from "./spinner.js";
5
+ import { Kbd } from "./kbd.js";
6
+ import * as React from "react";
7
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
8
+ import { AnimatePresence, motion, useReducedMotion } from "motion/react";
9
+ //#region src/action-bar.tsx
10
+ const JIGGLE_STEPS = 6;
11
+ const JIGGLE_INTERVAL = 50;
12
+ const JIGGLE_RANGE = 15;
13
+ /**
14
+ * SSR-safe platform detection. Returns `false` on the server and on the
15
+ * first client render so hydration matches, then resolves the real
16
+ * platform after mount. Avoids the `⌘S`/`Ctrl+S` hydration mismatch
17
+ * that a module-scope `navigator` read would cause.
18
+ */
19
+ function useIsMac() {
20
+ const [isMac, setIsMac] = React.useState(false);
21
+ React.useEffect(() => {
22
+ setIsMac(/Mac|iPhone|iPad/.test(navigator.userAgent));
23
+ }, []);
24
+ return isMac;
25
+ }
26
+ const ActionBarContext = React.createContext(null);
27
+ /**
28
+ * Global action bar for unsaved changes.
29
+ *
30
+ * Place once at the root layout. Forms register via `useActionBar()`.
31
+ *
32
+ * Features:
33
+ * - Multi-form aggregation (Save All / Reset All)
34
+ * - ⌘S / Ctrl+S keyboard shortcut
35
+ * - Navigation guard with Discord-style page jiggle
36
+ * - `beforeunload` guard for browser close/refresh
37
+ *
38
+ * @example
39
+ * ```tsx
40
+ * // Root layout — once
41
+ * <ActionBarProvider>{children}</ActionBarProvider>
42
+ *
43
+ * // Any form component
44
+ * useActionBar('profile', { hasChanges, saving, onSave, onReset });
45
+ * ```
46
+ */
47
+ function ActionBarProvider({ children, message = "You have unsaved changes", pluralMessage = (count) => `${count} unsaved changes`, blockedMessage = "Save or reset your changes before leaving this page", className }) {
48
+ const entriesRef = React.useRef(/* @__PURE__ */ new Map());
49
+ const [, forceUpdate] = React.useState(0);
50
+ const [jiggleTransform, setJiggleTransform] = React.useState(null);
51
+ const jiggleTimerRef = React.useRef(null);
52
+ const contentRef = React.useRef(null);
53
+ const isMac = useIsMac();
54
+ const prefersReducedMotion = useReducedMotion();
55
+ const reducedMotionRef = React.useRef(prefersReducedMotion);
56
+ reducedMotionRef.current = prefersReducedMotion;
57
+ const [blockedNotice, setBlockedNotice] = React.useState("");
58
+ const register = React.useCallback((id, entry) => {
59
+ const prev = entriesRef.current.get(id);
60
+ entriesRef.current.set(id, entry);
61
+ if (!prev || prev.hasChanges !== entry.hasChanges || prev.saving !== entry.saving) forceUpdate((n) => n + 1);
62
+ }, []);
63
+ const unregister = React.useCallback((id) => {
64
+ if (entriesRef.current.delete(id)) forceUpdate((n) => n + 1);
65
+ }, []);
66
+ const hasDirty = React.useCallback(() => {
67
+ for (const entry of entriesRef.current.values()) if (entry.hasChanges) return true;
68
+ return false;
69
+ }, []);
70
+ const jiggle = React.useCallback(() => {
71
+ setBlockedNotice("");
72
+ requestAnimationFrame(() => setBlockedNotice(blockedMessage));
73
+ if (reducedMotionRef.current) return;
74
+ if (jiggleTimerRef.current) return;
75
+ let step = 0;
76
+ function tick() {
77
+ step++;
78
+ if (step >= JIGGLE_STEPS) {
79
+ setJiggleTransform(null);
80
+ jiggleTimerRef.current = null;
81
+ return;
82
+ }
83
+ const x = (Math.random() - .5) * 2 * JIGGLE_RANGE;
84
+ const y = (Math.random() - .5) * 2 * JIGGLE_RANGE;
85
+ setJiggleTransform(`translate3d(${x.toFixed(5)}px, ${y.toFixed(5)}px, 0px)`);
86
+ jiggleTimerRef.current = setTimeout(tick, JIGGLE_INTERVAL);
87
+ }
88
+ tick();
89
+ }, [blockedMessage]);
90
+ const dirty = [];
91
+ let anySaving = false;
92
+ for (const entry of entriesRef.current.values()) {
93
+ if (entry.hasChanges) dirty.push(entry);
94
+ if (entry.saving) anySaving = true;
95
+ }
96
+ const showBar = dirty.length > 0 || anySaving;
97
+ const dirtyCount = dirty.length;
98
+ const displayMessage = dirtyCount > 1 ? pluralMessage(dirtyCount) : message;
99
+ const handleSaveAll = React.useCallback(async () => {
100
+ const saves = [...entriesRef.current.values()].filter((e) => e.hasChanges).map((e) => e.onSave());
101
+ await Promise.all(saves);
102
+ }, []);
103
+ const handleResetAll = React.useCallback(() => {
104
+ for (const entry of entriesRef.current.values()) if (entry.hasChanges) entry.onReset();
105
+ }, []);
106
+ React.useEffect(() => {
107
+ function handleKeyDown(e) {
108
+ if ((e.metaKey || e.ctrlKey) && e.key === "s") {
109
+ e.preventDefault();
110
+ if (hasDirty()) handleSaveAll();
111
+ }
112
+ }
113
+ document.addEventListener("keydown", handleKeyDown);
114
+ return () => document.removeEventListener("keydown", handleKeyDown);
115
+ }, [hasDirty, handleSaveAll]);
116
+ React.useEffect(() => {
117
+ function handleBeforeUnload(e) {
118
+ if (hasDirty()) e.preventDefault();
119
+ }
120
+ window.addEventListener("beforeunload", handleBeforeUnload);
121
+ return () => window.removeEventListener("beforeunload", handleBeforeUnload);
122
+ }, [hasDirty]);
123
+ const ctx = React.useMemo(() => ({
124
+ register,
125
+ unregister,
126
+ hasDirty,
127
+ jiggle
128
+ }), [
129
+ register,
130
+ unregister,
131
+ hasDirty,
132
+ jiggle
133
+ ]);
134
+ return /* @__PURE__ */ jsxs(ActionBarContext.Provider, {
135
+ value: ctx,
136
+ children: [
137
+ /* @__PURE__ */ jsx("div", {
138
+ "data-slot": "action-bar-shell",
139
+ ref: contentRef,
140
+ style: jiggleTransform ? { transform: jiggleTransform } : void 0,
141
+ children
142
+ }),
143
+ /* @__PURE__ */ jsx("span", {
144
+ "data-slot": "action-bar-status",
145
+ "aria-live": "polite",
146
+ className: "sr-only",
147
+ children: showBar ? displayMessage : ""
148
+ }),
149
+ /* @__PURE__ */ jsx("span", {
150
+ "data-slot": "action-bar-blocked-status",
151
+ "aria-live": "assertive",
152
+ className: "sr-only",
153
+ children: blockedNotice
154
+ }),
155
+ /* @__PURE__ */ jsx(AnimatePresence, { children: showBar && /* @__PURE__ */ jsx(motion.div, {
156
+ "data-slot": "action-bar",
157
+ initial: prefersReducedMotion ? {
158
+ opacity: 0,
159
+ x: "-50%"
160
+ } : {
161
+ opacity: 0,
162
+ y: 20,
163
+ x: "-50%"
164
+ },
165
+ animate: {
166
+ opacity: 1,
167
+ y: 0,
168
+ x: "-50%"
169
+ },
170
+ exit: prefersReducedMotion ? {
171
+ opacity: 0,
172
+ x: "-50%"
173
+ } : {
174
+ opacity: 0,
175
+ y: 20,
176
+ x: "-50%"
177
+ },
178
+ transition: {
179
+ duration: .2,
180
+ ease: "easeOut"
181
+ },
182
+ className: "fixed bottom-6 left-1/2 z-50",
183
+ children: /* @__PURE__ */ jsxs("div", {
184
+ "data-slot": "action-bar-content",
185
+ className: cn("flex items-center gap-6 rounded-xl border border-border/60 bg-card px-5 py-2.5 shadow-lg ring-1 ring-black/5 backdrop-blur-sm dark:ring-white/5", className),
186
+ children: [/* @__PURE__ */ jsx("span", {
187
+ "data-slot": "action-bar-message",
188
+ className: "whitespace-nowrap text-sm font-medium text-foreground",
189
+ children: displayMessage
190
+ }), /* @__PURE__ */ jsxs("div", {
191
+ "data-slot": "action-bar-actions",
192
+ className: "flex items-center gap-1.5",
193
+ children: [/* @__PURE__ */ jsx(Button, {
194
+ type: "button",
195
+ variant: "ghost",
196
+ disabled: anySaving,
197
+ onClick: handleResetAll,
198
+ className: "h-9 px-3 text-sm hover:text-destructive",
199
+ children: "Reset"
200
+ }), /* @__PURE__ */ jsx(Button, {
201
+ type: "button",
202
+ variant: "default",
203
+ disabled: anySaving,
204
+ onClick: handleSaveAll,
205
+ className: "h-9 px-4 text-sm",
206
+ children: anySaving ? /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(Spinner, { className: "mr-1.5 h-3.5 w-3.5" }), "Saving"] }) : /* @__PURE__ */ jsxs(Fragment, { children: ["Save", /* @__PURE__ */ jsx(Kbd, {
207
+ className: "ml-1.5",
208
+ children: isMac ? "⌘S" : "Ctrl+S"
209
+ })] })
210
+ })]
211
+ })]
212
+ })
213
+ }) })
214
+ ]
215
+ });
216
+ }
217
+ /**
218
+ * Register a form's unsaved state with the global ActionBar.
219
+ *
220
+ * Unregisters automatically on unmount.
221
+ *
222
+ * @param id — Unique key (e.g., 'profile', 'notifications')
223
+ * @param entry — Current form state
224
+ */
225
+ function useActionBar(id, entry) {
226
+ const ctx = React.useContext(ActionBarContext);
227
+ if (!ctx) throw new Error("useActionBar must be used within <ActionBarProvider>");
228
+ const { register, unregister } = ctx;
229
+ React.useEffect(() => {
230
+ register(id, entry);
231
+ });
232
+ React.useEffect(() => {
233
+ return () => unregister(id);
234
+ }, [id, unregister]);
235
+ }
236
+ /**
237
+ * Returns a function that guards navigation.
238
+ * If unsaved changes exist, triggers the jiggle and blocks navigation.
239
+ * Otherwise navigates normally via the provided callback.
240
+ *
241
+ * @param navigate — Your navigation function (e.g., `router.push`)
242
+ *
243
+ * @example
244
+ * ```tsx
245
+ * const router = useRouter();
246
+ * const guardedPush = useActionBarGuard(router.push);
247
+ * <button onClick={() => guardedPush('/settings')}>Settings</button>
248
+ * ```
249
+ */
250
+ function useActionBarGuard(navigate) {
251
+ const ctx = React.useContext(ActionBarContext);
252
+ return React.useCallback((href) => {
253
+ if (ctx?.hasDirty()) {
254
+ ctx.jiggle();
255
+ return false;
256
+ }
257
+ navigate(href);
258
+ return true;
259
+ }, [ctx, navigate]);
260
+ }
261
+ //#endregion
262
+ export { ActionBarProvider, useActionBar, useActionBarGuard };
263
+
264
+ //# sourceMappingURL=action-bar.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"action-bar.js","names":[],"sources":["../src/action-bar.tsx"],"sourcesContent":["\"use client\"\n\nimport * as React from \"react\"\nimport { AnimatePresence, motion, useReducedMotion } from \"motion/react\"\n\nimport { cn } from \"./lib/utils\"\nimport { Button } from \"./button\"\nimport { Spinner } from \"./spinner\"\nimport { Kbd } from \"./kbd\"\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\n/** State a form registers with the ActionBar. */\nexport interface ActionBarEntry {\n /** Whether this form has unsaved changes. */\n hasChanges: boolean\n /** Whether this form is currently saving. */\n saving: boolean\n /** Save this form's changes. */\n onSave: () => void | Promise<void>\n /** Discard this form's changes. */\n onReset: () => void\n}\n\ninterface ActionBarContextValue {\n register: (id: string, entry: ActionBarEntry) => void\n unregister: (id: string) => void\n /** Returns true if any registered form has unsaved changes. */\n hasDirty: () => boolean\n /** Trigger the jiggle effect on blocked navigation. */\n jiggle: () => void\n}\n\n// ---------------------------------------------------------------------------\n// Constants\n// ---------------------------------------------------------------------------\n\nconst JIGGLE_STEPS = 6\nconst JIGGLE_INTERVAL = 50\nconst JIGGLE_RANGE = 15\n\n/**\n * SSR-safe platform detection. Returns `false` on the server and on the\n * first client render so hydration matches, then resolves the real\n * platform after mount. Avoids the `⌘S`/`Ctrl+S` hydration mismatch\n * that a module-scope `navigator` read would cause.\n */\nfunction useIsMac(): boolean {\n const [isMac, setIsMac] = React.useState(false)\n React.useEffect(() => {\n setIsMac(/Mac|iPhone|iPad/.test(navigator.userAgent))\n }, [])\n return isMac\n}\n\n// ---------------------------------------------------------------------------\n// Context\n// ---------------------------------------------------------------------------\n\nconst ActionBarContext = React.createContext<ActionBarContextValue | null>(null)\n\n// ---------------------------------------------------------------------------\n// Provider\n// ---------------------------------------------------------------------------\n\nexport interface ActionBarProviderProps {\n children: React.ReactNode\n /** Message when one form has changes. */\n message?: string\n /** Message template for multiple dirty forms. */\n pluralMessage?: (count: number) => string\n /**\n * Announced to assistive tech (and the only feedback reduced-motion\n * users get) when guarded navigation is blocked.\n */\n blockedMessage?: string\n /** Additional className for the bar's outer wrapper. */\n className?: string\n}\n\n/**\n * Global action bar for unsaved changes.\n *\n * Place once at the root layout. Forms register via `useActionBar()`.\n *\n * Features:\n * - Multi-form aggregation (Save All / Reset All)\n * - ⌘S / Ctrl+S keyboard shortcut\n * - Navigation guard with Discord-style page jiggle\n * - `beforeunload` guard for browser close/refresh\n *\n * @example\n * ```tsx\n * // Root layout — once\n * <ActionBarProvider>{children}</ActionBarProvider>\n *\n * // Any form component\n * useActionBar('profile', { hasChanges, saving, onSave, onReset });\n * ```\n */\nfunction ActionBarProvider({\n children,\n message = \"You have unsaved changes\",\n pluralMessage = (count) => `${count} unsaved changes`,\n blockedMessage = \"Save or reset your changes before leaving this page\",\n className,\n}: ActionBarProviderProps) {\n const entriesRef = React.useRef(new Map<string, ActionBarEntry>())\n const [, forceUpdate] = React.useState(0)\n const [jiggleTransform, setJiggleTransform] = React.useState<string | null>(\n null\n )\n const jiggleTimerRef = React.useRef<ReturnType<typeof setTimeout> | null>(\n null\n )\n const contentRef = React.useRef<HTMLDivElement>(null)\n const isMac = useIsMac()\n const prefersReducedMotion = useReducedMotion()\n const reducedMotionRef = React.useRef(prefersReducedMotion)\n reducedMotionRef.current = prefersReducedMotion\n // Assertive announcement for blocked navigation. This is the *only*\n // feedback channel that works for screen-reader and reduced-motion\n // users (the visual jiggle is suppressed for them), so it is driven\n // independently of the shake.\n const [blockedNotice, setBlockedNotice] = React.useState(\"\")\n\n // --- Registry ---\n\n const register = React.useCallback((id: string, entry: ActionBarEntry) => {\n const prev = entriesRef.current.get(id)\n entriesRef.current.set(id, entry)\n if (\n !prev ||\n prev.hasChanges !== entry.hasChanges ||\n prev.saving !== entry.saving\n ) {\n forceUpdate((n) => n + 1)\n }\n }, [])\n\n const unregister = React.useCallback((id: string) => {\n if (entriesRef.current.delete(id)) {\n forceUpdate((n) => n + 1)\n }\n }, [])\n\n const hasDirty = React.useCallback(() => {\n for (const entry of entriesRef.current.values()) {\n if (entry.hasChanges) return true\n }\n return false\n }, [])\n\n // --- Jiggle ---\n\n const jiggle = React.useCallback(() => {\n // Announce to assistive tech on every blocked attempt. Clearing\n // first guarantees a text change so an identical message\n // re-announces on repeat presses.\n setBlockedNotice(\"\")\n requestAnimationFrame(() => setBlockedNotice(blockedMessage))\n\n // Vestibular safety: the random-translate shake is purely a motion\n // cue, so skip it under prefers-reduced-motion. The assertive\n // announcement above is the accessible equivalent.\n if (reducedMotionRef.current) return\n if (jiggleTimerRef.current) return\n\n let step = 0\n\n function tick() {\n step++\n if (step >= JIGGLE_STEPS) {\n setJiggleTransform(null)\n jiggleTimerRef.current = null\n return\n }\n const x = (Math.random() - 0.5) * 2 * JIGGLE_RANGE\n const y = (Math.random() - 0.5) * 2 * JIGGLE_RANGE\n setJiggleTransform(\n `translate3d(${x.toFixed(5)}px, ${y.toFixed(5)}px, 0px)`\n )\n jiggleTimerRef.current = setTimeout(tick, JIGGLE_INTERVAL)\n }\n\n tick()\n }, [blockedMessage])\n\n // --- Aggregated state ---\n\n const dirty: ActionBarEntry[] = []\n let anySaving = false\n\n for (const entry of entriesRef.current.values()) {\n if (entry.hasChanges) dirty.push(entry)\n if (entry.saving) anySaving = true\n }\n\n const showBar = dirty.length > 0 || anySaving\n const dirtyCount = dirty.length\n const displayMessage =\n dirtyCount > 1 ? pluralMessage(dirtyCount) : message\n\n // --- Save / Reset ---\n\n const handleSaveAll = React.useCallback(async () => {\n const saves = [...entriesRef.current.values()]\n .filter((e) => e.hasChanges)\n .map((e) => e.onSave())\n await Promise.all(saves)\n }, [])\n\n const handleResetAll = React.useCallback(() => {\n for (const entry of entriesRef.current.values()) {\n if (entry.hasChanges) entry.onReset()\n }\n }, [])\n\n // --- ⌘S / Ctrl+S ---\n\n React.useEffect(() => {\n function handleKeyDown(e: KeyboardEvent) {\n if ((e.metaKey || e.ctrlKey) && e.key === \"s\") {\n e.preventDefault()\n if (hasDirty()) {\n handleSaveAll()\n }\n }\n }\n\n document.addEventListener(\"keydown\", handleKeyDown)\n return () => document.removeEventListener(\"keydown\", handleKeyDown)\n }, [hasDirty, handleSaveAll])\n\n // --- beforeunload ---\n\n React.useEffect(() => {\n function handleBeforeUnload(e: BeforeUnloadEvent) {\n if (hasDirty()) {\n e.preventDefault()\n }\n }\n\n window.addEventListener(\"beforeunload\", handleBeforeUnload)\n return () => window.removeEventListener(\"beforeunload\", handleBeforeUnload)\n }, [hasDirty])\n\n // --- Context ---\n\n const ctx = React.useMemo(\n () => ({ register, unregister, hasDirty, jiggle }),\n [register, unregister, hasDirty, jiggle]\n )\n\n return (\n <ActionBarContext.Provider value={ctx}>\n <div\n data-slot=\"action-bar-shell\"\n ref={contentRef}\n style={jiggleTransform ? { transform: jiggleTransform } : undefined}\n >\n {children}\n </div>\n\n {/*\n Persistent SR-only live regions. They are always mounted so the\n announcement fires reliably when their text changes — a region\n mounted already-populated is not announced consistently across\n screen reader / browser combinations.\n */}\n <span data-slot=\"action-bar-status\" aria-live=\"polite\" className=\"sr-only\">\n {showBar ? displayMessage : \"\"}\n </span>\n <span\n data-slot=\"action-bar-blocked-status\"\n aria-live=\"assertive\"\n className=\"sr-only\"\n >\n {blockedNotice}\n </span>\n\n <AnimatePresence>\n {showBar && (\n <motion.div\n data-slot=\"action-bar\"\n initial={\n prefersReducedMotion\n ? { opacity: 0, x: \"-50%\" }\n : { opacity: 0, y: 20, x: \"-50%\" }\n }\n animate={{ opacity: 1, y: 0, x: \"-50%\" }}\n exit={\n prefersReducedMotion\n ? { opacity: 0, x: \"-50%\" }\n : { opacity: 0, y: 20, x: \"-50%\" }\n }\n transition={{ duration: 0.2, ease: \"easeOut\" }}\n className=\"fixed bottom-6 left-1/2 z-50\"\n >\n <div\n data-slot=\"action-bar-content\"\n className={cn(\n \"flex items-center gap-6 rounded-xl border border-border/60 bg-card px-5 py-2.5 shadow-lg ring-1 ring-black/5 backdrop-blur-sm dark:ring-white/5\",\n className\n )}\n >\n <span\n data-slot=\"action-bar-message\"\n className=\"whitespace-nowrap text-sm font-medium text-foreground\"\n >\n {displayMessage}\n </span>\n\n <div\n data-slot=\"action-bar-actions\"\n className=\"flex items-center gap-1.5\"\n >\n <Button\n type=\"button\"\n variant=\"ghost\"\n disabled={anySaving}\n onClick={handleResetAll}\n className=\"h-9 px-3 text-sm hover:text-destructive\"\n >\n Reset\n </Button>\n\n <Button\n type=\"button\"\n variant=\"default\"\n disabled={anySaving}\n onClick={handleSaveAll}\n className=\"h-9 px-4 text-sm\"\n >\n {anySaving ? (\n <>\n <Spinner className=\"mr-1.5 h-3.5 w-3.5\" />\n Saving\n </>\n ) : (\n <>\n Save\n <Kbd className=\"ml-1.5\">\n {isMac ? \"⌘S\" : \"Ctrl+S\"}\n </Kbd>\n </>\n )}\n </Button>\n </div>\n </div>\n </motion.div>\n )}\n </AnimatePresence>\n </ActionBarContext.Provider>\n )\n}\n\n// ---------------------------------------------------------------------------\n// Hook — register form state\n// ---------------------------------------------------------------------------\n\n/**\n * Register a form's unsaved state with the global ActionBar.\n *\n * Unregisters automatically on unmount.\n *\n * @param id — Unique key (e.g., 'profile', 'notifications')\n * @param entry — Current form state\n */\nfunction useActionBar(id: string, entry: ActionBarEntry) {\n const ctx = React.useContext(ActionBarContext)\n if (!ctx)\n throw new Error(\"useActionBar must be used within <ActionBarProvider>\")\n\n const { register, unregister } = ctx\n\n // Intentionally no dependency array: `entry` (and its `onSave`/\n // `onReset` closures) is rebuilt by the caller every render, so we\n // must re-register each render to keep the latest closures. The\n // `register` impl diffs the entry and only forces an update when\n // `hasChanges`/`saving` actually changed, so this can't loop.\n React.useEffect(() => {\n register(id, entry)\n })\n\n React.useEffect(() => {\n return () => unregister(id)\n }, [id, unregister])\n}\n\n// ---------------------------------------------------------------------------\n// Navigation guard hook\n// ---------------------------------------------------------------------------\n\n/**\n * Returns a function that guards navigation.\n * If unsaved changes exist, triggers the jiggle and blocks navigation.\n * Otherwise navigates normally via the provided callback.\n *\n * @param navigate — Your navigation function (e.g., `router.push`)\n *\n * @example\n * ```tsx\n * const router = useRouter();\n * const guardedPush = useActionBarGuard(router.push);\n * <button onClick={() => guardedPush('/settings')}>Settings</button>\n * ```\n */\nfunction useActionBarGuard(navigate: (href: string) => void) {\n const ctx = React.useContext(ActionBarContext)\n\n return React.useCallback(\n (href: string) => {\n if (ctx?.hasDirty()) {\n ctx.jiggle()\n return false\n }\n navigate(href)\n return true\n },\n [ctx, navigate]\n )\n}\n\n// ---------------------------------------------------------------------------\n// Exports\n// ---------------------------------------------------------------------------\n\nexport {\n ActionBarProvider,\n useActionBar,\n useActionBarGuard,\n}\n"],"mappings":"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"}