tempest-react-sdk 0.24.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 +25 -4
- 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/AreaChart.cjs +1 -1
- package/dist/charts/AreaChart.cjs.map +1 -1
- package/dist/charts/AreaChart.js +7 -7
- package/dist/charts/AreaChart.js.map +1 -1
- package/dist/charts/BarChart.cjs +1 -1
- package/dist/charts/BarChart.cjs.map +1 -1
- package/dist/charts/BarChart.js +7 -7
- package/dist/charts/BarChart.js.map +1 -1
- package/dist/charts/LineChart.cjs +1 -1
- package/dist/charts/LineChart.cjs.map +1 -1
- package/dist/charts/LineChart.js +6 -6
- package/dist/charts/LineChart.js.map +1 -1
- package/dist/charts/PieChart.cjs +1 -1
- package/dist/charts/PieChart.cjs.map +1 -1
- package/dist/charts/PieChart.js +6 -6
- package/dist/charts/PieChart.js.map +1 -1
- package/dist/charts/RadarChart.cjs +1 -1
- package/dist/charts/RadarChart.cjs.map +1 -1
- package/dist/charts/RadarChart.js +6 -6
- package/dist/charts/RadarChart.js.map +1 -1
- package/dist/charts/palette.cjs +1 -1
- package/dist/charts/palette.cjs.map +1 -1
- package/dist/charts/palette.js +19 -2
- package/dist/charts/palette.js.map +1 -1
- package/dist/charts/use-chart-colors.cjs +2 -0
- package/dist/charts/use-chart-colors.cjs.map +1 -0
- package/dist/charts/use-chart-colors.js +29 -0
- package/dist/charts/use-chart-colors.js.map +1 -0
- package/dist/charts.cjs +1 -1
- package/dist/charts.d.ts +61 -10
- package/dist/charts.js +8 -7
- package/dist/components/AvatarGroup/AvatarGroup.cjs +2 -0
- package/dist/components/AvatarGroup/AvatarGroup.cjs.map +1 -0
- package/dist/components/AvatarGroup/AvatarGroup.js +39 -0
- package/dist/components/AvatarGroup/AvatarGroup.js.map +1 -0
- package/dist/components/AvatarGroup/AvatarGroup.module.cjs +2 -0
- package/dist/components/AvatarGroup/AvatarGroup.module.cjs.map +1 -0
- package/dist/components/AvatarGroup/AvatarGroup.module.js +16 -0
- package/dist/components/AvatarGroup/AvatarGroup.module.js.map +1 -0
- 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/Lightbox/Lightbox.cjs +2 -0
- package/dist/components/Lightbox/Lightbox.cjs.map +1 -0
- package/dist/components/Lightbox/Lightbox.js +148 -0
- package/dist/components/Lightbox/Lightbox.js.map +1 -0
- package/dist/components/Lightbox/Lightbox.module.cjs +2 -0
- package/dist/components/Lightbox/Lightbox.module.cjs.map +1 -0
- package/dist/components/Lightbox/Lightbox.module.js +21 -0
- package/dist/components/Lightbox/Lightbox.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/SignaturePad/SignaturePad.cjs +2 -0
- package/dist/components/SignaturePad/SignaturePad.cjs.map +1 -0
- package/dist/components/SignaturePad/SignaturePad.js +115 -0
- package/dist/components/SignaturePad/SignaturePad.js.map +1 -0
- package/dist/components/SignaturePad/SignaturePad.module.cjs +2 -0
- package/dist/components/SignaturePad/SignaturePad.module.cjs.map +1 -0
- package/dist/components/SignaturePad/SignaturePad.module.js +11 -0
- package/dist/components/SignaturePad/SignaturePad.module.js.map +1 -0
- package/dist/components/Stepper/Stepper.cjs +1 -1
- package/dist/components/Stepper/Stepper.cjs.map +1 -1
- package/dist/components/Stepper/Stepper.js +43 -19
- package/dist/components/Stepper/Stepper.js.map +1 -1
- package/dist/components/Stepper/Stepper.module.cjs +1 -1
- package/dist/components/Stepper/Stepper.module.cjs.map +1 -1
- package/dist/components/Stepper/Stepper.module.js +6 -3
- package/dist/components/Stepper/Stepper.module.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/TreeView/TreeView.cjs +2 -0
- package/dist/components/TreeView/TreeView.cjs.map +1 -0
- package/dist/components/TreeView/TreeView.js +124 -0
- package/dist/components/TreeView/TreeView.js.map +1 -0
- package/dist/components/TreeView/TreeView.module.cjs +2 -0
- package/dist/components/TreeView/TreeView.module.cjs.map +1 -0
- package/dist/components/TreeView/TreeView.module.js +17 -0
- package/dist/components/TreeView/TreeView.module.js.map +1 -0
- 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 +2 -0
- package/dist/components/Wizard/Wizard.cjs.map +1 -0
- package/dist/components/Wizard/Wizard.js +111 -0
- package/dist/components/Wizard/Wizard.js.map +1 -0
- package/dist/components/Wizard/Wizard.module.cjs +2 -0
- package/dist/components/Wizard/Wizard.module.cjs.map +1 -0
- package/dist/components/Wizard/Wizard.module.js +10 -0
- package/dist/components/Wizard/Wizard.module.js.map +1 -0
- 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/create-offline-sync.cjs +1 -1
- package/dist/offline/create-offline-sync.cjs.map +1 -1
- package/dist/offline/create-offline-sync.js +8 -2
- package/dist/offline/create-offline-sync.js.map +1 -1
- 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 +1187 -2
- package/dist/tempest-react-sdk.js +261 -246
- 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/apply-theme.cjs +2 -0
- package/dist/theme/apply-theme.cjs.map +1 -0
- package/dist/theme/apply-theme.js +24 -0
- package/dist/theme/apply-theme.js.map +1 -0
- package/dist/theme/color.cjs +2 -0
- package/dist/theme/color.cjs.map +1 -0
- package/dist/theme/color.js +161 -0
- package/dist/theme/color.js.map +1 -0
- package/dist/theme/create-theme.cjs +5 -0
- package/dist/theme/create-theme.cjs.map +1 -0
- package/dist/theme/create-theme.js +141 -0
- package/dist/theme/create-theme.js.map +1 -0
- package/dist/theme/theme-presets.cjs +2 -0
- package/dist/theme/theme-presets.cjs.map +1 -0
- package/dist/theme/theme-presets.js +82 -0
- package/dist/theme/theme-presets.js.map +1 -0
- package/dist/utilities.css +432 -0
- 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 +14 -4
- 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
|
-
const e=require("../utils/ids.cjs"),t=require("./create-offline-store.cjs");function n(e){let t=typeof localStorage<`u`;return{get:()=>t?localStorage.getItem(e):null,set:n=>{t&&localStorage.setItem(e,n)},clear:()=>{t&&localStorage.removeItem(e)}}}function r(r){let i=t.createOfflineStore({databaseName:r.databaseName,version:r.version??1,tableName:r.tableName??`outbox`,indexes:`&id, recordId, enqueuedAt`,keyPath:`id`}),a=`get`in r.watermark?r.watermark:n(r.watermark.storageKey),o=r.idPrefix??`outbox`,s=r.isOnline??(()=>typeof navigator<`u`?navigator.onLine:!0),c=null,l=new Set,u={phase:`idle`,pending:0,lastSummary:null,lastError:null,lastSyncedAt:null},d=r.crossTab===!0,f=r.broadcastChannelName??`tempest-sync:${r.databaseName}`,p=d&&typeof BroadcastChannel<`u`?new BroadcastChannel(f):null,m=!1;function h(){for(let e of l)e(u)}function g(e){u={...u,...e},h(),p&&!m&&p.postMessage(u)}p&&(p.onmessage=e=>{m||(u=e.data,h())});async function _(){g({pending:await i.count()})}async function v(e){let t=await i.list(void 0,{orderBy:`enqueuedAt`});for(let n of t)try{await r.deliver(n),await i.delete(n.id),await r.onEntryDelivered?.(n),e.succeeded+=1}catch(t){let a=t instanceof Error?t.message:`delivery failed`;await i.update(n.id,{attempts:n.attempts+1,lastError:a}),await r.onEntryFailed?.(n,t),e.failed+=1,e.lastError=a}}async function y(){let e=a.get(),t=null,n;do{let i=await r.pullPage(e,t);for(let e of i.items)await r.applyRemote(e);t=i.nextCursor,n=i.serverTime}while(t);n&&a.set(n)}async function b(e){let t=Date.now(),n={trigger:e,succeeded:0,failed:0,durationMs:0,skipped:!1,lastError:null};return s()?(await v(n),await y(),n.durationMs=Date.now()-t,n):(n.skipped=!0,n.durationMs=Date.now()-t,n)}async function x(e){let t=typeof navigator<`u`?navigator.locks:void 0;return!d||!t?b(e):await t.request(`${f}:flush`,{ifAvailable:!0},async t=>t?b(e):null)??{trigger:e,succeeded:0,failed:0,durationMs:0,skipped:!1,lastError:null}}
|
|
1
|
+
const e=require("../utils/ids.cjs"),t=require("./create-offline-store.cjs");function n(e){let t=typeof localStorage<`u`;return{get:()=>t?localStorage.getItem(e):null,set:n=>{t&&localStorage.setItem(e,n)},clear:()=>{t&&localStorage.removeItem(e)}}}function r(r){let i=t.createOfflineStore({databaseName:r.databaseName,version:r.version??1,tableName:r.tableName??`outbox`,indexes:`&id, recordId, enqueuedAt`,keyPath:`id`}),a=`get`in r.watermark?r.watermark:n(r.watermark.storageKey),o=r.idPrefix??`outbox`,s=r.isOnline??(()=>typeof navigator<`u`?navigator.onLine:!0),c=null,l=new Set,u={phase:`idle`,pending:0,lastSummary:null,lastError:null,lastSyncedAt:null},d=r.crossTab===!0,f=r.broadcastChannelName??`tempest-sync:${r.databaseName}`,p=d&&typeof BroadcastChannel<`u`?new BroadcastChannel(f):null,m=!1;function h(){for(let e of l)e(u)}function g(e){u={...u,...e},h(),p&&!m&&p.postMessage(u)}p&&(p.onmessage=e=>{m||(u=e.data,h())});async function _(){g({pending:await i.count()})}async function v(e){let t=await i.list(void 0,{orderBy:`enqueuedAt`});for(let n of t)try{await r.deliver(n),await i.delete(n.id),await r.onEntryDelivered?.(n),e.succeeded+=1}catch(t){let a=t instanceof Error?t.message:`delivery failed`;await i.update(n.id,{attempts:n.attempts+1,lastError:a}),await r.onEntryFailed?.(n,t),e.failed+=1,e.lastError=a}}async function y(){let e=a.get(),t=null,n;do{let i=await r.pullPage(e,t);for(let e of i.items)await r.applyRemote(e);t=i.nextCursor,n=i.serverTime}while(t);n&&a.set(n)}async function b(e){let t=Date.now(),n={trigger:e,succeeded:0,failed:0,durationMs:0,skipped:!1,lastError:null};return s()?(await v(n),await y(),n.durationMs=Date.now()-t,n):(n.skipped=!0,n.durationMs=Date.now()-t,n)}async function x(e){let t=typeof navigator<`u`?navigator.locks:void 0;return!d||!t?b(e):await t.request(`${f}:flush`,{ifAvailable:!0},async t=>t?b(e):null)??{trigger:e,succeeded:0,failed:0,durationMs:0,skipped:!1,lastError:null}}_();let S=0;function C(){let e=Date.now();return S=e>S?e:S+1,S}return{async enqueue(t,n,r){let a={id:e.randomId(o),op:t,recordId:n,enqueuedAt:C(),attempts:0,payload:r};return await i.put(a),await _(),a.id},flush(e=`manual`){return c||=(g({phase:`syncing`}),x(e).then(async e=>(await _(),g({phase:e.skipped?`offline`:e.failed>0?`error`:`idle`,lastSummary:e,lastError:e.lastError,lastSyncedAt:e.skipped?u.lastSyncedAt:Date.now()}),e)).finally(()=>{c=null})),c},pendingCount(){return i.count()},listPending(){return i.list(void 0,{orderBy:`enqueuedAt`})},async clearOutbox(){await i.clear(),await _()},resetWatermark(){a.clear()},getState(){return u},subscribe(e){return l.add(e),()=>{l.delete(e)}},dispose(){m=!0,p?.close()}}}exports.createOfflineSync=r;
|
|
2
2
|
//# sourceMappingURL=create-offline-sync.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"create-offline-sync.cjs","names":[],"sources":["../../src/offline/create-offline-sync.ts"],"sourcesContent":["import { randomId } from \"../utils/ids\";\nimport { createOfflineStore } from \"./create-offline-store\";\n\n/**\n * Mutation kinds queued in the outbox.\n *\n * `create`/`update` carry a snapshot of the record; `delete` needs only the\n * record id. The distinction between `create` and `update` is advisory — the\n * engine treats both as \"deliver this record\" and leaves the create-vs-update\n * decision to the app's `deliver` callback (a `PUT` upsert usually ignores it).\n */\nexport type OutboxOp = \"create\" | \"update\" | \"delete\";\n\n/**\n * A single queued mutation.\n *\n * @typeParam TPayload - The record snapshot shape carried by\n * `create`/`update` entries (omitted for `delete`).\n */\nexport interface OutboxEntry<TPayload = unknown> {\n /** Stable per-entry id (generated with {@link randomId}). */\n id: string;\n /** The mutation kind. */\n op: OutboxOp;\n /** Primary key of the record the mutation targets. */\n recordId: string;\n /** Epoch milliseconds when the mutation was queued. */\n enqueuedAt: number;\n /** How many delivery attempts have been made so far. */\n attempts: number;\n /** Last delivery error message, kept for UI/debug. */\n lastError?: string;\n /** Record snapshot for `create`/`update`. Omitted for `delete`. */\n payload?: TPayload;\n}\n\n/**\n * Why a sync run was triggered. The listed values are the common ones; any\n * string is accepted so apps can add their own telemetry labels.\n */\nexport type SyncTrigger =\n \"boot\" | \"online-event\" | \"after-mutation\" | \"manual\" | \"interval\" | (string & {});\n\n/**\n * One page of the server delta pull.\n *\n * @typeParam TRemote - The server-side item shape.\n */\nexport interface PullPage<TRemote> {\n /** Items changed since the watermark, in this page. */\n items: TRemote[];\n /** Cursor for the next page, or `null` when this is the last page. */\n nextCursor: string | null;\n /**\n * Server clock to persist as the next watermark once the whole delta is\n * applied. `null` leaves the watermark unchanged.\n */\n serverTime: string | null;\n}\n\n/** Outcome of a single {@link OfflineSync.flush} run. */\nexport interface SyncRunSummary {\n /** The trigger passed to `flush`. */\n trigger: SyncTrigger;\n /** Entries delivered to the server this run. */\n succeeded: number;\n /** Entries that failed and stay queued for the next run. */\n failed: number;\n /** Total wall-clock milliseconds the run took. */\n durationMs: number;\n /** `true` when the run was skipped because the device was offline. */\n skipped: boolean;\n /** Last delivery error message seen this run, or `null` when none failed. */\n lastError: string | null;\n}\n\n/**\n * Coarse lifecycle phase of the sync engine, surfaced through\n * {@link OfflineSync.getState} / {@link OfflineSync.subscribe} for reactive UI.\n *\n * - `\"idle\"` — nothing in flight and the last run (if any) fully succeeded.\n * - `\"syncing\"` — a `flush` run is currently in progress.\n * - `\"offline\"` — the last run was skipped because the device was offline.\n * - `\"error\"` — the last run left at least one entry queued after a failure.\n */\nexport type SyncPhase = \"idle\" | \"syncing\" | \"offline\" | \"error\";\n\n/**\n * Immutable snapshot of the engine's reactive state. A fresh object is emitted\n * to subscribers on every change, so it is safe to use as a\n * `useSyncExternalStore` snapshot (reference equality signals \"no change\").\n */\nexport interface SyncState {\n /** Current lifecycle phase. */\n phase: SyncPhase;\n /** Number of mutations still queued in the outbox. */\n pending: number;\n /** Summary of the most recent `flush` run, or `null` before the first. */\n lastSummary: SyncRunSummary | null;\n /** Message of the most recent delivery failure, or `null`. */\n lastError: string | null;\n /** Epoch ms of the last non-skipped run, or `null` before the first. */\n lastSyncedAt: number | null;\n}\n\n/**\n * Pluggable persistence for the pull watermark (the \"changed since\" cursor).\n * Pass an object with a `storageKey` to use a `localStorage`-backed default.\n */\nexport interface WatermarkStore {\n /** Read the current watermark, or `null` when none is stored. */\n get: () => string | null;\n /** Persist a new watermark. */\n set: (value: string) => void;\n /** Drop the watermark (e.g. on logout / account switch). */\n clear: () => void;\n}\n\n/**\n * Configuration for {@link createOfflineSync}.\n *\n * The engine owns the outbox, the single-flight flush, the offline guard, the\n * paginated pull loop and the watermark; the three transport callbacks\n * (`deliver`, `pullPage`, `applyRemote`) are where the app plugs in its own\n * endpoints, record shape and conflict resolution.\n *\n * @typeParam TPayload - Record snapshot carried by outbox entries.\n * @typeParam TRemote - Server item shape returned by `pullPage`.\n */\nexport interface OfflineSyncConfig<TPayload, TRemote> {\n /** IndexedDB database name for the outbox (kept separate per queue). */\n databaseName: string;\n /** Outbox object-store name. Default `\"outbox\"`. */\n tableName?: string;\n /** Outbox schema version. Default `1`. */\n version?: number;\n /** Prefix for generated entry ids. Default `\"outbox\"`. */\n idPrefix?: string;\n /**\n * Deliver one queued mutation to the server. Throwing keeps the entry\n * queued (its `attempts`/`lastError` are bumped) for the next run.\n */\n deliver: (entry: OutboxEntry<TPayload>) => Promise<void>;\n /** Fetch one page of the server delta since `since`, from `cursor`. */\n pullPage: (since: string | null, cursor: string | null) => Promise<PullPage<TRemote>>;\n /**\n * Merge one pulled item into the local store. The app owns conflict\n * resolution here (e.g. last-write-wins, keeping newer local pending\n * edits, resolving tombstones and downloading blobs).\n */\n applyRemote: (item: TRemote) => Promise<void>;\n /** Watermark persistence, or `{ storageKey }` for a `localStorage` default. */\n watermark: WatermarkStore | { storageKey: string };\n /** Called after an entry is delivered and acked. */\n onEntryDelivered?: (entry: OutboxEntry<TPayload>) => void | Promise<void>;\n /** Called after an entry fails delivery (it stays queued). */\n onEntryFailed?: (entry: OutboxEntry<TPayload>, error: unknown) => void | Promise<void>;\n /**\n * Connectivity check. Default reads `navigator.onLine` (always online in\n * non-browser environments). When it returns `false`, `flush` is skipped.\n */\n isOnline?: () => boolean;\n /**\n * Broadcast {@link SyncState} across browser tabs of the same origin via a\n * `BroadcastChannel`, so every tab shows a coherent pending count / phase\n * (e.g. one tab flushing drops the badge to zero everywhere). The outbox is\n * already a shared IndexedDB; this only shares the in-memory state. Silently\n * ignored where `BroadcastChannel` is unavailable. Default `false`.\n *\n * When the Web Locks API is available, `flush` is additionally coordinated\n * *across* tabs: only one tab runs at a time and others skip while the lock\n * is held (they pick up the result via the broadcast). Delivery should still\n * be idempotent (upsert by client id). Without Web Locks, `flush` falls back\n * to per-tab single-flight.\n */\n crossTab?: boolean;\n /** Channel name when `crossTab` is on. Default `tempest-sync:${databaseName}`. */\n broadcastChannelName?: string;\n}\n\n/**\n * Offline-first sync engine: a durable outbox plus a paginated delta pull.\n *\n * @typeParam TPayload - Record snapshot carried by outbox entries.\n */\nexport interface OfflineSync<TPayload> {\n /**\n * Queue a mutation. Returns the generated entry id.\n *\n * @param op - The mutation kind.\n * @param recordId - Primary key of the affected record.\n * @param payload - Record snapshot (for `create`/`update`).\n */\n enqueue: (op: OutboxOp, recordId: string, payload?: TPayload) => Promise<string>;\n /**\n * Run a full sync (drain the outbox, then pull the delta). Concurrent\n * calls share one in-flight promise, so triggers never overlap.\n *\n * @param trigger - Label for why the run happened. Default `\"manual\"`.\n */\n flush: (trigger?: SyncTrigger) => Promise<SyncRunSummary>;\n /** Number of mutations still queued. */\n pendingCount: () => Promise<number>;\n /** The queued mutations in FIFO order. */\n listPending: () => Promise<OutboxEntry<TPayload>[]>;\n /** Drop every queued mutation (e.g. on logout). */\n clearOutbox: () => Promise<void>;\n /** Reset the pull watermark (e.g. on logout / account switch). */\n resetWatermark: () => void;\n /** Read the current reactive {@link SyncState} snapshot synchronously. */\n getState: () => SyncState;\n /**\n * Subscribe to {@link SyncState} changes. The listener fires on every\n * enqueue, flush transition and outbox clear.\n *\n * @param listener - Called with the new snapshot on each change.\n * @returns An unsubscribe function.\n */\n subscribe: (listener: (state: SyncState) => void) => () => void;\n /**\n * Release resources held by the engine — currently the cross-tab\n * `BroadcastChannel` when `crossTab` is enabled. Safe to call when none was\n * opened. Optional in long-lived apps (the channel is reclaimed on tab\n * close); call it in tests and on teardown.\n */\n dispose: () => void;\n}\n\n/**\n * Build a `localStorage`-backed {@link WatermarkStore}. Reads/writes are no-ops\n * when `localStorage` is unavailable (SSR / non-browser).\n *\n * @param key - The `localStorage` key.\n * @returns A watermark store persisting to `localStorage`.\n */\nfunction localStorageWatermark(key: string): WatermarkStore {\n const available = typeof localStorage !== \"undefined\";\n return {\n get: () => (available ? localStorage.getItem(key) : null),\n set: (value: string) => {\n if (available) localStorage.setItem(key, value);\n },\n clear: () => {\n if (available) localStorage.removeItem(key);\n },\n };\n}\n\n/**\n * Create an offline-first sync engine over an IndexedDB outbox.\n *\n * The engine drains queued mutations to the server (`deliver`) and pulls the\n * server delta back (`pullPage` + `applyRemote`), advancing a watermark so each\n * run only fetches what changed. `flush` is single-flight and skips cleanly\n * while offline; failed deliveries stay queued with their attempt count bumped.\n *\n * Dexie is an **optional peer dependency** (via {@link createOfflineStore}) —\n * install it (`npm i dexie`) when you use this engine.\n *\n * @typeParam TPayload - Record snapshot carried by outbox entries.\n * @typeParam TRemote - Server item shape returned by `pullPage`.\n * @param config - Transport callbacks + outbox/watermark configuration.\n * @returns The sync handle (`enqueue`, `flush`, `pendingCount`, …).\n *\n * @example\n * const sync = createOfflineSync<Note, NoteDto>({\n * databaseName: \"NotesOutbox\",\n * watermark: { storageKey: \"notes.watermark\" },\n * deliver: async (entry) => {\n * if (entry.op === \"delete\") return api.remove(entry.recordId);\n * await api.upsert(entry.recordId, entry.payload!);\n * },\n * pullPage: async (since, cursor) => {\n * const page = await api.changes(since, cursor);\n * return { items: page.items, nextCursor: page.next, serverTime: page.now };\n * },\n * applyRemote: async (dto) => {\n * if (dto.deleted) return localStore.remove(dto.id);\n * await localStore.save(fromDto(dto));\n * },\n * });\n * await sync.enqueue(\"create\", note.id, note);\n * await sync.flush(\"after-mutation\");\n */\nexport function createOfflineSync<TPayload = unknown, TRemote = unknown>(\n config: OfflineSyncConfig<TPayload, TRemote>,\n): OfflineSync<TPayload> {\n const outbox = createOfflineStore<OutboxEntry<TPayload>, string>({\n databaseName: config.databaseName,\n version: config.version ?? 1,\n tableName: config.tableName ?? \"outbox\",\n indexes: \"&id, recordId, enqueuedAt\",\n keyPath: \"id\",\n });\n\n const watermark: WatermarkStore =\n \"get\" in config.watermark\n ? config.watermark\n : localStorageWatermark(config.watermark.storageKey);\n\n const idPrefix = config.idPrefix ?? \"outbox\";\n const isOnline =\n config.isOnline ?? (() => (typeof navigator !== \"undefined\" ? navigator.onLine : true));\n\n let inflight: Promise<SyncRunSummary> | null = null;\n\n const listeners = new Set<(state: SyncState) => void>();\n let state: SyncState = {\n phase: \"idle\",\n pending: 0,\n lastSummary: null,\n lastError: null,\n lastSyncedAt: null,\n };\n\n const crossTab = config.crossTab === true;\n const channelName = config.broadcastChannelName ?? `tempest-sync:${config.databaseName}`;\n const channel: BroadcastChannel | null =\n crossTab && typeof BroadcastChannel !== \"undefined\"\n ? new BroadcastChannel(channelName)\n : null;\n let closed = false;\n\n function notify(): void {\n for (const listener of listeners) listener(state);\n }\n\n function setState(patch: Partial<SyncState>): void {\n state = { ...state, ...patch };\n notify();\n if (channel && !closed) channel.postMessage(state);\n }\n\n if (channel) {\n channel.onmessage = (event: MessageEvent<SyncState>) => {\n if (closed) return;\n state = event.data;\n notify();\n };\n }\n\n async function refreshPending(): Promise<void> {\n setState({ pending: await outbox.count() });\n }\n\n async function push(summary: SyncRunSummary): Promise<void> {\n const entries = await outbox.list(undefined, { orderBy: \"enqueuedAt\" });\n for (const entry of entries) {\n try {\n await config.deliver(entry);\n await outbox.delete(entry.id);\n await config.onEntryDelivered?.(entry);\n summary.succeeded += 1;\n } catch (cause) {\n const message = cause instanceof Error ? cause.message : \"delivery failed\";\n await outbox.update(entry.id, {\n attempts: entry.attempts + 1,\n lastError: message,\n } as Partial<OutboxEntry<TPayload>>);\n await config.onEntryFailed?.(entry, cause);\n summary.failed += 1;\n summary.lastError = message;\n }\n }\n }\n\n async function pull(): Promise<void> {\n const since = watermark.get();\n let cursor: string | null = null;\n let serverTime: string | null;\n do {\n const page = await config.pullPage(since, cursor);\n for (const item of page.items) {\n await config.applyRemote(item);\n }\n cursor = page.nextCursor;\n serverTime = page.serverTime;\n } while (cursor);\n if (serverTime) watermark.set(serverTime);\n }\n\n async function runOnce(trigger: SyncTrigger): Promise<SyncRunSummary> {\n const startedAt = Date.now();\n const summary: SyncRunSummary = {\n trigger,\n succeeded: 0,\n failed: 0,\n durationMs: 0,\n skipped: false,\n lastError: null,\n };\n if (!isOnline()) {\n summary.skipped = true;\n summary.durationMs = Date.now() - startedAt;\n return summary;\n }\n await push(summary);\n await pull();\n summary.durationMs = Date.now() - startedAt;\n return summary;\n }\n\n /**\n * Run one sync pass, serialized across tabs when possible.\n *\n * With `crossTab` on and the Web Locks API available, the pass is wrapped in\n * an `ifAvailable` lock request: whichever tab holds the lock runs, and the\n * others get `null` back instead of duplicating the work — their `SyncState`\n * catches up through the `BroadcastChannel`. The no-op summary keeps\n * `skipped: false` on purpose: `skipped` means \"device offline\" (it maps to\n * `phase: \"offline\"`), which is not what happened here. Falls back to a plain\n * per-tab run when `crossTab` is off or Web Locks is missing.\n *\n * @param trigger - What asked for this run, carried into the summary.\n * @returns The run summary, or an empty summary when another tab held the lock.\n */\n async function runGuarded(trigger: SyncTrigger): Promise<SyncRunSummary> {\n const locks = typeof navigator !== \"undefined\" ? navigator.locks : undefined;\n if (!crossTab || !locks) return runOnce(trigger);\n const result = await locks.request(\n `${channelName}:flush`,\n { ifAvailable: true },\n async (lock) => (lock ? runOnce(trigger) : null),\n );\n return (\n result ?? {\n trigger,\n succeeded: 0,\n failed: 0,\n durationMs: 0,\n skipped: false,\n lastError: null,\n }\n );\n }\n\n void refreshPending();\n\n return {\n async enqueue(op, recordId, payload) {\n const entry: OutboxEntry<TPayload> = {\n id: randomId(idPrefix),\n op,\n recordId,\n enqueuedAt: Date.now(),\n attempts: 0,\n payload,\n };\n await outbox.put(entry);\n await refreshPending();\n return entry.id;\n },\n flush(trigger: SyncTrigger = \"manual\") {\n if (!inflight) {\n setState({ phase: \"syncing\" });\n inflight = runGuarded(trigger)\n .then(async (summary) => {\n await refreshPending();\n setState({\n phase: summary.skipped\n ? \"offline\"\n : summary.failed > 0\n ? \"error\"\n : \"idle\",\n lastSummary: summary,\n lastError: summary.lastError,\n lastSyncedAt: summary.skipped ? state.lastSyncedAt : Date.now(),\n });\n return summary;\n })\n .finally(() => {\n inflight = null;\n });\n }\n return inflight;\n },\n pendingCount() {\n return outbox.count();\n },\n listPending() {\n return outbox.list(undefined, { orderBy: \"enqueuedAt\" });\n },\n async clearOutbox() {\n await outbox.clear();\n await refreshPending();\n },\n resetWatermark() {\n watermark.clear();\n },\n getState() {\n return state;\n },\n subscribe(listener) {\n listeners.add(listener);\n return () => {\n listeners.delete(listener);\n };\n },\n dispose() {\n closed = true;\n channel?.close();\n },\n };\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"create-offline-sync.cjs","names":[],"sources":["../../src/offline/create-offline-sync.ts"],"sourcesContent":["import { randomId } from \"../utils/ids\";\nimport { createOfflineStore } from \"./create-offline-store\";\n\n/**\n * Mutation kinds queued in the outbox.\n *\n * `create`/`update` carry a snapshot of the record; `delete` needs only the\n * record id. The distinction between `create` and `update` is advisory — the\n * engine treats both as \"deliver this record\" and leaves the create-vs-update\n * decision to the app's `deliver` callback (a `PUT` upsert usually ignores it).\n */\nexport type OutboxOp = \"create\" | \"update\" | \"delete\";\n\n/**\n * A single queued mutation.\n *\n * @typeParam TPayload - The record snapshot shape carried by\n * `create`/`update` entries (omitted for `delete`).\n */\nexport interface OutboxEntry<TPayload = unknown> {\n /** Stable per-entry id (generated with {@link randomId}). */\n id: string;\n /** The mutation kind. */\n op: OutboxOp;\n /** Primary key of the record the mutation targets. */\n recordId: string;\n /**\n * Epoch milliseconds when the mutation was queued, and the FIFO sort key for\n * `listPending()` and the delivery loop. Strictly increasing per engine\n * instance: entries queued inside the same millisecond are spaced by 1ms so\n * the order never depends on how the index breaks a tie.\n */\n enqueuedAt: number;\n /** How many delivery attempts have been made so far. */\n attempts: number;\n /** Last delivery error message, kept for UI/debug. */\n lastError?: string;\n /** Record snapshot for `create`/`update`. Omitted for `delete`. */\n payload?: TPayload;\n}\n\n/**\n * Why a sync run was triggered. The listed values are the common ones; any\n * string is accepted so apps can add their own telemetry labels.\n */\nexport type SyncTrigger =\n \"boot\" | \"online-event\" | \"after-mutation\" | \"manual\" | \"interval\" | (string & {});\n\n/**\n * One page of the server delta pull.\n *\n * @typeParam TRemote - The server-side item shape.\n */\nexport interface PullPage<TRemote> {\n /** Items changed since the watermark, in this page. */\n items: TRemote[];\n /** Cursor for the next page, or `null` when this is the last page. */\n nextCursor: string | null;\n /**\n * Server clock to persist as the next watermark once the whole delta is\n * applied. `null` leaves the watermark unchanged.\n */\n serverTime: string | null;\n}\n\n/** Outcome of a single {@link OfflineSync.flush} run. */\nexport interface SyncRunSummary {\n /** The trigger passed to `flush`. */\n trigger: SyncTrigger;\n /** Entries delivered to the server this run. */\n succeeded: number;\n /** Entries that failed and stay queued for the next run. */\n failed: number;\n /** Total wall-clock milliseconds the run took. */\n durationMs: number;\n /** `true` when the run was skipped because the device was offline. */\n skipped: boolean;\n /** Last delivery error message seen this run, or `null` when none failed. */\n lastError: string | null;\n}\n\n/**\n * Coarse lifecycle phase of the sync engine, surfaced through\n * {@link OfflineSync.getState} / {@link OfflineSync.subscribe} for reactive UI.\n *\n * - `\"idle\"` — nothing in flight and the last run (if any) fully succeeded.\n * - `\"syncing\"` — a `flush` run is currently in progress.\n * - `\"offline\"` — the last run was skipped because the device was offline.\n * - `\"error\"` — the last run left at least one entry queued after a failure.\n */\nexport type SyncPhase = \"idle\" | \"syncing\" | \"offline\" | \"error\";\n\n/**\n * Immutable snapshot of the engine's reactive state. A fresh object is emitted\n * to subscribers on every change, so it is safe to use as a\n * `useSyncExternalStore` snapshot (reference equality signals \"no change\").\n */\nexport interface SyncState {\n /** Current lifecycle phase. */\n phase: SyncPhase;\n /** Number of mutations still queued in the outbox. */\n pending: number;\n /** Summary of the most recent `flush` run, or `null` before the first. */\n lastSummary: SyncRunSummary | null;\n /** Message of the most recent delivery failure, or `null`. */\n lastError: string | null;\n /** Epoch ms of the last non-skipped run, or `null` before the first. */\n lastSyncedAt: number | null;\n}\n\n/**\n * Pluggable persistence for the pull watermark (the \"changed since\" cursor).\n * Pass an object with a `storageKey` to use a `localStorage`-backed default.\n */\nexport interface WatermarkStore {\n /** Read the current watermark, or `null` when none is stored. */\n get: () => string | null;\n /** Persist a new watermark. */\n set: (value: string) => void;\n /** Drop the watermark (e.g. on logout / account switch). */\n clear: () => void;\n}\n\n/**\n * Configuration for {@link createOfflineSync}.\n *\n * The engine owns the outbox, the single-flight flush, the offline guard, the\n * paginated pull loop and the watermark; the three transport callbacks\n * (`deliver`, `pullPage`, `applyRemote`) are where the app plugs in its own\n * endpoints, record shape and conflict resolution.\n *\n * @typeParam TPayload - Record snapshot carried by outbox entries.\n * @typeParam TRemote - Server item shape returned by `pullPage`.\n */\nexport interface OfflineSyncConfig<TPayload, TRemote> {\n /** IndexedDB database name for the outbox (kept separate per queue). */\n databaseName: string;\n /** Outbox object-store name. Default `\"outbox\"`. */\n tableName?: string;\n /** Outbox schema version. Default `1`. */\n version?: number;\n /** Prefix for generated entry ids. Default `\"outbox\"`. */\n idPrefix?: string;\n /**\n * Deliver one queued mutation to the server. Throwing keeps the entry\n * queued (its `attempts`/`lastError` are bumped) for the next run.\n */\n deliver: (entry: OutboxEntry<TPayload>) => Promise<void>;\n /** Fetch one page of the server delta since `since`, from `cursor`. */\n pullPage: (since: string | null, cursor: string | null) => Promise<PullPage<TRemote>>;\n /**\n * Merge one pulled item into the local store. The app owns conflict\n * resolution here (e.g. last-write-wins, keeping newer local pending\n * edits, resolving tombstones and downloading blobs).\n */\n applyRemote: (item: TRemote) => Promise<void>;\n /** Watermark persistence, or `{ storageKey }` for a `localStorage` default. */\n watermark: WatermarkStore | { storageKey: string };\n /** Called after an entry is delivered and acked. */\n onEntryDelivered?: (entry: OutboxEntry<TPayload>) => void | Promise<void>;\n /** Called after an entry fails delivery (it stays queued). */\n onEntryFailed?: (entry: OutboxEntry<TPayload>, error: unknown) => void | Promise<void>;\n /**\n * Connectivity check. Default reads `navigator.onLine` (always online in\n * non-browser environments). When it returns `false`, `flush` is skipped.\n */\n isOnline?: () => boolean;\n /**\n * Broadcast {@link SyncState} across browser tabs of the same origin via a\n * `BroadcastChannel`, so every tab shows a coherent pending count / phase\n * (e.g. one tab flushing drops the badge to zero everywhere). The outbox is\n * already a shared IndexedDB; this only shares the in-memory state. Silently\n * ignored where `BroadcastChannel` is unavailable. Default `false`.\n *\n * When the Web Locks API is available, `flush` is additionally coordinated\n * *across* tabs: only one tab runs at a time and others skip while the lock\n * is held (they pick up the result via the broadcast). Delivery should still\n * be idempotent (upsert by client id). Without Web Locks, `flush` falls back\n * to per-tab single-flight.\n */\n crossTab?: boolean;\n /** Channel name when `crossTab` is on. Default `tempest-sync:${databaseName}`. */\n broadcastChannelName?: string;\n}\n\n/**\n * Offline-first sync engine: a durable outbox plus a paginated delta pull.\n *\n * @typeParam TPayload - Record snapshot carried by outbox entries.\n */\nexport interface OfflineSync<TPayload> {\n /**\n * Queue a mutation. Returns the generated entry id.\n *\n * @param op - The mutation kind.\n * @param recordId - Primary key of the affected record.\n * @param payload - Record snapshot (for `create`/`update`).\n */\n enqueue: (op: OutboxOp, recordId: string, payload?: TPayload) => Promise<string>;\n /**\n * Run a full sync (drain the outbox, then pull the delta). Concurrent\n * calls share one in-flight promise, so triggers never overlap.\n *\n * @param trigger - Label for why the run happened. Default `\"manual\"`.\n */\n flush: (trigger?: SyncTrigger) => Promise<SyncRunSummary>;\n /** Number of mutations still queued. */\n pendingCount: () => Promise<number>;\n /** The queued mutations in FIFO order. */\n listPending: () => Promise<OutboxEntry<TPayload>[]>;\n /** Drop every queued mutation (e.g. on logout). */\n clearOutbox: () => Promise<void>;\n /** Reset the pull watermark (e.g. on logout / account switch). */\n resetWatermark: () => void;\n /** Read the current reactive {@link SyncState} snapshot synchronously. */\n getState: () => SyncState;\n /**\n * Subscribe to {@link SyncState} changes. The listener fires on every\n * enqueue, flush transition and outbox clear.\n *\n * @param listener - Called with the new snapshot on each change.\n * @returns An unsubscribe function.\n */\n subscribe: (listener: (state: SyncState) => void) => () => void;\n /**\n * Release resources held by the engine — currently the cross-tab\n * `BroadcastChannel` when `crossTab` is enabled. Safe to call when none was\n * opened. Optional in long-lived apps (the channel is reclaimed on tab\n * close); call it in tests and on teardown.\n */\n dispose: () => void;\n}\n\n/**\n * Build a `localStorage`-backed {@link WatermarkStore}. Reads/writes are no-ops\n * when `localStorage` is unavailable (SSR / non-browser).\n *\n * @param key - The `localStorage` key.\n * @returns A watermark store persisting to `localStorage`.\n */\nfunction localStorageWatermark(key: string): WatermarkStore {\n const available = typeof localStorage !== \"undefined\";\n return {\n get: () => (available ? localStorage.getItem(key) : null),\n set: (value: string) => {\n if (available) localStorage.setItem(key, value);\n },\n clear: () => {\n if (available) localStorage.removeItem(key);\n },\n };\n}\n\n/**\n * Create an offline-first sync engine over an IndexedDB outbox.\n *\n * The engine drains queued mutations to the server (`deliver`) and pulls the\n * server delta back (`pullPage` + `applyRemote`), advancing a watermark so each\n * run only fetches what changed. `flush` is single-flight and skips cleanly\n * while offline; failed deliveries stay queued with their attempt count bumped.\n *\n * Dexie is an **optional peer dependency** (via {@link createOfflineStore}) —\n * install it (`npm i dexie`) when you use this engine.\n *\n * @typeParam TPayload - Record snapshot carried by outbox entries.\n * @typeParam TRemote - Server item shape returned by `pullPage`.\n * @param config - Transport callbacks + outbox/watermark configuration.\n * @returns The sync handle (`enqueue`, `flush`, `pendingCount`, …).\n *\n * @example\n * const sync = createOfflineSync<Note, NoteDto>({\n * databaseName: \"NotesOutbox\",\n * watermark: { storageKey: \"notes.watermark\" },\n * deliver: async (entry) => {\n * if (entry.op === \"delete\") return api.remove(entry.recordId);\n * await api.upsert(entry.recordId, entry.payload!);\n * },\n * pullPage: async (since, cursor) => {\n * const page = await api.changes(since, cursor);\n * return { items: page.items, nextCursor: page.next, serverTime: page.now };\n * },\n * applyRemote: async (dto) => {\n * if (dto.deleted) return localStore.remove(dto.id);\n * await localStore.save(fromDto(dto));\n * },\n * });\n * await sync.enqueue(\"create\", note.id, note);\n * await sync.flush(\"after-mutation\");\n */\nexport function createOfflineSync<TPayload = unknown, TRemote = unknown>(\n config: OfflineSyncConfig<TPayload, TRemote>,\n): OfflineSync<TPayload> {\n const outbox = createOfflineStore<OutboxEntry<TPayload>, string>({\n databaseName: config.databaseName,\n version: config.version ?? 1,\n tableName: config.tableName ?? \"outbox\",\n indexes: \"&id, recordId, enqueuedAt\",\n keyPath: \"id\",\n });\n\n const watermark: WatermarkStore =\n \"get\" in config.watermark\n ? config.watermark\n : localStorageWatermark(config.watermark.storageKey);\n\n const idPrefix = config.idPrefix ?? \"outbox\";\n const isOnline =\n config.isOnline ?? (() => (typeof navigator !== \"undefined\" ? navigator.onLine : true));\n\n let inflight: Promise<SyncRunSummary> | null = null;\n\n const listeners = new Set<(state: SyncState) => void>();\n let state: SyncState = {\n phase: \"idle\",\n pending: 0,\n lastSummary: null,\n lastError: null,\n lastSyncedAt: null,\n };\n\n const crossTab = config.crossTab === true;\n const channelName = config.broadcastChannelName ?? `tempest-sync:${config.databaseName}`;\n const channel: BroadcastChannel | null =\n crossTab && typeof BroadcastChannel !== \"undefined\"\n ? new BroadcastChannel(channelName)\n : null;\n let closed = false;\n\n function notify(): void {\n for (const listener of listeners) listener(state);\n }\n\n function setState(patch: Partial<SyncState>): void {\n state = { ...state, ...patch };\n notify();\n if (channel && !closed) channel.postMessage(state);\n }\n\n if (channel) {\n channel.onmessage = (event: MessageEvent<SyncState>) => {\n if (closed) return;\n state = event.data;\n notify();\n };\n }\n\n async function refreshPending(): Promise<void> {\n setState({ pending: await outbox.count() });\n }\n\n async function push(summary: SyncRunSummary): Promise<void> {\n const entries = await outbox.list(undefined, { orderBy: \"enqueuedAt\" });\n for (const entry of entries) {\n try {\n await config.deliver(entry);\n await outbox.delete(entry.id);\n await config.onEntryDelivered?.(entry);\n summary.succeeded += 1;\n } catch (cause) {\n const message = cause instanceof Error ? cause.message : \"delivery failed\";\n await outbox.update(entry.id, {\n attempts: entry.attempts + 1,\n lastError: message,\n } as Partial<OutboxEntry<TPayload>>);\n await config.onEntryFailed?.(entry, cause);\n summary.failed += 1;\n summary.lastError = message;\n }\n }\n }\n\n async function pull(): Promise<void> {\n const since = watermark.get();\n let cursor: string | null = null;\n let serverTime: string | null;\n do {\n const page = await config.pullPage(since, cursor);\n for (const item of page.items) {\n await config.applyRemote(item);\n }\n cursor = page.nextCursor;\n serverTime = page.serverTime;\n } while (cursor);\n if (serverTime) watermark.set(serverTime);\n }\n\n async function runOnce(trigger: SyncTrigger): Promise<SyncRunSummary> {\n const startedAt = Date.now();\n const summary: SyncRunSummary = {\n trigger,\n succeeded: 0,\n failed: 0,\n durationMs: 0,\n skipped: false,\n lastError: null,\n };\n if (!isOnline()) {\n summary.skipped = true;\n summary.durationMs = Date.now() - startedAt;\n return summary;\n }\n await push(summary);\n await pull();\n summary.durationMs = Date.now() - startedAt;\n return summary;\n }\n\n /**\n * Run one sync pass, serialized across tabs when possible.\n *\n * With `crossTab` on and the Web Locks API available, the pass is wrapped in\n * an `ifAvailable` lock request: whichever tab holds the lock runs, and the\n * others get `null` back instead of duplicating the work — their `SyncState`\n * catches up through the `BroadcastChannel`. The no-op summary keeps\n * `skipped: false` on purpose: `skipped` means \"device offline\" (it maps to\n * `phase: \"offline\"`), which is not what happened here. Falls back to a plain\n * per-tab run when `crossTab` is off or Web Locks is missing.\n *\n * @param trigger - What asked for this run, carried into the summary.\n * @returns The run summary, or an empty summary when another tab held the lock.\n */\n async function runGuarded(trigger: SyncTrigger): Promise<SyncRunSummary> {\n const locks = typeof navigator !== \"undefined\" ? navigator.locks : undefined;\n if (!crossTab || !locks) return runOnce(trigger);\n const result = await locks.request(\n `${channelName}:flush`,\n { ifAvailable: true },\n async (lock) => (lock ? runOnce(trigger) : null),\n );\n return (\n result ?? {\n trigger,\n succeeded: 0,\n failed: 0,\n durationMs: 0,\n skipped: false,\n lastError: null,\n }\n );\n }\n\n void refreshPending();\n\n let lastEnqueuedAt = 0;\n\n /**\n * Timestamp for a new outbox entry, guaranteed to be strictly greater than\n * the previous one.\n *\n * `enqueuedAt` is the sort key for both `listPending()` and the delivery loop\n * in `flush()`. A plain `Date.now()` ties whenever two mutations are queued\n * within the same millisecond — which is normal in a burst — and a tie leaves\n * the order to the index, so a `create` could be delivered *after* the\n * `update` that depends on it. Advancing by 1ms on a tie keeps the queue FIFO\n * at the cost of a timestamp that can run a few milliseconds ahead of the wall\n * clock during a burst.\n *\n * Scope: this is per engine instance. Two tabs enqueueing in the same\n * millisecond can still tie; cross-tab FIFO would need a persisted sequence,\n * and the delivery loop is already single-flight across tabs via Web Locks.\n */\n function nextEnqueuedAt(): number {\n const now = Date.now();\n lastEnqueuedAt = now > lastEnqueuedAt ? now : lastEnqueuedAt + 1;\n return lastEnqueuedAt;\n }\n\n return {\n async enqueue(op, recordId, payload) {\n const entry: OutboxEntry<TPayload> = {\n id: randomId(idPrefix),\n op,\n recordId,\n enqueuedAt: nextEnqueuedAt(),\n attempts: 0,\n payload,\n };\n await outbox.put(entry);\n await refreshPending();\n return entry.id;\n },\n flush(trigger: SyncTrigger = \"manual\") {\n if (!inflight) {\n setState({ phase: \"syncing\" });\n inflight = runGuarded(trigger)\n .then(async (summary) => {\n await refreshPending();\n setState({\n phase: summary.skipped\n ? \"offline\"\n : summary.failed > 0\n ? \"error\"\n : \"idle\",\n lastSummary: summary,\n lastError: summary.lastError,\n lastSyncedAt: summary.skipped ? state.lastSyncedAt : Date.now(),\n });\n return summary;\n })\n .finally(() => {\n inflight = null;\n });\n }\n return inflight;\n },\n pendingCount() {\n return outbox.count();\n },\n listPending() {\n return outbox.list(undefined, { orderBy: \"enqueuedAt\" });\n },\n async clearOutbox() {\n await outbox.clear();\n await refreshPending();\n },\n resetWatermark() {\n watermark.clear();\n },\n getState() {\n return state;\n },\n subscribe(listener) {\n listeners.add(listener);\n return () => {\n listeners.delete(listener);\n };\n },\n dispose() {\n closed = true;\n channel?.close();\n },\n };\n}\n"],"mappings":"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"}
|
|
@@ -85,13 +85,19 @@ function r(r) {
|
|
|
85
85
|
lastError: null
|
|
86
86
|
};
|
|
87
87
|
}
|
|
88
|
-
|
|
88
|
+
_();
|
|
89
|
+
let S = 0;
|
|
90
|
+
function C() {
|
|
91
|
+
let e = Date.now();
|
|
92
|
+
return S = e > S ? e : S + 1, S;
|
|
93
|
+
}
|
|
94
|
+
return {
|
|
89
95
|
async enqueue(t, n, r) {
|
|
90
96
|
let a = {
|
|
91
97
|
id: e(o),
|
|
92
98
|
op: t,
|
|
93
99
|
recordId: n,
|
|
94
|
-
enqueuedAt:
|
|
100
|
+
enqueuedAt: C(),
|
|
95
101
|
attempts: 0,
|
|
96
102
|
payload: r
|
|
97
103
|
};
|