@braedonsaunders/appkit-ui 0.2.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 (300) hide show
  1. package/LICENSE +661 -0
  2. package/README.md +11 -0
  3. package/account-menu.d.ts +49 -0
  4. package/account-menu.d.ts.map +1 -0
  5. package/account-menu.js +66 -0
  6. package/account-menu.js.map +1 -0
  7. package/alert.d.ts +13 -0
  8. package/alert.d.ts.map +1 -0
  9. package/alert.js +22 -0
  10. package/alert.js.map +1 -0
  11. package/animated-number.d.ts +13 -0
  12. package/animated-number.d.ts.map +1 -0
  13. package/animated-number.js +53 -0
  14. package/animated-number.js.map +1 -0
  15. package/api-reference.d.ts +44 -0
  16. package/api-reference.d.ts.map +1 -0
  17. package/api-reference.js +82 -0
  18. package/api-reference.js.map +1 -0
  19. package/app-shell.d.ts +39 -0
  20. package/app-shell.d.ts.map +1 -0
  21. package/app-shell.js +21 -0
  22. package/app-shell.js.map +1 -0
  23. package/app-sidebar.d.ts +22 -0
  24. package/app-sidebar.d.ts.map +1 -0
  25. package/app-sidebar.js +30 -0
  26. package/app-sidebar.js.map +1 -0
  27. package/avatar.d.ts +9 -0
  28. package/avatar.d.ts.map +1 -0
  29. package/avatar.js +18 -0
  30. package/avatar.js.map +1 -0
  31. package/badge.d.ts +9 -0
  32. package/badge.d.ts.map +1 -0
  33. package/badge.js +23 -0
  34. package/badge.js.map +1 -0
  35. package/button.d.ts +24 -0
  36. package/button.d.ts.map +1 -0
  37. package/button.js +50 -0
  38. package/button.js.map +1 -0
  39. package/card.d.ts +21 -0
  40. package/card.d.ts.map +1 -0
  41. package/card.js +36 -0
  42. package/card.js.map +1 -0
  43. package/checkbox.d.ts +4 -0
  44. package/checkbox.d.ts.map +1 -0
  45. package/checkbox.js +6 -0
  46. package/checkbox.js.map +1 -0
  47. package/confirm-dialog.d.ts +23 -0
  48. package/confirm-dialog.d.ts.map +1 -0
  49. package/confirm-dialog.js +67 -0
  50. package/confirm-dialog.js.map +1 -0
  51. package/context-menu.d.ts +47 -0
  52. package/context-menu.d.ts.map +1 -0
  53. package/context-menu.js +90 -0
  54. package/context-menu.js.map +1 -0
  55. package/dialog.d.ts +25 -0
  56. package/dialog.d.ts.map +1 -0
  57. package/dialog.js +89 -0
  58. package/dialog.js.map +1 -0
  59. package/document-title.d.ts +11 -0
  60. package/document-title.d.ts.map +1 -0
  61. package/document-title.js +17 -0
  62. package/document-title.js.map +1 -0
  63. package/drawer.d.ts +63 -0
  64. package/drawer.d.ts.map +1 -0
  65. package/drawer.js +188 -0
  66. package/drawer.js.map +1 -0
  67. package/empty-state.d.ts +10 -0
  68. package/empty-state.d.ts.map +1 -0
  69. package/empty-state.js +7 -0
  70. package/empty-state.js.map +1 -0
  71. package/file-uploader.d.ts +67 -0
  72. package/file-uploader.d.ts.map +1 -0
  73. package/file-uploader.js +156 -0
  74. package/file-uploader.js.map +1 -0
  75. package/filter-chips.d.ts +47 -0
  76. package/filter-chips.d.ts.map +1 -0
  77. package/filter-chips.js +62 -0
  78. package/filter-chips.js.map +1 -0
  79. package/global-search.d.ts +41 -0
  80. package/global-search.d.ts.map +1 -0
  81. package/global-search.js +116 -0
  82. package/global-search.js.map +1 -0
  83. package/index.d.ts +70 -0
  84. package/index.d.ts.map +1 -0
  85. package/index.js +70 -0
  86. package/index.js.map +1 -0
  87. package/input.d.ts +9 -0
  88. package/input.d.ts.map +1 -0
  89. package/input.js +11 -0
  90. package/input.js.map +1 -0
  91. package/label.d.ts +3 -0
  92. package/label.d.ts.map +1 -0
  93. package/label.js +6 -0
  94. package/label.js.map +1 -0
  95. package/line-grid.d.ts +48 -0
  96. package/line-grid.d.ts.map +1 -0
  97. package/line-grid.js +155 -0
  98. package/line-grid.js.map +1 -0
  99. package/link-context.d.ts +44 -0
  100. package/link-context.d.ts.map +1 -0
  101. package/link-context.js +32 -0
  102. package/link-context.js.map +1 -0
  103. package/list-nav.d.ts +28 -0
  104. package/list-nav.d.ts.map +1 -0
  105. package/list-nav.js +41 -0
  106. package/list-nav.js.map +1 -0
  107. package/list-pagination.d.ts +27 -0
  108. package/list-pagination.d.ts.map +1 -0
  109. package/list-pagination.js +43 -0
  110. package/list-pagination.js.map +1 -0
  111. package/list-params.d.ts +41 -0
  112. package/list-params.d.ts.map +1 -0
  113. package/list-params.js +84 -0
  114. package/list-params.js.map +1 -0
  115. package/list-search-input-state.d.ts +13 -0
  116. package/list-search-input-state.d.ts.map +1 -0
  117. package/list-search-input-state.js +27 -0
  118. package/list-search-input-state.js.map +1 -0
  119. package/list-search-input.d.ts +16 -0
  120. package/list-search-input.d.ts.map +1 -0
  121. package/list-search-input.js +51 -0
  122. package/list-search-input.js.map +1 -0
  123. package/mobile-tab-bar.d.ts +14 -0
  124. package/mobile-tab-bar.d.ts.map +1 -0
  125. package/mobile-tab-bar.js +25 -0
  126. package/mobile-tab-bar.js.map +1 -0
  127. package/multi-select.d.ts +32 -0
  128. package/multi-select.d.ts.map +1 -0
  129. package/multi-select.js +52 -0
  130. package/multi-select.js.map +1 -0
  131. package/nav-overflow.d.ts +12 -0
  132. package/nav-overflow.d.ts.map +1 -0
  133. package/nav-overflow.js +30 -0
  134. package/nav-overflow.js.map +1 -0
  135. package/navigation-config-editor.d.ts +26 -0
  136. package/navigation-config-editor.d.ts.map +1 -0
  137. package/navigation-config-editor.js +57 -0
  138. package/navigation-config-editor.js.map +1 -0
  139. package/navigation-config.d.ts +48 -0
  140. package/navigation-config.d.ts.map +1 -0
  141. package/navigation-config.js +75 -0
  142. package/navigation-config.js.map +1 -0
  143. package/navigation-mode.d.ts +16 -0
  144. package/navigation-mode.d.ts.map +1 -0
  145. package/navigation-mode.js +30 -0
  146. package/navigation-mode.js.map +1 -0
  147. package/notifications-bell.d.ts +22 -0
  148. package/notifications-bell.d.ts.map +1 -0
  149. package/notifications-bell.js +30 -0
  150. package/notifications-bell.js.map +1 -0
  151. package/org-chart.d.ts +85 -0
  152. package/org-chart.d.ts.map +1 -0
  153. package/org-chart.js +193 -0
  154. package/org-chart.js.map +1 -0
  155. package/package.json +61 -0
  156. package/page-header.d.ts +32 -0
  157. package/page-header.d.ts.map +1 -0
  158. package/page-header.js +14 -0
  159. package/page-header.js.map +1 -0
  160. package/page-layout.d.ts +29 -0
  161. package/page-layout.d.ts.map +1 -0
  162. package/page-layout.js +23 -0
  163. package/page-layout.js.map +1 -0
  164. package/page-transition.d.ts +13 -0
  165. package/page-transition.d.ts.map +1 -0
  166. package/page-transition.js +14 -0
  167. package/page-transition.js.map +1 -0
  168. package/paged-table.d.ts +54 -0
  169. package/paged-table.d.ts.map +1 -0
  170. package/paged-table.js +74 -0
  171. package/paged-table.js.map +1 -0
  172. package/popover.d.ts +16 -0
  173. package/popover.d.ts.map +1 -0
  174. package/popover.js +99 -0
  175. package/popover.js.map +1 -0
  176. package/progress.d.ts +7 -0
  177. package/progress.d.ts.map +1 -0
  178. package/progress.js +8 -0
  179. package/progress.js.map +1 -0
  180. package/prompt-dialog.d.ts +21 -0
  181. package/prompt-dialog.d.ts.map +1 -0
  182. package/prompt-dialog.js +109 -0
  183. package/prompt-dialog.js.map +1 -0
  184. package/record-list.d.ts +76 -0
  185. package/record-list.d.ts.map +1 -0
  186. package/record-list.js +51 -0
  187. package/record-list.js.map +1 -0
  188. package/search-select.d.ts +42 -0
  189. package/search-select.d.ts.map +1 -0
  190. package/search-select.js +194 -0
  191. package/search-select.js.map +1 -0
  192. package/select-options.d.ts +16 -0
  193. package/select-options.d.ts.map +1 -0
  194. package/select-options.js +119 -0
  195. package/select-options.js.map +1 -0
  196. package/select.d.ts +24 -0
  197. package/select.d.ts.map +1 -0
  198. package/select.js +65 -0
  199. package/select.js.map +1 -0
  200. package/separator.d.ts +6 -0
  201. package/separator.d.ts.map +1 -0
  202. package/separator.js +7 -0
  203. package/separator.js.map +1 -0
  204. package/settings-layout.d.ts +79 -0
  205. package/settings-layout.d.ts.map +1 -0
  206. package/settings-layout.js +74 -0
  207. package/settings-layout.js.map +1 -0
  208. package/sidebar-nav.d.ts +67 -0
  209. package/sidebar-nav.d.ts.map +1 -0
  210. package/sidebar-nav.js +291 -0
  211. package/sidebar-nav.js.map +1 -0
  212. package/signature-pad.d.ts +16 -0
  213. package/signature-pad.d.ts.map +1 -0
  214. package/signature-pad.js +355 -0
  215. package/signature-pad.js.map +1 -0
  216. package/skeleton.d.ts +9 -0
  217. package/skeleton.d.ts.map +1 -0
  218. package/skeleton.js +12 -0
  219. package/skeleton.js.map +1 -0
  220. package/slider.d.ts +13 -0
  221. package/slider.d.ts.map +1 -0
  222. package/slider.js +15 -0
  223. package/slider.js.map +1 -0
  224. package/sortable-th.d.ts +28 -0
  225. package/sortable-th.d.ts.map +1 -0
  226. package/sortable-th.js +35 -0
  227. package/sortable-th.js.map +1 -0
  228. package/sparkline.d.ts +16 -0
  229. package/sparkline.d.ts.map +1 -0
  230. package/sparkline.js +46 -0
  231. package/sparkline.js.map +1 -0
  232. package/spinner.d.ts +11 -0
  233. package/spinner.d.ts.map +1 -0
  234. package/spinner.js +11 -0
  235. package/spinner.js.map +1 -0
  236. package/styles.css +166 -0
  237. package/subtab-nav.d.ts +17 -0
  238. package/subtab-nav.d.ts.map +1 -0
  239. package/subtab-nav.js +11 -0
  240. package/subtab-nav.js.map +1 -0
  241. package/switch.d.ts +9 -0
  242. package/switch.d.ts.map +1 -0
  243. package/switch.js +11 -0
  244. package/switch.js.map +1 -0
  245. package/tab-content.d.ts +24 -0
  246. package/tab-content.d.ts.map +1 -0
  247. package/tab-content.js +26 -0
  248. package/tab-content.js.map +1 -0
  249. package/table.d.ts +28 -0
  250. package/table.d.ts.map +1 -0
  251. package/table.js +21 -0
  252. package/table.js.map +1 -0
  253. package/tabs.d.ts +18 -0
  254. package/tabs.d.ts.map +1 -0
  255. package/tabs.js +18 -0
  256. package/tabs.js.map +1 -0
  257. package/text-context.d.ts +9 -0
  258. package/text-context.d.ts.map +1 -0
  259. package/text-context.js +12 -0
  260. package/text-context.js.map +1 -0
  261. package/textarea.d.ts +4 -0
  262. package/textarea.d.ts.map +1 -0
  263. package/textarea.js +6 -0
  264. package/textarea.js.map +1 -0
  265. package/theme-script.d.ts +3 -0
  266. package/theme-script.d.ts.map +1 -0
  267. package/theme-script.js +6 -0
  268. package/theme-script.js.map +1 -0
  269. package/theme.d.ts +28 -0
  270. package/theme.d.ts.map +1 -0
  271. package/theme.js +92 -0
  272. package/theme.js.map +1 -0
  273. package/toast.d.ts +52 -0
  274. package/toast.d.ts.map +1 -0
  275. package/toast.js +178 -0
  276. package/toast.js.map +1 -0
  277. package/tooltip.d.ts +12 -0
  278. package/tooltip.d.ts.map +1 -0
  279. package/tooltip.js +14 -0
  280. package/tooltip.js.map +1 -0
  281. package/top-nav.d.ts +18 -0
  282. package/top-nav.d.ts.map +1 -0
  283. package/top-nav.js +160 -0
  284. package/top-nav.js.map +1 -0
  285. package/upload-limits.d.ts +4 -0
  286. package/upload-limits.d.ts.map +1 -0
  287. package/upload-limits.js +21 -0
  288. package/upload-limits.js.map +1 -0
  289. package/use-element-size.d.ts +7 -0
  290. package/use-element-size.d.ts.map +1 -0
  291. package/use-element-size.js +21 -0
  292. package/use-element-size.js.map +1 -0
  293. package/utils.d.ts +4 -0
  294. package/utils.d.ts.map +1 -0
  295. package/utils.js +7 -0
  296. package/utils.js.map +1 -0
  297. package/workspace-launcher.d.ts +50 -0
  298. package/workspace-launcher.d.ts.map +1 -0
  299. package/workspace-launcher.js +127 -0
  300. package/workspace-launcher.js.map +1 -0
package/theme.d.ts ADDED
@@ -0,0 +1,28 @@
1
+ import * as React from 'react';
2
+ export type Theme = 'light' | 'dark' | 'system';
3
+ export type ResolvedTheme = 'light' | 'dark';
4
+ type ThemeContextValue = {
5
+ theme: Theme;
6
+ resolvedTheme: ResolvedTheme;
7
+ setTheme: (theme: Theme) => void;
8
+ mounted: boolean;
9
+ };
10
+ export declare function ThemeProvider({ children, storageKey, }: {
11
+ children: React.ReactNode;
12
+ storageKey?: string;
13
+ }): React.JSX.Element;
14
+ export declare function useTheme(): ThemeContextValue;
15
+ export type ThemeToggleLabels = {
16
+ label: string;
17
+ light: string;
18
+ system: string;
19
+ dark: string;
20
+ current: (theme: string) => string;
21
+ };
22
+ export declare function ThemeToggle({ collapsed, labels, className, }: {
23
+ collapsed?: boolean;
24
+ labels?: ThemeToggleLabels;
25
+ className?: string;
26
+ }): React.JSX.Element;
27
+ export {};
28
+ //# sourceMappingURL=theme.d.ts.map
package/theme.d.ts.map ADDED
@@ -0,0 +1 @@
1
+ {"version":3,"file":"theme.d.ts","sourceRoot":"","sources":["../src/theme.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAI9B,MAAM,MAAM,KAAK,GAAG,OAAO,GAAG,MAAM,GAAG,QAAQ,CAAA;AAC/C,MAAM,MAAM,aAAa,GAAG,OAAO,GAAG,MAAM,CAAA;AAE5C,KAAK,iBAAiB,GAAG;IACvB,KAAK,EAAE,KAAK,CAAA;IACZ,aAAa,EAAE,aAAa,CAAA;IAC5B,QAAQ,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAA;IAChC,OAAO,EAAE,OAAO,CAAA;CACjB,CAAA;AASD,wBAAgB,aAAa,CAAC,EAC5B,QAAQ,EACR,UAAoB,GACrB,EAAE;IACD,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAA;IACzB,UAAU,CAAC,EAAE,MAAM,CAAA;CACpB,qBA6DA;AAED,wBAAgB,QAAQ,IAAI,iBAAiB,CAI5C;AAQD,MAAM,MAAM,iBAAiB,GAAG;IAC9B,KAAK,EAAE,MAAM,CAAA;IACb,KAAK,EAAE,MAAM,CAAA;IACb,MAAM,EAAE,MAAM,CAAA;IACd,IAAI,EAAE,MAAM,CAAA;IACZ,OAAO,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,MAAM,CAAA;CACnC,CAAA;AAUD,wBAAgB,WAAW,CAAC,EAC1B,SAAiB,EACjB,MAAuB,EACvB,SAAS,GACV,EAAE;IACD,SAAS,CAAC,EAAE,OAAO,CAAA;IACnB,MAAM,CAAC,EAAE,iBAAiB,CAAA;IAC1B,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB,qBAoDA"}
package/theme.js ADDED
@@ -0,0 +1,92 @@
1
+ 'use client';
2
+ import { jsx as _jsx } from "react/jsx-runtime";
3
+ import * as React from 'react';
4
+ import { Monitor, Moon, Sun } from 'lucide-react';
5
+ import { cn } from './utils.js';
6
+ const ThemeContext = React.createContext(null);
7
+ const unavailableThemes = new Map();
8
+ function isTheme(value) {
9
+ return value === 'light' || value === 'dark' || value === 'system';
10
+ }
11
+ export function ThemeProvider({ children, storageKey = 'theme', }) {
12
+ const eventName = `appkit-theme-change:${storageKey}`;
13
+ const readTheme = React.useCallback(() => {
14
+ try {
15
+ const stored = localStorage.getItem(storageKey);
16
+ return isTheme(stored) ? stored : 'system';
17
+ }
18
+ catch {
19
+ return unavailableThemes.get(storageKey) ?? 'system';
20
+ }
21
+ }, [storageKey]);
22
+ const subscribeTheme = React.useCallback((onChange) => {
23
+ window.addEventListener('storage', onChange);
24
+ window.addEventListener(eventName, onChange);
25
+ return () => {
26
+ window.removeEventListener('storage', onChange);
27
+ window.removeEventListener(eventName, onChange);
28
+ };
29
+ }, [eventName]);
30
+ const subscribeSystem = React.useCallback((onChange) => {
31
+ const media = matchMedia('(prefers-color-scheme: dark)');
32
+ media.addEventListener('change', onChange);
33
+ return () => media.removeEventListener('change', onChange);
34
+ }, []);
35
+ const theme = React.useSyncExternalStore(subscribeTheme, readTheme, () => 'system');
36
+ const prefersDark = React.useSyncExternalStore(subscribeSystem, () => matchMedia('(prefers-color-scheme: dark)').matches, () => false);
37
+ const [mounted, setMounted] = React.useState(false);
38
+ const resolvedTheme = theme === 'system' ? (prefersDark ? 'dark' : 'light') : theme;
39
+ React.useEffect(() => setMounted(true), []);
40
+ React.useEffect(() => {
41
+ document.documentElement.classList.toggle('dark', resolvedTheme === 'dark');
42
+ document.documentElement.classList.toggle('light', resolvedTheme === 'light');
43
+ }, [resolvedTheme]);
44
+ const setTheme = React.useCallback((next) => {
45
+ try {
46
+ if (next === 'system')
47
+ localStorage.removeItem(storageKey);
48
+ else
49
+ localStorage.setItem(storageKey, next);
50
+ unavailableThemes.delete(storageKey);
51
+ }
52
+ catch {
53
+ unavailableThemes.set(storageKey, next);
54
+ }
55
+ window.dispatchEvent(new Event(eventName));
56
+ }, [eventName, storageKey]);
57
+ return (_jsx(ThemeContext.Provider, { value: { theme, resolvedTheme, setTheme, mounted }, children: children }));
58
+ }
59
+ export function useTheme() {
60
+ const context = React.useContext(ThemeContext);
61
+ if (!context)
62
+ throw new Error('useTheme must be used within ThemeProvider');
63
+ return context;
64
+ }
65
+ const THEME_OPTIONS = [
66
+ { value: 'light', icon: Sun },
67
+ { value: 'system', icon: Monitor },
68
+ { value: 'dark', icon: Moon },
69
+ ];
70
+ const DEFAULT_LABELS = {
71
+ label: 'Theme',
72
+ light: 'Light',
73
+ system: 'System',
74
+ dark: 'Dark',
75
+ current: (theme) => `Theme: ${theme}`,
76
+ };
77
+ export function ThemeToggle({ collapsed = false, labels = DEFAULT_LABELS, className, }) {
78
+ const { theme, setTheme, mounted } = useTheme();
79
+ if (collapsed) {
80
+ const active = THEME_OPTIONS.find((option) => option.value === theme) ?? THEME_OPTIONS[1];
81
+ const Icon = active.icon;
82
+ const activeLabel = labels[active.value];
83
+ const next = theme === 'light' ? 'dark' : theme === 'dark' ? 'system' : 'light';
84
+ return (_jsx("button", { type: "button", onClick: () => setTheme(next), title: labels.current(activeLabel), "aria-label": labels.current(activeLabel), className: cn('grid size-9 place-items-center rounded-md text-fg-muted transition-colors hover:bg-surface-hover hover:text-fg', className), children: mounted ? _jsx(Icon, { size: 16 }) : _jsx(Monitor, { size: 16, className: "opacity-0" }) }));
85
+ }
86
+ return (_jsx("div", { role: "radiogroup", "aria-label": labels.label, className: cn('flex items-center gap-0.5 rounded-lg border border-border bg-bg-subtle p-0.5', className), children: THEME_OPTIONS.map((option) => {
87
+ const Icon = option.icon;
88
+ const selected = mounted && theme === option.value;
89
+ return (_jsx("button", { type: "button", role: "radio", "aria-checked": selected, onClick: () => setTheme(option.value), title: labels[option.value], className: cn('inline-flex h-7 flex-1 items-center justify-center rounded-md transition-colors', selected ? 'bg-surface text-primary shadow-sm' : 'text-fg-muted hover:text-fg'), children: _jsx(Icon, { size: 15 }) }, option.value));
90
+ }) }));
91
+ }
92
+ //# sourceMappingURL=theme.js.map
package/theme.js.map ADDED
@@ -0,0 +1 @@
1
+ {"version":3,"file":"theme.js","sourceRoot":"","sources":["../src/theme.tsx"],"names":[],"mappings":"AAAA,YAAY,CAAA;;AAEZ,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAC9B,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,GAAG,EAAE,MAAM,cAAc,CAAA;AACjD,OAAO,EAAE,EAAE,EAAE,MAAM,SAAS,CAAA;AAY5B,MAAM,YAAY,GAAG,KAAK,CAAC,aAAa,CAA2B,IAAI,CAAC,CAAA;AACxE,MAAM,iBAAiB,GAAG,IAAI,GAAG,EAAiB,CAAA;AAElD,SAAS,OAAO,CAAC,KAAoB;IACnC,OAAO,KAAK,KAAK,OAAO,IAAI,KAAK,KAAK,MAAM,IAAI,KAAK,KAAK,QAAQ,CAAA;AACpE,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,EAC5B,QAAQ,EACR,UAAU,GAAG,OAAO,GAIrB;IACC,MAAM,SAAS,GAAG,uBAAuB,UAAU,EAAE,CAAA;IACrD,MAAM,SAAS,GAAG,KAAK,CAAC,WAAW,CAAC,GAAU,EAAE;QAC9C,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,YAAY,CAAC,OAAO,CAAC,UAAU,CAAC,CAAA;YAC/C,OAAO,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,QAAQ,CAAA;QAC5C,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,iBAAiB,CAAC,GAAG,CAAC,UAAU,CAAC,IAAI,QAAQ,CAAA;QACtD,CAAC;IACH,CAAC,EAAE,CAAC,UAAU,CAAC,CAAC,CAAA;IAChB,MAAM,cAAc,GAAG,KAAK,CAAC,WAAW,CACtC,CAAC,QAAoB,EAAE,EAAE;QACvB,MAAM,CAAC,gBAAgB,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAA;QAC5C,MAAM,CAAC,gBAAgB,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAA;QAC5C,OAAO,GAAG,EAAE;YACV,MAAM,CAAC,mBAAmB,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAA;YAC/C,MAAM,CAAC,mBAAmB,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAA;QACjD,CAAC,CAAA;IACH,CAAC,EACD,CAAC,SAAS,CAAC,CACZ,CAAA;IACD,MAAM,eAAe,GAAG,KAAK,CAAC,WAAW,CAAC,CAAC,QAAoB,EAAE,EAAE;QACjE,MAAM,KAAK,GAAG,UAAU,CAAC,8BAA8B,CAAC,CAAA;QACxD,KAAK,CAAC,gBAAgB,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAA;QAC1C,OAAO,GAAG,EAAE,CAAC,KAAK,CAAC,mBAAmB,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAA;IAC5D,CAAC,EAAE,EAAE,CAAC,CAAA;IACN,MAAM,KAAK,GAAG,KAAK,CAAC,oBAAoB,CAAQ,cAAc,EAAE,SAAS,EAAE,GAAG,EAAE,CAAC,QAAQ,CAAC,CAAA;IAC1F,MAAM,WAAW,GAAG,KAAK,CAAC,oBAAoB,CAC5C,eAAe,EACf,GAAG,EAAE,CAAC,UAAU,CAAC,8BAA8B,CAAC,CAAC,OAAO,EACxD,GAAG,EAAE,CAAC,KAAK,CACZ,CAAA;IACD,MAAM,CAAC,OAAO,EAAE,UAAU,CAAC,GAAG,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAA;IACnD,MAAM,aAAa,GACjB,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,KAAK,CAAA;IAE/D,KAAK,CAAC,SAAS,CAAC,GAAG,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,EAAE,CAAC,CAAA;IAC3C,KAAK,CAAC,SAAS,CAAC,GAAG,EAAE;QACnB,QAAQ,CAAC,eAAe,CAAC,SAAS,CAAC,MAAM,CAAC,MAAM,EAAE,aAAa,KAAK,MAAM,CAAC,CAAA;QAC3E,QAAQ,CAAC,eAAe,CAAC,SAAS,CAAC,MAAM,CAAC,OAAO,EAAE,aAAa,KAAK,OAAO,CAAC,CAAA;IAC/E,CAAC,EAAE,CAAC,aAAa,CAAC,CAAC,CAAA;IAEnB,MAAM,QAAQ,GAAG,KAAK,CAAC,WAAW,CAChC,CAAC,IAAW,EAAE,EAAE;QACd,IAAI,CAAC;YACH,IAAI,IAAI,KAAK,QAAQ;gBAAE,YAAY,CAAC,UAAU,CAAC,UAAU,CAAC,CAAA;;gBACrD,YAAY,CAAC,OAAO,CAAC,UAAU,EAAE,IAAI,CAAC,CAAA;YAC3C,iBAAiB,CAAC,MAAM,CAAC,UAAU,CAAC,CAAA;QACtC,CAAC;QAAC,MAAM,CAAC;YACP,iBAAiB,CAAC,GAAG,CAAC,UAAU,EAAE,IAAI,CAAC,CAAA;QACzC,CAAC;QACD,MAAM,CAAC,aAAa,CAAC,IAAI,KAAK,CAAC,SAAS,CAAC,CAAC,CAAA;IAC5C,CAAC,EACD,CAAC,SAAS,EAAE,UAAU,CAAC,CACxB,CAAA;IAED,OAAO,CACL,KAAC,YAAY,CAAC,QAAQ,IAAC,KAAK,EAAE,EAAE,KAAK,EAAE,aAAa,EAAE,QAAQ,EAAE,OAAO,EAAE,YACtE,QAAQ,GACa,CACzB,CAAA;AACH,CAAC;AAED,MAAM,UAAU,QAAQ;IACtB,MAAM,OAAO,GAAG,KAAK,CAAC,UAAU,CAAC,YAAY,CAAC,CAAA;IAC9C,IAAI,CAAC,OAAO;QAAE,MAAM,IAAI,KAAK,CAAC,4CAA4C,CAAC,CAAA;IAC3E,OAAO,OAAO,CAAA;AAChB,CAAC;AAED,MAAM,aAAa,GAAG;IACpB,EAAE,KAAK,EAAE,OAAgB,EAAE,IAAI,EAAE,GAAG,EAAE;IACtC,EAAE,KAAK,EAAE,QAAiB,EAAE,IAAI,EAAE,OAAO,EAAE;IAC3C,EAAE,KAAK,EAAE,MAAe,EAAE,IAAI,EAAE,IAAI,EAAE;CACvC,CAAA;AAUD,MAAM,cAAc,GAAsB;IACxC,KAAK,EAAE,OAAO;IACd,KAAK,EAAE,OAAO;IACd,MAAM,EAAE,QAAQ;IAChB,IAAI,EAAE,MAAM;IACZ,OAAO,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,UAAU,KAAK,EAAE;CACtC,CAAA;AAED,MAAM,UAAU,WAAW,CAAC,EAC1B,SAAS,GAAG,KAAK,EACjB,MAAM,GAAG,cAAc,EACvB,SAAS,GAKV;IACC,MAAM,EAAE,KAAK,EAAE,QAAQ,EAAE,OAAO,EAAE,GAAG,QAAQ,EAAE,CAAA;IAE/C,IAAI,SAAS,EAAE,CAAC;QACd,MAAM,MAAM,GAAG,aAAa,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,KAAK,KAAK,KAAK,CAAC,IAAI,aAAa,CAAC,CAAC,CAAE,CAAA;QAC1F,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,CAAA;QACxB,MAAM,WAAW,GAAG,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,CAAA;QACxC,MAAM,IAAI,GAAU,KAAK,KAAK,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,KAAK,MAAM,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAA;QACtF,OAAO,CACL,iBACE,IAAI,EAAC,QAAQ,EACb,OAAO,EAAE,GAAG,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,EAC7B,KAAK,EAAE,MAAM,CAAC,OAAO,CAAC,WAAW,CAAC,gBACtB,MAAM,CAAC,OAAO,CAAC,WAAW,CAAC,EACvC,SAAS,EAAE,EAAE,CACX,gHAAgH,EAChH,SAAS,CACV,YAEA,OAAO,CAAC,CAAC,CAAC,KAAC,IAAI,IAAC,IAAI,EAAE,EAAE,GAAI,CAAC,CAAC,CAAC,KAAC,OAAO,IAAC,IAAI,EAAE,EAAE,EAAE,SAAS,EAAC,WAAW,GAAG,GACpE,CACV,CAAA;IACH,CAAC;IAED,OAAO,CACL,cACE,IAAI,EAAC,YAAY,gBACL,MAAM,CAAC,KAAK,EACxB,SAAS,EAAE,EAAE,CAAC,8EAA8E,EAAE,SAAS,CAAC,YAEvG,aAAa,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE;YAC5B,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,CAAA;YACxB,MAAM,QAAQ,GAAG,OAAO,IAAI,KAAK,KAAK,MAAM,CAAC,KAAK,CAAA;YAClD,OAAO,CACL,iBAEE,IAAI,EAAC,QAAQ,EACb,IAAI,EAAC,OAAO,kBACE,QAAQ,EACtB,OAAO,EAAE,GAAG,EAAE,CAAC,QAAQ,CAAC,MAAM,CAAC,KAAK,CAAC,EACrC,KAAK,EAAE,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,EAC3B,SAAS,EAAE,EAAE,CACX,iFAAiF,EACjF,QAAQ,CAAC,CAAC,CAAC,mCAAmC,CAAC,CAAC,CAAC,6BAA6B,CAC/E,YAED,KAAC,IAAI,IAAC,IAAI,EAAE,EAAE,GAAI,IAXb,MAAM,CAAC,KAAK,CAYV,CACV,CAAA;QACH,CAAC,CAAC,GACE,CACP,CAAA;AACH,CAAC","sourcesContent":["'use client'\n\nimport * as React from 'react'\nimport { Monitor, Moon, Sun } from 'lucide-react'\nimport { cn } from './utils'\n\nexport type Theme = 'light' | 'dark' | 'system'\nexport type ResolvedTheme = 'light' | 'dark'\n\ntype ThemeContextValue = {\n theme: Theme\n resolvedTheme: ResolvedTheme\n setTheme: (theme: Theme) => void\n mounted: boolean\n}\n\nconst ThemeContext = React.createContext<ThemeContextValue | null>(null)\nconst unavailableThemes = new Map<string, Theme>()\n\nfunction isTheme(value: string | null): value is Theme {\n return value === 'light' || value === 'dark' || value === 'system'\n}\n\nexport function ThemeProvider({\n children,\n storageKey = 'theme',\n}: {\n children: React.ReactNode\n storageKey?: string\n}) {\n const eventName = `appkit-theme-change:${storageKey}`\n const readTheme = React.useCallback((): Theme => {\n try {\n const stored = localStorage.getItem(storageKey)\n return isTheme(stored) ? stored : 'system'\n } catch {\n return unavailableThemes.get(storageKey) ?? 'system'\n }\n }, [storageKey])\n const subscribeTheme = React.useCallback(\n (onChange: () => void) => {\n window.addEventListener('storage', onChange)\n window.addEventListener(eventName, onChange)\n return () => {\n window.removeEventListener('storage', onChange)\n window.removeEventListener(eventName, onChange)\n }\n },\n [eventName],\n )\n const subscribeSystem = React.useCallback((onChange: () => void) => {\n const media = matchMedia('(prefers-color-scheme: dark)')\n media.addEventListener('change', onChange)\n return () => media.removeEventListener('change', onChange)\n }, [])\n const theme = React.useSyncExternalStore<Theme>(subscribeTheme, readTheme, () => 'system')\n const prefersDark = React.useSyncExternalStore(\n subscribeSystem,\n () => matchMedia('(prefers-color-scheme: dark)').matches,\n () => false,\n )\n const [mounted, setMounted] = React.useState(false)\n const resolvedTheme: ResolvedTheme =\n theme === 'system' ? (prefersDark ? 'dark' : 'light') : theme\n\n React.useEffect(() => setMounted(true), [])\n React.useEffect(() => {\n document.documentElement.classList.toggle('dark', resolvedTheme === 'dark')\n document.documentElement.classList.toggle('light', resolvedTheme === 'light')\n }, [resolvedTheme])\n\n const setTheme = React.useCallback(\n (next: Theme) => {\n try {\n if (next === 'system') localStorage.removeItem(storageKey)\n else localStorage.setItem(storageKey, next)\n unavailableThemes.delete(storageKey)\n } catch {\n unavailableThemes.set(storageKey, next)\n }\n window.dispatchEvent(new Event(eventName))\n },\n [eventName, storageKey],\n )\n\n return (\n <ThemeContext.Provider value={{ theme, resolvedTheme, setTheme, mounted }}>\n {children}\n </ThemeContext.Provider>\n )\n}\n\nexport function useTheme(): ThemeContextValue {\n const context = React.useContext(ThemeContext)\n if (!context) throw new Error('useTheme must be used within ThemeProvider')\n return context\n}\n\nconst THEME_OPTIONS = [\n { value: 'light' as const, icon: Sun },\n { value: 'system' as const, icon: Monitor },\n { value: 'dark' as const, icon: Moon },\n]\n\nexport type ThemeToggleLabels = {\n label: string\n light: string\n system: string\n dark: string\n current: (theme: string) => string\n}\n\nconst DEFAULT_LABELS: ThemeToggleLabels = {\n label: 'Theme',\n light: 'Light',\n system: 'System',\n dark: 'Dark',\n current: (theme) => `Theme: ${theme}`,\n}\n\nexport function ThemeToggle({\n collapsed = false,\n labels = DEFAULT_LABELS,\n className,\n}: {\n collapsed?: boolean\n labels?: ThemeToggleLabels\n className?: string\n}) {\n const { theme, setTheme, mounted } = useTheme()\n\n if (collapsed) {\n const active = THEME_OPTIONS.find((option) => option.value === theme) ?? THEME_OPTIONS[1]!\n const Icon = active.icon\n const activeLabel = labels[active.value]\n const next: Theme = theme === 'light' ? 'dark' : theme === 'dark' ? 'system' : 'light'\n return (\n <button\n type=\"button\"\n onClick={() => setTheme(next)}\n title={labels.current(activeLabel)}\n aria-label={labels.current(activeLabel)}\n className={cn(\n 'grid size-9 place-items-center rounded-md text-fg-muted transition-colors hover:bg-surface-hover hover:text-fg',\n className,\n )}\n >\n {mounted ? <Icon size={16} /> : <Monitor size={16} className=\"opacity-0\" />}\n </button>\n )\n }\n\n return (\n <div\n role=\"radiogroup\"\n aria-label={labels.label}\n className={cn('flex items-center gap-0.5 rounded-lg border border-border bg-bg-subtle p-0.5', className)}\n >\n {THEME_OPTIONS.map((option) => {\n const Icon = option.icon\n const selected = mounted && theme === option.value\n return (\n <button\n key={option.value}\n type=\"button\"\n role=\"radio\"\n aria-checked={selected}\n onClick={() => setTheme(option.value)}\n title={labels[option.value]}\n className={cn(\n 'inline-flex h-7 flex-1 items-center justify-center rounded-md transition-colors',\n selected ? 'bg-surface text-primary shadow-sm' : 'text-fg-muted hover:text-fg',\n )}\n >\n <Icon size={15} />\n </button>\n )\n })}\n </div>\n )\n}\n"]}
package/toast.d.ts ADDED
@@ -0,0 +1,52 @@
1
+ import * as React from 'react';
2
+ export type ToastType = 'default' | 'success' | 'error' | 'warning' | 'info' | 'loading';
3
+ export type ToastAction = {
4
+ label: React.ReactNode;
5
+ onClick: (e: React.MouseEvent) => void;
6
+ };
7
+ export type Message = React.ReactNode;
8
+ export type ExternalToast = {
9
+ id?: string | number;
10
+ description?: React.ReactNode;
11
+ duration?: number;
12
+ icon?: React.ReactNode;
13
+ action?: ToastAction;
14
+ cancel?: ToastAction;
15
+ onDismiss?: (id: string | number) => void;
16
+ onAutoClose?: (id: string | number) => void;
17
+ className?: string;
18
+ };
19
+ export type ToastT = ExternalToast & {
20
+ id: string | number;
21
+ title?: React.ReactNode;
22
+ type: ToastType;
23
+ jsx?: React.ReactNode;
24
+ };
25
+ declare function toastFunction(message: Message, data?: ExternalToast): string | number;
26
+ /** sonner-compatible global toast API. */
27
+ export declare const toast: typeof toastFunction & {
28
+ success: (message: Message, data?: ExternalToast) => string | number;
29
+ error: (message: Message, data?: ExternalToast) => string | number;
30
+ warning: (message: Message, data?: ExternalToast) => string | number;
31
+ info: (message: Message, data?: ExternalToast) => string | number;
32
+ message: (message: Message, data?: ExternalToast) => string | number;
33
+ loading: (message: Message, data?: ExternalToast) => string | number;
34
+ custom: (jsx: (id: string | number) => React.ReactNode, data?: ExternalToast) => string | number;
35
+ promise: <T>(promise: Promise<T>, opts: {
36
+ loading: Message;
37
+ success: React.ReactNode | ((data: T) => Message);
38
+ error: Message | ((err: unknown) => Message);
39
+ }) => string | number;
40
+ dismiss: (id?: string | number) => string | number | undefined;
41
+ };
42
+ export type ToasterPosition = 'top-left' | 'top-center' | 'top-right' | 'bottom-left' | 'bottom-center' | 'bottom-right';
43
+ export declare function Toaster({ position, richColors, duration, closeButton, visibleToasts, className, }: {
44
+ position?: ToasterPosition;
45
+ richColors?: boolean;
46
+ duration?: number;
47
+ closeButton?: boolean;
48
+ visibleToasts?: number;
49
+ className?: string;
50
+ }): React.ReactPortal | null;
51
+ export {};
52
+ //# sourceMappingURL=toast.d.ts.map
package/toast.d.ts.map ADDED
@@ -0,0 +1 @@
1
+ {"version":3,"file":"toast.d.ts","sourceRoot":"","sources":["../src/toast.tsx"],"names":[],"mappings":"AASA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAM9B,MAAM,MAAM,SAAS,GAAG,SAAS,GAAG,SAAS,GAAG,OAAO,GAAG,SAAS,GAAG,MAAM,GAAG,SAAS,CAAA;AACxF,MAAM,MAAM,WAAW,GAAG;IAAE,KAAK,EAAE,KAAK,CAAC,SAAS,CAAC;IAAC,OAAO,EAAE,CAAC,CAAC,EAAE,KAAK,CAAC,UAAU,KAAK,IAAI,CAAA;CAAE,CAAA;AAC5F,MAAM,MAAM,OAAO,GAAG,KAAK,CAAC,SAAS,CAAA;AAErC,MAAM,MAAM,aAAa,GAAG;IAC1B,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM,CAAA;IACpB,WAAW,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;IAC7B,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,IAAI,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;IACtB,MAAM,CAAC,EAAE,WAAW,CAAA;IACpB,MAAM,CAAC,EAAE,WAAW,CAAA;IACpB,SAAS,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,KAAK,IAAI,CAAA;IACzC,WAAW,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,KAAK,IAAI,CAAA;IAC3C,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB,CAAA;AAED,MAAM,MAAM,MAAM,GAAG,aAAa,GAAG;IACnC,EAAE,EAAE,MAAM,GAAG,MAAM,CAAA;IACnB,KAAK,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;IACvB,IAAI,EAAE,SAAS,CAAA;IACf,GAAG,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;CACtB,CAAA;AAmED,iBAAS,aAAa,CAAC,OAAO,EAAE,OAAO,EAAE,IAAI,CAAC,EAAE,aAAa,mBAE5D;AAED,0CAA0C;AAC1C,eAAO,MAAM,KAAK;uBArCI,OAAO,SAAS,aAAa;qBAC/B,OAAO,SAAS,aAAa;uBAC3B,OAAO,SAAS,aAAa;oBAChC,OAAO,SAAS,aAAa;uBAJ1B,OAAO,SAAS,aAAa;uBAK7B,OAAO,SAAS,aAAa;kBAGlC,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,KAAK,KAAK,CAAC,SAAS,SAAS,aAAa;cAMlE,CAAC;iBAGC,OAAO;iDACiB,OAAO;eACjC,OAAO,GAAG,CAAC,CAAC,GAAG,EAAE,OAAO,KAAK,OAAO,CAAC;;mBA4BjC,MAAM,GAAG,MAAM;CAC9B,CAAA;AAMF,MAAM,MAAM,eAAe,GAAG,UAAU,GAAG,YAAY,GAAG,WAAW,GAAG,aAAa,GAAG,eAAe,GAAG,cAAc,CAAA;AAsCxH,wBAAgB,OAAO,CAAC,EACtB,QAAyB,EACzB,UAAkB,EAClB,QAAe,EACf,WAAmB,EACnB,aAAiB,EACjB,SAAS,GACV,EAAE;IACD,QAAQ,CAAC,EAAE,eAAe,CAAA;IAC1B,UAAU,CAAC,EAAE,OAAO,CAAA;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,WAAW,CAAC,EAAE,OAAO,CAAA;IACrB,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB,4BAmCA"}
package/toast.js ADDED
@@ -0,0 +1,178 @@
1
+ 'use client';
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ // A sonner-compatible toast primitive. The public surface mirrors sonner so an
4
+ // app switches by changing the import:
5
+ // import { toast, Toaster } from 'sonner' → from '@braedonsaunders/appkit-ui'
6
+ // `toast()` is a global imperative function (no provider/hook needed); a single
7
+ // <Toaster /> mounted at the app root subscribes and renders. Tokenized +
8
+ // animated with the appkit design system.
9
+ import * as React from 'react';
10
+ import { createPortal } from 'react-dom';
11
+ import { AnimatePresence, motion } from 'framer-motion';
12
+ import { Check, CircleAlert, Info, Loader2, TriangleAlert, X } from 'lucide-react';
13
+ import { cn } from './utils.js';
14
+ let counter = 0;
15
+ class Observer {
16
+ subscribers = [];
17
+ subscribe(fn) {
18
+ this.subscribers.push(fn);
19
+ return () => {
20
+ const i = this.subscribers.indexOf(fn);
21
+ if (i > -1)
22
+ this.subscribers.splice(i, 1);
23
+ };
24
+ }
25
+ publish(t) {
26
+ this.subscribers.forEach((s) => s(t));
27
+ }
28
+ create(data) {
29
+ const id = data.id ?? ++counter;
30
+ const { message, ...rest } = data;
31
+ this.publish({ ...rest, id, title: message ?? data.title, type: data.type ?? 'default' });
32
+ return id;
33
+ }
34
+ dismiss(id) {
35
+ if (id == null)
36
+ return id;
37
+ this.publish({ id, dismiss: true });
38
+ return id;
39
+ }
40
+ message = (message, data) => this.create({ ...data, message, type: 'default' });
41
+ success = (message, data) => this.create({ ...data, message, type: 'success' });
42
+ error = (message, data) => this.create({ ...data, message, type: 'error' });
43
+ warning = (message, data) => this.create({ ...data, message, type: 'warning' });
44
+ info = (message, data) => this.create({ ...data, message, type: 'info' });
45
+ loading = (message, data) => this.create({ duration: Infinity, ...data, message, type: 'loading' });
46
+ custom = (jsx, data) => {
47
+ const id = data?.id ?? ++counter;
48
+ this.publish({ ...data, id, type: 'default', jsx: jsx(id) });
49
+ return id;
50
+ };
51
+ promise = (promise, opts) => {
52
+ const id = this.loading(opts.loading);
53
+ promise.then((data) => this.create({ id, message: typeof opts.success === 'function' ? opts.success(data) : opts.success, type: 'success', duration: undefined }), (err) => this.create({ id, message: typeof opts.error === 'function' ? opts.error(err) : opts.error, type: 'error', duration: undefined }));
54
+ return id;
55
+ };
56
+ }
57
+ const ToastState = new Observer();
58
+ function toastFunction(message, data) {
59
+ return ToastState.create({ ...data, message });
60
+ }
61
+ /** sonner-compatible global toast API. */
62
+ export const toast = Object.assign(toastFunction, {
63
+ success: ToastState.success,
64
+ error: ToastState.error,
65
+ warning: ToastState.warning,
66
+ info: ToastState.info,
67
+ message: ToastState.message,
68
+ loading: ToastState.loading,
69
+ custom: ToastState.custom,
70
+ promise: ToastState.promise,
71
+ dismiss: (id) => ToastState.dismiss(id),
72
+ });
73
+ const POSITION_CLASS = {
74
+ 'top-left': 'top-0 left-0 items-start',
75
+ 'top-center': 'top-0 left-1/2 -translate-x-1/2 items-center',
76
+ 'top-right': 'top-0 right-0 items-end',
77
+ 'bottom-left': 'bottom-0 left-0 items-start',
78
+ 'bottom-center': 'bottom-0 left-1/2 -translate-x-1/2 items-center',
79
+ 'bottom-right': 'bottom-0 right-0 items-end',
80
+ };
81
+ const TYPE_ICON = {
82
+ default: null,
83
+ success: _jsx(Check, { className: "size-4" }),
84
+ error: _jsx(CircleAlert, { className: "size-4" }),
85
+ warning: _jsx(TriangleAlert, { className: "size-4" }),
86
+ info: _jsx(Info, { className: "size-4" }),
87
+ loading: _jsx(Loader2, { className: "size-4 animate-spin motion-reduce:animate-none" }),
88
+ };
89
+ const RICH = {
90
+ default: 'border-border bg-elevated text-fg',
91
+ success: 'border-success/25 bg-success-subtle text-success',
92
+ error: 'border-danger/25 bg-danger-subtle text-danger',
93
+ warning: 'border-warning/25 bg-warning-subtle text-warning',
94
+ info: 'border-info/25 bg-info-subtle text-info',
95
+ loading: 'border-border bg-elevated text-fg',
96
+ };
97
+ const ACCENT = {
98
+ default: 'text-fg-muted',
99
+ success: 'text-success',
100
+ error: 'text-danger',
101
+ warning: 'text-warning',
102
+ info: 'text-info',
103
+ loading: 'text-fg-muted',
104
+ };
105
+ export function Toaster({ position = 'bottom-right', richColors = false, duration = 4000, closeButton = false, visibleToasts = 4, className, }) {
106
+ const [toasts, setToasts] = React.useState([]);
107
+ const [mounted, setMounted] = React.useState(false);
108
+ React.useEffect(() => setMounted(true), []);
109
+ React.useEffect(() => ToastState.subscribe((t) => {
110
+ if ('dismiss' in t) {
111
+ setToasts((prev) => prev.filter((x) => x.id !== t.id));
112
+ return;
113
+ }
114
+ setToasts((prev) => {
115
+ const existing = prev.find((x) => x.id === t.id);
116
+ if (existing)
117
+ return prev.map((x) => (x.id === t.id ? { ...x, ...t } : x));
118
+ const next = [t, ...prev];
119
+ return next.slice(0, visibleToasts);
120
+ });
121
+ }), [visibleToasts]);
122
+ if (!mounted || typeof document === 'undefined')
123
+ return null;
124
+ const isTop = position.startsWith('top');
125
+ return createPortal(_jsx("div", { className: cn('pointer-events-none fixed z-[80] flex w-full max-w-[420px] flex-col gap-2 p-4 sm:p-6', POSITION_CLASS[position], className), children: _jsx(AnimatePresence, { initial: false, children: toasts.map((t) => (_jsx(ToastRow, { toast: t, defaultDuration: duration, richColors: richColors, closeButton: closeButton, isTop: isTop }, t.id))) }) }), document.body);
126
+ }
127
+ function ToastRow({ toast: t, defaultDuration, richColors, closeButton, isTop, }) {
128
+ const d = t.duration ?? (t.type === 'loading' ? Infinity : defaultDuration);
129
+ const timer = React.useRef(null);
130
+ const startedAt = React.useRef(0);
131
+ const remaining = React.useRef(d);
132
+ const clearTimer = React.useCallback(() => {
133
+ if (timer.current)
134
+ clearTimeout(timer.current);
135
+ timer.current = null;
136
+ }, []);
137
+ const runTimer = React.useCallback(() => {
138
+ if (!Number.isFinite(remaining.current))
139
+ return;
140
+ clearTimer();
141
+ startedAt.current = Date.now();
142
+ timer.current = setTimeout(() => {
143
+ t.onAutoClose?.(t.id);
144
+ ToastState.dismiss(t.id);
145
+ }, remaining.current);
146
+ }, [clearTimer, t]);
147
+ React.useEffect(() => {
148
+ remaining.current = d;
149
+ runTimer();
150
+ return clearTimer;
151
+ // Re-arm whenever the toast content/duration changes (e.g. promise resolve).
152
+ }, [clearTimer, d, runTimer]);
153
+ function pauseTimer() {
154
+ if (!timer.current)
155
+ return;
156
+ remaining.current = Math.max(0, remaining.current - (Date.now() - startedAt.current));
157
+ clearTimer();
158
+ }
159
+ function resumeTimer() {
160
+ if (!timer.current)
161
+ runTimer();
162
+ }
163
+ function close() {
164
+ t.onDismiss?.(t.id);
165
+ ToastState.dismiss(t.id);
166
+ }
167
+ if (t.jsx) {
168
+ return (_jsx(motion.div, { layout: true, initial: { opacity: 0, y: isTop ? -16 : 16, scale: 0.96 }, animate: { opacity: 1, y: 0, scale: 1 }, exit: { opacity: 0, scale: 0.96, transition: { duration: 0.15 } }, transition: { type: 'spring', damping: 26, stiffness: 320 }, className: "pointer-events-auto w-full", children: t.jsx }));
169
+ }
170
+ return (_jsxs(motion.div, { layout: true, role: "status", onMouseEnter: pauseTimer, onMouseLeave: resumeTimer, initial: { opacity: 0, y: isTop ? -16 : 16, scale: 0.96 }, animate: { opacity: 1, y: 0, scale: 1 }, exit: { opacity: 0, scale: 0.96, transition: { duration: 0.15 } }, transition: { type: 'spring', damping: 26, stiffness: 320 }, className: cn('pointer-events-auto flex w-full items-start gap-3 rounded-lg border px-4 py-3 shadow-lg', richColors ? RICH[t.type] : 'border-border bg-elevated text-fg', t.className), children: [t.icon ?? TYPE_ICON[t.type] ? (_jsx("span", { className: cn('mt-0.5 shrink-0', richColors ? '' : ACCENT[t.type]), children: t.icon ?? TYPE_ICON[t.type] })) : null, _jsxs("div", { className: "min-w-0 flex-1 space-y-0.5", children: [t.title ? _jsx("div", { className: "text-sm font-semibold", children: t.title }) : null, t.description ? _jsx("div", { className: cn('text-sm', richColors ? 'opacity-90' : 'text-fg-muted'), children: t.description }) : null, t.action || t.cancel ? (_jsxs("div", { className: "flex items-center gap-2 pt-1.5", children: [t.action ? (_jsx("button", { type: "button", onClick: (e) => {
171
+ t.action.onClick(e);
172
+ close();
173
+ }, className: "rounded-md bg-primary px-2.5 py-1 text-xs font-medium text-primary-fg hover:bg-primary-hover", children: t.action.label })) : null, t.cancel ? (_jsx("button", { type: "button", onClick: (e) => {
174
+ t.cancel.onClick?.(e);
175
+ close();
176
+ }, className: "rounded-md px-2.5 py-1 text-xs font-medium text-fg-muted hover:bg-surface-hover", children: t.cancel.label })) : null] })) : null] }), closeButton ? (_jsx("button", { type: "button", onClick: close, "aria-label": "Dismiss", className: "-mr-1 rounded-md p-1 text-current opacity-60 transition-opacity hover:opacity-100", children: _jsx(X, { className: "size-4" }) })) : null] }));
177
+ }
178
+ //# sourceMappingURL=toast.js.map
package/toast.js.map ADDED
@@ -0,0 +1 @@
1
+ {"version":3,"file":"toast.js","sourceRoot":"","sources":["../src/toast.tsx"],"names":[],"mappings":"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","sourcesContent":["'use client'\n\n// A sonner-compatible toast primitive. The public surface mirrors sonner so an\n// app switches by changing the import:\n// import { toast, Toaster } from 'sonner' → from '@braedonsaunders/appkit-ui'\n// `toast()` is a global imperative function (no provider/hook needed); a single\n// <Toaster /> mounted at the app root subscribes and renders. Tokenized +\n// animated with the appkit design system.\n\nimport * as React from 'react'\nimport { createPortal } from 'react-dom'\nimport { AnimatePresence, motion } from 'framer-motion'\nimport { Check, CircleAlert, Info, Loader2, TriangleAlert, X } from 'lucide-react'\nimport { cn } from './utils'\n\nexport type ToastType = 'default' | 'success' | 'error' | 'warning' | 'info' | 'loading'\nexport type ToastAction = { label: React.ReactNode; onClick: (e: React.MouseEvent) => void }\nexport type Message = React.ReactNode\n\nexport type ExternalToast = {\n id?: string | number\n description?: React.ReactNode\n duration?: number\n icon?: React.ReactNode\n action?: ToastAction\n cancel?: ToastAction\n onDismiss?: (id: string | number) => void\n onAutoClose?: (id: string | number) => void\n className?: string\n}\n\nexport type ToastT = ExternalToast & {\n id: string | number\n title?: React.ReactNode\n type: ToastType\n jsx?: React.ReactNode\n}\n\ntype Signal = ToastT | { id: string | number; dismiss: true }\n\nlet counter = 0\n\nclass Observer {\n private subscribers: Array<(t: Signal) => void> = []\n\n subscribe(fn: (t: Signal) => void) {\n this.subscribers.push(fn)\n return () => {\n const i = this.subscribers.indexOf(fn)\n if (i > -1) this.subscribers.splice(i, 1)\n }\n }\n\n private publish(t: Signal) {\n this.subscribers.forEach((s) => s(t))\n }\n\n create(data: ExternalToast & { message?: Message; title?: React.ReactNode; type?: ToastType; jsx?: React.ReactNode }) {\n const id = data.id ?? ++counter\n const { message, ...rest } = data\n this.publish({ ...rest, id, title: message ?? data.title, type: data.type ?? 'default' })\n return id\n }\n\n dismiss(id?: string | number) {\n if (id == null) return id\n this.publish({ id, dismiss: true })\n return id\n }\n\n message = (message: Message, data?: ExternalToast) => this.create({ ...data, message, type: 'default' })\n success = (message: Message, data?: ExternalToast) => this.create({ ...data, message, type: 'success' })\n error = (message: Message, data?: ExternalToast) => this.create({ ...data, message, type: 'error' })\n warning = (message: Message, data?: ExternalToast) => this.create({ ...data, message, type: 'warning' })\n info = (message: Message, data?: ExternalToast) => this.create({ ...data, message, type: 'info' })\n loading = (message: Message, data?: ExternalToast) =>\n this.create({ duration: Infinity, ...data, message, type: 'loading' })\n\n custom = (jsx: (id: string | number) => React.ReactNode, data?: ExternalToast) => {\n const id = data?.id ?? ++counter\n this.publish({ ...data, id, type: 'default', jsx: jsx(id) })\n return id\n }\n\n promise = <T,>(\n promise: Promise<T>,\n opts: {\n loading: Message\n success: Message | ((data: T) => Message)\n error: Message | ((err: unknown) => Message)\n },\n ) => {\n const id = this.loading(opts.loading)\n promise.then(\n (data) => this.create({ id, message: typeof opts.success === 'function' ? (opts.success as (d: T) => Message)(data) : opts.success, type: 'success', duration: undefined }),\n (err) => this.create({ id, message: typeof opts.error === 'function' ? (opts.error as (e: unknown) => Message)(err) : opts.error, type: 'error', duration: undefined }),\n )\n return id\n }\n}\n\nconst ToastState = new Observer()\n\nfunction toastFunction(message: Message, data?: ExternalToast) {\n return ToastState.create({ ...data, message })\n}\n\n/** sonner-compatible global toast API. */\nexport const toast = Object.assign(toastFunction, {\n success: ToastState.success,\n error: ToastState.error,\n warning: ToastState.warning,\n info: ToastState.info,\n message: ToastState.message,\n loading: ToastState.loading,\n custom: ToastState.custom,\n promise: ToastState.promise,\n dismiss: (id?: string | number) => ToastState.dismiss(id),\n})\n\n// ---------------------------------------------------------------------------\n// <Toaster /> — mount once at the app root.\n// ---------------------------------------------------------------------------\n\nexport type ToasterPosition = 'top-left' | 'top-center' | 'top-right' | 'bottom-left' | 'bottom-center' | 'bottom-right'\n\nconst POSITION_CLASS: Record<ToasterPosition, string> = {\n 'top-left': 'top-0 left-0 items-start',\n 'top-center': 'top-0 left-1/2 -translate-x-1/2 items-center',\n 'top-right': 'top-0 right-0 items-end',\n 'bottom-left': 'bottom-0 left-0 items-start',\n 'bottom-center': 'bottom-0 left-1/2 -translate-x-1/2 items-center',\n 'bottom-right': 'bottom-0 right-0 items-end',\n}\n\nconst TYPE_ICON: Record<ToastType, React.ReactNode> = {\n default: null,\n success: <Check className=\"size-4\" />,\n error: <CircleAlert className=\"size-4\" />,\n warning: <TriangleAlert className=\"size-4\" />,\n info: <Info className=\"size-4\" />,\n loading: <Loader2 className=\"size-4 animate-spin motion-reduce:animate-none\" />,\n}\n\nconst RICH: Record<ToastType, string> = {\n default: 'border-border bg-elevated text-fg',\n success: 'border-success/25 bg-success-subtle text-success',\n error: 'border-danger/25 bg-danger-subtle text-danger',\n warning: 'border-warning/25 bg-warning-subtle text-warning',\n info: 'border-info/25 bg-info-subtle text-info',\n loading: 'border-border bg-elevated text-fg',\n}\n\nconst ACCENT: Record<ToastType, string> = {\n default: 'text-fg-muted',\n success: 'text-success',\n error: 'text-danger',\n warning: 'text-warning',\n info: 'text-info',\n loading: 'text-fg-muted',\n}\n\nexport function Toaster({\n position = 'bottom-right',\n richColors = false,\n duration = 4000,\n closeButton = false,\n visibleToasts = 4,\n className,\n}: {\n position?: ToasterPosition\n richColors?: boolean\n duration?: number\n closeButton?: boolean\n visibleToasts?: number\n className?: string\n}) {\n const [toasts, setToasts] = React.useState<ToastT[]>([])\n const [mounted, setMounted] = React.useState(false)\n React.useEffect(() => setMounted(true), [])\n\n React.useEffect(\n () =>\n ToastState.subscribe((t) => {\n if ('dismiss' in t) {\n setToasts((prev) => prev.filter((x) => x.id !== t.id))\n return\n }\n setToasts((prev) => {\n const existing = prev.find((x) => x.id === t.id)\n if (existing) return prev.map((x) => (x.id === t.id ? { ...x, ...t } : x))\n const next = [t, ...prev]\n return next.slice(0, visibleToasts)\n })\n }),\n [visibleToasts],\n )\n\n if (!mounted || typeof document === 'undefined') return null\n const isTop = position.startsWith('top')\n\n return createPortal(\n <div className={cn('pointer-events-none fixed z-[80] flex w-full max-w-[420px] flex-col gap-2 p-4 sm:p-6', POSITION_CLASS[position], className)}>\n <AnimatePresence initial={false}>\n {toasts.map((t) => (\n <ToastRow key={t.id} toast={t} defaultDuration={duration} richColors={richColors} closeButton={closeButton} isTop={isTop} />\n ))}\n </AnimatePresence>\n </div>,\n document.body,\n )\n}\n\nfunction ToastRow({\n toast: t,\n defaultDuration,\n richColors,\n closeButton,\n isTop,\n}: {\n toast: ToastT\n defaultDuration: number\n richColors: boolean\n closeButton: boolean\n isTop: boolean\n}) {\n const d = t.duration ?? (t.type === 'loading' ? Infinity : defaultDuration)\n const timer = React.useRef<ReturnType<typeof setTimeout> | null>(null)\n const startedAt = React.useRef(0)\n const remaining = React.useRef(d)\n\n const clearTimer = React.useCallback(() => {\n if (timer.current) clearTimeout(timer.current)\n timer.current = null\n }, [])\n\n const runTimer = React.useCallback(() => {\n if (!Number.isFinite(remaining.current)) return\n clearTimer()\n startedAt.current = Date.now()\n timer.current = setTimeout(() => {\n t.onAutoClose?.(t.id)\n ToastState.dismiss(t.id)\n }, remaining.current)\n }, [clearTimer, t])\n\n React.useEffect(() => {\n remaining.current = d\n runTimer()\n return clearTimer\n // Re-arm whenever the toast content/duration changes (e.g. promise resolve).\n }, [clearTimer, d, runTimer])\n\n function pauseTimer() {\n if (!timer.current) return\n remaining.current = Math.max(0, remaining.current - (Date.now() - startedAt.current))\n clearTimer()\n }\n\n function resumeTimer() {\n if (!timer.current) runTimer()\n }\n\n function close() {\n t.onDismiss?.(t.id)\n ToastState.dismiss(t.id)\n }\n\n if (t.jsx) {\n return (\n <motion.div\n layout\n initial={{ opacity: 0, y: isTop ? -16 : 16, scale: 0.96 }}\n animate={{ opacity: 1, y: 0, scale: 1 }}\n exit={{ opacity: 0, scale: 0.96, transition: { duration: 0.15 } }}\n transition={{ type: 'spring', damping: 26, stiffness: 320 }}\n className=\"pointer-events-auto w-full\"\n >\n {t.jsx}\n </motion.div>\n )\n }\n\n return (\n <motion.div\n layout\n role=\"status\"\n onMouseEnter={pauseTimer}\n onMouseLeave={resumeTimer}\n initial={{ opacity: 0, y: isTop ? -16 : 16, scale: 0.96 }}\n animate={{ opacity: 1, y: 0, scale: 1 }}\n exit={{ opacity: 0, scale: 0.96, transition: { duration: 0.15 } }}\n transition={{ type: 'spring', damping: 26, stiffness: 320 }}\n className={cn(\n 'pointer-events-auto flex w-full items-start gap-3 rounded-lg border px-4 py-3 shadow-lg',\n richColors ? RICH[t.type] : 'border-border bg-elevated text-fg',\n t.className,\n )}\n >\n {t.icon ?? TYPE_ICON[t.type] ? (\n <span className={cn('mt-0.5 shrink-0', richColors ? '' : ACCENT[t.type])}>\n {t.icon ?? TYPE_ICON[t.type]}\n </span>\n ) : null}\n <div className=\"min-w-0 flex-1 space-y-0.5\">\n {t.title ? <div className=\"text-sm font-semibold\">{t.title}</div> : null}\n {t.description ? <div className={cn('text-sm', richColors ? 'opacity-90' : 'text-fg-muted')}>{t.description}</div> : null}\n {t.action || t.cancel ? (\n <div className=\"flex items-center gap-2 pt-1.5\">\n {t.action ? (\n <button\n type=\"button\"\n onClick={(e) => {\n t.action!.onClick(e)\n close()\n }}\n className=\"rounded-md bg-primary px-2.5 py-1 text-xs font-medium text-primary-fg hover:bg-primary-hover\"\n >\n {t.action.label}\n </button>\n ) : null}\n {t.cancel ? (\n <button\n type=\"button\"\n onClick={(e) => {\n t.cancel!.onClick?.(e)\n close()\n }}\n className=\"rounded-md px-2.5 py-1 text-xs font-medium text-fg-muted hover:bg-surface-hover\"\n >\n {t.cancel.label}\n </button>\n ) : null}\n </div>\n ) : null}\n </div>\n {closeButton ? (\n <button\n type=\"button\"\n onClick={close}\n aria-label=\"Dismiss\"\n className=\"-mr-1 rounded-md p-1 text-current opacity-60 transition-opacity hover:opacity-100\"\n >\n <X className=\"size-4\" />\n </button>\n ) : null}\n </motion.div>\n )\n}\n"]}
package/tooltip.d.ts ADDED
@@ -0,0 +1,12 @@
1
+ import * as React from 'react';
2
+ export type TooltipProps = {
3
+ content: React.ReactNode;
4
+ children: React.ReactNode;
5
+ className?: string;
6
+ };
7
+ /**
8
+ * Tooltip — hover/focus label with an inverted surface (dark-on-light,
9
+ * light-on-dark). Fades in above the trigger; dismissed on blur/leave.
10
+ */
11
+ export declare function Tooltip({ content, children, className }: TooltipProps): React.JSX.Element;
12
+ //# sourceMappingURL=tooltip.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tooltip.d.ts","sourceRoot":"","sources":["../src/tooltip.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAI9B,MAAM,MAAM,YAAY,GAAG;IACzB,OAAO,EAAE,KAAK,CAAC,SAAS,CAAA;IACxB,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAA;IACzB,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB,CAAA;AAED;;;GAGG;AACH,wBAAgB,OAAO,CAAC,EAAE,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,EAAE,YAAY,qBA8BrE"}
package/tooltip.js ADDED
@@ -0,0 +1,14 @@
1
+ 'use client';
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import * as React from 'react';
4
+ import { AnimatePresence, motion } from 'framer-motion';
5
+ import { cn } from './utils.js';
6
+ /**
7
+ * Tooltip — hover/focus label with an inverted surface (dark-on-light,
8
+ * light-on-dark). Fades in above the trigger; dismissed on blur/leave.
9
+ */
10
+ export function Tooltip({ content, children, className }) {
11
+ const [open, setOpen] = React.useState(false);
12
+ return (_jsxs("span", { className: "relative inline-flex", onMouseEnter: () => setOpen(true), onMouseLeave: () => setOpen(false), onFocus: () => setOpen(true), onBlur: () => setOpen(false), children: [children, _jsx(AnimatePresence, { children: open ? (_jsx(motion.span, { role: "tooltip", initial: { opacity: 0, y: 4, scale: 0.96 }, animate: { opacity: 1, y: 0, scale: 1 }, exit: { opacity: 0, y: 4, scale: 0.96 }, transition: { duration: 0.13, ease: [0.22, 1, 0.36, 1] }, className: cn('pointer-events-none absolute bottom-full left-1/2 z-[60] mb-2 -translate-x-1/2 whitespace-nowrap rounded-md bg-fg px-2 py-1 text-xs font-medium text-bg shadow-md', className), children: content })) : null })] }));
13
+ }
14
+ //# sourceMappingURL=tooltip.js.map
package/tooltip.js.map ADDED
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tooltip.js","sourceRoot":"","sources":["../src/tooltip.tsx"],"names":[],"mappings":"AAAA,YAAY,CAAA;;AAEZ,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAC9B,OAAO,EAAE,eAAe,EAAE,MAAM,EAAE,MAAM,eAAe,CAAA;AACvD,OAAO,EAAE,EAAE,EAAE,MAAM,SAAS,CAAA;AAQ5B;;;GAGG;AACH,MAAM,UAAU,OAAO,CAAC,EAAE,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAgB;IACpE,MAAM,CAAC,IAAI,EAAE,OAAO,CAAC,GAAG,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAA;IAC7C,OAAO,CACL,gBACE,SAAS,EAAC,sBAAsB,EAChC,YAAY,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,EACjC,YAAY,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC,EAClC,OAAO,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,EAC5B,MAAM,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC,aAE3B,QAAQ,EACT,KAAC,eAAe,cACb,IAAI,CAAC,CAAC,CAAC,CACN,KAAC,MAAM,CAAC,IAAI,IACV,IAAI,EAAC,SAAS,EACd,OAAO,EAAE,EAAE,OAAO,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,EAC1C,OAAO,EAAE,EAAE,OAAO,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,EACvC,IAAI,EAAE,EAAE,OAAO,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,EACvC,UAAU,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,IAAI,EAAE,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,EACxD,SAAS,EAAE,EAAE,CACX,mKAAmK,EACnK,SAAS,CACV,YAEA,OAAO,GACI,CACf,CAAC,CAAC,CAAC,IAAI,GACQ,IACb,CACR,CAAA;AACH,CAAC","sourcesContent":["'use client'\n\nimport * as React from 'react'\nimport { AnimatePresence, motion } from 'framer-motion'\nimport { cn } from './utils'\n\nexport type TooltipProps = {\n content: React.ReactNode\n children: React.ReactNode\n className?: string\n}\n\n/**\n * Tooltip — hover/focus label with an inverted surface (dark-on-light,\n * light-on-dark). Fades in above the trigger; dismissed on blur/leave.\n */\nexport function Tooltip({ content, children, className }: TooltipProps) {\n const [open, setOpen] = React.useState(false)\n return (\n <span\n className=\"relative inline-flex\"\n onMouseEnter={() => setOpen(true)}\n onMouseLeave={() => setOpen(false)}\n onFocus={() => setOpen(true)}\n onBlur={() => setOpen(false)}\n >\n {children}\n <AnimatePresence>\n {open ? (\n <motion.span\n role=\"tooltip\"\n initial={{ opacity: 0, y: 4, scale: 0.96 }}\n animate={{ opacity: 1, y: 0, scale: 1 }}\n exit={{ opacity: 0, y: 4, scale: 0.96 }}\n transition={{ duration: 0.13, ease: [0.22, 1, 0.36, 1] }}\n className={cn(\n 'pointer-events-none absolute bottom-full left-1/2 z-[60] mb-2 -translate-x-1/2 whitespace-nowrap rounded-md bg-fg px-2 py-1 text-xs font-medium text-bg shadow-md',\n className,\n )}\n >\n {content}\n </motion.span>\n ) : null}\n </AnimatePresence>\n </span>\n )\n}\n"]}
package/top-nav.d.ts ADDED
@@ -0,0 +1,18 @@
1
+ import * as React from 'react';
2
+ import { type SidebarNavGroup } from './sidebar-nav.js';
3
+ import { type LinkRender } from './link-context.js';
4
+ export declare function TopNav({ groups, pathname, linkRender, moreLabel, ariaLabel, className, itemClassName, activeItemClassName, inactiveItemClassName, }: {
5
+ groups: SidebarNavGroup[];
6
+ pathname: string;
7
+ linkRender?: LinkRender;
8
+ moreLabel?: string;
9
+ ariaLabel?: string;
10
+ className?: string;
11
+ /** Shared typography/spacing overrides for every top-level navigation item. */
12
+ itemClassName?: string;
13
+ /** Overrides applied only to the active top-level item. */
14
+ activeItemClassName?: string;
15
+ /** Overrides applied only to inactive top-level items. */
16
+ inactiveItemClassName?: string;
17
+ }): React.JSX.Element;
18
+ //# sourceMappingURL=top-nav.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"top-nav.d.ts","sourceRoot":"","sources":["../src/top-nav.tsx"],"names":[],"mappings":"AAKA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAI9B,OAAO,EAKL,KAAK,eAAe,EAErB,MAAM,eAAe,CAAA;AACtB,OAAO,EAAqB,KAAK,UAAU,EAAE,MAAM,gBAAgB,CAAA;AAKnE,wBAAgB,MAAM,CAAC,EACrB,MAAM,EACN,QAAQ,EACR,UAA8B,EAC9B,SAAkB,EAClB,SAAgC,EAChC,SAAS,EACT,aAAa,EACb,mBAAmB,EACnB,qBAAqB,GACtB,EAAE;IACD,MAAM,EAAE,eAAe,EAAE,CAAA;IACzB,QAAQ,EAAE,MAAM,CAAA;IAChB,UAAU,CAAC,EAAE,UAAU,CAAA;IACvB,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,+EAA+E;IAC/E,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB,2DAA2D;IAC3D,mBAAmB,CAAC,EAAE,MAAM,CAAA;IAC5B,0DAA0D;IAC1D,qBAAqB,CAAC,EAAE,MAAM,CAAA;CAC/B,qBA+OA"}