tempest-react-sdk 0.25.0 → 0.26.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/README.md +14 -1
- package/bin/lib/alias/collect.mjs +94 -0
- package/bin/lib/alias/collect.test.mjs +95 -0
- package/bin/lib/alias/discover.mjs +77 -0
- package/bin/lib/alias/discover.test.mjs +189 -0
- package/bin/lib/alias/index.mjs +88 -0
- package/bin/lib/alias/index.test.mjs +138 -0
- package/bin/lib/alias/rewrite-css.mjs +76 -0
- package/bin/lib/alias/rewrite-css.test.mjs +85 -0
- package/bin/lib/alias/rewrite.mjs +141 -0
- package/bin/lib/alias/rewrite.test.mjs +148 -0
- package/bin/lib/alias/specifier.mjs +49 -0
- package/bin/lib/alias/specifier.test.mjs +85 -0
- package/bin/lib/alias/tsconfig.mjs +116 -0
- package/bin/lib/alias/typescript.mjs +23 -0
- package/bin/lib/icons/generate.mjs +156 -0
- package/bin/lib/icons/generate.test.mjs +125 -0
- package/bin/tempest.mjs +158 -13
- package/dist/audio/use-audio.cjs +1 -1
- package/dist/audio/use-audio.cjs.map +1 -1
- package/dist/audio/use-audio.js +12 -12
- package/dist/audio/use-audio.js.map +1 -1
- package/dist/charts/palette.cjs +1 -1
- package/dist/charts/palette.cjs.map +1 -1
- package/dist/charts/palette.js +2 -2
- package/dist/charts/palette.js.map +1 -1
- package/dist/charts.d.ts +5 -3
- package/dist/components/ClickOutside/ClickOutside.cjs +1 -1
- package/dist/components/ClickOutside/ClickOutside.cjs.map +1 -1
- package/dist/components/ClickOutside/ClickOutside.js +3 -1
- package/dist/components/ClickOutside/ClickOutside.js.map +1 -1
- package/dist/components/DataTable/DataTable.cjs +1 -1
- package/dist/components/DataTable/DataTable.cjs.map +1 -1
- package/dist/components/DataTable/DataTable.js +21 -23
- package/dist/components/DataTable/DataTable.js.map +1 -1
- package/dist/components/Kanban/Kanban.cjs +2 -0
- package/dist/components/Kanban/Kanban.cjs.map +1 -0
- package/dist/components/Kanban/Kanban.js +102 -0
- package/dist/components/Kanban/Kanban.js.map +1 -0
- package/dist/components/Kanban/Kanban.module.cjs +2 -0
- package/dist/components/Kanban/Kanban.module.cjs.map +1 -0
- package/dist/components/Kanban/Kanban.module.js +19 -0
- package/dist/components/Kanban/Kanban.module.js.map +1 -0
- package/dist/components/NotificationCenter/NotificationCenter.cjs +2 -0
- package/dist/components/NotificationCenter/NotificationCenter.cjs.map +1 -0
- package/dist/components/NotificationCenter/NotificationCenter.js +83 -0
- package/dist/components/NotificationCenter/NotificationCenter.js.map +1 -0
- package/dist/components/NotificationCenter/NotificationCenter.module.cjs +2 -0
- package/dist/components/NotificationCenter/NotificationCenter.module.cjs.map +1 -0
- package/dist/components/NotificationCenter/NotificationCenter.module.js +21 -0
- package/dist/components/NotificationCenter/NotificationCenter.module.js.map +1 -0
- package/dist/components/NotificationCenter/use-notification-inbox.cjs +2 -0
- package/dist/components/NotificationCenter/use-notification-inbox.cjs.map +1 -0
- package/dist/components/NotificationCenter/use-notification-inbox.js +63 -0
- package/dist/components/NotificationCenter/use-notification-inbox.js.map +1 -0
- package/dist/components/RefreshIndicator/RefreshIndicator.cjs +1 -1
- package/dist/components/RefreshIndicator/RefreshIndicator.cjs.map +1 -1
- package/dist/components/RefreshIndicator/RefreshIndicator.js +17 -17
- package/dist/components/RefreshIndicator/RefreshIndicator.js.map +1 -1
- package/dist/components/Tooltip/Tooltip.cjs +1 -1
- package/dist/components/Tooltip/Tooltip.cjs.map +1 -1
- package/dist/components/Tooltip/Tooltip.js +26 -20
- package/dist/components/Tooltip/Tooltip.js.map +1 -1
- package/dist/components/VirtualTable/VirtualTable.cjs +2 -0
- package/dist/components/VirtualTable/VirtualTable.cjs.map +1 -0
- package/dist/components/VirtualTable/VirtualTable.js +116 -0
- package/dist/components/VirtualTable/VirtualTable.js.map +1 -0
- package/dist/components/VirtualTable/VirtualTable.module.cjs +2 -0
- package/dist/components/VirtualTable/VirtualTable.module.cjs.map +1 -0
- package/dist/components/VirtualTable/VirtualTable.module.js +20 -0
- package/dist/components/VirtualTable/VirtualTable.module.js.map +1 -0
- package/dist/components/Wizard/Wizard.cjs +1 -1
- package/dist/components/Wizard/Wizard.cjs.map +1 -1
- package/dist/components/Wizard/Wizard.js +53 -53
- package/dist/components/Wizard/Wizard.js.map +1 -1
- package/dist/geo/use-position-tracker.cjs +1 -1
- package/dist/geo/use-position-tracker.cjs.map +1 -1
- package/dist/geo/use-position-tracker.js +3 -1
- package/dist/geo/use-position-tracker.js.map +1 -1
- package/dist/hooks/use-async.cjs +1 -1
- package/dist/hooks/use-async.cjs.map +1 -1
- package/dist/hooks/use-async.js +3 -1
- package/dist/hooks/use-async.js.map +1 -1
- package/dist/hooks/use-click-outside.cjs +1 -1
- package/dist/hooks/use-click-outside.cjs.map +1 -1
- package/dist/hooks/use-click-outside.js +3 -1
- package/dist/hooks/use-click-outside.js.map +1 -1
- package/dist/hooks/use-deep-memo.cjs.map +1 -1
- package/dist/hooks/use-deep-memo.js.map +1 -1
- package/dist/hooks/use-event-listener.cjs +1 -1
- package/dist/hooks/use-event-listener.cjs.map +1 -1
- package/dist/hooks/use-event-listener.js +3 -1
- package/dist/hooks/use-event-listener.js.map +1 -1
- package/dist/hooks/use-interval.cjs +1 -1
- package/dist/hooks/use-interval.cjs.map +1 -1
- package/dist/hooks/use-interval.js +3 -1
- package/dist/hooks/use-interval.js.map +1 -1
- package/dist/hooks/use-is-first-render.cjs.map +1 -1
- package/dist/hooks/use-is-first-render.js.map +1 -1
- package/dist/hooks/use-long-press-handlers.cjs +1 -1
- package/dist/hooks/use-long-press-handlers.cjs.map +1 -1
- package/dist/hooks/use-long-press-handlers.js +25 -23
- package/dist/hooks/use-long-press-handlers.js.map +1 -1
- package/dist/hooks/use-long-press.cjs +1 -1
- package/dist/hooks/use-long-press.cjs.map +1 -1
- package/dist/hooks/use-long-press.js +3 -1
- package/dist/hooks/use-long-press.js.map +1 -1
- package/dist/hooks/use-online.cjs +1 -1
- package/dist/hooks/use-online.cjs.map +1 -1
- package/dist/hooks/use-online.js +6 -4
- package/dist/hooks/use-online.js.map +1 -1
- package/dist/hooks/use-previous.cjs.map +1 -1
- package/dist/hooks/use-previous.js.map +1 -1
- package/dist/hooks/use-service-worker-update.cjs +1 -1
- package/dist/hooks/use-service-worker-update.cjs.map +1 -1
- package/dist/hooks/use-service-worker-update.js +3 -1
- package/dist/hooks/use-service-worker-update.js.map +1 -1
- package/dist/hooks/use-sortable.cjs +2 -0
- package/dist/hooks/use-sortable.cjs.map +1 -0
- package/dist/hooks/use-sortable.js +169 -0
- package/dist/hooks/use-sortable.js.map +1 -0
- package/dist/hooks/use-stable-callback.cjs.map +1 -1
- package/dist/hooks/use-stable-callback.js.map +1 -1
- package/dist/hooks/use-timeout.cjs +1 -1
- package/dist/hooks/use-timeout.cjs.map +1 -1
- package/dist/hooks/use-timeout.js +3 -1
- package/dist/hooks/use-timeout.js.map +1 -1
- package/dist/icons/Icon.cjs +2 -0
- package/dist/icons/Icon.cjs.map +1 -0
- package/dist/icons/Icon.js +24 -0
- package/dist/icons/Icon.js.map +1 -0
- package/dist/icons/IconProvider.cjs +2 -0
- package/dist/icons/IconProvider.cjs.map +1 -0
- package/dist/icons/IconProvider.js +24 -0
- package/dist/icons/IconProvider.js.map +1 -0
- package/dist/icons/generated/aliases.cjs +2 -0
- package/dist/icons/generated/aliases.cjs.map +1 -0
- package/dist/icons/generated/aliases.js +255 -0
- package/dist/icons/generated/aliases.js.map +1 -0
- package/dist/icons/generated/icon-names.cjs +2 -0
- package/dist/icons/generated/icon-names.cjs.map +1 -0
- package/dist/icons/generated/icon-names.js +6 -0
- package/dist/icons/generated/icon-names.js.map +1 -0
- package/dist/icons/generated/loaders.cjs +2 -0
- package/dist/icons/generated/loaders.cjs.map +1 -0
- package/dist/icons/generated/loaders.js +32 -0
- package/dist/icons/generated/loaders.js.map +1 -0
- package/dist/icons/generated/shard-a.cjs +2 -0
- package/dist/icons/generated/shard-a.cjs.map +1 -0
- package/dist/icons/generated/shard-a.js +114 -0
- package/dist/icons/generated/shard-a.js.map +1 -0
- package/dist/icons/generated/shard-b.cjs +2 -0
- package/dist/icons/generated/shard-b.cjs.map +1 -0
- package/dist/icons/generated/shard-b.js +156 -0
- package/dist/icons/generated/shard-b.js.map +1 -0
- package/dist/icons/generated/shard-c.cjs +2 -0
- package/dist/icons/generated/shard-c.cjs.map +1 -0
- package/dist/icons/generated/shard-c.js +269 -0
- package/dist/icons/generated/shard-c.js.map +1 -0
- package/dist/icons/generated/shard-d.cjs +2 -0
- package/dist/icons/generated/shard-d.cjs.map +1 -0
- package/dist/icons/generated/shard-d.js +62 -0
- package/dist/icons/generated/shard-d.js.map +1 -0
- package/dist/icons/generated/shard-e.cjs +2 -0
- package/dist/icons/generated/shard-e.cjs.map +1 -0
- package/dist/icons/generated/shard-e.js +32 -0
- package/dist/icons/generated/shard-e.js.map +1 -0
- package/dist/icons/generated/shard-f.cjs +2 -0
- package/dist/icons/generated/shard-f.cjs.map +1 -0
- package/dist/icons/generated/shard-f.js +139 -0
- package/dist/icons/generated/shard-f.js.map +1 -0
- package/dist/icons/generated/shard-g.cjs +2 -0
- package/dist/icons/generated/shard-g.cjs.map +1 -0
- package/dist/icons/generated/shard-g.js +61 -0
- package/dist/icons/generated/shard-g.js.map +1 -0
- package/dist/icons/generated/shard-h.cjs +2 -0
- package/dist/icons/generated/shard-h.cjs.map +1 -0
- package/dist/icons/generated/shard-h.js +63 -0
- package/dist/icons/generated/shard-h.js.map +1 -0
- package/dist/icons/generated/shard-i.cjs +2 -0
- package/dist/icons/generated/shard-i.cjs.map +1 -0
- package/dist/icons/generated/shard-i.js +30 -0
- package/dist/icons/generated/shard-i.js.map +1 -0
- package/dist/icons/generated/shard-j.cjs +2 -0
- package/dist/icons/generated/shard-j.cjs.map +1 -0
- package/dist/icons/generated/shard-j.js +10 -0
- package/dist/icons/generated/shard-j.js.map +1 -0
- package/dist/icons/generated/shard-k.cjs +2 -0
- package/dist/icons/generated/shard-k.cjs.map +1 -0
- package/dist/icons/generated/shard-k.js +16 -0
- package/dist/icons/generated/shard-k.js.map +1 -0
- package/dist/icons/generated/shard-l.cjs +2 -0
- package/dist/icons/generated/shard-l.cjs.map +1 -0
- package/dist/icons/generated/shard-l.js +88 -0
- package/dist/icons/generated/shard-l.js.map +1 -0
- package/dist/icons/generated/shard-m.cjs +2 -0
- package/dist/icons/generated/shard-m.cjs.map +1 -0
- package/dist/icons/generated/shard-m.js +140 -0
- package/dist/icons/generated/shard-m.js.map +1 -0
- package/dist/icons/generated/shard-n.cjs +2 -0
- package/dist/icons/generated/shard-n.cjs.map +1 -0
- package/dist/icons/generated/shard-n.js +24 -0
- package/dist/icons/generated/shard-n.js.map +1 -0
- package/dist/icons/generated/shard-o.cjs +2 -0
- package/dist/icons/generated/shard-o.cjs.map +1 -0
- package/dist/icons/generated/shard-o.js +17 -0
- package/dist/icons/generated/shard-o.js.map +1 -0
- package/dist/icons/generated/shard-p.cjs +2 -0
- package/dist/icons/generated/shard-p.cjs.map +1 -0
- package/dist/icons/generated/shard-p.js +115 -0
- package/dist/icons/generated/shard-p.js.map +1 -0
- package/dist/icons/generated/shard-q.cjs +2 -0
- package/dist/icons/generated/shard-q.cjs.map +1 -0
- package/dist/icons/generated/shard-q.js +10 -0
- package/dist/icons/generated/shard-q.js.map +1 -0
- package/dist/icons/generated/shard-r.cjs +2 -0
- package/dist/icons/generated/shard-r.cjs.map +1 -0
- package/dist/icons/generated/shard-r.js +77 -0
- package/dist/icons/generated/shard-r.js.map +1 -0
- package/dist/icons/generated/shard-s.cjs +2 -0
- package/dist/icons/generated/shard-s.cjs.map +1 -0
- package/dist/icons/generated/shard-s.js +255 -0
- package/dist/icons/generated/shard-s.js.map +1 -0
- package/dist/icons/generated/shard-t.cjs +2 -0
- package/dist/icons/generated/shard-t.cjs.map +1 -0
- package/dist/icons/generated/shard-t.js +109 -0
- package/dist/icons/generated/shard-t.js.map +1 -0
- package/dist/icons/generated/shard-u.cjs +2 -0
- package/dist/icons/generated/shard-u.cjs.map +1 -0
- package/dist/icons/generated/shard-u.js +49 -0
- package/dist/icons/generated/shard-u.js.map +1 -0
- package/dist/icons/generated/shard-v.cjs +2 -0
- package/dist/icons/generated/shard-v.cjs.map +1 -0
- package/dist/icons/generated/shard-v.js +30 -0
- package/dist/icons/generated/shard-v.js.map +1 -0
- package/dist/icons/generated/shard-w.cjs +2 -0
- package/dist/icons/generated/shard-w.cjs.map +1 -0
- package/dist/icons/generated/shard-w.js +48 -0
- package/dist/icons/generated/shard-w.js.map +1 -0
- package/dist/icons/generated/shard-x.cjs +2 -0
- package/dist/icons/generated/shard-x.cjs.map +1 -0
- package/dist/icons/generated/shard-x.js +10 -0
- package/dist/icons/generated/shard-x.js.map +1 -0
- package/dist/icons/generated/shard-z.cjs +2 -0
- package/dist/icons/generated/shard-z.cjs.map +1 -0
- package/dist/icons/generated/shard-z.js +25 -0
- package/dist/icons/generated/shard-z.js.map +1 -0
- package/dist/icons/icon-context.cjs +2 -0
- package/dist/icons/icon-context.cjs.map +1 -0
- package/dist/icons/icon-context.js +13 -0
- package/dist/icons/icon-context.js.map +1 -0
- package/dist/icons/is-icon-name.cjs +2 -0
- package/dist/icons/is-icon-name.cjs.map +1 -0
- package/dist/icons/is-icon-name.js +10 -0
- package/dist/icons/is-icon-name.js.map +1 -0
- package/dist/icons/shard-cache.cjs +2 -0
- package/dist/icons/shard-cache.cjs.map +1 -0
- package/dist/icons/shard-cache.js +41 -0
- package/dist/icons/shard-cache.js.map +1 -0
- package/dist/icons/use-icon.cjs +2 -0
- package/dist/icons/use-icon.cjs.map +1 -0
- package/dist/icons/use-icon.js +20 -0
- package/dist/icons/use-icon.js.map +1 -0
- package/dist/icons-virtual.d.ts +22 -0
- package/dist/icons.cjs +1 -0
- package/dist/icons.d.ts +220 -0
- package/dist/icons.js +9 -0
- package/dist/offline/use-offline-sync.cjs +1 -1
- package/dist/offline/use-offline-sync.cjs.map +1 -1
- package/dist/offline/use-offline-sync.js +3 -1
- package/dist/offline/use-offline-sync.js.map +1 -1
- package/dist/push/use-push-subscription.cjs +1 -1
- package/dist/push/use-push-subscription.cjs.map +1 -1
- package/dist/push/use-push-subscription.js +3 -1
- package/dist/push/use-push-subscription.js.map +1 -1
- package/dist/sse/use-event-stream.cjs +1 -1
- package/dist/sse/use-event-stream.cjs.map +1 -1
- package/dist/sse/use-event-stream.js +3 -1
- package/dist/sse/use-event-stream.js.map +1 -1
- package/dist/styles.css +1 -1
- package/dist/tempest-react-sdk.cjs +1 -1
- package/dist/tempest-react-sdk.d.ts +585 -3
- package/dist/tempest-react-sdk.js +189 -183
- package/dist/theme/ThemeProvider.cjs +1 -1
- package/dist/theme/ThemeProvider.cjs.map +1 -1
- package/dist/theme/ThemeProvider.js +6 -2
- package/dist/theme/ThemeProvider.js.map +1 -1
- package/dist/theme/color.cjs +1 -1
- package/dist/theme/color.cjs.map +1 -1
- package/dist/theme/color.js +77 -46
- package/dist/theme/color.js.map +1 -1
- package/dist/theme/create-theme.cjs +1 -1
- package/dist/theme/create-theme.cjs.map +1 -1
- package/dist/theme/create-theme.js +9 -3
- package/dist/theme/create-theme.js.map +1 -1
- package/dist/utils/compare-values.cjs +2 -0
- package/dist/utils/compare-values.cjs.map +1 -0
- package/dist/utils/compare-values.js +8 -0
- package/dist/utils/compare-values.js.map +1 -0
- package/dist/vision/use-camera-stream.cjs +1 -1
- package/dist/vision/use-camera-stream.cjs.map +1 -1
- package/dist/vision/use-camera-stream.js +3 -1
- package/dist/vision/use-camera-stream.js.map +1 -1
- package/dist/vite/create-vite-config.cjs +1 -1
- package/dist/vite/create-vite-config.cjs.map +1 -1
- package/dist/vite/create-vite-config.js +30 -22
- package/dist/vite/create-vite-config.js.map +1 -1
- package/dist/vite/tempest-icons.cjs +9 -0
- package/dist/vite/tempest-icons.cjs.map +1 -0
- package/dist/vite/tempest-icons.js +99 -0
- package/dist/vite/tempest-icons.js.map +1 -0
- package/dist/vite.cjs +1 -1
- package/dist/vite.d.ts +79 -0
- package/dist/vite.js +6 -5
- package/dist/ws/use-web-socket.cjs +1 -1
- package/dist/ws/use-web-socket.cjs.map +1 -1
- package/dist/ws/use-web-socket.js +3 -1
- package/dist/ws/use-web-socket.js.map +1 -1
- package/package.json +12 -3
- package/template/package.json +1 -1
package/dist/icons.d.ts
ADDED
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
import { LucideIcon } from 'lucide-react';
|
|
2
|
+
import { ReactNode } from 'react';
|
|
3
|
+
import { SVGProps } from 'react';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Build an icon registry from statically imported lucide components.
|
|
7
|
+
*
|
|
8
|
+
* The point is that the imports are static, so the bundler keeps exactly the
|
|
9
|
+
* icons named here and tree-shakes the rest — the opposite of `DynamicIcon`,
|
|
10
|
+
* which forces a chunk boundary for all ~2000 icons whether you use them or not.
|
|
11
|
+
*
|
|
12
|
+
* @example
|
|
13
|
+
* import { createIconRegistry } from "tempest-react-sdk/icons";
|
|
14
|
+
* import { Save, Trash2 } from "lucide-react";
|
|
15
|
+
*
|
|
16
|
+
* export const icons = createIconRegistry({ save: Save, "trash-2": Trash2 });
|
|
17
|
+
*
|
|
18
|
+
* @param icons - Slug → icon component.
|
|
19
|
+
* @returns The registry, ready for `IconProvider`.
|
|
20
|
+
*/
|
|
21
|
+
export declare function createIconRegistry(icons: Record<string, LucideIcon>): IconRegistry;
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Render a lucide icon by slug.
|
|
25
|
+
*
|
|
26
|
+
* All ~2000 lucide icons are addressable, without the cost that makes
|
|
27
|
+
* `lucide-react`'s own `DynamicIcon` unusable: its icon map holds a dynamic
|
|
28
|
+
* `import()` per icon, so a bundler has to emit ~2000 chunk boundaries and the
|
|
29
|
+
* browser floods with requests. Here a slug the app wrote as a literal is
|
|
30
|
+
* resolved from a static registry, and a slug only known at runtime pulls a
|
|
31
|
+
* single shard covering every icon sharing its initial letter.
|
|
32
|
+
*
|
|
33
|
+
* An unknown slug renders `fallback` (nothing, by default) and warns in dev only
|
|
34
|
+
* — it never throws, because a bad name from an API must not take down the tree.
|
|
35
|
+
*
|
|
36
|
+
* @example
|
|
37
|
+
* <Icon name="save" size={18} />
|
|
38
|
+
* <Icon name={row.iconSlug} fallback={<span className="skeleton" />} />
|
|
39
|
+
*/
|
|
40
|
+
export declare function Icon({ name, size, strokeWidth, fallback, ...rest }: IconProps): ReactNode;
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Lucide's 248 deprecated slugs, mapped to the canonical slug that
|
|
44
|
+
* replaced them (`alert-circle` → `circle-alert`).
|
|
45
|
+
*
|
|
46
|
+
* Kept so a name stored in a database years ago keeps rendering after a lucide
|
|
47
|
+
* bump renames it. Resolution goes through here first, so an alias loads the
|
|
48
|
+
* shard of its *canonical* slug.
|
|
49
|
+
*/
|
|
50
|
+
export declare const iconAliases: Record<string, string>;
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Every icon slug lucide ships, as a union of string literals.
|
|
54
|
+
*
|
|
55
|
+
* Erased at compile time, so the 1997 members cost no bytes — they buy
|
|
56
|
+
* autocomplete and a typo caught by `tsc` instead of at runtime.
|
|
57
|
+
*/
|
|
58
|
+
export declare type IconName = "a-arrow-down" | "a-arrow-up" | "a-large-small" | "accessibility" | "activity" | "activity-square" | "ad" | "air-vent" | "airplay" | "alarm-check" | "alarm-clock" | "alarm-clock-check" | "alarm-clock-minus" | "alarm-clock-off" | "alarm-clock-plus" | "alarm-minus" | "alarm-plus" | "alarm-smoke" | "album" | "alert-circle" | "alert-octagon" | "alert-triangle" | "align-center" | "align-center-horizontal" | "align-center-vertical" | "align-end-horizontal" | "align-end-vertical" | "align-horizontal-distribute-center" | "align-horizontal-distribute-end" | "align-horizontal-distribute-start" | "align-horizontal-justify-center" | "align-horizontal-justify-end" | "align-horizontal-justify-start" | "align-horizontal-space-around" | "align-horizontal-space-between" | "align-justify" | "align-left" | "align-right" | "align-start-horizontal" | "align-start-vertical" | "align-vertical-distribute-center" | "align-vertical-distribute-end" | "align-vertical-distribute-start" | "align-vertical-justify-center" | "align-vertical-justify-end" | "align-vertical-justify-start" | "align-vertical-space-around" | "align-vertical-space-between" | "ambulance" | "ampersand" | "ampersands" | "amphora" | "anchor" | "angry" | "annoyed" | "antenna" | "anvil" | "aperture" | "app-window" | "app-window-mac" | "apple" | "archive" | "archive-restore" | "archive-x" | "area-chart" | "armchair" | "arrow-big-down" | "arrow-big-down-dash" | "arrow-big-left" | "arrow-big-left-dash" | "arrow-big-right" | "arrow-big-right-dash" | "arrow-big-up" | "arrow-big-up-dash" | "arrow-down" | "arrow-down-0-1" | "arrow-down-01" | "arrow-down-1-0" | "arrow-down-10" | "arrow-down-a-z" | "arrow-down-az" | "arrow-down-circle" | "arrow-down-from-line" | "arrow-down-left" | "arrow-down-left-from-circle" | "arrow-down-left-from-square" | "arrow-down-left-square" | "arrow-down-narrow-wide" | "arrow-down-right" | "arrow-down-right-from-circle" | "arrow-down-right-from-square" | "arrow-down-right-square" | "arrow-down-square" | "arrow-down-to-dot" | "arrow-down-to-line" | "arrow-down-up" | "arrow-down-wide-narrow" | "arrow-down-z-a" | "arrow-down-za" | "arrow-left" | "arrow-left-circle" | "arrow-left-from-line" | "arrow-left-right" | "arrow-left-square" | "arrow-left-to-line" | "arrow-right" | "arrow-right-circle" | "arrow-right-from-line" | "arrow-right-left" | "arrow-right-square" | "arrow-right-to-line" | "arrow-up" | "arrow-up-0-1" | "arrow-up-01" | "arrow-up-1-0" | "arrow-up-10" | "arrow-up-a-z" | "arrow-up-az" | "arrow-up-circle" | "arrow-up-down" | "arrow-up-from-dot" | "arrow-up-from-line" | "arrow-up-left" | "arrow-up-left-from-circle" | "arrow-up-left-from-square" | "arrow-up-left-square" | "arrow-up-narrow-wide" | "arrow-up-right" | "arrow-up-right-from-circle" | "arrow-up-right-from-square" | "arrow-up-right-square" | "arrow-up-square" | "arrow-up-to-line" | "arrow-up-wide-narrow" | "arrow-up-z-a" | "arrow-up-za" | "arrows-up-from-line" | "asterisk" | "asterisk-square" | "astroid" | "at-sign" | "atom" | "audio-lines" | "audio-waveform" | "award" | "axe" | "axis-3-d" | "axis-3d" | "baby" | "backpack" | "badge" | "badge-alert" | "badge-cent" | "badge-check" | "badge-dollar-sign" | "badge-euro" | "badge-help" | "badge-indian-rupee" | "badge-info" | "badge-japanese-yen" | "badge-minus" | "badge-percent" | "badge-plus" | "badge-pound-sterling" | "badge-question-mark" | "badge-russian-ruble" | "badge-swiss-franc" | "badge-turkish-lira" | "badge-x" | "baggage-claim" | "balloon" | "ban" | "banana" | "bandage" | "banknote" | "banknote-arrow-down" | "banknote-arrow-up" | "banknote-check" | "banknote-x" | "bar-chart" | "bar-chart-2" | "bar-chart-3" | "bar-chart-4" | "bar-chart-big" | "bar-chart-horizontal" | "bar-chart-horizontal-big" | "barcode" | "barrel" | "baseline" | "bath" | "battery" | "battery-charging" | "battery-full" | "battery-low" | "battery-medium" | "battery-plus" | "battery-warning" | "beaker" | "bean" | "bean-off" | "bed" | "bed-double" | "bed-single" | "beef" | "beef-off" | "beer" | "beer-off" | "bell" | "bell-check" | "bell-dot" | "bell-electric" | "bell-minus" | "bell-off" | "bell-plus" | "bell-ring" | "between-horizonal-end" | "between-horizonal-start" | "between-horizontal-end" | "between-horizontal-start" | "between-vertical-end" | "between-vertical-start" | "biceps-flexed" | "bike" | "binary" | "binoculars" | "biohazard" | "bird" | "birdhouse" | "bitcoin" | "blend" | "blender" | "blinds" | "blocks" | "bluetooth" | "bluetooth-connected" | "bluetooth-off" | "bluetooth-searching" | "bold" | "bolt" | "bomb" | "bone" | "bone-fracture" | "book" | "book-a" | "book-alert" | "book-audio" | "book-check" | "book-copy" | "book-dashed" | "book-down" | "book-headphones" | "book-heart" | "book-image" | "book-key" | "book-lock" | "book-marked" | "book-minus" | "book-open" | "book-open-check" | "book-open-text" | "book-plus" | "book-search" | "book-template" | "book-text" | "book-type" | "book-up" | "book-up-2" | "book-user" | "book-x" | "bookmark" | "bookmark-check" | "bookmark-minus" | "bookmark-off" | "bookmark-plus" | "bookmark-x" | "boom-box" | "bot" | "bot-message-square" | "bot-off" | "bottle-wine" | "bow-arrow" | "box" | "box-select" | "boxes" | "braces" | "brackets" | "brain" | "brain-circuit" | "brain-cog" | "brick-wall" | "brick-wall-fire" | "brick-wall-shield" | "briefcase" | "briefcase-business" | "briefcase-conveyor-belt" | "briefcase-medical" | "bring-to-front" | "broccoli" | "brush" | "brush-cleaning" | "bubbles" | "bug" | "bug-off" | "bug-play" | "building" | "building-2" | "bus" | "bus-front" | "cable" | "cable-car" | "cake" | "cake-slice" | "calculator" | "calendar" | "calendar-1" | "calendar-arrow-down" | "calendar-arrow-up" | "calendar-check" | "calendar-check-2" | "calendar-clock" | "calendar-cog" | "calendar-days" | "calendar-fold" | "calendar-heart" | "calendar-minus" | "calendar-minus-2" | "calendar-off" | "calendar-plus" | "calendar-plus-2" | "calendar-range" | "calendar-search" | "calendar-sync" | "calendar-x" | "calendar-x-2" | "calendars" | "camera" | "camera-off" | "candlestick-chart" | "candy" | "candy-cane" | "candy-off" | "cannabis" | "cannabis-off" | "captions" | "captions-off" | "car" | "car-front" | "car-taxi-front" | "caravan" | "card-sim" | "carrot" | "case-lower" | "case-sensitive" | "case-upper" | "cassette-tape" | "cast" | "castle" | "cat" | "cctv" | "cctv-off" | "chart-area" | "chart-bar" | "chart-bar-big" | "chart-bar-decreasing" | "chart-bar-increasing" | "chart-bar-stacked" | "chart-candlestick" | "chart-column" | "chart-column-big" | "chart-column-decreasing" | "chart-column-increasing" | "chart-column-stacked" | "chart-gantt" | "chart-line" | "chart-network" | "chart-no-axes-column" | "chart-no-axes-column-decreasing" | "chart-no-axes-column-increasing" | "chart-no-axes-combined" | "chart-no-axes-gantt" | "chart-pie" | "chart-scatter" | "chart-spline" | "check" | "check-check" | "check-circle" | "check-circle-2" | "check-line" | "check-square" | "check-square-2" | "chef-hat" | "cherry" | "chess-bishop" | "chess-king" | "chess-knight" | "chess-pawn" | "chess-queen" | "chess-rook" | "chevron-down" | "chevron-down-circle" | "chevron-down-square" | "chevron-first" | "chevron-last" | "chevron-left" | "chevron-left-circle" | "chevron-left-square" | "chevron-right" | "chevron-right-circle" | "chevron-right-square" | "chevron-up" | "chevron-up-circle" | "chevron-up-square" | "chevrons-down" | "chevrons-down-up" | "chevrons-left" | "chevrons-left-right" | "chevrons-left-right-ellipsis" | "chevrons-right" | "chevrons-right-left" | "chevrons-up" | "chevrons-up-down" | "church" | "cigarette" | "cigarette-off" | "circle" | "circle-alert" | "circle-arrow-down" | "circle-arrow-left" | "circle-arrow-out-down-left" | "circle-arrow-out-down-right" | "circle-arrow-out-up-left" | "circle-arrow-out-up-right" | "circle-arrow-right" | "circle-arrow-up" | "circle-check" | "circle-check-big" | "circle-chevron-down" | "circle-chevron-left" | "circle-chevron-right" | "circle-chevron-up" | "circle-dashed" | "circle-divide" | "circle-dollar-sign" | "circle-dot" | "circle-dot-dashed" | "circle-ellipsis" | "circle-equal" | "circle-euro" | "circle-fading-arrow-up" | "circle-fading-plus" | "circle-gauge" | "circle-help" | "circle-minus" | "circle-off" | "circle-parking" | "circle-parking-off" | "circle-pause" | "circle-percent" | "circle-pile" | "circle-play" | "circle-plus" | "circle-pound-sterling" | "circle-power" | "circle-question-mark" | "circle-slash" | "circle-slash-2" | "circle-slashed" | "circle-small" | "circle-star" | "circle-stop" | "circle-user" | "circle-user-round" | "circle-x" | "circuit-board" | "citrus" | "clapperboard" | "clipboard" | "clipboard-check" | "clipboard-clock" | "clipboard-copy" | "clipboard-edit" | "clipboard-list" | "clipboard-minus" | "clipboard-paste" | "clipboard-pen" | "clipboard-pen-line" | "clipboard-plus" | "clipboard-signature" | "clipboard-type" | "clipboard-x" | "clock" | "clock-1" | "clock-10" | "clock-11" | "clock-12" | "clock-2" | "clock-3" | "clock-4" | "clock-5" | "clock-6" | "clock-7" | "clock-8" | "clock-9" | "clock-alert" | "clock-arrow-down" | "clock-arrow-left" | "clock-arrow-right" | "clock-arrow-up" | "clock-check" | "clock-fading" | "clock-plus" | "closed-caption" | "cloud" | "cloud-alert" | "cloud-backup" | "cloud-check" | "cloud-cog" | "cloud-download" | "cloud-drizzle" | "cloud-fog" | "cloud-hail" | "cloud-lightning" | "cloud-moon" | "cloud-moon-rain" | "cloud-off" | "cloud-rain" | "cloud-rain-wind" | "cloud-snow" | "cloud-sun" | "cloud-sun-rain" | "cloud-sync" | "cloud-upload" | "cloudy" | "clover" | "club" | "code" | "code-2" | "code-square" | "code-xml" | "coffee" | "cog" | "coins" | "columns" | "columns-2" | "columns-3" | "columns-3-cog" | "columns-4" | "columns-settings" | "combine" | "command" | "compass" | "component" | "computer" | "concierge-bell" | "cone" | "construction" | "contact" | "contact-2" | "contact-round" | "container" | "contrast" | "cookie" | "cooking-pot" | "copy" | "copy-check" | "copy-minus" | "copy-plus" | "copy-slash" | "copy-x" | "copyleft" | "copyright" | "corner-down-left" | "corner-down-right" | "corner-left-down" | "corner-left-up" | "corner-right-down" | "corner-right-up" | "corner-up-left" | "corner-up-right" | "cpu" | "creative-commons" | "credit-card" | "croissant" | "crop" | "cross" | "crosshair" | "crown" | "cuboid" | "cup-soda" | "curly-braces" | "currency" | "cylinder" | "dam" | "database" | "database-arrow-down" | "database-arrow-up" | "database-backup" | "database-check" | "database-minus" | "database-plus" | "database-search" | "database-x" | "database-zap" | "decimals-arrow-left" | "decimals-arrow-right" | "delete" | "dessert" | "diameter" | "diamond" | "diamond-minus" | "diamond-percent" | "diamond-plus" | "dice-1" | "dice-2" | "dice-3" | "dice-4" | "dice-5" | "dice-6" | "dices" | "diff" | "disc" | "disc-2" | "disc-3" | "disc-album" | "divide" | "divide-circle" | "divide-square" | "dna" | "dna-off" | "dock" | "dog" | "dollar-sign" | "donut" | "door-closed" | "door-closed-locked" | "door-open" | "dot" | "dot-square" | "download" | "download-cloud" | "drafting-compass" | "drama" | "drill" | "drone" | "droplet" | "droplet-off" | "droplets" | "drum" | "drumstick" | "dumbbell" | "ear" | "ear-off" | "earth" | "earth-lock" | "eclipse" | "edit" | "edit-2" | "edit-3" | "egg" | "egg-fried" | "egg-off" | "ellipse" | "ellipsis" | "ellipsis-vertical" | "equal" | "equal-approximately" | "equal-not" | "equal-square" | "eraser" | "ethernet-port" | "euro" | "ev-charger" | "expand" | "external-link" | "eye" | "eye-closed" | "eye-dashed" | "eye-off" | "factory" | "fan" | "fast-forward" | "feather" | "fence" | "ferris-wheel" | "file" | "file-archive" | "file-audio" | "file-audio-2" | "file-axis-3-d" | "file-axis-3d" | "file-badge" | "file-badge-2" | "file-bar-chart" | "file-bar-chart-2" | "file-box" | "file-braces" | "file-braces-corner" | "file-chart-column" | "file-chart-column-increasing" | "file-chart-line" | "file-chart-pie" | "file-check" | "file-check-2" | "file-check-corner" | "file-clock" | "file-code" | "file-code-2" | "file-code-corner" | "file-cog" | "file-cog-2" | "file-diff" | "file-digit" | "file-down" | "file-edit" | "file-exclamation-point" | "file-headphone" | "file-heart" | "file-image" | "file-input" | "file-json" | "file-json-2" | "file-key" | "file-key-2" | "file-line-chart" | "file-lock" | "file-lock-2" | "file-minus" | "file-minus-2" | "file-minus-corner" | "file-music" | "file-output" | "file-pen" | "file-pen-line" | "file-pie-chart" | "file-play" | "file-plus" | "file-plus-2" | "file-plus-corner" | "file-question" | "file-question-mark" | "file-scan" | "file-search" | "file-search-2" | "file-search-corner" | "file-signal" | "file-signature" | "file-sliders" | "file-spreadsheet" | "file-stack" | "file-symlink" | "file-terminal" | "file-text" | "file-type" | "file-type-2" | "file-type-corner" | "file-up" | "file-user" | "file-video" | "file-video-2" | "file-video-camera" | "file-volume" | "file-volume-2" | "file-warning" | "file-x" | "file-x-2" | "file-x-corner" | "files" | "film" | "filter" | "filter-x" | "fingerprint-pattern" | "fire-extinguisher" | "fish" | "fish-off" | "fish-symbol" | "fishing-hook" | "fishing-rod" | "flag" | "flag-off" | "flag-triangle-left" | "flag-triangle-right" | "flame" | "flame-kindling" | "flashlight" | "flashlight-off" | "flask-conical" | "flask-conical-off" | "flask-round" | "flip-horizontal" | "flip-horizontal-2" | "flip-vertical" | "flip-vertical-2" | "flower" | "flower-2" | "focus" | "fold-horizontal" | "fold-vertical" | "folder" | "folder-archive" | "folder-bookmark" | "folder-check" | "folder-clock" | "folder-closed" | "folder-code" | "folder-cog" | "folder-cog-2" | "folder-dot" | "folder-down" | "folder-edit" | "folder-git" | "folder-git-2" | "folder-heart" | "folder-input" | "folder-kanban" | "folder-key" | "folder-lock" | "folder-minus" | "folder-open" | "folder-open-dot" | "folder-output" | "folder-pen" | "folder-plus" | "folder-root" | "folder-search" | "folder-search-2" | "folder-symlink" | "folder-sync" | "folder-tree" | "folder-up" | "folder-x" | "folders" | "footprints" | "fork-knife" | "fork-knife-crossed" | "forklift" | "form" | "form-input" | "forward" | "frame" | "frown" | "fuel" | "fullscreen" | "function-square" | "funnel" | "funnel-plus" | "funnel-x" | "gallery-horizontal" | "gallery-horizontal-end" | "gallery-thumbnails" | "gallery-vertical" | "gallery-vertical-end" | "gamepad" | "gamepad-2" | "gamepad-directional" | "gantt-chart" | "gantt-chart-square" | "gauge" | "gauge-circle" | "gavel" | "gem" | "georgian-lari" | "ghost" | "gift" | "git-branch" | "git-branch-minus" | "git-branch-plus" | "git-commit" | "git-commit-horizontal" | "git-commit-vertical" | "git-compare" | "git-compare-arrows" | "git-fork" | "git-graph" | "git-merge" | "git-merge-conflict" | "git-pull-request" | "git-pull-request-arrow" | "git-pull-request-closed" | "git-pull-request-create" | "git-pull-request-create-arrow" | "git-pull-request-draft" | "glass-water" | "glasses" | "globe" | "globe-2" | "globe-check" | "globe-lock" | "globe-off" | "globe-x" | "goal" | "gpu" | "grab" | "graduation-cap" | "grape" | "grid" | "grid-2-x-2" | "grid-2-x-2-check" | "grid-2-x-2-plus" | "grid-2-x-2-x" | "grid-2x2" | "grid-2x2-check" | "grid-2x2-plus" | "grid-2x2-x" | "grid-3-x-3" | "grid-3x2" | "grid-3x3" | "grip" | "grip-horizontal" | "grip-vertical" | "group" | "guitar" | "ham" | "hamburger" | "hammer" | "hand" | "hand-coins" | "hand-fist" | "hand-grab" | "hand-heart" | "hand-helping" | "hand-metal" | "hand-platter" | "handbag" | "handshake" | "hard-drive" | "hard-drive-download" | "hard-drive-upload" | "hard-hat" | "hash" | "hat-glasses" | "haze" | "hd" | "hdmi-port" | "heading" | "heading-1" | "heading-2" | "heading-3" | "heading-4" | "heading-5" | "heading-6" | "headphone-off" | "headphones" | "headset" | "heart" | "heart-crack" | "heart-handshake" | "heart-minus" | "heart-off" | "heart-plus" | "heart-pulse" | "heart-x" | "heater" | "helicopter" | "help-circle" | "helping-hand" | "hexagon" | "highlighter" | "history" | "home" | "hop" | "hop-off" | "hospital" | "hotel" | "hourglass" | "house" | "house-heart" | "house-plug" | "house-plus" | "house-wifi" | "ice-cream" | "ice-cream-2" | "ice-cream-bowl" | "ice-cream-cone" | "id-card" | "id-card-lanyard" | "image" | "image-down" | "image-minus" | "image-off" | "image-play" | "image-plus" | "image-up" | "image-upscale" | "images" | "import" | "inbox" | "indent" | "indent-decrease" | "indent-increase" | "indian-rupee" | "infinity" | "info" | "inspect" | "inspection-panel" | "italic" | "iteration-ccw" | "iteration-cw" | "japanese-yen" | "joystick" | "kanban" | "kanban-square" | "kanban-square-dashed" | "kayak" | "key" | "key-round" | "key-square" | "keyboard" | "keyboard-music" | "keyboard-off" | "lamp" | "lamp-ceiling" | "lamp-desk" | "lamp-floor" | "lamp-wall-down" | "lamp-wall-up" | "land-plot" | "landmark" | "languages" | "laptop" | "laptop-2" | "laptop-minimal" | "laptop-minimal-check" | "lasso" | "lasso-select" | "laugh" | "layers" | "layers-2" | "layers-3" | "layers-minus" | "layers-plus" | "layout" | "layout-dashboard" | "layout-grid" | "layout-list" | "layout-panel-left" | "layout-panel-top" | "layout-template" | "leaf" | "leafy-green" | "lectern" | "lens-concave" | "lens-convex" | "letter-text" | "library" | "library-big" | "library-square" | "life-buoy" | "ligature" | "lightbulb" | "lightbulb-off" | "line-chart" | "line-dot-right-horizontal" | "line-squiggle" | "line-style" | "link" | "link-2" | "link-2-off" | "list" | "list-check" | "list-checks" | "list-chevrons-down-up" | "list-chevrons-up-down" | "list-collapse" | "list-end" | "list-filter" | "list-filter-plus" | "list-indent-decrease" | "list-indent-increase" | "list-minus" | "list-music" | "list-ordered" | "list-plus" | "list-restart" | "list-sort-ascending" | "list-sort-descending" | "list-start" | "list-todo" | "list-tree" | "list-video" | "list-x" | "loader" | "loader-2" | "loader-circle" | "loader-pinwheel" | "locate" | "locate-fixed" | "locate-off" | "location-edit" | "lock" | "lock-keyhole" | "lock-keyhole-open" | "lock-open" | "log-in" | "log-out" | "logs" | "lollipop" | "luggage" | "m-square" | "magnet" | "mail" | "mail-check" | "mail-minus" | "mail-open" | "mail-plus" | "mail-question" | "mail-question-mark" | "mail-search" | "mail-warning" | "mail-x" | "mailbox" | "mails" | "map" | "map-minus" | "map-pin" | "map-pin-check" | "map-pin-check-inside" | "map-pin-house" | "map-pin-minus" | "map-pin-minus-inside" | "map-pin-off" | "map-pin-pen" | "map-pin-plus" | "map-pin-plus-inside" | "map-pin-search" | "map-pin-x" | "map-pin-x-inside" | "map-pinned" | "map-plus" | "mars" | "mars-stroke" | "martini" | "maximize" | "maximize-2" | "medal" | "megaphone" | "megaphone-off" | "meh" | "memory-stick" | "menu" | "menu-square" | "merge" | "message-circle" | "message-circle-check" | "message-circle-code" | "message-circle-dashed" | "message-circle-heart" | "message-circle-more" | "message-circle-off" | "message-circle-plus" | "message-circle-question" | "message-circle-question-mark" | "message-circle-reply" | "message-circle-warning" | "message-circle-x" | "message-square" | "message-square-check" | "message-square-code" | "message-square-dashed" | "message-square-diff" | "message-square-dot" | "message-square-heart" | "message-square-lock" | "message-square-more" | "message-square-off" | "message-square-plus" | "message-square-quote" | "message-square-reply" | "message-square-share" | "message-square-text" | "message-square-warning" | "message-square-x" | "messages-square" | "metronome" | "mic" | "mic-2" | "mic-off" | "mic-vocal" | "microchip" | "microscope" | "microwave" | "milestone" | "milk" | "milk-off" | "minimize" | "minimize-2" | "minus" | "minus-circle" | "minus-square" | "mirror-rectangular" | "mirror-round" | "monitor" | "monitor-check" | "monitor-cloud" | "monitor-cog" | "monitor-dot" | "monitor-down" | "monitor-off" | "monitor-pause" | "monitor-play" | "monitor-smartphone" | "monitor-speaker" | "monitor-stop" | "monitor-up" | "monitor-x" | "moon" | "moon-star" | "more-horizontal" | "more-vertical" | "motorbike" | "mountain" | "mountain-snow" | "mouse" | "mouse-left" | "mouse-off" | "mouse-pointer" | "mouse-pointer-2" | "mouse-pointer-2-off" | "mouse-pointer-ban" | "mouse-pointer-click" | "mouse-pointer-square-dashed" | "mouse-right" | "move" | "move-3-d" | "move-3d" | "move-diagonal" | "move-diagonal-2" | "move-down" | "move-down-left" | "move-down-right" | "move-horizontal" | "move-left" | "move-right" | "move-up" | "move-up-left" | "move-up-right" | "move-vertical" | "music" | "music-2" | "music-3" | "music-4" | "navigation" | "navigation-2" | "navigation-2-off" | "navigation-off" | "network" | "newspaper" | "nfc" | "non-binary" | "notebook" | "notebook-pen" | "notebook-tabs" | "notebook-text" | "notepad-text" | "notepad-text-dashed" | "nut" | "nut-off" | "octagon" | "octagon-alert" | "octagon-minus" | "octagon-pause" | "octagon-x" | "omega" | "option" | "orbit" | "origami" | "outdent" | "package" | "package-2" | "package-check" | "package-minus" | "package-open" | "package-plus" | "package-search" | "package-x" | "paint-bucket" | "paint-roller" | "paintbrush" | "paintbrush-2" | "paintbrush-vertical" | "palette" | "palmtree" | "panda" | "panel-bottom" | "panel-bottom-close" | "panel-bottom-dashed" | "panel-bottom-inactive" | "panel-bottom-open" | "panel-left" | "panel-left-close" | "panel-left-dashed" | "panel-left-inactive" | "panel-left-open" | "panel-left-right-dashed" | "panel-right" | "panel-right-close" | "panel-right-dashed" | "panel-right-inactive" | "panel-right-open" | "panel-top" | "panel-top-bottom-dashed" | "panel-top-close" | "panel-top-dashed" | "panel-top-inactive" | "panel-top-open" | "panels-left-bottom" | "panels-left-right" | "panels-right-bottom" | "panels-top-bottom" | "panels-top-left" | "paper-bag" | "paperclip" | "parasol" | "parentheses" | "parking-circle" | "parking-circle-off" | "parking-meter" | "parking-square" | "parking-square-off" | "party-popper" | "pause" | "pause-circle" | "pause-octagon" | "paw-print" | "pc-case" | "pen" | "pen-box" | "pen-line" | "pen-off" | "pen-square" | "pen-tool" | "pencil" | "pencil-line" | "pencil-off" | "pencil-ruler" | "pencil-sparkles" | "pentagon" | "percent" | "percent-circle" | "percent-diamond" | "percent-square" | "person-standing" | "phi" | "philippine-peso" | "phone" | "phone-call" | "phone-forwarded" | "phone-incoming" | "phone-missed" | "phone-off" | "phone-outgoing" | "pi" | "pi-square" | "piano" | "pickaxe" | "picture-in-picture" | "picture-in-picture-2" | "pie-chart" | "piggy-bank" | "pilcrow" | "pilcrow-left" | "pilcrow-right" | "pilcrow-square" | "pill" | "pill-bottle" | "pin" | "pin-off" | "pipette" | "pizza" | "plane" | "plane-landing" | "plane-takeoff" | "play" | "play-circle" | "play-off" | "play-square" | "plug" | "plug-2" | "plug-zap" | "plug-zap-2" | "plus" | "plus-circle" | "plus-square" | "pocket-knife" | "podcast" | "podium" | "pointer" | "pointer-off" | "popcorn" | "popsicle" | "pound-sterling" | "power" | "power-circle" | "power-off" | "power-square" | "presentation" | "printer" | "printer-check" | "printer-x" | "projector" | "proportions" | "puzzle" | "pyramid" | "qr-code" | "quote" | "rabbit" | "radar" | "radiation" | "radical" | "radio" | "radio-off" | "radio-receiver" | "radio-tower" | "radius" | "rainbow" | "rat" | "ratio" | "receipt" | "receipt-cent" | "receipt-euro" | "receipt-indian-rupee" | "receipt-japanese-yen" | "receipt-pound-sterling" | "receipt-russian-ruble" | "receipt-swiss-franc" | "receipt-text" | "receipt-turkish-lira" | "rectangle-circle" | "rectangle-ellipsis" | "rectangle-goggles" | "rectangle-horizontal" | "rectangle-vertical" | "recycle" | "redo" | "redo-2" | "redo-dot" | "refresh-ccw" | "refresh-ccw-dot" | "refresh-cw" | "refresh-cw-off" | "refrigerator" | "regex" | "remove-formatting" | "repeat" | "repeat-1" | "repeat-2" | "repeat-off" | "replace" | "replace-all" | "reply" | "reply-all" | "rewind" | "ribbon" | "road" | "rocket" | "rocking-chair" | "roller-coaster" | "rose" | "rotate-3-d" | "rotate-3d" | "rotate-ccw" | "rotate-ccw-key" | "rotate-ccw-square" | "rotate-cw" | "rotate-cw-square" | "route" | "route-off" | "router" | "rows" | "rows-2" | "rows-3" | "rows-4" | "rss" | "ruler" | "ruler-dimension-line" | "russian-ruble" | "sailboat" | "salad" | "sandwich" | "satellite" | "satellite-dish" | "saudi-riyal" | "save" | "save-all" | "save-check" | "save-off" | "save-pen" | "save-plus" | "scale" | "scale-3-d" | "scale-3d" | "scaling" | "scan" | "scan-barcode" | "scan-box" | "scan-eye" | "scan-face" | "scan-heart" | "scan-line" | "scan-qr-code" | "scan-search" | "scan-text" | "scatter-chart" | "school" | "school-2" | "scissors" | "scissors-line-dashed" | "scissors-square" | "scissors-square-dashed-bottom" | "scooter" | "screen-share" | "screen-share-off" | "scroll" | "scroll-text" | "search" | "search-alert" | "search-check" | "search-code" | "search-slash" | "search-x" | "section" | "send" | "send-horizonal" | "send-horizontal" | "send-to-back" | "separator-horizontal" | "separator-vertical" | "server" | "server-cog" | "server-crash" | "server-off" | "server-plus" | "settings" | "settings-2" | "shapes" | "share" | "share-2" | "sheet" | "shell" | "shelving-unit" | "shield" | "shield-alert" | "shield-ban" | "shield-check" | "shield-close" | "shield-cog" | "shield-cog-corner" | "shield-ellipsis" | "shield-half" | "shield-keyhole" | "shield-minus" | "shield-off" | "shield-plus" | "shield-question" | "shield-question-mark" | "shield-user" | "shield-x" | "ship" | "ship-wheel" | "shirt" | "shopping-bag" | "shopping-basket" | "shopping-cart" | "shovel" | "shower-head" | "shredder" | "shrimp" | "shrink" | "shrub" | "shuffle" | "sidebar" | "sidebar-close" | "sidebar-open" | "sigma" | "sigma-square" | "signal" | "signal-high" | "signal-low" | "signal-medium" | "signal-zero" | "signature" | "signpost" | "signpost-big" | "siren" | "skip-back" | "skip-forward" | "skull" | "slash" | "slash-square" | "slice" | "sliders" | "sliders-horizontal" | "sliders-vertical" | "smartphone" | "smartphone-charging" | "smartphone-nfc" | "smile" | "smile-plus" | "snail" | "snowflake" | "soap-dispenser-droplet" | "sofa" | "solar-panel" | "sort-asc" | "sort-desc" | "soup" | "space" | "spade" | "sparkle" | "sparkles" | "speaker" | "speech" | "spell-check" | "spell-check-2" | "spline" | "spline-pointer" | "split" | "split-square-horizontal" | "split-square-vertical" | "spool" | "sport-shoe" | "spotlight" | "spray-can" | "sprout" | "square" | "square-activity" | "square-arrow-down" | "square-arrow-down-left" | "square-arrow-down-right" | "square-arrow-left" | "square-arrow-out-down-left" | "square-arrow-out-down-right" | "square-arrow-out-up-left" | "square-arrow-out-up-right" | "square-arrow-right" | "square-arrow-right-enter" | "square-arrow-right-exit" | "square-arrow-up" | "square-arrow-up-left" | "square-arrow-up-right" | "square-asterisk" | "square-bottom-dashed-scissors" | "square-centerline-dashed-horizontal" | "square-centerline-dashed-vertical" | "square-chart-gantt" | "square-check" | "square-check-big" | "square-chevron-down" | "square-chevron-left" | "square-chevron-right" | "square-chevron-up" | "square-code" | "square-dashed" | "square-dashed-bottom" | "square-dashed-bottom-code" | "square-dashed-kanban" | "square-dashed-mouse-pointer" | "square-dashed-text" | "square-dashed-top-solid" | "square-divide" | "square-dot" | "square-equal" | "square-function" | "square-gantt-chart" | "square-kanban" | "square-library" | "square-m" | "square-menu" | "square-minus" | "square-mouse-pointer" | "square-parking" | "square-parking-off" | "square-pause" | "square-pen" | "square-percent" | "square-pi" | "square-pilcrow" | "square-play" | "square-plus" | "square-power" | "square-radical" | "square-round-corner" | "square-scissors" | "square-sigma" | "square-slash" | "square-split-horizontal" | "square-split-vertical" | "square-square" | "square-stack" | "square-star" | "square-stop" | "square-terminal" | "square-user" | "square-user-round" | "square-x" | "squares-exclude" | "squares-intersect" | "squares-subtract" | "squares-unite" | "squircle" | "squircle-dashed" | "squirrel" | "stamp" | "star" | "star-check" | "star-half" | "star-minus" | "star-off" | "star-plus" | "star-x" | "stars" | "step-back" | "step-forward" | "stethoscope" | "sticker" | "sticky-note" | "sticky-note-check" | "sticky-note-minus" | "sticky-note-off" | "sticky-note-plus" | "sticky-note-x" | "sticky-notes" | "stone" | "stop-circle" | "store" | "stretch-horizontal" | "stretch-vertical" | "strikethrough" | "subscript" | "subtitles" | "summary" | "sun" | "sun-dim" | "sun-medium" | "sun-moon" | "sun-snow" | "sunrise" | "sunset" | "superscript" | "swatch-book" | "swiss-franc" | "switch-camera" | "sword" | "swords" | "syringe" | "table" | "table-2" | "table-cells-merge" | "table-cells-split" | "table-columns-split" | "table-config" | "table-of-contents" | "table-properties" | "table-rows-split" | "tablet" | "tablet-smartphone" | "tablets" | "tag" | "tag-plus" | "tag-x" | "tags" | "tally-1" | "tally-2" | "tally-3" | "tally-4" | "tally-5" | "tangent" | "target" | "telescope" | "tent" | "tent-tree" | "terminal" | "terminal-square" | "test-tube" | "test-tube-2" | "test-tube-diagonal" | "test-tubes" | "text" | "text-align-center" | "text-align-end" | "text-align-justify" | "text-align-start" | "text-cursor" | "text-cursor-input" | "text-initial" | "text-quote" | "text-search" | "text-select" | "text-selection" | "text-wrap" | "theater" | "thermometer" | "thermometer-snowflake" | "thermometer-sun" | "thumbs-down" | "thumbs-up" | "ticket" | "ticket-check" | "ticket-minus" | "ticket-percent" | "ticket-plus" | "ticket-slash" | "ticket-x" | "tickets" | "tickets-plane" | "timeline" | "timer" | "timer-off" | "timer-reset" | "toggle-left" | "toggle-right" | "toilet" | "tool-case" | "toolbox" | "tornado" | "torus" | "touchpad" | "touchpad-off" | "towel-rack" | "tower-control" | "toy-brick" | "tractor" | "traffic-cone" | "train" | "train-front" | "train-front-tunnel" | "train-track" | "tram-front" | "transgender" | "trash" | "trash-2" | "tree-deciduous" | "tree-palm" | "tree-pine" | "trees" | "trending-down" | "trending-up" | "trending-up-down" | "triangle" | "triangle-alert" | "triangle-dashed" | "triangle-right" | "trophy" | "truck" | "truck-electric" | "turkish-lira" | "turntable" | "turtle" | "tv" | "tv-2" | "tv-minimal" | "tv-minimal-play" | "type" | "type-outline" | "umbrella" | "umbrella-off" | "underline" | "undo" | "undo-2" | "undo-dot" | "unfold-horizontal" | "unfold-vertical" | "ungroup" | "university" | "unlink" | "unlink-2" | "unlock" | "unlock-keyhole" | "unplug" | "upload" | "upload-cloud" | "usb" | "user" | "user-2" | "user-check" | "user-check-2" | "user-circle" | "user-circle-2" | "user-cog" | "user-cog-2" | "user-key" | "user-lock" | "user-minus" | "user-minus-2" | "user-pen" | "user-plus" | "user-plus-2" | "user-round" | "user-round-arrow-left" | "user-round-check" | "user-round-cog" | "user-round-key" | "user-round-minus" | "user-round-pen" | "user-round-plus" | "user-round-search" | "user-round-x" | "user-search" | "user-square" | "user-square-2" | "user-star" | "user-x" | "user-x-2" | "users" | "users-2" | "users-round" | "utensils" | "utensils-crossed" | "utility-pole" | "van" | "variable" | "vault" | "vector-square" | "vegan" | "venetian-mask" | "venus" | "venus-and-mars" | "verified" | "vibrate" | "vibrate-off" | "video" | "video-off" | "videotape" | "view" | "voicemail" | "volleyball" | "volume" | "volume-1" | "volume-2" | "volume-off" | "volume-x" | "vote" | "wallet" | "wallet-2" | "wallet-cards" | "wallet-minimal" | "wallpaper" | "wand" | "wand-2" | "wand-sparkles" | "warehouse" | "washing-machine" | "watch" | "waves" | "waves-arrow-down" | "waves-arrow-up" | "waves-horizontal" | "waves-ladder" | "waves-vertical" | "waypoints" | "webcam" | "webcam-off" | "webhook" | "webhook-off" | "weight" | "weight-tilde" | "wheat" | "wheat-off" | "whole-word" | "wifi" | "wifi-cog" | "wifi-high" | "wifi-low" | "wifi-off" | "wifi-pen" | "wifi-sync" | "wifi-zero" | "wind" | "wind-arrow-down" | "wine" | "wine-off" | "workflow" | "worm" | "wrap-text" | "wrench" | "wrench-off" | "x" | "x-circle" | "x-line-top" | "x-octagon" | "x-square" | "zap" | "zap-off" | "zodiac-aquarius" | "zodiac-aries" | "zodiac-cancer" | "zodiac-capricorn" | "zodiac-gemini" | "zodiac-leo" | "zodiac-libra" | "zodiac-ophiuchus" | "zodiac-pisces" | "zodiac-sagittarius" | "zodiac-scorpio" | "zodiac-taurus" | "zodiac-virgo" | "zoom-in" | "zoom-out";
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Every addressable icon slug — canonical names plus deprecated aliases,
|
|
62
|
+
* 1997 in total, sorted.
|
|
63
|
+
*
|
|
64
|
+
* Importing this pulls in the whole list (~6 KB brotli). Reach for it when you
|
|
65
|
+
* are building a picker; `<Icon>` itself does not need it.
|
|
66
|
+
*/
|
|
67
|
+
export declare const iconNames: readonly IconName[];
|
|
68
|
+
|
|
69
|
+
export declare interface IconProps extends Omit<SVGProps<SVGSVGElement>, "ref"> {
|
|
70
|
+
/**
|
|
71
|
+
* The lucide slug, kebab-case: `"save"`, `"trash-2"`, `"circle-alert"`.
|
|
72
|
+
*
|
|
73
|
+
* Typed as the union of every slug lucide ships, so a typo is a compile
|
|
74
|
+
* error — while still accepting a plain `string` for the case this component
|
|
75
|
+
* exists for: a name that arrives from an API, a CMS or a config table.
|
|
76
|
+
*/
|
|
77
|
+
name: IconName | (string & {});
|
|
78
|
+
/** Width and height in px. Defaults to the provider's value, then lucide's `24`. */
|
|
79
|
+
size?: number | string;
|
|
80
|
+
/** Stroke width. Defaults to the provider's value, then lucide's `2`. */
|
|
81
|
+
strokeWidth?: number;
|
|
82
|
+
/**
|
|
83
|
+
* Rendered while the icon's shard is in flight, and for a slug that does not
|
|
84
|
+
* exist at all. Defaults to nothing.
|
|
85
|
+
*
|
|
86
|
+
* Pass a same-sized placeholder when the surrounding layout would otherwise
|
|
87
|
+
* shift. Note that a slug already in the registry or the cache never renders
|
|
88
|
+
* this — it resolves during render.
|
|
89
|
+
*/
|
|
90
|
+
fallback?: ReactNode;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Provide a static icon registry and shared `<Icon>` defaults to a subtree.
|
|
95
|
+
*
|
|
96
|
+
* Entirely optional: without it `<Icon>` still resolves any of lucide's ~2000
|
|
97
|
+
* slugs by fetching the shard that owns it. What the provider buys is the
|
|
98
|
+
* zero-request path for the slugs an app actually uses, plus one place to set
|
|
99
|
+
* `size`/`strokeWidth` instead of repeating them at every call site.
|
|
100
|
+
*
|
|
101
|
+
* @example
|
|
102
|
+
* import { IconProvider } from "tempest-react-sdk/icons";
|
|
103
|
+
* import { staticIcons } from "virtual:tempest-icons";
|
|
104
|
+
*
|
|
105
|
+
* <IconProvider registry={staticIcons} size={18}>
|
|
106
|
+
* <App />
|
|
107
|
+
* </IconProvider>
|
|
108
|
+
*/
|
|
109
|
+
export declare function IconProvider({ registry, size, strokeWidth, children, }: IconProviderProps): ReactNode;
|
|
110
|
+
|
|
111
|
+
export declare interface IconProviderProps {
|
|
112
|
+
/**
|
|
113
|
+
* Icons resolved with zero extra requests.
|
|
114
|
+
*
|
|
115
|
+
* Pass `staticIcons` from the `virtual:tempest-icons` module the
|
|
116
|
+
* `tempestIcons()` Vite plugin generates, or a table built by
|
|
117
|
+
* `createIconRegistry`. Slugs found here never trigger a shard fetch.
|
|
118
|
+
*/
|
|
119
|
+
registry?: IconRegistry;
|
|
120
|
+
/** Default `size` for every `<Icon>` below. Lucide's own default is `24`. */
|
|
121
|
+
size?: number | string;
|
|
122
|
+
/** Default `strokeWidth` for every `<Icon>` below. Lucide's own default is `2`. */
|
|
123
|
+
strokeWidth?: number;
|
|
124
|
+
children: ReactNode;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/** A slug → icon-component table, as produced by `createIconRegistry`. */
|
|
128
|
+
export declare type IconRegistry = Readonly<Record<string, LucideIcon>>;
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* Whether a slug is ready, still loading, or not an icon at all.
|
|
132
|
+
*
|
|
133
|
+
* `"missing"` is only reported once that is actually knowable: either lucide has
|
|
134
|
+
* no icons under that initial letter, or the letter's shard already settled
|
|
135
|
+
* without the slug in it.
|
|
136
|
+
*
|
|
137
|
+
* @param slug - Any icon slug, canonical or deprecated.
|
|
138
|
+
* @returns The slug's resolution state.
|
|
139
|
+
*/
|
|
140
|
+
export declare function iconStatus(slug: string): "ready" | "loading" | "missing";
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* Narrow an arbitrary string to a known icon slug.
|
|
144
|
+
*
|
|
145
|
+
* Use it at the edge where untrusted names arrive — an API response, a CMS field,
|
|
146
|
+
* a URL parameter — so the rest of the code works with `IconName` and a bad value
|
|
147
|
+
* is handled once, where you can decide what to show instead.
|
|
148
|
+
*
|
|
149
|
+
* Note that this imports the full slug list (~6 KB brotli). `<Icon>` alone does
|
|
150
|
+
* not, so only reach for this when you genuinely need to validate.
|
|
151
|
+
*
|
|
152
|
+
* @example
|
|
153
|
+
* const slug = isIconName(row.icon) ? row.icon : "circle-help";
|
|
154
|
+
*
|
|
155
|
+
* @param value - Any string.
|
|
156
|
+
* @returns `true` when `value` is a slug lucide ships, alias included.
|
|
157
|
+
*/
|
|
158
|
+
export declare function isIconName(value: string): value is IconName;
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
* Load the shard that owns `slug`, if it is not loaded or loading already.
|
|
162
|
+
*
|
|
163
|
+
* Resolves without error for an unknown slug: a name that came from an API is
|
|
164
|
+
* data, not a programming mistake, so the caller renders its fallback instead of
|
|
165
|
+
* seeing an exception thrown mid-render.
|
|
166
|
+
*
|
|
167
|
+
* @param slug - Any icon slug, canonical or deprecated.
|
|
168
|
+
* @returns A promise that settles once the shard is in the cache.
|
|
169
|
+
*/
|
|
170
|
+
export declare function loadIcon(slug: string): Promise<void>;
|
|
171
|
+
|
|
172
|
+
/**
|
|
173
|
+
* Read an icon out of the cache without triggering a fetch.
|
|
174
|
+
*
|
|
175
|
+
* @param slug - Any icon slug, canonical or deprecated.
|
|
176
|
+
* @returns The icon component, or `undefined` when its shard is not loaded yet.
|
|
177
|
+
*/
|
|
178
|
+
export declare function peekIcon(slug: string): LucideIcon | undefined;
|
|
179
|
+
|
|
180
|
+
/**
|
|
181
|
+
* Warm the cache for slugs you know you are about to render.
|
|
182
|
+
*
|
|
183
|
+
* Useful right before opening a menu or a picker: the shards land while the user
|
|
184
|
+
* is still reaching for it, so nothing flashes a fallback.
|
|
185
|
+
*
|
|
186
|
+
* @param slugs - Icon slugs to preload.
|
|
187
|
+
* @returns A promise that settles when every needed shard is in the cache.
|
|
188
|
+
*/
|
|
189
|
+
export declare function preloadIcons(slugs: readonly string[]): Promise<void>;
|
|
190
|
+
|
|
191
|
+
/**
|
|
192
|
+
* Map a slug to the canonical slug that owns the icon.
|
|
193
|
+
*
|
|
194
|
+
* Lucide keeps 248 deprecated aliases (`alert-circle` → `circle-alert`), and a
|
|
195
|
+
* slug persisted in a database years ago is exactly the case this feature exists
|
|
196
|
+
* for, so an alias must keep resolving after a lucide bump renames it.
|
|
197
|
+
*
|
|
198
|
+
* @param slug - Any icon slug, canonical or deprecated.
|
|
199
|
+
* @returns The canonical slug.
|
|
200
|
+
*/
|
|
201
|
+
export declare function resolveIconAlias(slug: string): string;
|
|
202
|
+
|
|
203
|
+
/**
|
|
204
|
+
* Resolve an icon slug to its component.
|
|
205
|
+
*
|
|
206
|
+
* Resolution is synchronous whenever it can be: the provider registry first, then
|
|
207
|
+
* the shard cache. Both are plain reads during render, so a slug the app declared
|
|
208
|
+
* statically — or one whose shard a sibling icon already pulled in — is returned
|
|
209
|
+
* on the first frame with no intermediate empty state.
|
|
210
|
+
*
|
|
211
|
+
* Only a genuinely cold slug falls through to the effect, which fetches the shard
|
|
212
|
+
* for that initial letter and re-renders once it lands.
|
|
213
|
+
*
|
|
214
|
+
* @param slug - Any icon slug, canonical or deprecated. `undefined` skips work.
|
|
215
|
+
* @returns The icon component, or `undefined` while it is loading or if the slug
|
|
216
|
+
* does not exist.
|
|
217
|
+
*/
|
|
218
|
+
export declare function useIcon(slug: string | undefined): LucideIcon | undefined;
|
|
219
|
+
|
|
220
|
+
export { }
|
package/dist/icons.js
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { iconAliases as e } from "./icons/generated/aliases.js";
|
|
2
|
+
import { iconNames as t } from "./icons/generated/icon-names.js";
|
|
3
|
+
import { createIconRegistry as n } from "./icons/icon-context.js";
|
|
4
|
+
import { iconStatus as r, loadIcon as i, peekIcon as a, preloadIcons as o, resolveIconAlias as s } from "./icons/shard-cache.js";
|
|
5
|
+
import { useIcon as c } from "./icons/use-icon.js";
|
|
6
|
+
import { Icon as l } from "./icons/Icon.js";
|
|
7
|
+
import { IconProvider as u } from "./icons/IconProvider.js";
|
|
8
|
+
import { isIconName as d } from "./icons/is-icon-name.js";
|
|
9
|
+
export { l as Icon, u as IconProvider, n as createIconRegistry, e as iconAliases, t as iconNames, r as iconStatus, d as isIconName, i as loadIcon, a as peekIcon, o as preloadIcons, s as resolveIconAlias, c as useIcon };
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
let e=require("react");function t(t,n={}){let{flushOnMount:r=!1,flushOnOnline:i=!0,intervalMs:a=0}=n,o=(0,e.useSyncExternalStore)(t.subscribe,t.getState,t.getState),s=(0,e.useRef)(t.flush);return
|
|
1
|
+
let e=require("react");function t(t,n={}){let{flushOnMount:r=!1,flushOnOnline:i=!0,intervalMs:a=0}=n,o=(0,e.useSyncExternalStore)(t.subscribe,t.getState,t.getState),s=(0,e.useRef)(t.flush);return(0,e.useEffect)(()=>{s.current=t.flush},[t.flush]),(0,e.useEffect)(()=>{r&&s.current(`boot`)},[r]),(0,e.useEffect)(()=>{if(!i||typeof window>`u`)return;let e=()=>{s.current(`online-event`)};return window.addEventListener(`online`,e),()=>window.removeEventListener(`online`,e)},[i]),(0,e.useEffect)(()=>{if(a<=0||typeof window>`u`)return;let e=window.setInterval(()=>{s.current(`interval`)},a);return()=>window.clearInterval(e)},[a]),{...o,syncing:o.phase===`syncing`,enqueue:t.enqueue,flush:t.flush}}function n(e){return e.phase===`syncing`?`syncing`:e.phase===`offline`?`offline`:e.phase===`error`?`error`:e.pending>0?`pending`:`idle`}function r(t){let r=(0,e.useSyncExternalStore)(t.subscribe,t.getState,t.getState);return{tone:n(r),pending:r.pending,syncing:r.phase===`syncing`,offline:r.phase===`offline`,lastError:r.lastError}}exports.useOfflineSync=t,exports.useSyncStatus=r;
|
|
2
2
|
//# sourceMappingURL=use-offline-sync.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"use-offline-sync.cjs","names":[],"sources":["../../src/offline/use-offline-sync.ts"],"sourcesContent":["import { useEffect, useRef, useSyncExternalStore } from \"react\";\nimport type {\n OfflineSync,\n OutboxOp,\n SyncRunSummary,\n SyncState,\n SyncTrigger,\n} from \"./create-offline-sync\";\n\n/**\n * Options for {@link useOfflineSync}. All auto-flush triggers are opt-in except\n * `flushOnOnline`, which defaults to `true` so the app catches up the moment\n * connectivity returns.\n */\nexport interface UseOfflineSyncOptions {\n /** Flush once when the component mounts (trigger `\"boot\"`). Default `false`. */\n flushOnMount?: boolean;\n /**\n * Flush when the browser fires the `online` event (trigger\n * `\"online-event\"`). Default `true`.\n */\n flushOnOnline?: boolean;\n /**\n * Flush on this interval in milliseconds (trigger `\"interval\"`). `0`\n * disables the timer. Default `0`.\n */\n intervalMs?: number;\n}\n\n/**\n * Reactive view of an {@link OfflineSync} engine, plus its imperative actions.\n * Extends {@link SyncState} so `phase`, `pending`, `lastSummary`, `lastError`\n * and `lastSyncedAt` are read directly off the result.\n *\n * @typeParam TPayload - Record snapshot carried by outbox entries.\n */\nexport interface UseOfflineSyncResult<TPayload> extends SyncState {\n /** `true` while a flush run is in progress (`phase === \"syncing\"`). */\n syncing: boolean;\n /** Queue a mutation. Mirrors {@link OfflineSync.enqueue}. */\n enqueue: (op: OutboxOp, recordId: string, payload?: TPayload) => Promise<string>;\n /** Trigger a flush run. Mirrors {@link OfflineSync.flush}. */\n flush: (trigger?: SyncTrigger) => Promise<SyncRunSummary>;\n}\n\n/**\n * Subscribe a React component to an {@link OfflineSync} engine.\n *\n * Re-renders whenever the engine's {@link SyncState} changes (enqueue, flush\n * transition, outbox clear) via `useSyncExternalStore`, and optionally wires\n * auto-flush on mount, on the `online` event and on an interval. The engine\n * itself is created once by the app and passed in — the hook never owns it, so\n * multiple components can observe the same queue.\n *\n * @typeParam TPayload - Record snapshot carried by outbox entries.\n * @param sync - The engine returned by `createOfflineSync`.\n * @param options - Auto-flush triggers.\n * @returns The reactive state merged with `enqueue`/`flush` actions.\n *\n * @example\n * const { pending, syncing, phase, flush } = useOfflineSync(notesSync, {\n * flushOnMount: true,\n * intervalMs: 30_000,\n * });\n * return <SyncStatusBadge pending={pending} syncing={syncing} phase={phase} />;\n */\nexport function useOfflineSync<TPayload>(\n sync: OfflineSync<TPayload>,\n options: UseOfflineSyncOptions = {},\n): UseOfflineSyncResult<TPayload> {\n const { flushOnMount = false, flushOnOnline = true, intervalMs = 0 } = options;\n\n const state = useSyncExternalStore(sync.subscribe, sync.getState, sync.getState);\n\n const flushRef = useRef(sync.flush);\n flushRef.current = sync.flush;\n\n useEffect(() => {\n if (flushOnMount) void flushRef.current(\"boot\");\n }, [flushOnMount]);\n\n useEffect(() => {\n if (!flushOnOnline || typeof window === \"undefined\") return;\n const handleOnline = (): void => {\n void flushRef.current(\"online-event\");\n };\n window.addEventListener(\"online\", handleOnline);\n return () => window.removeEventListener(\"online\", handleOnline);\n }, [flushOnOnline]);\n\n useEffect(() => {\n if (intervalMs <= 0 || typeof window === \"undefined\") return;\n const id = window.setInterval(() => {\n void flushRef.current(\"interval\");\n }, intervalMs);\n return () => window.clearInterval(id);\n }, [intervalMs]);\n\n return {\n ...state,\n syncing: state.phase === \"syncing\",\n enqueue: sync.enqueue,\n flush: sync.flush,\n };\n}\n\n/**\n * Presentation-ready tone for a sync status indicator. Collapses the engine's\n * {@link SyncState} into the single most relevant signal for a badge/pill.\n */\nexport type SyncTone = \"idle\" | \"syncing\" | \"pending\" | \"offline\" | \"error\";\n\n/**\n * Compact status snapshot for a status badge/pill. Prefer this over\n * {@link useOfflineSync} when a component only needs to *display* status and\n * does not trigger flushes itself.\n */\nexport interface SyncStatus {\n /** The dominant tone to render. */\n tone: SyncTone;\n /** Number of mutations still queued. */\n pending: number;\n /** `true` while a flush run is in progress. */\n syncing: boolean;\n /** `true` when the last run was skipped for being offline. */\n offline: boolean;\n /** Message of the most recent delivery failure, or `null`. */\n lastError: string | null;\n}\n\n/**\n * Derive the dominant {@link SyncTone} from an engine snapshot.\n *\n * Precedence: syncing → offline → error → pending → idle. `syncing` wins so an\n * in-flight run always reads as active even while entries remain queued.\n *\n * @param state - The engine {@link SyncState}.\n * @returns The tone to render.\n */\nfunction toneFromState(state: SyncState): SyncTone {\n if (state.phase === \"syncing\") return \"syncing\";\n if (state.phase === \"offline\") return \"offline\";\n if (state.phase === \"error\") return \"error\";\n if (state.pending > 0) return \"pending\";\n return \"idle\";\n}\n\n/**\n * Subscribe to an {@link OfflineSync} engine and return a display-only\n * {@link SyncStatus}. A thin read-only companion to {@link useOfflineSync},\n * intended to feed a `<SyncStatusBadge>` without exposing flush actions.\n *\n * @typeParam TPayload - Record snapshot carried by outbox entries.\n * @param sync - The engine returned by `createOfflineSync`.\n * @returns The compact status snapshot.\n */\nexport function useSyncStatus<TPayload>(sync: OfflineSync<TPayload>): SyncStatus {\n const state = useSyncExternalStore(sync.subscribe, sync.getState, sync.getState);\n return {\n tone: toneFromState(state),\n pending: state.pending,\n syncing: state.phase === \"syncing\",\n offline: state.phase === \"offline\",\n lastError: state.lastError,\n };\n}\n"],"mappings":"uBAkEA,SAAgB,EACZ,EACA,EAAiC,CAAC,EACJ,CAC9B,GAAM,CAAE,eAAe,GAAO,gBAAgB,GAAM,aAAa,GAAM,EAEjE,GAAA,EAAA,EAAA,qBAAA,CAA6B,EAAK,UAAW,EAAK,SAAU,EAAK,QAAQ,EAEzE,GAAA,EAAA,EAAA,OAAA,CAAkB,EAAK,KAAK,
|
|
1
|
+
{"version":3,"file":"use-offline-sync.cjs","names":[],"sources":["../../src/offline/use-offline-sync.ts"],"sourcesContent":["import { useEffect, useRef, useSyncExternalStore } from \"react\";\nimport type {\n OfflineSync,\n OutboxOp,\n SyncRunSummary,\n SyncState,\n SyncTrigger,\n} from \"./create-offline-sync\";\n\n/**\n * Options for {@link useOfflineSync}. All auto-flush triggers are opt-in except\n * `flushOnOnline`, which defaults to `true` so the app catches up the moment\n * connectivity returns.\n */\nexport interface UseOfflineSyncOptions {\n /** Flush once when the component mounts (trigger `\"boot\"`). Default `false`. */\n flushOnMount?: boolean;\n /**\n * Flush when the browser fires the `online` event (trigger\n * `\"online-event\"`). Default `true`.\n */\n flushOnOnline?: boolean;\n /**\n * Flush on this interval in milliseconds (trigger `\"interval\"`). `0`\n * disables the timer. Default `0`.\n */\n intervalMs?: number;\n}\n\n/**\n * Reactive view of an {@link OfflineSync} engine, plus its imperative actions.\n * Extends {@link SyncState} so `phase`, `pending`, `lastSummary`, `lastError`\n * and `lastSyncedAt` are read directly off the result.\n *\n * @typeParam TPayload - Record snapshot carried by outbox entries.\n */\nexport interface UseOfflineSyncResult<TPayload> extends SyncState {\n /** `true` while a flush run is in progress (`phase === \"syncing\"`). */\n syncing: boolean;\n /** Queue a mutation. Mirrors {@link OfflineSync.enqueue}. */\n enqueue: (op: OutboxOp, recordId: string, payload?: TPayload) => Promise<string>;\n /** Trigger a flush run. Mirrors {@link OfflineSync.flush}. */\n flush: (trigger?: SyncTrigger) => Promise<SyncRunSummary>;\n}\n\n/**\n * Subscribe a React component to an {@link OfflineSync} engine.\n *\n * Re-renders whenever the engine's {@link SyncState} changes (enqueue, flush\n * transition, outbox clear) via `useSyncExternalStore`, and optionally wires\n * auto-flush on mount, on the `online` event and on an interval. The engine\n * itself is created once by the app and passed in — the hook never owns it, so\n * multiple components can observe the same queue.\n *\n * @typeParam TPayload - Record snapshot carried by outbox entries.\n * @param sync - The engine returned by `createOfflineSync`.\n * @param options - Auto-flush triggers.\n * @returns The reactive state merged with `enqueue`/`flush` actions.\n *\n * @example\n * const { pending, syncing, phase, flush } = useOfflineSync(notesSync, {\n * flushOnMount: true,\n * intervalMs: 30_000,\n * });\n * return <SyncStatusBadge pending={pending} syncing={syncing} phase={phase} />;\n */\nexport function useOfflineSync<TPayload>(\n sync: OfflineSync<TPayload>,\n options: UseOfflineSyncOptions = {},\n): UseOfflineSyncResult<TPayload> {\n const { flushOnMount = false, flushOnOnline = true, intervalMs = 0 } = options;\n\n const state = useSyncExternalStore(sync.subscribe, sync.getState, sync.getState);\n\n const flushRef = useRef(sync.flush);\n useEffect(() => {\n flushRef.current = sync.flush;\n }, [sync.flush]);\n\n useEffect(() => {\n if (flushOnMount) void flushRef.current(\"boot\");\n }, [flushOnMount]);\n\n useEffect(() => {\n if (!flushOnOnline || typeof window === \"undefined\") return;\n const handleOnline = (): void => {\n void flushRef.current(\"online-event\");\n };\n window.addEventListener(\"online\", handleOnline);\n return () => window.removeEventListener(\"online\", handleOnline);\n }, [flushOnOnline]);\n\n useEffect(() => {\n if (intervalMs <= 0 || typeof window === \"undefined\") return;\n const id = window.setInterval(() => {\n void flushRef.current(\"interval\");\n }, intervalMs);\n return () => window.clearInterval(id);\n }, [intervalMs]);\n\n return {\n ...state,\n syncing: state.phase === \"syncing\",\n enqueue: sync.enqueue,\n flush: sync.flush,\n };\n}\n\n/**\n * Presentation-ready tone for a sync status indicator. Collapses the engine's\n * {@link SyncState} into the single most relevant signal for a badge/pill.\n */\nexport type SyncTone = \"idle\" | \"syncing\" | \"pending\" | \"offline\" | \"error\";\n\n/**\n * Compact status snapshot for a status badge/pill. Prefer this over\n * {@link useOfflineSync} when a component only needs to *display* status and\n * does not trigger flushes itself.\n */\nexport interface SyncStatus {\n /** The dominant tone to render. */\n tone: SyncTone;\n /** Number of mutations still queued. */\n pending: number;\n /** `true` while a flush run is in progress. */\n syncing: boolean;\n /** `true` when the last run was skipped for being offline. */\n offline: boolean;\n /** Message of the most recent delivery failure, or `null`. */\n lastError: string | null;\n}\n\n/**\n * Derive the dominant {@link SyncTone} from an engine snapshot.\n *\n * Precedence: syncing → offline → error → pending → idle. `syncing` wins so an\n * in-flight run always reads as active even while entries remain queued.\n *\n * @param state - The engine {@link SyncState}.\n * @returns The tone to render.\n */\nfunction toneFromState(state: SyncState): SyncTone {\n if (state.phase === \"syncing\") return \"syncing\";\n if (state.phase === \"offline\") return \"offline\";\n if (state.phase === \"error\") return \"error\";\n if (state.pending > 0) return \"pending\";\n return \"idle\";\n}\n\n/**\n * Subscribe to an {@link OfflineSync} engine and return a display-only\n * {@link SyncStatus}. A thin read-only companion to {@link useOfflineSync},\n * intended to feed a `<SyncStatusBadge>` without exposing flush actions.\n *\n * @typeParam TPayload - Record snapshot carried by outbox entries.\n * @param sync - The engine returned by `createOfflineSync`.\n * @returns The compact status snapshot.\n */\nexport function useSyncStatus<TPayload>(sync: OfflineSync<TPayload>): SyncStatus {\n const state = useSyncExternalStore(sync.subscribe, sync.getState, sync.getState);\n return {\n tone: toneFromState(state),\n pending: state.pending,\n syncing: state.phase === \"syncing\",\n offline: state.phase === \"offline\",\n lastError: state.lastError,\n };\n}\n"],"mappings":"uBAkEA,SAAgB,EACZ,EACA,EAAiC,CAAC,EACJ,CAC9B,GAAM,CAAE,eAAe,GAAO,gBAAgB,GAAM,aAAa,GAAM,EAEjE,GAAA,EAAA,EAAA,qBAAA,CAA6B,EAAK,UAAW,EAAK,SAAU,EAAK,QAAQ,EAEzE,GAAA,EAAA,EAAA,OAAA,CAAkB,EAAK,KAAK,EA0BlC,OAzBA,EAAA,EAAA,UAAA,KAAgB,CACZ,EAAS,QAAU,EAAK,KAC5B,EAAG,CAAC,EAAK,KAAK,CAAC,GAEf,EAAA,EAAA,UAAA,KAAgB,CACR,GAAc,EAAc,QAAQ,MAAM,CAClD,EAAG,CAAC,CAAY,CAAC,GAEjB,EAAA,EAAA,UAAA,KAAgB,CACZ,GAAI,CAAC,GAAiB,OAAO,OAAW,IAAa,OACrD,IAAM,MAA2B,CAC7B,EAAc,QAAQ,cAAc,CACxC,EAEA,OADA,OAAO,iBAAiB,SAAU,CAAY,MACjC,OAAO,oBAAoB,SAAU,CAAY,CAClE,EAAG,CAAC,CAAa,CAAC,GAElB,EAAA,EAAA,UAAA,KAAgB,CACZ,GAAI,GAAc,GAAK,OAAO,OAAW,IAAa,OACtD,IAAM,EAAK,OAAO,gBAAkB,CAChC,EAAc,QAAQ,UAAU,CACpC,EAAG,CAAU,EACb,UAAa,OAAO,cAAc,CAAE,CACxC,EAAG,CAAC,CAAU,CAAC,EAER,CACH,GAAG,EACH,QAAS,EAAM,QAAU,UACzB,QAAS,EAAK,QACd,MAAO,EAAK,KAChB,CACJ,CAmCA,SAAS,EAAc,EAA4B,CAK/C,OAJI,EAAM,QAAU,UAAkB,UAClC,EAAM,QAAU,UAAkB,UAClC,EAAM,QAAU,QAAgB,QAChC,EAAM,QAAU,EAAU,UACvB,MACX,CAWA,SAAgB,EAAwB,EAAyC,CAC7E,IAAM,GAAA,EAAA,EAAA,qBAAA,CAA6B,EAAK,UAAW,EAAK,SAAU,EAAK,QAAQ,EAC/E,MAAO,CACH,KAAM,EAAc,CAAK,EACzB,QAAS,EAAM,QACf,QAAS,EAAM,QAAU,UACzB,QAAS,EAAM,QAAU,UACzB,UAAW,EAAM,SACrB,CACJ"}
|
|
@@ -2,7 +2,9 @@ import { useEffect as e, useRef as t, useSyncExternalStore as n } from "react";
|
|
|
2
2
|
//#region src/offline/use-offline-sync.ts
|
|
3
3
|
function r(r, i = {}) {
|
|
4
4
|
let { flushOnMount: a = !1, flushOnOnline: o = !0, intervalMs: s = 0 } = i, c = n(r.subscribe, r.getState, r.getState), l = t(r.flush);
|
|
5
|
-
return
|
|
5
|
+
return e(() => {
|
|
6
|
+
l.current = r.flush;
|
|
7
|
+
}, [r.flush]), e(() => {
|
|
6
8
|
a && l.current("boot");
|
|
7
9
|
}, [a]), e(() => {
|
|
8
10
|
if (!o || typeof window > "u") return;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"use-offline-sync.js","names":[],"sources":["../../src/offline/use-offline-sync.ts"],"sourcesContent":["import { useEffect, useRef, useSyncExternalStore } from \"react\";\nimport type {\n OfflineSync,\n OutboxOp,\n SyncRunSummary,\n SyncState,\n SyncTrigger,\n} from \"./create-offline-sync\";\n\n/**\n * Options for {@link useOfflineSync}. All auto-flush triggers are opt-in except\n * `flushOnOnline`, which defaults to `true` so the app catches up the moment\n * connectivity returns.\n */\nexport interface UseOfflineSyncOptions {\n /** Flush once when the component mounts (trigger `\"boot\"`). Default `false`. */\n flushOnMount?: boolean;\n /**\n * Flush when the browser fires the `online` event (trigger\n * `\"online-event\"`). Default `true`.\n */\n flushOnOnline?: boolean;\n /**\n * Flush on this interval in milliseconds (trigger `\"interval\"`). `0`\n * disables the timer. Default `0`.\n */\n intervalMs?: number;\n}\n\n/**\n * Reactive view of an {@link OfflineSync} engine, plus its imperative actions.\n * Extends {@link SyncState} so `phase`, `pending`, `lastSummary`, `lastError`\n * and `lastSyncedAt` are read directly off the result.\n *\n * @typeParam TPayload - Record snapshot carried by outbox entries.\n */\nexport interface UseOfflineSyncResult<TPayload> extends SyncState {\n /** `true` while a flush run is in progress (`phase === \"syncing\"`). */\n syncing: boolean;\n /** Queue a mutation. Mirrors {@link OfflineSync.enqueue}. */\n enqueue: (op: OutboxOp, recordId: string, payload?: TPayload) => Promise<string>;\n /** Trigger a flush run. Mirrors {@link OfflineSync.flush}. */\n flush: (trigger?: SyncTrigger) => Promise<SyncRunSummary>;\n}\n\n/**\n * Subscribe a React component to an {@link OfflineSync} engine.\n *\n * Re-renders whenever the engine's {@link SyncState} changes (enqueue, flush\n * transition, outbox clear) via `useSyncExternalStore`, and optionally wires\n * auto-flush on mount, on the `online` event and on an interval. The engine\n * itself is created once by the app and passed in — the hook never owns it, so\n * multiple components can observe the same queue.\n *\n * @typeParam TPayload - Record snapshot carried by outbox entries.\n * @param sync - The engine returned by `createOfflineSync`.\n * @param options - Auto-flush triggers.\n * @returns The reactive state merged with `enqueue`/`flush` actions.\n *\n * @example\n * const { pending, syncing, phase, flush } = useOfflineSync(notesSync, {\n * flushOnMount: true,\n * intervalMs: 30_000,\n * });\n * return <SyncStatusBadge pending={pending} syncing={syncing} phase={phase} />;\n */\nexport function useOfflineSync<TPayload>(\n sync: OfflineSync<TPayload>,\n options: UseOfflineSyncOptions = {},\n): UseOfflineSyncResult<TPayload> {\n const { flushOnMount = false, flushOnOnline = true, intervalMs = 0 } = options;\n\n const state = useSyncExternalStore(sync.subscribe, sync.getState, sync.getState);\n\n const flushRef = useRef(sync.flush);\n flushRef.current = sync.flush;\n\n useEffect(() => {\n if (flushOnMount) void flushRef.current(\"boot\");\n }, [flushOnMount]);\n\n useEffect(() => {\n if (!flushOnOnline || typeof window === \"undefined\") return;\n const handleOnline = (): void => {\n void flushRef.current(\"online-event\");\n };\n window.addEventListener(\"online\", handleOnline);\n return () => window.removeEventListener(\"online\", handleOnline);\n }, [flushOnOnline]);\n\n useEffect(() => {\n if (intervalMs <= 0 || typeof window === \"undefined\") return;\n const id = window.setInterval(() => {\n void flushRef.current(\"interval\");\n }, intervalMs);\n return () => window.clearInterval(id);\n }, [intervalMs]);\n\n return {\n ...state,\n syncing: state.phase === \"syncing\",\n enqueue: sync.enqueue,\n flush: sync.flush,\n };\n}\n\n/**\n * Presentation-ready tone for a sync status indicator. Collapses the engine's\n * {@link SyncState} into the single most relevant signal for a badge/pill.\n */\nexport type SyncTone = \"idle\" | \"syncing\" | \"pending\" | \"offline\" | \"error\";\n\n/**\n * Compact status snapshot for a status badge/pill. Prefer this over\n * {@link useOfflineSync} when a component only needs to *display* status and\n * does not trigger flushes itself.\n */\nexport interface SyncStatus {\n /** The dominant tone to render. */\n tone: SyncTone;\n /** Number of mutations still queued. */\n pending: number;\n /** `true` while a flush run is in progress. */\n syncing: boolean;\n /** `true` when the last run was skipped for being offline. */\n offline: boolean;\n /** Message of the most recent delivery failure, or `null`. */\n lastError: string | null;\n}\n\n/**\n * Derive the dominant {@link SyncTone} from an engine snapshot.\n *\n * Precedence: syncing → offline → error → pending → idle. `syncing` wins so an\n * in-flight run always reads as active even while entries remain queued.\n *\n * @param state - The engine {@link SyncState}.\n * @returns The tone to render.\n */\nfunction toneFromState(state: SyncState): SyncTone {\n if (state.phase === \"syncing\") return \"syncing\";\n if (state.phase === \"offline\") return \"offline\";\n if (state.phase === \"error\") return \"error\";\n if (state.pending > 0) return \"pending\";\n return \"idle\";\n}\n\n/**\n * Subscribe to an {@link OfflineSync} engine and return a display-only\n * {@link SyncStatus}. A thin read-only companion to {@link useOfflineSync},\n * intended to feed a `<SyncStatusBadge>` without exposing flush actions.\n *\n * @typeParam TPayload - Record snapshot carried by outbox entries.\n * @param sync - The engine returned by `createOfflineSync`.\n * @returns The compact status snapshot.\n */\nexport function useSyncStatus<TPayload>(sync: OfflineSync<TPayload>): SyncStatus {\n const state = useSyncExternalStore(sync.subscribe, sync.getState, sync.getState);\n return {\n tone: toneFromState(state),\n pending: state.pending,\n syncing: state.phase === \"syncing\",\n offline: state.phase === \"offline\",\n lastError: state.lastError,\n };\n}\n"],"mappings":";;AAkEA,SAAgB,EACZ,GACA,IAAiC,CAAC,GACJ;CAC9B,IAAM,EAAE,kBAAe,IAAO,mBAAgB,IAAM,gBAAa,MAAM,GAEjE,IAAQ,EAAqB,EAAK,WAAW,EAAK,UAAU,EAAK,QAAQ,GAEzE,IAAW,EAAO,EAAK,KAAK;
|
|
1
|
+
{"version":3,"file":"use-offline-sync.js","names":[],"sources":["../../src/offline/use-offline-sync.ts"],"sourcesContent":["import { useEffect, useRef, useSyncExternalStore } from \"react\";\nimport type {\n OfflineSync,\n OutboxOp,\n SyncRunSummary,\n SyncState,\n SyncTrigger,\n} from \"./create-offline-sync\";\n\n/**\n * Options for {@link useOfflineSync}. All auto-flush triggers are opt-in except\n * `flushOnOnline`, which defaults to `true` so the app catches up the moment\n * connectivity returns.\n */\nexport interface UseOfflineSyncOptions {\n /** Flush once when the component mounts (trigger `\"boot\"`). Default `false`. */\n flushOnMount?: boolean;\n /**\n * Flush when the browser fires the `online` event (trigger\n * `\"online-event\"`). Default `true`.\n */\n flushOnOnline?: boolean;\n /**\n * Flush on this interval in milliseconds (trigger `\"interval\"`). `0`\n * disables the timer. Default `0`.\n */\n intervalMs?: number;\n}\n\n/**\n * Reactive view of an {@link OfflineSync} engine, plus its imperative actions.\n * Extends {@link SyncState} so `phase`, `pending`, `lastSummary`, `lastError`\n * and `lastSyncedAt` are read directly off the result.\n *\n * @typeParam TPayload - Record snapshot carried by outbox entries.\n */\nexport interface UseOfflineSyncResult<TPayload> extends SyncState {\n /** `true` while a flush run is in progress (`phase === \"syncing\"`). */\n syncing: boolean;\n /** Queue a mutation. Mirrors {@link OfflineSync.enqueue}. */\n enqueue: (op: OutboxOp, recordId: string, payload?: TPayload) => Promise<string>;\n /** Trigger a flush run. Mirrors {@link OfflineSync.flush}. */\n flush: (trigger?: SyncTrigger) => Promise<SyncRunSummary>;\n}\n\n/**\n * Subscribe a React component to an {@link OfflineSync} engine.\n *\n * Re-renders whenever the engine's {@link SyncState} changes (enqueue, flush\n * transition, outbox clear) via `useSyncExternalStore`, and optionally wires\n * auto-flush on mount, on the `online` event and on an interval. The engine\n * itself is created once by the app and passed in — the hook never owns it, so\n * multiple components can observe the same queue.\n *\n * @typeParam TPayload - Record snapshot carried by outbox entries.\n * @param sync - The engine returned by `createOfflineSync`.\n * @param options - Auto-flush triggers.\n * @returns The reactive state merged with `enqueue`/`flush` actions.\n *\n * @example\n * const { pending, syncing, phase, flush } = useOfflineSync(notesSync, {\n * flushOnMount: true,\n * intervalMs: 30_000,\n * });\n * return <SyncStatusBadge pending={pending} syncing={syncing} phase={phase} />;\n */\nexport function useOfflineSync<TPayload>(\n sync: OfflineSync<TPayload>,\n options: UseOfflineSyncOptions = {},\n): UseOfflineSyncResult<TPayload> {\n const { flushOnMount = false, flushOnOnline = true, intervalMs = 0 } = options;\n\n const state = useSyncExternalStore(sync.subscribe, sync.getState, sync.getState);\n\n const flushRef = useRef(sync.flush);\n useEffect(() => {\n flushRef.current = sync.flush;\n }, [sync.flush]);\n\n useEffect(() => {\n if (flushOnMount) void flushRef.current(\"boot\");\n }, [flushOnMount]);\n\n useEffect(() => {\n if (!flushOnOnline || typeof window === \"undefined\") return;\n const handleOnline = (): void => {\n void flushRef.current(\"online-event\");\n };\n window.addEventListener(\"online\", handleOnline);\n return () => window.removeEventListener(\"online\", handleOnline);\n }, [flushOnOnline]);\n\n useEffect(() => {\n if (intervalMs <= 0 || typeof window === \"undefined\") return;\n const id = window.setInterval(() => {\n void flushRef.current(\"interval\");\n }, intervalMs);\n return () => window.clearInterval(id);\n }, [intervalMs]);\n\n return {\n ...state,\n syncing: state.phase === \"syncing\",\n enqueue: sync.enqueue,\n flush: sync.flush,\n };\n}\n\n/**\n * Presentation-ready tone for a sync status indicator. Collapses the engine's\n * {@link SyncState} into the single most relevant signal for a badge/pill.\n */\nexport type SyncTone = \"idle\" | \"syncing\" | \"pending\" | \"offline\" | \"error\";\n\n/**\n * Compact status snapshot for a status badge/pill. Prefer this over\n * {@link useOfflineSync} when a component only needs to *display* status and\n * does not trigger flushes itself.\n */\nexport interface SyncStatus {\n /** The dominant tone to render. */\n tone: SyncTone;\n /** Number of mutations still queued. */\n pending: number;\n /** `true` while a flush run is in progress. */\n syncing: boolean;\n /** `true` when the last run was skipped for being offline. */\n offline: boolean;\n /** Message of the most recent delivery failure, or `null`. */\n lastError: string | null;\n}\n\n/**\n * Derive the dominant {@link SyncTone} from an engine snapshot.\n *\n * Precedence: syncing → offline → error → pending → idle. `syncing` wins so an\n * in-flight run always reads as active even while entries remain queued.\n *\n * @param state - The engine {@link SyncState}.\n * @returns The tone to render.\n */\nfunction toneFromState(state: SyncState): SyncTone {\n if (state.phase === \"syncing\") return \"syncing\";\n if (state.phase === \"offline\") return \"offline\";\n if (state.phase === \"error\") return \"error\";\n if (state.pending > 0) return \"pending\";\n return \"idle\";\n}\n\n/**\n * Subscribe to an {@link OfflineSync} engine and return a display-only\n * {@link SyncStatus}. A thin read-only companion to {@link useOfflineSync},\n * intended to feed a `<SyncStatusBadge>` without exposing flush actions.\n *\n * @typeParam TPayload - Record snapshot carried by outbox entries.\n * @param sync - The engine returned by `createOfflineSync`.\n * @returns The compact status snapshot.\n */\nexport function useSyncStatus<TPayload>(sync: OfflineSync<TPayload>): SyncStatus {\n const state = useSyncExternalStore(sync.subscribe, sync.getState, sync.getState);\n return {\n tone: toneFromState(state),\n pending: state.pending,\n syncing: state.phase === \"syncing\",\n offline: state.phase === \"offline\",\n lastError: state.lastError,\n };\n}\n"],"mappings":";;AAkEA,SAAgB,EACZ,GACA,IAAiC,CAAC,GACJ;CAC9B,IAAM,EAAE,kBAAe,IAAO,mBAAgB,IAAM,gBAAa,MAAM,GAEjE,IAAQ,EAAqB,EAAK,WAAW,EAAK,UAAU,EAAK,QAAQ,GAEzE,IAAW,EAAO,EAAK,KAAK;CA0BlC,OAzBA,QAAgB;EACZ,EAAS,UAAU,EAAK;CAC5B,GAAG,CAAC,EAAK,KAAK,CAAC,GAEf,QAAgB;EACZ,AAAI,KAAc,EAAc,QAAQ,MAAM;CAClD,GAAG,CAAC,CAAY,CAAC,GAEjB,QAAgB;EACZ,IAAI,CAAC,KAAiB,OAAO,SAAW,KAAa;EACrD,IAAM,UAA2B;GAC7B,EAAc,QAAQ,cAAc;EACxC;EAEA,OADA,OAAO,iBAAiB,UAAU,CAAY,SACjC,OAAO,oBAAoB,UAAU,CAAY;CAClE,GAAG,CAAC,CAAa,CAAC,GAElB,QAAgB;EACZ,IAAI,KAAc,KAAK,OAAO,SAAW,KAAa;EACtD,IAAM,IAAK,OAAO,kBAAkB;GAChC,EAAc,QAAQ,UAAU;EACpC,GAAG,CAAU;EACb,aAAa,OAAO,cAAc,CAAE;CACxC,GAAG,CAAC,CAAU,CAAC,GAER;EACH,GAAG;EACH,SAAS,EAAM,UAAU;EACzB,SAAS,EAAK;EACd,OAAO,EAAK;CAChB;AACJ;AAmCA,SAAS,EAAc,GAA4B;CAK/C,OAJI,EAAM,UAAU,YAAkB,YAClC,EAAM,UAAU,YAAkB,YAClC,EAAM,UAAU,UAAgB,UAChC,EAAM,UAAU,IAAU,YACvB;AACX;AAWA,SAAgB,EAAwB,GAAyC;CAC7E,IAAM,IAAQ,EAAqB,EAAK,WAAW,EAAK,UAAU,EAAK,QAAQ;CAC/E,OAAO;EACH,MAAM,EAAc,CAAK;EACzB,SAAS,EAAM;EACf,SAAS,EAAM,UAAU;EACzB,SAAS,EAAM,UAAU;EACzB,WAAW,EAAM;CACrB;AACJ"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
const e=require("./utils.cjs"),t=require("./web-push-client.cjs");let n=require("react");function r(r){let i=(0,n.useRef)(r);i.current=r;let a=(0,n.useMemo)(()=>new t.WebPushClient({vapidPublicKey:r.vapidPublicKey,onSubscribe:e=>i.current.onSubscribe(e),onUnsubscribe:e=>i.current.onUnsubscribe?.(e),getRegistration:r.getRegistration}),[r.vapidPublicKey,r.getRegistration]),[o]=(0,n.useState)(()=>e.isPushSupported()),[s,c]=(0,n.useState)(()=>a.permission()),[l,u]=(0,n.useState)(!1),[d,f]=(0,n.useState)(!1),[p,m]=(0,n.useState)(null),h=(0,n.useCallback)(async()=>{if(o){c(a.permission());try{let e=await a.isSubscribed();u(e)}catch(e){m(e instanceof Error?e:Error(String(e)))}}},[a,o]);return(0,n.useEffect)(()=>{h()},[h]),{supported:o,permission:s,subscribed:l,loading:d,error:p,subscribe:(0,n.useCallback)(async()=>{if(o){f(!0),m(null);try{await a.subscribe(),u(!0),c(a.permission())}catch(e){throw m(e instanceof Error?e:Error(String(e))),e}finally{f(!1)}}},[a,o]),unsubscribe:(0,n.useCallback)(async()=>{if(o){f(!0),m(null);try{await a.unsubscribe(),u(!1)}catch(e){throw m(e instanceof Error?e:Error(String(e))),e}finally{f(!1)}}},[a,o]),refresh:h}}exports.usePushSubscription=r;
|
|
1
|
+
const e=require("./utils.cjs"),t=require("./web-push-client.cjs");let n=require("react");function r(r){let i=(0,n.useRef)(r);(0,n.useEffect)(()=>{i.current=r},[r]);let a=(0,n.useMemo)(()=>new t.WebPushClient({vapidPublicKey:r.vapidPublicKey,onSubscribe:e=>i.current.onSubscribe(e),onUnsubscribe:e=>i.current.onUnsubscribe?.(e),getRegistration:r.getRegistration}),[r.vapidPublicKey,r.getRegistration]),[o]=(0,n.useState)(()=>e.isPushSupported()),[s,c]=(0,n.useState)(()=>a.permission()),[l,u]=(0,n.useState)(!1),[d,f]=(0,n.useState)(!1),[p,m]=(0,n.useState)(null),h=(0,n.useCallback)(async()=>{if(o){c(a.permission());try{let e=await a.isSubscribed();u(e)}catch(e){m(e instanceof Error?e:Error(String(e)))}}},[a,o]);return(0,n.useEffect)(()=>{h()},[h]),{supported:o,permission:s,subscribed:l,loading:d,error:p,subscribe:(0,n.useCallback)(async()=>{if(o){f(!0),m(null);try{await a.subscribe(),u(!0),c(a.permission())}catch(e){throw m(e instanceof Error?e:Error(String(e))),e}finally{f(!1)}}},[a,o]),unsubscribe:(0,n.useCallback)(async()=>{if(o){f(!0),m(null);try{await a.unsubscribe(),u(!1)}catch(e){throw m(e instanceof Error?e:Error(String(e))),e}finally{f(!1)}}},[a,o]),refresh:h}}exports.usePushSubscription=r;
|
|
2
2
|
//# sourceMappingURL=use-push-subscription.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"use-push-subscription.cjs","names":[],"sources":["../../src/push/use-push-subscription.ts"],"sourcesContent":["
|
|
1
|
+
{"version":3,"file":"use-push-subscription.cjs","names":[],"sources":["../../src/push/use-push-subscription.ts"],"sourcesContent":["/* eslint-disable react-hooks/refs -- the ref is read inside deferred callbacks, not during render */\nimport { useCallback, useEffect, useMemo, useRef, useState } from \"react\";\nimport { WebPushClient, type WebPushClientConfig } from \"./web-push-client\";\nimport { isPushSupported } from \"./utils\";\n\nexport interface UsePushSubscriptionResult {\n /** True when the browser exposes the Push + Notification APIs. */\n supported: boolean;\n /** Current `Notification.permission` value, or `\"unsupported\"`. */\n permission: NotificationPermission | \"unsupported\";\n /** True when a subscription is active on this device. */\n subscribed: boolean;\n /** True while a subscribe/unsubscribe call is in-flight. */\n loading: boolean;\n /** Last error thrown by subscribe/unsubscribe, if any. */\n error: Error | null;\n subscribe: () => Promise<void>;\n unsubscribe: () => Promise<void>;\n /** Re-read the current subscription/permission state from the browser. */\n refresh: () => Promise<void>;\n}\n\n/**\n * React hook around {@link WebPushClient}. Tracks subscription, permission and\n * loading state; exposes imperative `subscribe`/`unsubscribe` actions.\n *\n * The hook does NOT register the service worker — the host app must do that\n * (e.g. via `vite-plugin-pwa` or a manual `navigator.serviceWorker.register`).\n *\n * @example\n * const push = usePushSubscription({\n * vapidPublicKey: import.meta.env.VITE_VAPID_PUBLIC_KEY,\n * onSubscribe: (sub) => api.post(\"/webpush/subscribe\", { body: sub }),\n * onUnsubscribe: () => api.delete(\"/webpush/my\"),\n * });\n */\nexport function usePushSubscription(config: WebPushClientConfig): UsePushSubscriptionResult {\n const configRef = useRef(config);\n useEffect(() => {\n configRef.current = config;\n }, [config]);\n\n const client = useMemo(\n () =>\n new WebPushClient({\n vapidPublicKey: config.vapidPublicKey,\n onSubscribe: (sub) => configRef.current.onSubscribe(sub),\n onUnsubscribe: (sub) => configRef.current.onUnsubscribe?.(sub),\n getRegistration: config.getRegistration,\n }),\n [config.vapidPublicKey, config.getRegistration],\n );\n\n const [supported] = useState<boolean>(() => isPushSupported());\n const [permission, setPermission] = useState<NotificationPermission | \"unsupported\">(() =>\n client.permission(),\n );\n const [subscribed, setSubscribed] = useState<boolean>(false);\n const [loading, setLoading] = useState<boolean>(false);\n const [error, setError] = useState<Error | null>(null);\n\n const refresh = useCallback(async () => {\n if (!supported) return;\n setPermission(client.permission());\n try {\n const active = await client.isSubscribed();\n setSubscribed(active);\n } catch (err) {\n setError(err instanceof Error ? err : new Error(String(err)));\n }\n }, [client, supported]);\n\n useEffect(() => {\n void refresh();\n }, [refresh]);\n\n const subscribe = useCallback(async () => {\n if (!supported) return;\n setLoading(true);\n setError(null);\n try {\n await client.subscribe();\n setSubscribed(true);\n setPermission(client.permission());\n } catch (err) {\n setError(err instanceof Error ? err : new Error(String(err)));\n throw err;\n } finally {\n setLoading(false);\n }\n }, [client, supported]);\n\n const unsubscribe = useCallback(async () => {\n if (!supported) return;\n setLoading(true);\n setError(null);\n try {\n await client.unsubscribe();\n setSubscribed(false);\n } catch (err) {\n setError(err instanceof Error ? err : new Error(String(err)));\n throw err;\n } finally {\n setLoading(false);\n }\n }, [client, supported]);\n\n return {\n supported,\n permission,\n subscribed,\n loading,\n error,\n subscribe,\n unsubscribe,\n refresh,\n };\n}\n"],"mappings":"yFAoCA,SAAgB,EAAoB,EAAwD,CACxF,IAAM,GAAA,EAAA,EAAA,OAAA,CAAmB,CAAM,GAC/B,EAAA,EAAA,UAAA,KAAgB,CACZ,EAAU,QAAU,CACxB,EAAG,CAAC,CAAM,CAAC,EAEX,IAAM,GAAA,EAAA,EAAA,QAAA,KAEE,IAAI,EAAA,cAAc,CACd,eAAgB,EAAO,eACvB,YAAc,GAAQ,EAAU,QAAQ,YAAY,CAAG,EACvD,cAAgB,GAAQ,EAAU,QAAQ,gBAAgB,CAAG,EAC7D,gBAAiB,EAAO,eAC5B,CAAC,EACL,CAAC,EAAO,eAAgB,EAAO,eAAe,CAClD,EAEM,CAAC,IAAA,EAAA,EAAA,SAAA,KAAqC,EAAA,gBAAgB,CAAC,EACvD,CAAC,EAAY,IAAA,EAAA,EAAA,SAAA,KACf,EAAO,WAAW,CACtB,EACM,CAAC,EAAY,IAAA,EAAA,EAAA,SAAA,CAAmC,EAAK,EACrD,CAAC,EAAS,IAAA,EAAA,EAAA,SAAA,CAAgC,EAAK,EAC/C,CAAC,EAAO,IAAA,EAAA,EAAA,SAAA,CAAmC,IAAI,EAE/C,GAAA,EAAA,EAAA,YAAA,CAAsB,SAAY,CAC/B,KACL,GAAc,EAAO,WAAW,CAAC,EACjC,GAAI,CACA,IAAM,EAAS,MAAM,EAAO,aAAa,EACzC,EAAc,CAAM,CACxB,OAAS,EAAK,CACV,EAAS,aAAe,MAAQ,EAAU,MAAM,OAAO,CAAG,CAAC,CAAC,CAChE,CANiC,CAOrC,EAAG,CAAC,EAAQ,CAAS,CAAC,EAqCtB,OAnCA,EAAA,EAAA,UAAA,KAAgB,CACZ,EAAa,CACjB,EAAG,CAAC,CAAO,CAAC,EAiCL,CACH,YACA,aACA,aACA,UACA,QACA,WAAA,EAAA,EAAA,YAAA,CArC0B,SAAY,CACjC,KAEL,CADA,EAAW,EAAI,EACf,EAAS,IAAI,EACb,GAAI,CACA,MAAM,EAAO,UAAU,EACvB,EAAc,EAAI,EAClB,EAAc,EAAO,WAAW,CAAC,CACrC,OAAS,EAAK,CAEV,MADA,EAAS,aAAe,MAAQ,EAAU,MAAM,OAAO,CAAG,CAAC,CAAC,EACtD,CACV,QAAU,CACN,EAAW,EAAK,CACpB,CAVa,CAWjB,EAAG,CAAC,EAAQ,CAAS,CAuBjB,EACA,aAAA,EAAA,EAAA,YAAA,CAtB4B,SAAY,CACnC,KAEL,CADA,EAAW,EAAI,EACf,EAAS,IAAI,EACb,GAAI,CACA,MAAM,EAAO,YAAY,EACzB,EAAc,EAAK,CACvB,OAAS,EAAK,CAEV,MADA,EAAS,aAAe,MAAQ,EAAU,MAAM,OAAO,CAAG,CAAC,CAAC,EACtD,CACV,QAAU,CACN,EAAW,EAAK,CACpB,CATa,CAUjB,EAAG,CAAC,EAAQ,CAAS,CASjB,EACA,SACJ,CACJ"}
|
|
@@ -4,7 +4,9 @@ import { useCallback as n, useEffect as r, useMemo as i, useRef as a, useState a
|
|
|
4
4
|
//#region src/push/use-push-subscription.ts
|
|
5
5
|
function s(s) {
|
|
6
6
|
let c = a(s);
|
|
7
|
-
|
|
7
|
+
r(() => {
|
|
8
|
+
c.current = s;
|
|
9
|
+
}, [s]);
|
|
8
10
|
let l = i(() => new t({
|
|
9
11
|
vapidPublicKey: s.vapidPublicKey,
|
|
10
12
|
onSubscribe: (e) => c.current.onSubscribe(e),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"use-push-subscription.js","names":[],"sources":["../../src/push/use-push-subscription.ts"],"sourcesContent":["
|
|
1
|
+
{"version":3,"file":"use-push-subscription.js","names":[],"sources":["../../src/push/use-push-subscription.ts"],"sourcesContent":["/* eslint-disable react-hooks/refs -- the ref is read inside deferred callbacks, not during render */\nimport { useCallback, useEffect, useMemo, useRef, useState } from \"react\";\nimport { WebPushClient, type WebPushClientConfig } from \"./web-push-client\";\nimport { isPushSupported } from \"./utils\";\n\nexport interface UsePushSubscriptionResult {\n /** True when the browser exposes the Push + Notification APIs. */\n supported: boolean;\n /** Current `Notification.permission` value, or `\"unsupported\"`. */\n permission: NotificationPermission | \"unsupported\";\n /** True when a subscription is active on this device. */\n subscribed: boolean;\n /** True while a subscribe/unsubscribe call is in-flight. */\n loading: boolean;\n /** Last error thrown by subscribe/unsubscribe, if any. */\n error: Error | null;\n subscribe: () => Promise<void>;\n unsubscribe: () => Promise<void>;\n /** Re-read the current subscription/permission state from the browser. */\n refresh: () => Promise<void>;\n}\n\n/**\n * React hook around {@link WebPushClient}. Tracks subscription, permission and\n * loading state; exposes imperative `subscribe`/`unsubscribe` actions.\n *\n * The hook does NOT register the service worker — the host app must do that\n * (e.g. via `vite-plugin-pwa` or a manual `navigator.serviceWorker.register`).\n *\n * @example\n * const push = usePushSubscription({\n * vapidPublicKey: import.meta.env.VITE_VAPID_PUBLIC_KEY,\n * onSubscribe: (sub) => api.post(\"/webpush/subscribe\", { body: sub }),\n * onUnsubscribe: () => api.delete(\"/webpush/my\"),\n * });\n */\nexport function usePushSubscription(config: WebPushClientConfig): UsePushSubscriptionResult {\n const configRef = useRef(config);\n useEffect(() => {\n configRef.current = config;\n }, [config]);\n\n const client = useMemo(\n () =>\n new WebPushClient({\n vapidPublicKey: config.vapidPublicKey,\n onSubscribe: (sub) => configRef.current.onSubscribe(sub),\n onUnsubscribe: (sub) => configRef.current.onUnsubscribe?.(sub),\n getRegistration: config.getRegistration,\n }),\n [config.vapidPublicKey, config.getRegistration],\n );\n\n const [supported] = useState<boolean>(() => isPushSupported());\n const [permission, setPermission] = useState<NotificationPermission | \"unsupported\">(() =>\n client.permission(),\n );\n const [subscribed, setSubscribed] = useState<boolean>(false);\n const [loading, setLoading] = useState<boolean>(false);\n const [error, setError] = useState<Error | null>(null);\n\n const refresh = useCallback(async () => {\n if (!supported) return;\n setPermission(client.permission());\n try {\n const active = await client.isSubscribed();\n setSubscribed(active);\n } catch (err) {\n setError(err instanceof Error ? err : new Error(String(err)));\n }\n }, [client, supported]);\n\n useEffect(() => {\n void refresh();\n }, [refresh]);\n\n const subscribe = useCallback(async () => {\n if (!supported) return;\n setLoading(true);\n setError(null);\n try {\n await client.subscribe();\n setSubscribed(true);\n setPermission(client.permission());\n } catch (err) {\n setError(err instanceof Error ? err : new Error(String(err)));\n throw err;\n } finally {\n setLoading(false);\n }\n }, [client, supported]);\n\n const unsubscribe = useCallback(async () => {\n if (!supported) return;\n setLoading(true);\n setError(null);\n try {\n await client.unsubscribe();\n setSubscribed(false);\n } catch (err) {\n setError(err instanceof Error ? err : new Error(String(err)));\n throw err;\n } finally {\n setLoading(false);\n }\n }, [client, supported]);\n\n return {\n supported,\n permission,\n subscribed,\n loading,\n error,\n subscribe,\n unsubscribe,\n refresh,\n };\n}\n"],"mappings":";;;;AAoCA,SAAgB,EAAoB,GAAwD;CACxF,IAAM,IAAY,EAAO,CAAM;CAC/B,QAAgB;EACZ,EAAU,UAAU;CACxB,GAAG,CAAC,CAAM,CAAC;CAEX,IAAM,IAAS,QAEP,IAAI,EAAc;EACd,gBAAgB,EAAO;EACvB,cAAc,MAAQ,EAAU,QAAQ,YAAY,CAAG;EACvD,gBAAgB,MAAQ,EAAU,QAAQ,gBAAgB,CAAG;EAC7D,iBAAiB,EAAO;CAC5B,CAAC,GACL,CAAC,EAAO,gBAAgB,EAAO,eAAe,CAClD,GAEM,CAAC,KAAa,QAAwB,EAAgB,CAAC,GACvD,CAAC,GAAY,KAAiB,QAChC,EAAO,WAAW,CACtB,GACM,CAAC,GAAY,KAAiB,EAAkB,EAAK,GACrD,CAAC,GAAS,KAAc,EAAkB,EAAK,GAC/C,CAAC,GAAO,KAAY,EAAuB,IAAI,GAE/C,IAAU,EAAY,YAAY;EAC/B,OACL;KAAc,EAAO,WAAW,CAAC;GACjC,IAAI;IACA,IAAM,IAAS,MAAM,EAAO,aAAa;IACzC,EAAc,CAAM;GACxB,SAAS,GAAK;IACV,EAAS,aAAe,QAAQ,IAAU,MAAM,OAAO,CAAG,CAAC,CAAC;GAChE;EANiC;CAOrC,GAAG,CAAC,GAAQ,CAAS,CAAC;CAqCtB,OAnCA,QAAgB;EACZ,EAAa;CACjB,GAAG,CAAC,CAAO,CAAC,GAiCL;EACH;EACA;EACA;EACA;EACA;EACA,WArCc,EAAY,YAAY;GACjC,OAEL;IADA,EAAW,EAAI,GACf,EAAS,IAAI;IACb,IAAI;KAGA,AAFA,MAAM,EAAO,UAAU,GACvB,EAAc,EAAI,GAClB,EAAc,EAAO,WAAW,CAAC;IACrC,SAAS,GAAK;KAEV,MADA,EAAS,aAAe,QAAQ,IAAU,MAAM,OAAO,CAAG,CAAC,CAAC,GACtD;IACV,UAAU;KACN,EAAW,EAAK;IACpB;GAVa;EAWjB,GAAG,CAAC,GAAQ,CAAS,CAuBjB;EACA,aAtBgB,EAAY,YAAY;GACnC,OAEL;IADA,EAAW,EAAI,GACf,EAAS,IAAI;IACb,IAAI;KAEA,AADA,MAAM,EAAO,YAAY,GACzB,EAAc,EAAK;IACvB,SAAS,GAAK;KAEV,MADA,EAAS,aAAe,QAAQ,IAAU,MAAM,OAAO,CAAG,CAAC,CAAC,GACtD;IACV,UAAU;KACN,EAAW,EAAK;IACpB;GATa;EAUjB,GAAG,CAAC,GAAQ,CAAS,CASjB;EACA;CACJ;AACJ"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
const e=require("./create-event-stream.cjs");let t=require("react");function n(n,r={}){let{enabled:i=!0,onMessage:a,...o}=r,[s,c]=(0,t.useState)(`idle`),[l,u]=(0,t.useState)(null),d=(0,t.useRef)(null),f=(0,t.useRef)(a);return
|
|
1
|
+
const e=require("./create-event-stream.cjs");let t=require("react");function n(n,r={}){let{enabled:i=!0,onMessage:a,...o}=r,[s,c]=(0,t.useState)(`idle`),[l,u]=(0,t.useState)(null),d=(0,t.useRef)(null),f=(0,t.useRef)(a);return(0,t.useEffect)(()=>{f.current=a},[a]),(0,t.useEffect)(()=>{if(!i||!n){c(`idle`);return}let t=e.createEventStream(n,{...o,onStatusChange:c,onMessage:e=>{u(e),f.current?.(e)}});return d.current=t.reconnect,()=>{t.close(),d.current=null}},[n,i]),{status:s,lastMessage:l,reconnect:()=>d.current?.()}}exports.useEventStream=n;
|
|
2
2
|
//# sourceMappingURL=use-event-stream.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"use-event-stream.cjs","names":[],"sources":["../../src/sse/use-event-stream.ts"],"sourcesContent":["import { useEffect, useRef, useState } from \"react\";\nimport {\n createEventStream,\n type CreateEventStreamOptions,\n type EventStreamMessage,\n type EventStreamStatus,\n} from \"./create-event-stream\";\n\nexport interface UseEventStreamOptions<T> extends Omit<\n CreateEventStreamOptions<T>,\n \"onStatusChange\"\n> {\n /** When false, the stream is not opened. Useful for \"wait for auth\". Default: true. */\n enabled?: boolean;\n}\n\nexport interface UseEventStreamResult<T> {\n status: EventStreamStatus;\n /** Last message received (excluding heartbeats). */\n lastMessage: EventStreamMessage<T> | null;\n /** Force a reconnect. */\n reconnect: () => void;\n}\n\n/**\n * React hook wrapper around {@link createEventStream}. Connection lifecycle is\n * tied to the component (and the `url`/`enabled` dependencies); the stream\n * closes on unmount.\n *\n * @example\n * useEventStream<Notification>(`${API}/notifications/stream`, {\n * enabled: !!user,\n * withCredentials: true,\n * onMessage: ({ data }) => addNotification(data),\n * });\n */\nexport function useEventStream<T = unknown>(\n url: string,\n options: UseEventStreamOptions<T> = {},\n): UseEventStreamResult<T> {\n const { enabled = true, onMessage, ...rest } = options;\n const [status, setStatus] = useState<EventStreamStatus>(\"idle\");\n const [lastMessage, setLastMessage] = useState<EventStreamMessage<T> | null>(null);\n const reconnectRef = useRef<(() => void) | null>(null);\n\n const onMessageRef = useRef(onMessage);\n onMessageRef.current = onMessage;\n\n useEffect(() => {\n if (!enabled || !url) {\n setStatus(\"idle\");\n return;\n }\n\n const controller = createEventStream<T>(url, {\n ...rest,\n onStatusChange: setStatus,\n onMessage: (message) => {\n setLastMessage(message);\n onMessageRef.current?.(message);\n },\n });\n reconnectRef.current = controller.reconnect;\n\n return () => {\n controller.close();\n reconnectRef.current = null;\n };\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [url, enabled]);\n\n return {\n status,\n lastMessage,\n reconnect: () => reconnectRef.current?.(),\n };\n}\n"],"mappings":"oEAoCA,SAAgB,EACZ,EACA,EAAoC,CAAC,EACd,CACvB,GAAM,CAAE,UAAU,GAAM,YAAW,GAAG,GAAS,EACzC,CAAC,EAAQ,IAAA,EAAA,EAAA,SAAA,CAAyC,MAAM,EACxD,CAAC,EAAa,IAAA,EAAA,EAAA,SAAA,CAAyD,IAAI,EAC3E,GAAA,EAAA,EAAA,OAAA,CAA2C,IAAI,EAE/C,GAAA,EAAA,EAAA,OAAA,CAAsB,CAAS,
|
|
1
|
+
{"version":3,"file":"use-event-stream.cjs","names":[],"sources":["../../src/sse/use-event-stream.ts"],"sourcesContent":["import { useEffect, useRef, useState } from \"react\";\nimport {\n createEventStream,\n type CreateEventStreamOptions,\n type EventStreamMessage,\n type EventStreamStatus,\n} from \"./create-event-stream\";\n\nexport interface UseEventStreamOptions<T> extends Omit<\n CreateEventStreamOptions<T>,\n \"onStatusChange\"\n> {\n /** When false, the stream is not opened. Useful for \"wait for auth\". Default: true. */\n enabled?: boolean;\n}\n\nexport interface UseEventStreamResult<T> {\n status: EventStreamStatus;\n /** Last message received (excluding heartbeats). */\n lastMessage: EventStreamMessage<T> | null;\n /** Force a reconnect. */\n reconnect: () => void;\n}\n\n/**\n * React hook wrapper around {@link createEventStream}. Connection lifecycle is\n * tied to the component (and the `url`/`enabled` dependencies); the stream\n * closes on unmount.\n *\n * @example\n * useEventStream<Notification>(`${API}/notifications/stream`, {\n * enabled: !!user,\n * withCredentials: true,\n * onMessage: ({ data }) => addNotification(data),\n * });\n */\nexport function useEventStream<T = unknown>(\n url: string,\n options: UseEventStreamOptions<T> = {},\n): UseEventStreamResult<T> {\n const { enabled = true, onMessage, ...rest } = options;\n const [status, setStatus] = useState<EventStreamStatus>(\"idle\");\n const [lastMessage, setLastMessage] = useState<EventStreamMessage<T> | null>(null);\n const reconnectRef = useRef<(() => void) | null>(null);\n\n const onMessageRef = useRef(onMessage);\n useEffect(() => {\n onMessageRef.current = onMessage;\n }, [onMessage]);\n\n useEffect(() => {\n if (!enabled || !url) {\n setStatus(\"idle\");\n return;\n }\n\n const controller = createEventStream<T>(url, {\n ...rest,\n onStatusChange: setStatus,\n onMessage: (message) => {\n setLastMessage(message);\n onMessageRef.current?.(message);\n },\n });\n reconnectRef.current = controller.reconnect;\n\n return () => {\n controller.close();\n reconnectRef.current = null;\n };\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [url, enabled]);\n\n return {\n status,\n lastMessage,\n reconnect: () => reconnectRef.current?.(),\n };\n}\n"],"mappings":"oEAoCA,SAAgB,EACZ,EACA,EAAoC,CAAC,EACd,CACvB,GAAM,CAAE,UAAU,GAAM,YAAW,GAAG,GAAS,EACzC,CAAC,EAAQ,IAAA,EAAA,EAAA,SAAA,CAAyC,MAAM,EACxD,CAAC,EAAa,IAAA,EAAA,EAAA,SAAA,CAAyD,IAAI,EAC3E,GAAA,EAAA,EAAA,OAAA,CAA2C,IAAI,EAE/C,GAAA,EAAA,EAAA,OAAA,CAAsB,CAAS,EA4BrC,OA3BA,EAAA,EAAA,UAAA,KAAgB,CACZ,EAAa,QAAU,CAC3B,EAAG,CAAC,CAAS,CAAC,GAEd,EAAA,EAAA,UAAA,KAAgB,CACZ,GAAI,CAAC,GAAW,CAAC,EAAK,CAClB,EAAU,MAAM,EAChB,MACJ,CAEA,IAAM,EAAa,EAAA,kBAAqB,EAAK,CACzC,GAAG,EACH,eAAgB,EAChB,UAAY,GAAY,CACpB,EAAe,CAAO,EACtB,EAAa,UAAU,CAAO,CAClC,CACJ,CAAC,EAGD,MAFA,GAAa,QAAU,EAAW,cAErB,CACT,EAAW,MAAM,EACjB,EAAa,QAAU,IAC3B,CAEJ,EAAG,CAAC,EAAK,CAAO,CAAC,EAEV,CACH,SACA,cACA,cAAiB,EAAa,UAAU,CAC5C,CACJ"}
|
|
@@ -3,7 +3,9 @@ import { useEffect as t, useRef as n, useState as r } from "react";
|
|
|
3
3
|
//#region src/sse/use-event-stream.ts
|
|
4
4
|
function i(i, a = {}) {
|
|
5
5
|
let { enabled: o = !0, onMessage: s, ...c } = a, [l, u] = r("idle"), [d, f] = r(null), p = n(null), m = n(s);
|
|
6
|
-
return
|
|
6
|
+
return t(() => {
|
|
7
|
+
m.current = s;
|
|
8
|
+
}, [s]), t(() => {
|
|
7
9
|
if (!o || !i) {
|
|
8
10
|
u("idle");
|
|
9
11
|
return;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"use-event-stream.js","names":[],"sources":["../../src/sse/use-event-stream.ts"],"sourcesContent":["import { useEffect, useRef, useState } from \"react\";\nimport {\n createEventStream,\n type CreateEventStreamOptions,\n type EventStreamMessage,\n type EventStreamStatus,\n} from \"./create-event-stream\";\n\nexport interface UseEventStreamOptions<T> extends Omit<\n CreateEventStreamOptions<T>,\n \"onStatusChange\"\n> {\n /** When false, the stream is not opened. Useful for \"wait for auth\". Default: true. */\n enabled?: boolean;\n}\n\nexport interface UseEventStreamResult<T> {\n status: EventStreamStatus;\n /** Last message received (excluding heartbeats). */\n lastMessage: EventStreamMessage<T> | null;\n /** Force a reconnect. */\n reconnect: () => void;\n}\n\n/**\n * React hook wrapper around {@link createEventStream}. Connection lifecycle is\n * tied to the component (and the `url`/`enabled` dependencies); the stream\n * closes on unmount.\n *\n * @example\n * useEventStream<Notification>(`${API}/notifications/stream`, {\n * enabled: !!user,\n * withCredentials: true,\n * onMessage: ({ data }) => addNotification(data),\n * });\n */\nexport function useEventStream<T = unknown>(\n url: string,\n options: UseEventStreamOptions<T> = {},\n): UseEventStreamResult<T> {\n const { enabled = true, onMessage, ...rest } = options;\n const [status, setStatus] = useState<EventStreamStatus>(\"idle\");\n const [lastMessage, setLastMessage] = useState<EventStreamMessage<T> | null>(null);\n const reconnectRef = useRef<(() => void) | null>(null);\n\n const onMessageRef = useRef(onMessage);\n onMessageRef.current = onMessage;\n\n useEffect(() => {\n if (!enabled || !url) {\n setStatus(\"idle\");\n return;\n }\n\n const controller = createEventStream<T>(url, {\n ...rest,\n onStatusChange: setStatus,\n onMessage: (message) => {\n setLastMessage(message);\n onMessageRef.current?.(message);\n },\n });\n reconnectRef.current = controller.reconnect;\n\n return () => {\n controller.close();\n reconnectRef.current = null;\n };\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [url, enabled]);\n\n return {\n status,\n lastMessage,\n reconnect: () => reconnectRef.current?.(),\n };\n}\n"],"mappings":";;;AAoCA,SAAgB,EACZ,GACA,IAAoC,CAAC,GACd;CACvB,IAAM,EAAE,aAAU,IAAM,cAAW,GAAG,MAAS,GACzC,CAAC,GAAQ,KAAa,EAA4B,MAAM,GACxD,CAAC,GAAa,KAAkB,EAAuC,IAAI,GAC3E,IAAe,EAA4B,IAAI,GAE/C,IAAe,EAAO,CAAS;
|
|
1
|
+
{"version":3,"file":"use-event-stream.js","names":[],"sources":["../../src/sse/use-event-stream.ts"],"sourcesContent":["import { useEffect, useRef, useState } from \"react\";\nimport {\n createEventStream,\n type CreateEventStreamOptions,\n type EventStreamMessage,\n type EventStreamStatus,\n} from \"./create-event-stream\";\n\nexport interface UseEventStreamOptions<T> extends Omit<\n CreateEventStreamOptions<T>,\n \"onStatusChange\"\n> {\n /** When false, the stream is not opened. Useful for \"wait for auth\". Default: true. */\n enabled?: boolean;\n}\n\nexport interface UseEventStreamResult<T> {\n status: EventStreamStatus;\n /** Last message received (excluding heartbeats). */\n lastMessage: EventStreamMessage<T> | null;\n /** Force a reconnect. */\n reconnect: () => void;\n}\n\n/**\n * React hook wrapper around {@link createEventStream}. Connection lifecycle is\n * tied to the component (and the `url`/`enabled` dependencies); the stream\n * closes on unmount.\n *\n * @example\n * useEventStream<Notification>(`${API}/notifications/stream`, {\n * enabled: !!user,\n * withCredentials: true,\n * onMessage: ({ data }) => addNotification(data),\n * });\n */\nexport function useEventStream<T = unknown>(\n url: string,\n options: UseEventStreamOptions<T> = {},\n): UseEventStreamResult<T> {\n const { enabled = true, onMessage, ...rest } = options;\n const [status, setStatus] = useState<EventStreamStatus>(\"idle\");\n const [lastMessage, setLastMessage] = useState<EventStreamMessage<T> | null>(null);\n const reconnectRef = useRef<(() => void) | null>(null);\n\n const onMessageRef = useRef(onMessage);\n useEffect(() => {\n onMessageRef.current = onMessage;\n }, [onMessage]);\n\n useEffect(() => {\n if (!enabled || !url) {\n setStatus(\"idle\");\n return;\n }\n\n const controller = createEventStream<T>(url, {\n ...rest,\n onStatusChange: setStatus,\n onMessage: (message) => {\n setLastMessage(message);\n onMessageRef.current?.(message);\n },\n });\n reconnectRef.current = controller.reconnect;\n\n return () => {\n controller.close();\n reconnectRef.current = null;\n };\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [url, enabled]);\n\n return {\n status,\n lastMessage,\n reconnect: () => reconnectRef.current?.(),\n };\n}\n"],"mappings":";;;AAoCA,SAAgB,EACZ,GACA,IAAoC,CAAC,GACd;CACvB,IAAM,EAAE,aAAU,IAAM,cAAW,GAAG,MAAS,GACzC,CAAC,GAAQ,KAAa,EAA4B,MAAM,GACxD,CAAC,GAAa,KAAkB,EAAuC,IAAI,GAC3E,IAAe,EAA4B,IAAI,GAE/C,IAAe,EAAO,CAAS;CA4BrC,OA3BA,QAAgB;EACZ,EAAa,UAAU;CAC3B,GAAG,CAAC,CAAS,CAAC,GAEd,QAAgB;EACZ,IAAI,CAAC,KAAW,CAAC,GAAK;GAClB,EAAU,MAAM;GAChB;EACJ;EAEA,IAAM,IAAa,EAAqB,GAAK;GACzC,GAAG;GACH,gBAAgB;GAChB,YAAY,MAAY;IAEpB,AADA,EAAe,CAAO,GACtB,EAAa,UAAU,CAAO;GAClC;EACJ,CAAC;EAGD,OAFA,EAAa,UAAU,EAAW,iBAErB;GAET,AADA,EAAW,MAAM,GACjB,EAAa,UAAU;EAC3B;CAEJ,GAAG,CAAC,GAAK,CAAO,CAAC,GAEV;EACH;EACA;EACA,iBAAiB,EAAa,UAAU;CAC5C;AACJ"}
|