@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.
- package/LICENSE +661 -0
- package/README.md +11 -0
- package/account-menu.d.ts +49 -0
- package/account-menu.d.ts.map +1 -0
- package/account-menu.js +66 -0
- package/account-menu.js.map +1 -0
- package/alert.d.ts +13 -0
- package/alert.d.ts.map +1 -0
- package/alert.js +22 -0
- package/alert.js.map +1 -0
- package/animated-number.d.ts +13 -0
- package/animated-number.d.ts.map +1 -0
- package/animated-number.js +53 -0
- package/animated-number.js.map +1 -0
- package/api-reference.d.ts +44 -0
- package/api-reference.d.ts.map +1 -0
- package/api-reference.js +82 -0
- package/api-reference.js.map +1 -0
- package/app-shell.d.ts +39 -0
- package/app-shell.d.ts.map +1 -0
- package/app-shell.js +21 -0
- package/app-shell.js.map +1 -0
- package/app-sidebar.d.ts +22 -0
- package/app-sidebar.d.ts.map +1 -0
- package/app-sidebar.js +30 -0
- package/app-sidebar.js.map +1 -0
- package/avatar.d.ts +9 -0
- package/avatar.d.ts.map +1 -0
- package/avatar.js +18 -0
- package/avatar.js.map +1 -0
- package/badge.d.ts +9 -0
- package/badge.d.ts.map +1 -0
- package/badge.js +23 -0
- package/badge.js.map +1 -0
- package/button.d.ts +24 -0
- package/button.d.ts.map +1 -0
- package/button.js +50 -0
- package/button.js.map +1 -0
- package/card.d.ts +21 -0
- package/card.d.ts.map +1 -0
- package/card.js +36 -0
- package/card.js.map +1 -0
- package/checkbox.d.ts +4 -0
- package/checkbox.d.ts.map +1 -0
- package/checkbox.js +6 -0
- package/checkbox.js.map +1 -0
- package/confirm-dialog.d.ts +23 -0
- package/confirm-dialog.d.ts.map +1 -0
- package/confirm-dialog.js +67 -0
- package/confirm-dialog.js.map +1 -0
- package/context-menu.d.ts +47 -0
- package/context-menu.d.ts.map +1 -0
- package/context-menu.js +90 -0
- package/context-menu.js.map +1 -0
- package/dialog.d.ts +25 -0
- package/dialog.d.ts.map +1 -0
- package/dialog.js +89 -0
- package/dialog.js.map +1 -0
- package/document-title.d.ts +11 -0
- package/document-title.d.ts.map +1 -0
- package/document-title.js +17 -0
- package/document-title.js.map +1 -0
- package/drawer.d.ts +63 -0
- package/drawer.d.ts.map +1 -0
- package/drawer.js +188 -0
- package/drawer.js.map +1 -0
- package/empty-state.d.ts +10 -0
- package/empty-state.d.ts.map +1 -0
- package/empty-state.js +7 -0
- package/empty-state.js.map +1 -0
- package/file-uploader.d.ts +67 -0
- package/file-uploader.d.ts.map +1 -0
- package/file-uploader.js +156 -0
- package/file-uploader.js.map +1 -0
- package/filter-chips.d.ts +47 -0
- package/filter-chips.d.ts.map +1 -0
- package/filter-chips.js +62 -0
- package/filter-chips.js.map +1 -0
- package/global-search.d.ts +41 -0
- package/global-search.d.ts.map +1 -0
- package/global-search.js +116 -0
- package/global-search.js.map +1 -0
- package/index.d.ts +70 -0
- package/index.d.ts.map +1 -0
- package/index.js +70 -0
- package/index.js.map +1 -0
- package/input.d.ts +9 -0
- package/input.d.ts.map +1 -0
- package/input.js +11 -0
- package/input.js.map +1 -0
- package/label.d.ts +3 -0
- package/label.d.ts.map +1 -0
- package/label.js +6 -0
- package/label.js.map +1 -0
- package/line-grid.d.ts +48 -0
- package/line-grid.d.ts.map +1 -0
- package/line-grid.js +155 -0
- package/line-grid.js.map +1 -0
- package/link-context.d.ts +44 -0
- package/link-context.d.ts.map +1 -0
- package/link-context.js +32 -0
- package/link-context.js.map +1 -0
- package/list-nav.d.ts +28 -0
- package/list-nav.d.ts.map +1 -0
- package/list-nav.js +41 -0
- package/list-nav.js.map +1 -0
- package/list-pagination.d.ts +27 -0
- package/list-pagination.d.ts.map +1 -0
- package/list-pagination.js +43 -0
- package/list-pagination.js.map +1 -0
- package/list-params.d.ts +41 -0
- package/list-params.d.ts.map +1 -0
- package/list-params.js +84 -0
- package/list-params.js.map +1 -0
- package/list-search-input-state.d.ts +13 -0
- package/list-search-input-state.d.ts.map +1 -0
- package/list-search-input-state.js +27 -0
- package/list-search-input-state.js.map +1 -0
- package/list-search-input.d.ts +16 -0
- package/list-search-input.d.ts.map +1 -0
- package/list-search-input.js +51 -0
- package/list-search-input.js.map +1 -0
- package/mobile-tab-bar.d.ts +14 -0
- package/mobile-tab-bar.d.ts.map +1 -0
- package/mobile-tab-bar.js +25 -0
- package/mobile-tab-bar.js.map +1 -0
- package/multi-select.d.ts +32 -0
- package/multi-select.d.ts.map +1 -0
- package/multi-select.js +52 -0
- package/multi-select.js.map +1 -0
- package/nav-overflow.d.ts +12 -0
- package/nav-overflow.d.ts.map +1 -0
- package/nav-overflow.js +30 -0
- package/nav-overflow.js.map +1 -0
- package/navigation-config-editor.d.ts +26 -0
- package/navigation-config-editor.d.ts.map +1 -0
- package/navigation-config-editor.js +57 -0
- package/navigation-config-editor.js.map +1 -0
- package/navigation-config.d.ts +48 -0
- package/navigation-config.d.ts.map +1 -0
- package/navigation-config.js +75 -0
- package/navigation-config.js.map +1 -0
- package/navigation-mode.d.ts +16 -0
- package/navigation-mode.d.ts.map +1 -0
- package/navigation-mode.js +30 -0
- package/navigation-mode.js.map +1 -0
- package/notifications-bell.d.ts +22 -0
- package/notifications-bell.d.ts.map +1 -0
- package/notifications-bell.js +30 -0
- package/notifications-bell.js.map +1 -0
- package/org-chart.d.ts +85 -0
- package/org-chart.d.ts.map +1 -0
- package/org-chart.js +193 -0
- package/org-chart.js.map +1 -0
- package/package.json +61 -0
- package/page-header.d.ts +32 -0
- package/page-header.d.ts.map +1 -0
- package/page-header.js +14 -0
- package/page-header.js.map +1 -0
- package/page-layout.d.ts +29 -0
- package/page-layout.d.ts.map +1 -0
- package/page-layout.js +23 -0
- package/page-layout.js.map +1 -0
- package/page-transition.d.ts +13 -0
- package/page-transition.d.ts.map +1 -0
- package/page-transition.js +14 -0
- package/page-transition.js.map +1 -0
- package/paged-table.d.ts +54 -0
- package/paged-table.d.ts.map +1 -0
- package/paged-table.js +74 -0
- package/paged-table.js.map +1 -0
- package/popover.d.ts +16 -0
- package/popover.d.ts.map +1 -0
- package/popover.js +99 -0
- package/popover.js.map +1 -0
- package/progress.d.ts +7 -0
- package/progress.d.ts.map +1 -0
- package/progress.js +8 -0
- package/progress.js.map +1 -0
- package/prompt-dialog.d.ts +21 -0
- package/prompt-dialog.d.ts.map +1 -0
- package/prompt-dialog.js +109 -0
- package/prompt-dialog.js.map +1 -0
- package/record-list.d.ts +76 -0
- package/record-list.d.ts.map +1 -0
- package/record-list.js +51 -0
- package/record-list.js.map +1 -0
- package/search-select.d.ts +42 -0
- package/search-select.d.ts.map +1 -0
- package/search-select.js +194 -0
- package/search-select.js.map +1 -0
- package/select-options.d.ts +16 -0
- package/select-options.d.ts.map +1 -0
- package/select-options.js +119 -0
- package/select-options.js.map +1 -0
- package/select.d.ts +24 -0
- package/select.d.ts.map +1 -0
- package/select.js +65 -0
- package/select.js.map +1 -0
- package/separator.d.ts +6 -0
- package/separator.d.ts.map +1 -0
- package/separator.js +7 -0
- package/separator.js.map +1 -0
- package/settings-layout.d.ts +79 -0
- package/settings-layout.d.ts.map +1 -0
- package/settings-layout.js +74 -0
- package/settings-layout.js.map +1 -0
- package/sidebar-nav.d.ts +67 -0
- package/sidebar-nav.d.ts.map +1 -0
- package/sidebar-nav.js +291 -0
- package/sidebar-nav.js.map +1 -0
- package/signature-pad.d.ts +16 -0
- package/signature-pad.d.ts.map +1 -0
- package/signature-pad.js +355 -0
- package/signature-pad.js.map +1 -0
- package/skeleton.d.ts +9 -0
- package/skeleton.d.ts.map +1 -0
- package/skeleton.js +12 -0
- package/skeleton.js.map +1 -0
- package/slider.d.ts +13 -0
- package/slider.d.ts.map +1 -0
- package/slider.js +15 -0
- package/slider.js.map +1 -0
- package/sortable-th.d.ts +28 -0
- package/sortable-th.d.ts.map +1 -0
- package/sortable-th.js +35 -0
- package/sortable-th.js.map +1 -0
- package/sparkline.d.ts +16 -0
- package/sparkline.d.ts.map +1 -0
- package/sparkline.js +46 -0
- package/sparkline.js.map +1 -0
- package/spinner.d.ts +11 -0
- package/spinner.d.ts.map +1 -0
- package/spinner.js +11 -0
- package/spinner.js.map +1 -0
- package/styles.css +166 -0
- package/subtab-nav.d.ts +17 -0
- package/subtab-nav.d.ts.map +1 -0
- package/subtab-nav.js +11 -0
- package/subtab-nav.js.map +1 -0
- package/switch.d.ts +9 -0
- package/switch.d.ts.map +1 -0
- package/switch.js +11 -0
- package/switch.js.map +1 -0
- package/tab-content.d.ts +24 -0
- package/tab-content.d.ts.map +1 -0
- package/tab-content.js +26 -0
- package/tab-content.js.map +1 -0
- package/table.d.ts +28 -0
- package/table.d.ts.map +1 -0
- package/table.js +21 -0
- package/table.js.map +1 -0
- package/tabs.d.ts +18 -0
- package/tabs.d.ts.map +1 -0
- package/tabs.js +18 -0
- package/tabs.js.map +1 -0
- package/text-context.d.ts +9 -0
- package/text-context.d.ts.map +1 -0
- package/text-context.js +12 -0
- package/text-context.js.map +1 -0
- package/textarea.d.ts +4 -0
- package/textarea.d.ts.map +1 -0
- package/textarea.js +6 -0
- package/textarea.js.map +1 -0
- package/theme-script.d.ts +3 -0
- package/theme-script.d.ts.map +1 -0
- package/theme-script.js +6 -0
- package/theme-script.js.map +1 -0
- package/theme.d.ts +28 -0
- package/theme.d.ts.map +1 -0
- package/theme.js +92 -0
- package/theme.js.map +1 -0
- package/toast.d.ts +52 -0
- package/toast.d.ts.map +1 -0
- package/toast.js +178 -0
- package/toast.js.map +1 -0
- package/tooltip.d.ts +12 -0
- package/tooltip.d.ts.map +1 -0
- package/tooltip.js +14 -0
- package/tooltip.js.map +1 -0
- package/top-nav.d.ts +18 -0
- package/top-nav.d.ts.map +1 -0
- package/top-nav.js +160 -0
- package/top-nav.js.map +1 -0
- package/upload-limits.d.ts +4 -0
- package/upload-limits.d.ts.map +1 -0
- package/upload-limits.js +21 -0
- package/upload-limits.js.map +1 -0
- package/use-element-size.d.ts +7 -0
- package/use-element-size.d.ts.map +1 -0
- package/use-element-size.js +21 -0
- package/use-element-size.js.map +1 -0
- package/utils.d.ts +4 -0
- package/utils.d.ts.map +1 -0
- package/utils.js +7 -0
- package/utils.js.map +1 -0
- package/workspace-launcher.d.ts +50 -0
- package/workspace-launcher.d.ts.map +1 -0
- package/workspace-launcher.js +127 -0
- 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":"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","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":"AAAA,YAAY,CAAA;;AAEZ,+EAA+E;AAC/E,uCAAuC;AACvC,sFAAsF;AACtF,gFAAgF;AAChF,0EAA0E;AAC1E,0CAA0C;AAE1C,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAC9B,OAAO,EAAE,YAAY,EAAE,MAAM,WAAW,CAAA;AACxC,OAAO,EAAE,eAAe,EAAE,MAAM,EAAE,MAAM,eAAe,CAAA;AACvD,OAAO,EAAE,KAAK,EAAE,WAAW,EAAE,IAAI,EAAE,OAAO,EAAE,aAAa,EAAE,CAAC,EAAE,MAAM,cAAc,CAAA;AAClF,OAAO,EAAE,EAAE,EAAE,MAAM,SAAS,CAAA;AA2B5B,IAAI,OAAO,GAAG,CAAC,CAAA;AAEf,MAAM,QAAQ;IACJ,WAAW,GAA+B,EAAE,CAAA;IAEpD,SAAS,CAAC,EAAuB;QAC/B,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;QACzB,OAAO,GAAG,EAAE;YACV,MAAM,CAAC,GAAG,IAAI,CAAC,WAAW,CAAC,OAAO,CAAC,EAAE,CAAC,CAAA;YACtC,IAAI,CAAC,GAAG,CAAC,CAAC;gBAAE,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,CAAA;QAC3C,CAAC,CAAA;IACH,CAAC;IAEO,OAAO,CAAC,CAAS;QACvB,IAAI,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAA;IACvC,CAAC;IAED,MAAM,CAAC,IAA6G;QAClH,MAAM,EAAE,GAAG,IAAI,CAAC,EAAE,IAAI,EAAE,OAAO,CAAA;QAC/B,MAAM,EAAE,OAAO,EAAE,GAAG,IAAI,EAAE,GAAG,IAAI,CAAA;QACjC,IAAI,CAAC,OAAO,CAAC,EAAE,GAAG,IAAI,EAAE,EAAE,EAAE,KAAK,EAAE,OAAO,IAAI,IAAI,CAAC,KAAK,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,IAAI,SAAS,EAAE,CAAC,CAAA;QACzF,OAAO,EAAE,CAAA;IACX,CAAC;IAED,OAAO,CAAC,EAAoB;QAC1B,IAAI,EAAE,IAAI,IAAI;YAAE,OAAO,EAAE,CAAA;QACzB,IAAI,CAAC,OAAO,CAAC,EAAE,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAA;QACnC,OAAO,EAAE,CAAA;IACX,CAAC;IAED,OAAO,GAAG,CAAC,OAAgB,EAAE,IAAoB,EAAE,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,GAAG,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC,CAAA;IACxG,OAAO,GAAG,CAAC,OAAgB,EAAE,IAAoB,EAAE,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,GAAG,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC,CAAA;IACxG,KAAK,GAAG,CAAC,OAAgB,EAAE,IAAoB,EAAE,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,GAAG,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,CAAA;IACpG,OAAO,GAAG,CAAC,OAAgB,EAAE,IAAoB,EAAE,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,GAAG,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC,CAAA;IACxG,IAAI,GAAG,CAAC,OAAgB,EAAE,IAAoB,EAAE,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,GAAG,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC,CAAA;IAClG,OAAO,GAAG,CAAC,OAAgB,EAAE,IAAoB,EAAE,EAAE,CACnD,IAAI,CAAC,MAAM,CAAC,EAAE,QAAQ,EAAE,QAAQ,EAAE,GAAG,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC,CAAA;IAExE,MAAM,GAAG,CAAC,GAA6C,EAAE,IAAoB,EAAE,EAAE;QAC/E,MAAM,EAAE,GAAG,IAAI,EAAE,EAAE,IAAI,EAAE,OAAO,CAAA;QAChC,IAAI,CAAC,OAAO,CAAC,EAAE,GAAG,IAAI,EAAE,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,GAAG,EAAE,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC,CAAA;QAC5D,OAAO,EAAE,CAAA;IACX,CAAC,CAAA;IAED,OAAO,GAAG,CACR,OAAmB,EACnB,IAIC,EACD,EAAE;QACF,MAAM,EAAE,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,CAAA;QACrC,OAAO,CAAC,IAAI,CACV,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,EAAE,EAAE,OAAO,EAAE,OAAO,IAAI,CAAC,OAAO,KAAK,UAAU,CAAC,CAAC,CAAE,IAAI,CAAC,OAA6B,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,QAAQ,EAAE,SAAS,EAAE,CAAC,EAC3K,CAAC,GAAG,EAAE,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,EAAE,EAAE,OAAO,EAAE,OAAO,IAAI,CAAC,KAAK,KAAK,UAAU,CAAC,CAAC,CAAE,IAAI,CAAC,KAAiC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,EAAE,IAAI,EAAE,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,CAAC,CACxK,CAAA;QACD,OAAO,EAAE,CAAA;IACX,CAAC,CAAA;CACF;AAED,MAAM,UAAU,GAAG,IAAI,QAAQ,EAAE,CAAA;AAEjC,SAAS,aAAa,CAAC,OAAgB,EAAE,IAAoB;IAC3D,OAAO,UAAU,CAAC,MAAM,CAAC,EAAE,GAAG,IAAI,EAAE,OAAO,EAAE,CAAC,CAAA;AAChD,CAAC;AAED,0CAA0C;AAC1C,MAAM,CAAC,MAAM,KAAK,GAAG,MAAM,CAAC,MAAM,CAAC,aAAa,EAAE;IAChD,OAAO,EAAE,UAAU,CAAC,OAAO;IAC3B,KAAK,EAAE,UAAU,CAAC,KAAK;IACvB,OAAO,EAAE,UAAU,CAAC,OAAO;IAC3B,IAAI,EAAE,UAAU,CAAC,IAAI;IACrB,OAAO,EAAE,UAAU,CAAC,OAAO;IAC3B,OAAO,EAAE,UAAU,CAAC,OAAO;IAC3B,MAAM,EAAE,UAAU,CAAC,MAAM;IACzB,OAAO,EAAE,UAAU,CAAC,OAAO;IAC3B,OAAO,EAAE,CAAC,EAAoB,EAAE,EAAE,CAAC,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC;CAC1D,CAAC,CAAA;AAQF,MAAM,cAAc,GAAoC;IACtD,UAAU,EAAE,0BAA0B;IACtC,YAAY,EAAE,8CAA8C;IAC5D,WAAW,EAAE,yBAAyB;IACtC,aAAa,EAAE,6BAA6B;IAC5C,eAAe,EAAE,iDAAiD;IAClE,cAAc,EAAE,4BAA4B;CAC7C,CAAA;AAED,MAAM,SAAS,GAAuC;IACpD,OAAO,EAAE,IAAI;IACb,OAAO,EAAE,KAAC,KAAK,IAAC,SAAS,EAAC,QAAQ,GAAG;IACrC,KAAK,EAAE,KAAC,WAAW,IAAC,SAAS,EAAC,QAAQ,GAAG;IACzC,OAAO,EAAE,KAAC,aAAa,IAAC,SAAS,EAAC,QAAQ,GAAG;IAC7C,IAAI,EAAE,KAAC,IAAI,IAAC,SAAS,EAAC,QAAQ,GAAG;IACjC,OAAO,EAAE,KAAC,OAAO,IAAC,SAAS,EAAC,gDAAgD,GAAG;CAChF,CAAA;AAED,MAAM,IAAI,GAA8B;IACtC,OAAO,EAAE,mCAAmC;IAC5C,OAAO,EAAE,kDAAkD;IAC3D,KAAK,EAAE,+CAA+C;IACtD,OAAO,EAAE,kDAAkD;IAC3D,IAAI,EAAE,yCAAyC;IAC/C,OAAO,EAAE,mCAAmC;CAC7C,CAAA;AAED,MAAM,MAAM,GAA8B;IACxC,OAAO,EAAE,eAAe;IACxB,OAAO,EAAE,cAAc;IACvB,KAAK,EAAE,aAAa;IACpB,OAAO,EAAE,cAAc;IACvB,IAAI,EAAE,WAAW;IACjB,OAAO,EAAE,eAAe;CACzB,CAAA;AAED,MAAM,UAAU,OAAO,CAAC,EACtB,QAAQ,GAAG,cAAc,EACzB,UAAU,GAAG,KAAK,EAClB,QAAQ,GAAG,IAAI,EACf,WAAW,GAAG,KAAK,EACnB,aAAa,GAAG,CAAC,EACjB,SAAS,GAQV;IACC,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,GAAG,KAAK,CAAC,QAAQ,CAAW,EAAE,CAAC,CAAA;IACxD,MAAM,CAAC,OAAO,EAAE,UAAU,CAAC,GAAG,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAA;IACnD,KAAK,CAAC,SAAS,CAAC,GAAG,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,EAAE,CAAC,CAAA;IAE3C,KAAK,CAAC,SAAS,CACb,GAAG,EAAE,CACH,UAAU,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,EAAE;QACzB,IAAI,SAAS,IAAI,CAAC,EAAE,CAAC;YACnB,SAAS,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAA;YACtD,OAAM;QACR,CAAC;QACD,SAAS,CAAC,CAAC,IAAI,EAAE,EAAE;YACjB,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,EAAE,CAAC,CAAA;YAChD,IAAI,QAAQ;gBAAE,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAA;YAC1E,MAAM,IAAI,GAAG,CAAC,CAAC,EAAE,GAAG,IAAI,CAAC,CAAA;YACzB,OAAO,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,aAAa,CAAC,CAAA;QACrC,CAAC,CAAC,CAAA;IACJ,CAAC,CAAC,EACJ,CAAC,aAAa,CAAC,CAChB,CAAA;IAED,IAAI,CAAC,OAAO,IAAI,OAAO,QAAQ,KAAK,WAAW;QAAE,OAAO,IAAI,CAAA;IAC5D,MAAM,KAAK,GAAG,QAAQ,CAAC,UAAU,CAAC,KAAK,CAAC,CAAA;IAExC,OAAO,YAAY,CACjB,cAAK,SAAS,EAAE,EAAE,CAAC,sFAAsF,EAAE,cAAc,CAAC,QAAQ,CAAC,EAAE,SAAS,CAAC,YAC7I,KAAC,eAAe,IAAC,OAAO,EAAE,KAAK,YAC5B,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CACjB,KAAC,QAAQ,IAAY,KAAK,EAAE,CAAC,EAAE,eAAe,EAAE,QAAQ,EAAE,UAAU,EAAE,UAAU,EAAE,WAAW,EAAE,WAAW,EAAE,KAAK,EAAE,KAAK,IAAzG,CAAC,CAAC,EAAE,CAAyG,CAC7H,CAAC,GACc,GACd,EACN,QAAQ,CAAC,IAAI,CACd,CAAA;AACH,CAAC;AAED,SAAS,QAAQ,CAAC,EAChB,KAAK,EAAE,CAAC,EACR,eAAe,EACf,UAAU,EACV,WAAW,EACX,KAAK,GAON;IACC,MAAM,CAAC,GAAG,CAAC,CAAC,QAAQ,IAAI,CAAC,CAAC,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,eAAe,CAAC,CAAA;IAC3E,MAAM,KAAK,GAAG,KAAK,CAAC,MAAM,CAAuC,IAAI,CAAC,CAAA;IACtE,MAAM,SAAS,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAAA;IACjC,MAAM,SAAS,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAAA;IAEjC,MAAM,UAAU,GAAG,KAAK,CAAC,WAAW,CAAC,GAAG,EAAE;QACxC,IAAI,KAAK,CAAC,OAAO;YAAE,YAAY,CAAC,KAAK,CAAC,OAAO,CAAC,CAAA;QAC9C,KAAK,CAAC,OAAO,GAAG,IAAI,CAAA;IACtB,CAAC,EAAE,EAAE,CAAC,CAAA;IAEN,MAAM,QAAQ,GAAG,KAAK,CAAC,WAAW,CAAC,GAAG,EAAE;QACtC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,SAAS,CAAC,OAAO,CAAC;YAAE,OAAM;QAC/C,UAAU,EAAE,CAAA;QACZ,SAAS,CAAC,OAAO,GAAG,IAAI,CAAC,GAAG,EAAE,CAAA;QAC9B,KAAK,CAAC,OAAO,GAAG,UAAU,CAAC,GAAG,EAAE;YAC9B,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAA;YACrB,UAAU,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,CAAA;QAC1B,CAAC,EAAE,SAAS,CAAC,OAAO,CAAC,CAAA;IACvB,CAAC,EAAE,CAAC,UAAU,EAAE,CAAC,CAAC,CAAC,CAAA;IAEnB,KAAK,CAAC,SAAS,CAAC,GAAG,EAAE;QACnB,SAAS,CAAC,OAAO,GAAG,CAAC,CAAA;QACrB,QAAQ,EAAE,CAAA;QACV,OAAO,UAAU,CAAA;QACjB,6EAA6E;IAC/E,CAAC,EAAE,CAAC,UAAU,EAAE,CAAC,EAAE,QAAQ,CAAC,CAAC,CAAA;IAE7B,SAAS,UAAU;QACjB,IAAI,CAAC,KAAK,CAAC,OAAO;YAAE,OAAM;QAC1B,SAAS,CAAC,OAAO,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,SAAS,CAAC,OAAO,GAAG,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,SAAS,CAAC,OAAO,CAAC,CAAC,CAAA;QACrF,UAAU,EAAE,CAAA;IACd,CAAC;IAED,SAAS,WAAW;QAClB,IAAI,CAAC,KAAK,CAAC,OAAO;YAAE,QAAQ,EAAE,CAAA;IAChC,CAAC;IAED,SAAS,KAAK;QACZ,CAAC,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAA;QACnB,UAAU,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,CAAA;IAC1B,CAAC;IAED,IAAI,CAAC,CAAC,GAAG,EAAE,CAAC;QACV,OAAO,CACL,KAAC,MAAM,CAAC,GAAG,IACT,MAAM,QACN,OAAO,EAAE,EAAE,OAAO,EAAE,CAAC,EAAE,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,EACzD,OAAO,EAAE,EAAE,OAAO,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,EACvC,IAAI,EAAE,EAAE,OAAO,EAAE,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,UAAU,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,EAAE,EACjE,UAAU,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,EAAE,EAAE,SAAS,EAAE,GAAG,EAAE,EAC3D,SAAS,EAAC,4BAA4B,YAErC,CAAC,CAAC,GAAG,GACK,CACd,CAAA;IACH,CAAC;IAED,OAAO,CACL,MAAC,MAAM,CAAC,GAAG,IACT,MAAM,QACN,IAAI,EAAC,QAAQ,EACb,YAAY,EAAE,UAAU,EACxB,YAAY,EAAE,WAAW,EACzB,OAAO,EAAE,EAAE,OAAO,EAAE,CAAC,EAAE,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,EACzD,OAAO,EAAE,EAAE,OAAO,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,EACvC,IAAI,EAAE,EAAE,OAAO,EAAE,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,UAAU,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,EAAE,EACjE,UAAU,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,EAAE,EAAE,SAAS,EAAE,GAAG,EAAE,EAC3D,SAAS,EAAE,EAAE,CACX,yFAAyF,EACzF,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,mCAAmC,EAC/D,CAAC,CAAC,SAAS,CACZ,aAEA,CAAC,CAAC,IAAI,IAAI,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAC7B,eAAM,SAAS,EAAE,EAAE,CAAC,iBAAiB,EAAE,UAAU,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,YACrE,CAAC,CAAC,IAAI,IAAI,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,GACvB,CACR,CAAC,CAAC,CAAC,IAAI,EACR,eAAK,SAAS,EAAC,4BAA4B,aACxC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,cAAK,SAAS,EAAC,uBAAuB,YAAE,CAAC,CAAC,KAAK,GAAO,CAAC,CAAC,CAAC,IAAI,EACvE,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,cAAK,SAAS,EAAE,EAAE,CAAC,SAAS,EAAE,UAAU,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,eAAe,CAAC,YAAG,CAAC,CAAC,WAAW,GAAO,CAAC,CAAC,CAAC,IAAI,EACxH,CAAC,CAAC,MAAM,IAAI,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CACtB,eAAK,SAAS,EAAC,gCAAgC,aAC5C,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CACV,iBACE,IAAI,EAAC,QAAQ,EACb,OAAO,EAAE,CAAC,CAAC,EAAE,EAAE;oCACb,CAAC,CAAC,MAAO,CAAC,OAAO,CAAC,CAAC,CAAC,CAAA;oCACpB,KAAK,EAAE,CAAA;gCACT,CAAC,EACD,SAAS,EAAC,8FAA8F,YAEvG,CAAC,CAAC,MAAM,CAAC,KAAK,GACR,CACV,CAAC,CAAC,CAAC,IAAI,EACP,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CACV,iBACE,IAAI,EAAC,QAAQ,EACb,OAAO,EAAE,CAAC,CAAC,EAAE,EAAE;oCACb,CAAC,CAAC,MAAO,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,CAAA;oCACtB,KAAK,EAAE,CAAA;gCACT,CAAC,EACD,SAAS,EAAC,iFAAiF,YAE1F,CAAC,CAAC,MAAM,CAAC,KAAK,GACR,CACV,CAAC,CAAC,CAAC,IAAI,IACJ,CACP,CAAC,CAAC,CAAC,IAAI,IACJ,EACL,WAAW,CAAC,CAAC,CAAC,CACb,iBACE,IAAI,EAAC,QAAQ,EACb,OAAO,EAAE,KAAK,gBACH,SAAS,EACpB,SAAS,EAAC,mFAAmF,YAE7F,KAAC,CAAC,IAAC,SAAS,EAAC,QAAQ,GAAG,GACjB,CACV,CAAC,CAAC,CAAC,IAAI,IACG,CACd,CAAA;AACH,CAAC","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
|
package/tooltip.d.ts.map
ADDED
|
@@ -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
|
package/top-nav.d.ts.map
ADDED
|
@@ -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"}
|