@lattice-php/lattice 0.20.0 → 0.22.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 +10 -0
- package/dist/action/components/action-form.d.ts +6 -1
- package/dist/action/components/action-form.js +48 -58
- package/dist/action/components/action-form.js.map +1 -1
- package/dist/action/components/action-trigger-provider.d.ts +1 -1
- package/dist/action/components/action-trigger-provider.js.map +1 -1
- package/dist/action/components/action.js +2 -1
- package/dist/action/components/action.js.map +1 -1
- package/dist/action/hooks/use-action.d.ts +1 -1
- package/dist/action/hooks/use-action.js +42 -33
- package/dist/action/hooks/use-action.js.map +1 -1
- package/dist/action/index.d.ts +0 -2
- package/dist/action/index.js +1 -2
- package/dist/action/lib/action-label.d.ts +2 -0
- package/dist/action/lib/action-label.js +9 -0
- package/dist/action/lib/action-label.js.map +1 -0
- package/dist/action/lib/run-action.d.ts +7 -7
- package/dist/action/lib/run-action.js +8 -7
- package/dist/action/lib/run-action.js.map +1 -1
- package/dist/chat/plugin.d.ts +0 -1
- package/dist/chat/plugin.js.map +1 -1
- package/dist/clipboard/index.d.ts +0 -4
- package/dist/clipboard/index.js +1 -15
- package/dist/{events → core}/event-names.js +1 -1
- package/dist/core/event-names.js.map +1 -0
- package/dist/core/hooks/use-window-event.d.ts +8 -0
- package/dist/core/hooks/use-window-event.js +22 -0
- package/dist/core/hooks/use-window-event.js.map +1 -0
- package/dist/core/index.js +3 -3
- package/dist/core/types.d.ts +8 -73
- package/dist/create-app.js +1 -1
- package/dist/effects/dispatch.js +1 -1
- package/dist/effects/dispatch.js.map +1 -1
- package/dist/effects/registry.d.ts +2 -18
- package/dist/effects/registry.js +4 -8
- package/dist/effects/registry.js.map +1 -1
- package/dist/event-bridge.js +10 -23
- package/dist/event-bridge.js.map +1 -1
- package/dist/form/components/fields/date-picker-field.js +1 -1
- package/dist/form/components/fields/file-upload.js +4 -6
- package/dist/form/components/fields/file-upload.js.map +1 -1
- package/dist/form/components/fields/select.js +2 -2
- package/dist/form/components/fields/select.js.map +1 -1
- package/dist/form/components/fields/table-rows.js +3 -15
- package/dist/form/components/fields/table-rows.js.map +1 -1
- package/dist/form/components/form.js +11 -24
- package/dist/form/components/form.js.map +1 -1
- package/dist/form/embed.d.ts +4 -0
- package/dist/form/embed.js +3 -1
- package/dist/form/lib/collect-fields.d.ts +7 -0
- package/dist/form/lib/collect-fields.js +19 -0
- package/dist/form/lib/collect-fields.js.map +1 -0
- package/dist/form/lib/field-errors.d.ts +3 -0
- package/dist/form/lib/field-errors.js +11 -0
- package/dist/form/lib/field-errors.js.map +1 -0
- package/dist/format/format-context.d.ts +6 -0
- package/dist/format/format-context.js +17 -0
- package/dist/format/format-context.js.map +1 -0
- package/dist/format/number.d.ts +1 -1
- package/dist/format/number.js.map +1 -1
- package/dist/format/value.d.ts +1 -1
- package/dist/format/value.js.map +1 -1
- package/dist/i18n/backend.js +1 -1
- package/dist/i18n/index.js +2 -2
- package/dist/i18n/instance.js +1 -1
- package/dist/i18n/locale-reload.d.ts +1 -1
- package/dist/i18n/locale-reload.js +7 -6
- package/dist/i18n/locale-reload.js.map +1 -1
- package/dist/i18n/locale.js +1 -1
- package/dist/i18n/locale.js.map +1 -1
- package/dist/i18n/page-props.js +1 -1
- package/dist/i18n/shared-props.js +1 -3
- package/dist/i18n/shared-props.js.map +1 -1
- package/dist/i18n/timezone.js +1 -1
- package/dist/i18n/timezone.js.map +1 -1
- package/dist/index.d.ts +6 -7
- package/dist/index.js +7 -8
- package/dist/lattice.css +105 -0
- package/dist/layout/components/callouts.js +1 -1
- package/dist/layout/components/sidebar.js +15 -48
- package/dist/layout/components/sidebar.js.map +1 -1
- package/dist/layout/plugin.d.ts +0 -1
- package/dist/layout/plugin.js.map +1 -1
- package/dist/lib/is-truthy.d.ts +2 -0
- package/dist/lib/is-truthy.js +9 -0
- package/dist/lib/is-truthy.js.map +1 -0
- package/dist/lib/use-debounced-callback.d.ts +10 -0
- package/dist/lib/use-debounced-callback.js +34 -0
- package/dist/lib/use-debounced-callback.js.map +1 -0
- package/dist/lib/use-media-query.d.ts +5 -0
- package/dist/lib/use-media-query.js +26 -0
- package/dist/lib/use-media-query.js.map +1 -0
- package/dist/lib/use-persistent-state.d.ts +13 -0
- package/dist/lib/use-persistent-state.js +62 -0
- package/dist/lib/use-persistent-state.js.map +1 -0
- package/dist/notifications/components/notifications.js +4 -1
- package/dist/notifications/components/notifications.js.map +1 -1
- package/dist/notifications/plugin.d.ts +0 -1
- package/dist/notifications/plugin.js.map +1 -1
- package/dist/provider-base.js +1 -1
- package/dist/realtime/listeners.d.ts +1 -1
- package/dist/realtime/listeners.js +1 -1
- package/dist/realtime/listeners.js.map +1 -1
- package/dist/registry.d.ts +5 -0
- package/dist/registry.js.map +1 -1
- package/dist/remote/components/data-list.js +1 -1
- package/dist/remote/plugin.d.ts +0 -1
- package/dist/remote/plugin.js.map +1 -1
- package/dist/table/components/bulk-bar.js +18 -15
- package/dist/table/components/bulk-bar.js.map +1 -1
- package/dist/table/components/cells/boolean-cell.js +1 -3
- package/dist/table/components/cells/boolean-cell.js.map +1 -1
- package/dist/table/components/cells/copyable-cell.d.ts +9 -0
- package/dist/table/components/cells/copyable-cell.js +17 -0
- package/dist/table/components/cells/copyable-cell.js.map +1 -0
- package/dist/table/components/cells/money-cell.js +7 -18
- package/dist/table/components/cells/money-cell.js.map +1 -1
- package/dist/table/components/cells/number-cell.js +14 -27
- package/dist/table/components/cells/number-cell.js.map +1 -1
- package/dist/table/components/cells/numeric-cell.d.ts +10 -0
- package/dist/table/components/cells/numeric-cell.js +25 -0
- package/dist/table/components/cells/numeric-cell.js.map +1 -0
- package/dist/table/components/cells/stack-cell.js +1 -1
- package/dist/table/components/cells/text-cell.js +4 -5
- package/dist/table/components/cells/text-cell.js.map +1 -1
- package/dist/table/components/filter-controls.js +1 -3
- package/dist/table/components/filter-controls.js.map +1 -1
- package/dist/table/components/table-cell.js.map +1 -1
- package/dist/table/components/table-search.js +4 -7
- package/dist/table/components/table-search.js.map +1 -1
- package/dist/table/components/table.js +2 -3
- package/dist/table/components/table.js.map +1 -1
- package/dist/table/hooks/use-column-visibility.js +29 -58
- package/dist/table/hooks/use-column-visibility.js.map +1 -1
- package/dist/table/hooks/use-table.js +5 -13
- package/dist/table/hooks/use-table.js.map +1 -1
- package/dist/table/lib/bulk.d.ts +2 -0
- package/dist/table/lib/bulk.js +5 -2
- package/dist/table/lib/bulk.js.map +1 -1
- package/dist/table/lib/query.js +1 -1
- package/dist/table/lib/query.js.map +1 -1
- package/dist/table/plugin.d.ts +0 -1
- package/dist/table/plugin.js.map +1 -1
- package/dist/table/types.d.ts +4 -57
- package/dist/toast/callout.js +1 -1
- package/dist/toast/callout.js.map +1 -1
- package/dist/toast/index.d.ts +1 -1
- package/dist/toast/index.js +2 -2
- package/dist/toast/toast.d.ts +0 -2
- package/dist/toast/toast.js +3 -10
- package/dist/toast/toast.js.map +1 -1
- package/dist/toast/toaster.js +2 -2
- package/dist/types/generated.d.ts +224 -80
- package/dist/types/index.d.ts +1 -1
- package/dist/ui/button.d.ts +2 -2
- package/dist/ui/chart-view.js +7 -30
- package/dist/ui/chart-view.js.map +1 -1
- package/dist/ui/click-behavior.d.ts +4 -4
- package/dist/ui/click-behavior.js.map +1 -1
- package/dist/ui/collapsible.js +3 -15
- package/dist/ui/collapsible.js.map +1 -1
- package/dist/ui/combobox.js +6 -3
- package/dist/ui/combobox.js.map +1 -1
- package/dist/ui/confirm-dialog.js +1 -1
- package/dist/ui/confirm-dialog.js.map +1 -1
- package/dist/ui/control.d.ts +1 -1
- package/dist/ui/dialog.d.ts +6 -2
- package/dist/ui/dialog.js +29 -5
- package/dist/ui/dialog.js.map +1 -1
- package/dist/ui/fragment.js +1 -1
- package/dist/ui/fragment.js.map +1 -1
- package/dist/ui/icon-button.d.ts +1 -1
- package/dist/ui/image-preview.js +1 -1
- package/dist/ui/image-preview.js.map +1 -1
- package/dist/ui/modal.js +6 -3
- package/dist/ui/modal.js.map +1 -1
- package/dist/ui/pill.d.ts +2 -0
- package/dist/ui/pill.js +10 -0
- package/dist/ui/pill.js.map +1 -0
- package/dist/ui/plugin.js.map +1 -1
- package/dist/ui/progress.js +1 -1
- package/dist/ui/section.js +2 -15
- package/dist/ui/section.js.map +1 -1
- package/dist/ui/segmented-pills.js +2 -1
- package/dist/ui/segmented-pills.js.map +1 -1
- package/dist/ui/tabs.js +12 -10
- package/dist/ui/tabs.js.map +1 -1
- package/dist/ui/tree-context.js +11 -13
- package/dist/ui/tree-context.js.map +1 -1
- package/dist/ui/tree.js +1 -1
- package/dist/ui/tree.js.map +1 -1
- package/dist/ui/use-collapsible-state.d.ts +7 -0
- package/dist/ui/use-collapsible-state.js +21 -0
- package/dist/ui/use-collapsible-state.js.map +1 -0
- package/dist-standalone/chunks/chart-view-C6R5iPra.js +36 -0
- package/dist-standalone/chunks/{date-picker-field-VbH9xrQO.js → date-picker-field-DhhEB-Mh.js} +1 -1
- package/dist-standalone/chunks/{page-props-AIa5UR6n.js → page-props-DOfg30l5.js} +1 -1
- package/dist-standalone/chunks/{rich-editor-field-DLQTyt36.js → rich-editor-field-DORXTHPw.js} +2 -2
- package/dist-standalone/chunks/{subscriptions-DY2tj9Im.js → subscriptions-DK_s_F2g.js} +1 -1
- package/dist-standalone/chunks/use-effect-dispatcher-EVZxmfoo.js +97 -0
- package/dist-standalone/lattice.css +1 -1
- package/dist-standalone/lattice.js +15 -15
- package/dist-standalone/manifest.json +8 -8
- package/package.json +3 -3
- package/dist/clipboard/index.js.map +0 -1
- package/dist/events/event-names.js.map +0 -1
- package/dist/table/components/table-action-node.d.ts +0 -4
- package/dist/table/components/table-action-node.js +0 -24
- package/dist/table/components/table-action-node.js.map +0 -1
- package/dist-standalone/chunks/chart-view-wJmnVu7L.js +0 -36
- package/dist-standalone/chunks/use-effect-dispatcher-feEs0GCP.js +0 -97
- /package/dist/{events → core}/event-names.d.ts +0 -0
package/dist/index.js
CHANGED
|
@@ -1,17 +1,16 @@
|
|
|
1
1
|
import { initializeTheme, updateAppearance, useAppearance } from "./appearance/index.js";
|
|
2
2
|
import { createPlugin, createRegistry, eagerComponent, extendRegistry, lazyComponent } from "./core/registry.js";
|
|
3
3
|
import { useColumnRegistry, useComponentRegistry } from "./core/registry-context.js";
|
|
4
|
-
import { LATTICE_EVENT } from "./
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
4
|
+
import { LATTICE_EVENT } from "./core/event-names.js";
|
|
5
|
+
import { LATTICE_REF_HEADER, withRefHeader } from "./core/component-ref.js";
|
|
6
|
+
import { withHeaders } from "./core/headers.js";
|
|
7
7
|
import { Icon, SpriteProvider } from "./icons/sprite.js";
|
|
8
8
|
import { IconRenderer, IconRendererProvider } from "./icons/icon-renderer.js";
|
|
9
9
|
import { CollapsedContext, useCollapsed } from "./core/collapsed-context.js";
|
|
10
10
|
import { Renderer } from "./core/renderer.js";
|
|
11
|
+
import { onToast } from "./toast/toast.js";
|
|
12
|
+
import { onCallout } from "./toast/callout.js";
|
|
11
13
|
import { Toaster } from "./toast/toaster.js";
|
|
12
|
-
import { EventBridge } from "./event-bridge.js";
|
|
13
|
-
import { LATTICE_REF_HEADER, withRefHeader } from "./core/component-ref.js";
|
|
14
|
-
import { withHeaders } from "./core/headers.js";
|
|
15
14
|
import Callouts from "./layout/components/callouts.js";
|
|
16
15
|
import { builtinEffectHandlers, effectHandler, mergeEffectHandlers } from "./effects/registry.js";
|
|
17
16
|
import { dispatchActionError, dispatchEffects, getActionEffects, isActionEffect } from "./effects/dispatch.js";
|
|
@@ -21,6 +20,7 @@ import { layoutComponents } from "./layout/plugin.js";
|
|
|
21
20
|
import SchemaLayout from "./layout/components/schema-layout.js";
|
|
22
21
|
import { RealtimeListeners } from "./realtime/listeners.js";
|
|
23
22
|
import { createLayoutResolver, createPageResolver, pageComponentName, withVisitHeaders } from "./inertia.js";
|
|
23
|
+
import { EventBridge } from "./event-bridge.js";
|
|
24
24
|
import { useChat } from "./chat/hooks/use-chat.js";
|
|
25
25
|
import { chatComponents } from "./chat/plugin.js";
|
|
26
26
|
import { copyToClipboard } from "./ui/copyable-text.js";
|
|
@@ -28,6 +28,5 @@ import { columnCell } from "./table/registry.js";
|
|
|
28
28
|
import { registry } from "./registry.js";
|
|
29
29
|
import { createLatticeApp } from "./create-app.js";
|
|
30
30
|
import { registerRichEditorExtension } from "./form/rich-editor/registry.js";
|
|
31
|
-
import { useClipboard } from "./clipboard/index.js";
|
|
32
31
|
import { Provider } from "./provider.js";
|
|
33
|
-
export { Callouts, EventBridge, Icon, IconRenderer, IconRendererProvider, LATTICE_EVENT, LATTICE_REF_HEADER, OutletContext, Provider, RealtimeListeners, Renderer, SchemaLayout, CollapsedContext as SidebarCollapsedContext, SpriteProvider, Toaster, builtinEffectHandlers, chatComponents, columnCell, copyToClipboard, createLatticeApp, createLayoutResolver, createPageResolver, createPlugin, createRegistry, dispatchActionError, dispatchEffects, eagerComponent, effectHandler, extendRegistry, getActionEffects, initializeTheme, isActionEffect, layoutComponents, lazyComponent, mergeEffectHandlers, onCallout, onToast, pageComponentName, registerRichEditorExtension, registry,
|
|
32
|
+
export { Callouts, EventBridge, Icon, IconRenderer, IconRendererProvider, LATTICE_EVENT, LATTICE_REF_HEADER, OutletContext, Provider, RealtimeListeners, Renderer, SchemaLayout, CollapsedContext as SidebarCollapsedContext, SpriteProvider, Toaster, builtinEffectHandlers, chatComponents, columnCell, copyToClipboard, createLatticeApp, createLayoutResolver, createPageResolver, createPlugin, createRegistry, dispatchActionError, dispatchEffects, eagerComponent, effectHandler, extendRegistry, getActionEffects, initializeTheme, isActionEffect, layoutComponents, lazyComponent, mergeEffectHandlers, onCallout, onToast, pageComponentName, registerRichEditorExtension, registry, updateAppearance, useAppearance, useChat, useColumnRegistry, useComponentRegistry, useEffectDispatcher, useCollapsed as useSidebarCollapsed, withHeaders, withRefHeader, withVisitHeaders };
|
package/dist/lattice.css
CHANGED
|
@@ -85,6 +85,7 @@
|
|
|
85
85
|
|
|
86
86
|
--lt-duration-fast: 120ms;
|
|
87
87
|
--lt-duration-base: 160ms;
|
|
88
|
+
--lt-duration-slow: 240ms;
|
|
88
89
|
|
|
89
90
|
--lt-sidebar-w: 16rem;
|
|
90
91
|
--lt-sidebar-w-collapsed: 4rem;
|
|
@@ -96,6 +97,20 @@
|
|
|
96
97
|
color-scheme: light;
|
|
97
98
|
}
|
|
98
99
|
|
|
100
|
+
/*
|
|
101
|
+
* Radix keeps dialogs mounted until their exit animation ends, so reduced
|
|
102
|
+
* motion zeroes the durations instead of removing the animations — the
|
|
103
|
+
* animation events still fire and close stays instant.
|
|
104
|
+
*/
|
|
105
|
+
@media (prefers-reduced-motion: reduce) {
|
|
106
|
+
:root,
|
|
107
|
+
[data-theme="light"] {
|
|
108
|
+
--lt-duration-fast: 0ms;
|
|
109
|
+
--lt-duration-base: 0ms;
|
|
110
|
+
--lt-duration-slow: 0ms;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
99
114
|
[data-theme="dark"],
|
|
100
115
|
.dark {
|
|
101
116
|
--lt-bg: var(--background, oklch(0.145 0 0));
|
|
@@ -205,6 +220,14 @@
|
|
|
205
220
|
--font-weight-lt-bold: var(--lt-font-weight-bold);
|
|
206
221
|
--animate-lt-toast-in: lt-toast-in var(--lt-duration-base) ease-out;
|
|
207
222
|
--animate-lt-toast-out: lt-toast-out var(--lt-duration-fast) ease-in;
|
|
223
|
+
--animate-lt-fade-in: lt-fade-in var(--lt-duration-base) ease-out;
|
|
224
|
+
--animate-lt-fade-out: lt-fade-out var(--lt-duration-fast) ease-in;
|
|
225
|
+
--animate-lt-dialog-in: lt-dialog-in var(--lt-duration-base) ease-out;
|
|
226
|
+
--animate-lt-dialog-out: lt-dialog-out var(--lt-duration-fast) ease-in;
|
|
227
|
+
--animate-lt-sheet-in-start: lt-sheet-in-start var(--lt-duration-slow) ease-out;
|
|
228
|
+
--animate-lt-sheet-out-start: lt-sheet-out-start var(--lt-duration-fast) ease-in;
|
|
229
|
+
--animate-lt-sheet-in-end: lt-sheet-in-end var(--lt-duration-slow) ease-out;
|
|
230
|
+
--animate-lt-sheet-out-end: lt-sheet-out-end var(--lt-duration-fast) ease-in;
|
|
208
231
|
}
|
|
209
232
|
|
|
210
233
|
@theme {
|
|
@@ -285,6 +308,88 @@
|
|
|
285
308
|
}
|
|
286
309
|
}
|
|
287
310
|
|
|
311
|
+
@keyframes lt-fade-in {
|
|
312
|
+
from {
|
|
313
|
+
opacity: 0;
|
|
314
|
+
}
|
|
315
|
+
to {
|
|
316
|
+
opacity: 1;
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
@keyframes lt-fade-out {
|
|
321
|
+
from {
|
|
322
|
+
opacity: 1;
|
|
323
|
+
}
|
|
324
|
+
to {
|
|
325
|
+
opacity: 0;
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
/* Centering uses Tailwind's standalone translate property, which composes
|
|
330
|
+
with transform — so these keyframes may only animate opacity and scale,
|
|
331
|
+
never a translate of their own. */
|
|
332
|
+
@keyframes lt-dialog-in {
|
|
333
|
+
from {
|
|
334
|
+
opacity: 0;
|
|
335
|
+
transform: scale(0.98);
|
|
336
|
+
}
|
|
337
|
+
to {
|
|
338
|
+
opacity: 1;
|
|
339
|
+
transform: scale(1);
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
@keyframes lt-dialog-out {
|
|
344
|
+
from {
|
|
345
|
+
opacity: 1;
|
|
346
|
+
transform: scale(1);
|
|
347
|
+
}
|
|
348
|
+
to {
|
|
349
|
+
opacity: 0;
|
|
350
|
+
transform: scale(0.98);
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
/* Sheet slides are physical (translateX): under RTL a sheet docks to the
|
|
355
|
+
correct logical edge but enters from the mirrored side. Shipped locales
|
|
356
|
+
are LTR. */
|
|
357
|
+
@keyframes lt-sheet-in-start {
|
|
358
|
+
from {
|
|
359
|
+
transform: translateX(-100%);
|
|
360
|
+
}
|
|
361
|
+
to {
|
|
362
|
+
transform: translateX(0);
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
@keyframes lt-sheet-out-start {
|
|
367
|
+
from {
|
|
368
|
+
transform: translateX(0);
|
|
369
|
+
}
|
|
370
|
+
to {
|
|
371
|
+
transform: translateX(-100%);
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
@keyframes lt-sheet-in-end {
|
|
376
|
+
from {
|
|
377
|
+
transform: translateX(100%);
|
|
378
|
+
}
|
|
379
|
+
to {
|
|
380
|
+
transform: translateX(0);
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
@keyframes lt-sheet-out-end {
|
|
385
|
+
from {
|
|
386
|
+
transform: translateX(0);
|
|
387
|
+
}
|
|
388
|
+
to {
|
|
389
|
+
transform: translateX(100%);
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
|
|
288
393
|
/*
|
|
289
394
|
* Named colours. Semantic names alias the theme tokens; hue names carry their
|
|
290
395
|
* own oklch values with `.dark` overrides. Renderers resolve a named colour to
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { onCallout } from "../../toast/callout.js";
|
|
2
1
|
import { cn } from "../../lib/utils.js";
|
|
3
2
|
import { Icon } from "../../icons/sprite.js";
|
|
4
3
|
import { RenderNode } from "../../core/renderer.js";
|
|
4
|
+
import { onCallout } from "../../toast/callout.js";
|
|
5
5
|
import { useT } from "../../i18n/instance.js";
|
|
6
6
|
import { variantStyles } from "../../toast/variant-styles.js";
|
|
7
7
|
import { useEffect, useState } from "react";
|
|
@@ -1,70 +1,37 @@
|
|
|
1
|
-
import { LATTICE_EVENT } from "../../
|
|
1
|
+
import { LATTICE_EVENT } from "../../core/event-names.js";
|
|
2
|
+
import { useWindowEvent } from "../../core/hooks/use-window-event.js";
|
|
2
3
|
import { cn } from "../../lib/utils.js";
|
|
3
4
|
import { CollapsedContext } from "../../core/collapsed-context.js";
|
|
4
5
|
import { nodeIdentity } from "../../core/test-id.js";
|
|
6
|
+
import { useMediaQuery } from "../../lib/use-media-query.js";
|
|
7
|
+
import { useCollapsibleState } from "../../ui/use-collapsible-state.js";
|
|
5
8
|
import { router } from "@inertiajs/react";
|
|
6
9
|
import { useEffect, useState } from "react";
|
|
7
10
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
8
11
|
//#region resources/js/layout/components/sidebar.tsx
|
|
9
12
|
var DESKTOP_QUERY = "(min-width: 768px)";
|
|
10
|
-
function readStored(key, remember) {
|
|
11
|
-
if (!remember || typeof window === "undefined") return false;
|
|
12
|
-
return window.localStorage.getItem(key) === "true";
|
|
13
|
-
}
|
|
14
13
|
function matchesTarget(event, identity) {
|
|
15
14
|
const target = event.detail?.target;
|
|
16
15
|
return target == null || target === identity;
|
|
17
16
|
}
|
|
18
|
-
function useIsDesktop() {
|
|
19
|
-
const supported = () => typeof window !== "undefined" && typeof window.matchMedia === "function";
|
|
20
|
-
const [isDesktop, setIsDesktop] = useState(() => supported() ? window.matchMedia(DESKTOP_QUERY).matches : true);
|
|
21
|
-
useEffect(() => {
|
|
22
|
-
if (!supported()) return;
|
|
23
|
-
const query = window.matchMedia(DESKTOP_QUERY);
|
|
24
|
-
const update = () => setIsDesktop(query.matches);
|
|
25
|
-
update();
|
|
26
|
-
query.addEventListener("change", update);
|
|
27
|
-
return () => query.removeEventListener("change", update);
|
|
28
|
-
}, []);
|
|
29
|
-
return isDesktop;
|
|
30
|
-
}
|
|
31
17
|
var SidebarComponent = ({ children, node }) => {
|
|
32
18
|
const collapsible = node.props.collapsible;
|
|
33
19
|
const rememberState = node.props.rememberState;
|
|
34
20
|
const identity = nodeIdentity(node);
|
|
35
21
|
const storageKey = `lattice:sidebar:${identity ?? "default"}`;
|
|
36
|
-
const isDesktop =
|
|
37
|
-
const [collapsed,
|
|
22
|
+
const isDesktop = useMediaQuery(DESKTOP_QUERY, true);
|
|
23
|
+
const [collapsed, toggleCollapsed] = useCollapsibleState(storageKey, false, collapsible && rememberState);
|
|
38
24
|
const [mobileOpen, setMobileOpen] = useState(false);
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
if (
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
const next = !value;
|
|
46
|
-
if (rememberState && typeof window !== "undefined") window.localStorage.setItem(storageKey, String(next));
|
|
47
|
-
return next;
|
|
48
|
-
});
|
|
49
|
-
} else setMobileOpen((open) => !open);
|
|
50
|
-
}
|
|
51
|
-
window.addEventListener(LATTICE_EVENT.toggleSidebar, toggle);
|
|
52
|
-
return () => window.removeEventListener(LATTICE_EVENT.toggleSidebar, toggle);
|
|
53
|
-
}, [
|
|
54
|
-
identity,
|
|
55
|
-
collapsible,
|
|
56
|
-
rememberState,
|
|
57
|
-
storageKey
|
|
58
|
-
]);
|
|
25
|
+
useWindowEvent(LATTICE_EVENT.toggleSidebar, (event) => {
|
|
26
|
+
if (!matchesTarget(event, identity)) return;
|
|
27
|
+
if (window.matchMedia?.(DESKTOP_QUERY).matches ?? true) {
|
|
28
|
+
if (collapsible) toggleCollapsed();
|
|
29
|
+
} else setMobileOpen((open) => !open);
|
|
30
|
+
});
|
|
59
31
|
useEffect(() => router.on("navigate", () => setMobileOpen(false)), []);
|
|
60
|
-
|
|
61
|
-
if (
|
|
62
|
-
|
|
63
|
-
if (event.key === "Escape") setMobileOpen(false);
|
|
64
|
-
}
|
|
65
|
-
window.addEventListener("keydown", close);
|
|
66
|
-
return () => window.removeEventListener("keydown", close);
|
|
67
|
-
}, [mobileOpen]);
|
|
32
|
+
useWindowEvent("keydown", (event) => {
|
|
33
|
+
if (event.key === "Escape") setMobileOpen(false);
|
|
34
|
+
}, { enabled: mobileOpen });
|
|
68
35
|
const isCollapsed = collapsible && collapsed && isDesktop;
|
|
69
36
|
return /* @__PURE__ */ jsxs(CollapsedContext.Provider, {
|
|
70
37
|
value: isCollapsed,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sidebar.js","names":[],"sources":["../../../resources/js/layout/components/sidebar.tsx"],"sourcesContent":["import { router } from \"@inertiajs/react\";\nimport { useEffect, useState } from \"react\";\nimport type { RendererComponent } from \"@lattice-php/lattice/core/types\";\nimport { CollapsedContext } from \"@lattice-php/lattice/core/collapsed-context\";\nimport { LATTICE_EVENT } from \"@lattice-php/lattice/
|
|
1
|
+
{"version":3,"file":"sidebar.js","names":[],"sources":["../../../resources/js/layout/components/sidebar.tsx"],"sourcesContent":["import { router } from \"@inertiajs/react\";\nimport { useEffect, useState } from \"react\";\nimport type { RendererComponent } from \"@lattice-php/lattice/core/types\";\nimport { CollapsedContext } from \"@lattice-php/lattice/core/collapsed-context\";\nimport { LATTICE_EVENT } from \"@lattice-php/lattice/core/event-names\";\nimport { useWindowEvent } from \"@lattice-php/lattice/core/hooks/use-window-event\";\nimport { nodeIdentity } from \"@lattice-php/lattice/core/test-id\";\nimport { cn } from \"@lattice-php/lattice/lib/utils\";\nimport { useMediaQuery } from \"@lattice-php/lattice/lib/use-media-query\";\nimport { useCollapsibleState } from \"@lattice-php/lattice/ui/use-collapsible-state\";\n\nconst DESKTOP_QUERY = \"(min-width: 768px)\";\n\nfunction matchesTarget(event: Event, identity: string | undefined): boolean {\n const target = (event as CustomEvent<{ target?: string }>).detail?.target;\n\n return target == null || target === identity;\n}\n\nconst SidebarComponent: RendererComponent<\"sidebar\"> = ({ children, node }) => {\n const collapsible = node.props.collapsible;\n const rememberState = node.props.rememberState;\n const identity = nodeIdentity(node);\n const storageKey = `lattice:sidebar:${identity ?? \"default\"}`;\n const isDesktop = useMediaQuery(DESKTOP_QUERY, true);\n\n const [collapsed, toggleCollapsed] = useCollapsibleState(\n storageKey,\n false,\n collapsible && rememberState,\n );\n const [mobileOpen, setMobileOpen] = useState(false);\n\n useWindowEvent(LATTICE_EVENT.toggleSidebar, (event) => {\n if (!matchesTarget(event, identity)) {\n return;\n }\n\n if (window.matchMedia?.(DESKTOP_QUERY).matches ?? true) {\n if (collapsible) {\n toggleCollapsed();\n }\n } else {\n setMobileOpen((open) => !open);\n }\n });\n\n useEffect(() => router.on(\"navigate\", () => setMobileOpen(false)), []);\n\n useWindowEvent(\n \"keydown\",\n (event) => {\n if ((event as KeyboardEvent).key === \"Escape\") {\n setMobileOpen(false);\n }\n },\n { enabled: mobileOpen },\n );\n\n const isCollapsed = collapsible && collapsed && isDesktop;\n\n return (\n <CollapsedContext.Provider value={isCollapsed}>\n {mobileOpen ? (\n <div\n aria-hidden=\"true\"\n className=\"fixed inset-0 z-lt-overlay bg-lt-overlay md:hidden\"\n data-test=\"sidebar-backdrop\"\n onClick={() => setMobileOpen(false)}\n />\n ) : null}\n <aside\n className={cn(\n \"fixed inset-y-0 left-0 z-lt-modal flex h-svh w-72 max-w-[80vw] shrink-0 flex-col gap-4 border-r border-lt-border bg-lt-bg p-4 transition-transform\",\n \"md:sticky md:top-0 md:z-auto md:max-w-none md:translate-x-0 md:transition-[width]\",\n mobileOpen ? \"translate-x-0\" : \"-translate-x-full\",\n isCollapsed\n ? \"md:w-16 md:overflow-visible\"\n : \"md:w-64 md:overflow-x-hidden md:overflow-y-auto\",\n )}\n data-collapsed={isCollapsed ? \"true\" : \"false\"}\n data-lattice-component={identity}\n data-test=\"sidebar\"\n >\n {children}\n </aside>\n </CollapsedContext.Provider>\n );\n};\n\nexport default SidebarComponent;\n"],"mappings":";;;;;;;;;;;AAWA,IAAM,gBAAgB;AAEtB,SAAS,cAAc,OAAc,UAAuC;CAC1E,MAAM,SAAU,MAA2C,QAAQ;CAEnE,OAAO,UAAU,QAAQ,WAAW;AACtC;AAEA,IAAM,oBAAkD,EAAE,UAAU,WAAW;CAC7E,MAAM,cAAc,KAAK,MAAM;CAC/B,MAAM,gBAAgB,KAAK,MAAM;CACjC,MAAM,WAAW,aAAa,IAAI;CAClC,MAAM,aAAa,mBAAmB,YAAY;CAClD,MAAM,YAAY,cAAc,eAAe,IAAI;CAEnD,MAAM,CAAC,WAAW,mBAAmB,oBACnC,YACA,OACA,eAAe,aACjB;CACA,MAAM,CAAC,YAAY,iBAAiB,SAAS,KAAK;CAElD,eAAe,cAAc,gBAAgB,UAAU;EACrD,IAAI,CAAC,cAAc,OAAO,QAAQ,GAChC;EAGF,IAAI,OAAO,aAAa,aAAa,EAAE,WAAW;OAC5C,aACF,gBAAgB;EAAA,OAGlB,eAAe,SAAS,CAAC,IAAI;CAEjC,CAAC;CAED,gBAAgB,OAAO,GAAG,kBAAkB,cAAc,KAAK,CAAC,GAAG,CAAC,CAAC;CAErE,eACE,YACC,UAAU;EACT,IAAK,MAAwB,QAAQ,UACnC,cAAc,KAAK;CAEvB,GACA,EAAE,SAAS,WAAW,CACxB;CAEA,MAAM,cAAc,eAAe,aAAa;CAEhD,OACE,qBAAC,iBAAiB,UAAlB;EAA2B,OAAO;YAAlC,CACG,aACC,oBAAC,OAAD;GACE,eAAY;GACZ,WAAU;GACV,aAAU;GACV,eAAe,cAAc,KAAK;EACnC,CAAA,IACC,MACJ,oBAAC,SAAD;GACE,WAAW,GACT,sJACA,qFACA,aAAa,kBAAkB,qBAC/B,cACI,gCACA,iDACN;GACA,kBAAgB,cAAc,SAAS;GACvC,0BAAwB;GACxB,aAAU;GAET;EACI,CAAA,CACkB;;AAE/B"}
|
package/dist/layout/plugin.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"plugin.js","names":[],"sources":["../../resources/js/layout/plugin.ts"],"sourcesContent":["import {\n createPlugin,\n eagerComponent,\n type ComponentRegistryFor,\n} from \"@lattice-php/lattice/core/registry\";\nimport BreadcrumbsComponent from \"./components/breadcrumbs\";\nimport CalloutsComponent from \"./components/callouts\";\nimport DropdownComponent from \"./components/dropdown\";\nimport MenuComponent from \"./components/menu\";\nimport MenuItemComponent from \"./components/menu-item\";\nimport OutletComponent from \"./components/outlet\";\nimport SidebarComponent from \"./components/sidebar\";\nimport TopbarComponent from \"./components/topbar\";\n\nexport
|
|
1
|
+
{"version":3,"file":"plugin.js","names":[],"sources":["../../resources/js/layout/plugin.ts"],"sourcesContent":["import {\n createPlugin,\n eagerComponent,\n type ComponentRegistryFor,\n} from \"@lattice-php/lattice/core/registry\";\nimport type { LayoutNodeType } from \"@lattice-php/lattice/types/generated\";\nimport BreadcrumbsComponent from \"./components/breadcrumbs\";\nimport CalloutsComponent from \"./components/callouts\";\nimport DropdownComponent from \"./components/dropdown\";\nimport MenuComponent from \"./components/menu\";\nimport MenuItemComponent from \"./components/menu-item\";\nimport OutletComponent from \"./components/outlet\";\nimport SidebarComponent from \"./components/sidebar\";\nimport TopbarComponent from \"./components/topbar\";\n\nexport const layoutComponents = createPlugin({\n components: {\n breadcrumbs: eagerComponent(BreadcrumbsComponent),\n callouts: eagerComponent(CalloutsComponent),\n dropdown: eagerComponent(DropdownComponent),\n menu: eagerComponent(MenuComponent),\n \"menu-item\": eagerComponent(MenuItemComponent),\n outlet: eagerComponent(OutletComponent),\n sidebar: eagerComponent(SidebarComponent),\n topbar: eagerComponent(TopbarComponent),\n } satisfies ComponentRegistryFor<LayoutNodeType>,\n name: \"lattice/layout\",\n});\n"],"mappings":";;;;;;;;;;AAeA,IAAa,mBAAmB,aAAa;CAC3C,YAAY;EACV,aAAa,eAAe,oBAAoB;EAChD,UAAU,eAAe,QAAiB;EAC1C,UAAU,eAAe,iBAAiB;EAC1C,MAAM,eAAe,aAAa;EAClC,aAAa,eAAe,iBAAiB;EAC7C,QAAQ,eAAe,eAAe;EACtC,SAAS,eAAe,gBAAgB;EACxC,QAAQ,eAAe,eAAe;CACxC;CACA,MAAM;AACR,CAAC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
//#region resources/js/lib/is-truthy.ts
|
|
2
|
+
/** Coerce a wire value (boolean, `1`/`0`, `"1"`/`"true"`) to a boolean. */
|
|
3
|
+
function isTruthy(value) {
|
|
4
|
+
return value === true || value === 1 || value === "1" || value === "true";
|
|
5
|
+
}
|
|
6
|
+
//#endregion
|
|
7
|
+
export { isTruthy };
|
|
8
|
+
|
|
9
|
+
//# sourceMappingURL=is-truthy.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"is-truthy.js","names":[],"sources":["../../resources/js/lib/is-truthy.ts"],"sourcesContent":["/** Coerce a wire value (boolean, `1`/`0`, `\"1\"`/`\"true\"`) to a boolean. */\nexport function isTruthy(value: unknown): boolean {\n return value === true || value === 1 || value === \"1\" || value === \"true\";\n}\n"],"mappings":";;AACA,SAAgB,SAAS,OAAyB;CAChD,OAAO,UAAU,QAAQ,UAAU,KAAK,UAAU,OAAO,UAAU;AACrE"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export type DebouncedCallback<A extends unknown[]> = {
|
|
2
|
+
(...args: A): void;
|
|
3
|
+
cancel: () => void;
|
|
4
|
+
};
|
|
5
|
+
/**
|
|
6
|
+
* A debounced wrapper around `callback` that is stable across renders (it reads
|
|
7
|
+
* the latest callback via a ref) and clears its pending timer on unmount, so a
|
|
8
|
+
* late fire can never run against a torn-down component.
|
|
9
|
+
*/
|
|
10
|
+
export declare function useDebouncedCallback<A extends unknown[]>(callback: (...args: A) => void, delayMs: number): DebouncedCallback<A>;
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { useCallback, useEffect, useMemo, useRef } from "react";
|
|
2
|
+
//#region resources/js/lib/use-debounced-callback.ts
|
|
3
|
+
/**
|
|
4
|
+
* A debounced wrapper around `callback` that is stable across renders (it reads
|
|
5
|
+
* the latest callback via a ref) and clears its pending timer on unmount, so a
|
|
6
|
+
* late fire can never run against a torn-down component.
|
|
7
|
+
*/
|
|
8
|
+
function useDebouncedCallback(callback, delayMs) {
|
|
9
|
+
const callbackRef = useRef(callback);
|
|
10
|
+
callbackRef.current = callback;
|
|
11
|
+
const timerRef = useRef(null);
|
|
12
|
+
const cancel = useCallback(() => {
|
|
13
|
+
if (timerRef.current !== null) {
|
|
14
|
+
clearTimeout(timerRef.current);
|
|
15
|
+
timerRef.current = null;
|
|
16
|
+
}
|
|
17
|
+
}, []);
|
|
18
|
+
useEffect(() => cancel, [cancel]);
|
|
19
|
+
return useMemo(() => {
|
|
20
|
+
const debounced = (...args) => {
|
|
21
|
+
cancel();
|
|
22
|
+
timerRef.current = setTimeout(() => {
|
|
23
|
+
timerRef.current = null;
|
|
24
|
+
callbackRef.current(...args);
|
|
25
|
+
}, delayMs);
|
|
26
|
+
};
|
|
27
|
+
debounced.cancel = cancel;
|
|
28
|
+
return debounced;
|
|
29
|
+
}, [cancel, delayMs]);
|
|
30
|
+
}
|
|
31
|
+
//#endregion
|
|
32
|
+
export { useDebouncedCallback };
|
|
33
|
+
|
|
34
|
+
//# sourceMappingURL=use-debounced-callback.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"use-debounced-callback.js","names":[],"sources":["../../resources/js/lib/use-debounced-callback.ts"],"sourcesContent":["import { useCallback, useEffect, useMemo, useRef } from \"react\";\n\nexport type DebouncedCallback<A extends unknown[]> = {\n (...args: A): void;\n cancel: () => void;\n};\n\n/**\n * A debounced wrapper around `callback` that is stable across renders (it reads\n * the latest callback via a ref) and clears its pending timer on unmount, so a\n * late fire can never run against a torn-down component.\n */\nexport function useDebouncedCallback<A extends unknown[]>(\n callback: (...args: A) => void,\n delayMs: number,\n): DebouncedCallback<A> {\n const callbackRef = useRef(callback);\n callbackRef.current = callback;\n\n const timerRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n\n const cancel = useCallback(() => {\n if (timerRef.current !== null) {\n clearTimeout(timerRef.current);\n timerRef.current = null;\n }\n }, []);\n\n useEffect(() => cancel, [cancel]);\n\n return useMemo(() => {\n const debounced = (...args: A): void => {\n cancel();\n timerRef.current = setTimeout(() => {\n timerRef.current = null;\n callbackRef.current(...args);\n }, delayMs);\n };\n\n debounced.cancel = cancel;\n\n return debounced;\n }, [cancel, delayMs]);\n}\n"],"mappings":";;;;;;;AAYA,SAAgB,qBACd,UACA,SACsB;CACtB,MAAM,cAAc,OAAO,QAAQ;CACnC,YAAY,UAAU;CAEtB,MAAM,WAAW,OAA6C,IAAI;CAElE,MAAM,SAAS,kBAAkB;EAC/B,IAAI,SAAS,YAAY,MAAM;GAC7B,aAAa,SAAS,OAAO;GAC7B,SAAS,UAAU;EACrB;CACF,GAAG,CAAC,CAAC;CAEL,gBAAgB,QAAQ,CAAC,MAAM,CAAC;CAEhC,OAAO,cAAc;EACnB,MAAM,aAAa,GAAG,SAAkB;GACtC,OAAO;GACP,SAAS,UAAU,iBAAiB;IAClC,SAAS,UAAU;IACnB,YAAY,QAAQ,GAAG,IAAI;GAC7B,GAAG,OAAO;EACZ;EAEA,UAAU,SAAS;EAEnB,OAAO;CACT,GAAG,CAAC,QAAQ,OAAO,CAAC;AACtB"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { useEffect, useState } from "react";
|
|
2
|
+
//#region resources/js/lib/use-media-query.ts
|
|
3
|
+
function matches(query, fallback) {
|
|
4
|
+
if (typeof window === "undefined" || typeof window.matchMedia !== "function") return fallback;
|
|
5
|
+
return window.matchMedia(query).matches;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Track a CSS media query. `fallback` is the SSR / no-`matchMedia` value and the
|
|
9
|
+
* initial state before the effect subscribes.
|
|
10
|
+
*/
|
|
11
|
+
function useMediaQuery(query, fallback = false) {
|
|
12
|
+
const [state, setState] = useState(() => matches(query, fallback));
|
|
13
|
+
useEffect(() => {
|
|
14
|
+
if (typeof window === "undefined" || typeof window.matchMedia !== "function") return;
|
|
15
|
+
const media = window.matchMedia(query);
|
|
16
|
+
const update = () => setState(media.matches);
|
|
17
|
+
update();
|
|
18
|
+
media.addEventListener("change", update);
|
|
19
|
+
return () => media.removeEventListener("change", update);
|
|
20
|
+
}, [query]);
|
|
21
|
+
return state;
|
|
22
|
+
}
|
|
23
|
+
//#endregion
|
|
24
|
+
export { useMediaQuery };
|
|
25
|
+
|
|
26
|
+
//# sourceMappingURL=use-media-query.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"use-media-query.js","names":[],"sources":["../../resources/js/lib/use-media-query.ts"],"sourcesContent":["import { useEffect, useState } from \"react\";\n\nfunction matches(query: string, fallback: boolean): boolean {\n if (typeof window === \"undefined\" || typeof window.matchMedia !== \"function\") {\n return fallback;\n }\n\n return window.matchMedia(query).matches;\n}\n\n/**\n * Track a CSS media query. `fallback` is the SSR / no-`matchMedia` value and the\n * initial state before the effect subscribes.\n */\nexport function useMediaQuery(query: string, fallback = false): boolean {\n const [state, setState] = useState(() => matches(query, fallback));\n\n useEffect(() => {\n if (typeof window === \"undefined\" || typeof window.matchMedia !== \"function\") {\n return;\n }\n\n const media = window.matchMedia(query);\n const update = (): void => setState(media.matches);\n\n update();\n media.addEventListener(\"change\", update);\n\n return () => media.removeEventListener(\"change\", update);\n }, [query]);\n\n return state;\n}\n"],"mappings":";;AAEA,SAAS,QAAQ,OAAe,UAA4B;CAC1D,IAAI,OAAO,WAAW,eAAe,OAAO,OAAO,eAAe,YAChE,OAAO;CAGT,OAAO,OAAO,WAAW,KAAK,EAAE;AAClC;;;;;AAMA,SAAgB,cAAc,OAAe,WAAW,OAAgB;CACtE,MAAM,CAAC,OAAO,YAAY,eAAe,QAAQ,OAAO,QAAQ,CAAC;CAEjE,gBAAgB;EACd,IAAI,OAAO,WAAW,eAAe,OAAO,OAAO,eAAe,YAChE;EAGF,MAAM,QAAQ,OAAO,WAAW,KAAK;EACrC,MAAM,eAAqB,SAAS,MAAM,OAAO;EAEjD,OAAO;EACP,MAAM,iBAAiB,UAAU,MAAM;EAEvC,aAAa,MAAM,oBAAoB,UAAU,MAAM;CACzD,GAAG,CAAC,KAAK,CAAC;CAEV,OAAO;AACT"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { Dispatch, SetStateAction } from 'react';
|
|
2
|
+
export type PersistentStateOptions<T> = {
|
|
3
|
+
enabled?: boolean;
|
|
4
|
+
parse?: (raw: string) => T;
|
|
5
|
+
serialize?: (value: T) => string | null;
|
|
6
|
+
};
|
|
7
|
+
/**
|
|
8
|
+
* `useState` backed by `localStorage`. The SSR guard and read/write `try/catch`
|
|
9
|
+
* live here once; `parse`/`serialize` default to JSON. Persistence happens in
|
|
10
|
+
* the setter (not inside the state updater), so a StrictMode double-invoke never
|
|
11
|
+
* double-writes, and a `serialize` returning `null` removes the key.
|
|
12
|
+
*/
|
|
13
|
+
export declare function usePersistentState<T>(key: string, fallback: T | (() => T), options?: PersistentStateOptions<T>): [T, Dispatch<SetStateAction<T>>];
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { useCallback, useRef, useState } from "react";
|
|
2
|
+
//#region resources/js/lib/use-persistent-state.ts
|
|
3
|
+
/**
|
|
4
|
+
* `useState` backed by `localStorage`. The SSR guard and read/write `try/catch`
|
|
5
|
+
* live here once; `parse`/`serialize` default to JSON. Persistence happens in
|
|
6
|
+
* the setter (not inside the state updater), so a StrictMode double-invoke never
|
|
7
|
+
* double-writes, and a `serialize` returning `null` removes the key.
|
|
8
|
+
*/
|
|
9
|
+
function usePersistentState(key, fallback, options = {}) {
|
|
10
|
+
const { enabled = true, parse, serialize } = options;
|
|
11
|
+
const resolveFallback = () => typeof fallback === "function" ? fallback() : fallback;
|
|
12
|
+
const [value, setValue] = useState(() => {
|
|
13
|
+
if (!enabled || typeof window === "undefined") return resolveFallback();
|
|
14
|
+
let raw;
|
|
15
|
+
try {
|
|
16
|
+
raw = window.localStorage.getItem(key);
|
|
17
|
+
} catch {
|
|
18
|
+
return resolveFallback();
|
|
19
|
+
}
|
|
20
|
+
if (raw === null) return resolveFallback();
|
|
21
|
+
try {
|
|
22
|
+
return parse ? parse(raw) : JSON.parse(raw);
|
|
23
|
+
} catch {
|
|
24
|
+
try {
|
|
25
|
+
window.localStorage.removeItem(key);
|
|
26
|
+
} catch {
|
|
27
|
+
return resolveFallback();
|
|
28
|
+
}
|
|
29
|
+
return resolveFallback();
|
|
30
|
+
}
|
|
31
|
+
});
|
|
32
|
+
const valueRef = useRef(value);
|
|
33
|
+
valueRef.current = value;
|
|
34
|
+
const persistRef = useRef({
|
|
35
|
+
enabled,
|
|
36
|
+
key,
|
|
37
|
+
serialize
|
|
38
|
+
});
|
|
39
|
+
persistRef.current = {
|
|
40
|
+
enabled,
|
|
41
|
+
key,
|
|
42
|
+
serialize
|
|
43
|
+
};
|
|
44
|
+
return [value, useCallback((action) => {
|
|
45
|
+
const next = typeof action === "function" ? action(valueRef.current) : action;
|
|
46
|
+
valueRef.current = next;
|
|
47
|
+
setValue(next);
|
|
48
|
+
const { enabled: on, key: storageKey, serialize: encode } = persistRef.current;
|
|
49
|
+
if (!on || typeof window === "undefined") return;
|
|
50
|
+
try {
|
|
51
|
+
const encoded = encode ? encode(next) : JSON.stringify(next);
|
|
52
|
+
if (encoded === null) window.localStorage.removeItem(storageKey);
|
|
53
|
+
else window.localStorage.setItem(storageKey, encoded);
|
|
54
|
+
} catch {
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
}, [])];
|
|
58
|
+
}
|
|
59
|
+
//#endregion
|
|
60
|
+
export { usePersistentState };
|
|
61
|
+
|
|
62
|
+
//# sourceMappingURL=use-persistent-state.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"use-persistent-state.js","names":[],"sources":["../../resources/js/lib/use-persistent-state.ts"],"sourcesContent":["import type { Dispatch, SetStateAction } from \"react\";\nimport { useCallback, useRef, useState } from \"react\";\n\nexport type PersistentStateOptions<T> = {\n enabled?: boolean;\n parse?: (raw: string) => T;\n serialize?: (value: T) => string | null;\n};\n\n/**\n * `useState` backed by `localStorage`. The SSR guard and read/write `try/catch`\n * live here once; `parse`/`serialize` default to JSON. Persistence happens in\n * the setter (not inside the state updater), so a StrictMode double-invoke never\n * double-writes, and a `serialize` returning `null` removes the key.\n */\nexport function usePersistentState<T>(\n key: string,\n fallback: T | (() => T),\n options: PersistentStateOptions<T> = {},\n): [T, Dispatch<SetStateAction<T>>] {\n const { enabled = true, parse, serialize } = options;\n\n const resolveFallback = (): T =>\n typeof fallback === \"function\" ? (fallback as () => T)() : fallback;\n\n const [value, setValue] = useState<T>(() => {\n if (!enabled || typeof window === \"undefined\") {\n return resolveFallback();\n }\n\n let raw: string | null;\n try {\n raw = window.localStorage.getItem(key);\n } catch {\n return resolveFallback();\n }\n\n if (raw === null) {\n return resolveFallback();\n }\n\n try {\n return parse ? parse(raw) : (JSON.parse(raw) as T);\n } catch {\n // Drop corrupt data so it cannot resurface on the next read.\n try {\n window.localStorage.removeItem(key);\n } catch {\n return resolveFallback();\n }\n\n return resolveFallback();\n }\n });\n\n const valueRef = useRef(value);\n valueRef.current = value;\n\n const persistRef = useRef({ enabled, key, serialize });\n persistRef.current = { enabled, key, serialize };\n\n const setPersistentValue = useCallback<Dispatch<SetStateAction<T>>>((action) => {\n const next =\n typeof action === \"function\" ? (action as (prev: T) => T)(valueRef.current) : action;\n\n valueRef.current = next;\n setValue(next);\n\n const { enabled: on, key: storageKey, serialize: encode } = persistRef.current;\n\n if (!on || typeof window === \"undefined\") {\n return;\n }\n\n try {\n const encoded = encode ? encode(next) : JSON.stringify(next);\n\n if (encoded === null) {\n window.localStorage.removeItem(storageKey);\n } else {\n window.localStorage.setItem(storageKey, encoded);\n }\n } catch {\n return;\n }\n }, []);\n\n return [value, setPersistentValue];\n}\n"],"mappings":";;;;;;;;AAeA,SAAgB,mBACd,KACA,UACA,UAAqC,CAAC,GACJ;CAClC,MAAM,EAAE,UAAU,MAAM,OAAO,cAAc;CAE7C,MAAM,wBACJ,OAAO,aAAa,aAAc,SAAqB,IAAI;CAE7D,MAAM,CAAC,OAAO,YAAY,eAAkB;EAC1C,IAAI,CAAC,WAAW,OAAO,WAAW,aAChC,OAAO,gBAAgB;EAGzB,IAAI;EACJ,IAAI;GACF,MAAM,OAAO,aAAa,QAAQ,GAAG;EACvC,QAAQ;GACN,OAAO,gBAAgB;EACzB;EAEA,IAAI,QAAQ,MACV,OAAO,gBAAgB;EAGzB,IAAI;GACF,OAAO,QAAQ,MAAM,GAAG,IAAK,KAAK,MAAM,GAAG;EAC7C,QAAQ;GAEN,IAAI;IACF,OAAO,aAAa,WAAW,GAAG;GACpC,QAAQ;IACN,OAAO,gBAAgB;GACzB;GAEA,OAAO,gBAAgB;EACzB;CACF,CAAC;CAED,MAAM,WAAW,OAAO,KAAK;CAC7B,SAAS,UAAU;CAEnB,MAAM,aAAa,OAAO;EAAE;EAAS;EAAK;CAAU,CAAC;CACrD,WAAW,UAAU;EAAE;EAAS;EAAK;CAAU;CA4B/C,OAAO,CAAC,OA1BmB,aAA0C,WAAW;EAC9E,MAAM,OACJ,OAAO,WAAW,aAAc,OAA0B,SAAS,OAAO,IAAI;EAEhF,SAAS,UAAU;EACnB,SAAS,IAAI;EAEb,MAAM,EAAE,SAAS,IAAI,KAAK,YAAY,WAAW,WAAW,WAAW;EAEvE,IAAI,CAAC,MAAM,OAAO,WAAW,aAC3B;EAGF,IAAI;GACF,MAAM,UAAU,SAAS,OAAO,IAAI,IAAI,KAAK,UAAU,IAAI;GAE3D,IAAI,YAAY,MACd,OAAO,aAAa,WAAW,UAAU;QAEzC,OAAO,aAAa,QAAQ,YAAY,OAAO;EAEnD,QAAQ;GACN;EACF;CACF,GAAG,CAAC,CAEW,CAAkB;AACnC"}
|
|
@@ -79,7 +79,10 @@ var NotificationsComponent = ({ node }) => {
|
|
|
79
79
|
open: store.open,
|
|
80
80
|
onOpenChange: store.setOpen,
|
|
81
81
|
children: /* @__PURE__ */ jsxs(DialogContent, {
|
|
82
|
-
|
|
82
|
+
"aria-describedby": void 0,
|
|
83
|
+
className: "p-0",
|
|
84
|
+
placement: "end",
|
|
85
|
+
width: "sm",
|
|
83
86
|
children: [/* @__PURE__ */ jsx(DialogTitle, {
|
|
84
87
|
className: "sr-only",
|
|
85
88
|
children: label
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"notifications.js","names":[],"sources":["../../../resources/js/notifications/components/notifications.tsx"],"sourcesContent":["import { Component, lazy, Suspense, type ReactNode } from \"react\";\nimport { Badge } from \"@lattice-php/lattice/ui/badge\";\nimport { Dialog, DialogContent, DialogTitle } from \"@lattice-php/lattice/ui/dialog\";\nimport {\n Popover as PopoverRoot,\n PopoverContent,\n PopoverTrigger,\n} from \"@lattice-php/lattice/ui/popover\";\nimport { Icon } from \"@lattice-php/lattice/icons\";\nimport { useT } from \"@lattice-php/lattice/i18n\";\nimport type { RendererComponent } from \"@lattice-php/lattice/core/types\";\nimport { useNotifications } from \"@lattice-php/lattice/notifications/store\";\nimport type { NotificationItem } from \"@lattice-php/lattice/notifications/types\";\nimport { NotificationList } from \"./notification-list\";\n\nconst NotificationsEcho = lazy(() =>\n import(\"./notifications-echo\").then((m) => ({ default: m.NotificationsEcho })),\n);\n\nclass EchoBoundary extends Component<{ children: ReactNode }, { failed: boolean }> {\n state = { failed: false };\n\n static getDerivedStateFromError(): { failed: boolean } {\n return { failed: true };\n }\n\n componentDidCatch(): void {\n console.warn(\n \"[lattice] The notifications bell declares a realtime channel but Echo is unavailable. Install @laravel/echo-react and call configureEcho().\",\n );\n }\n\n render(): ReactNode {\n return this.state.failed ? null : this.props.children;\n }\n}\n\nconst NotificationsComponent: RendererComponent<\"notifications\"> = ({ node }) => {\n const { t } = useT(\"lattice\");\n const store = useNotifications({\n endpoint: node.props.endpoint,\n pollingInterval: node.props.pollingInterval,\n });\n\n const label = t(\"notifications.label\", \"Notifications\");\n\n const trigger = (\n <span className=\"relative inline-flex items-center justify-center rounded-lt-sm p-2 hover:bg-lt-muted\">\n <Icon name=\"bell\" className=\"size-lt-icon-md\" />\n {store.unreadCount > 0 ? (\n <Badge\n variant=\"destructive\"\n data-test=\"notifications-badge\"\n className=\"absolute -right-0.5 -top-0.5 min-w-4 px-1 py-0 text-[10px]\"\n >\n {store.unreadCount}\n </Badge>\n ) : null}\n </span>\n );\n\n const panel = (\n <div className=\"w-80\" data-test=\"notifications-panel\">\n <div className=\"flex items-center justify-between border-b border-lt-border px-3 py-2\">\n <span className=\"text-sm font-medium\">{t(\"notifications.heading\", \"Notifications\")}</span>\n {store.unreadCount > 0 ? (\n <button\n type=\"button\"\n className=\"text-xs text-lt-muted-fg hover:text-lt-fg\"\n onClick={store.markAllRead}\n >\n {t(\"notifications.mark-all-read\", \"Mark all read\")}\n </button>\n ) : null}\n </div>\n <NotificationList\n notifications={store.notifications}\n status={store.status}\n hasMore={store.hasMore}\n onMarkRead={store.markRead}\n onDismiss={store.dismiss}\n onLoadMore={store.loadMore}\n />\n </div>\n );\n\n return (\n <>\n {node.props.channel ? (\n <EchoBoundary>\n <Suspense fallback={null}>\n <NotificationsEcho\n channel={node.props.channel}\n onReceive={(item: NotificationItem) => store.receive(item)}\n />\n </Suspense>\n </EchoBoundary>\n ) : null}\n\n {node.props.slideOut ? (\n <>\n <button\n type=\"button\"\n aria-label={label}\n data-test=\"notifications-trigger\"\n onClick={() => store.setOpen(true)}\n >\n {trigger}\n </button>\n <Dialog open={store.open} onOpenChange={store.setOpen}>\n <DialogContent className=\"
|
|
1
|
+
{"version":3,"file":"notifications.js","names":[],"sources":["../../../resources/js/notifications/components/notifications.tsx"],"sourcesContent":["import { Component, lazy, Suspense, type ReactNode } from \"react\";\nimport { Badge } from \"@lattice-php/lattice/ui/badge\";\nimport { Dialog, DialogContent, DialogTitle } from \"@lattice-php/lattice/ui/dialog\";\nimport {\n Popover as PopoverRoot,\n PopoverContent,\n PopoverTrigger,\n} from \"@lattice-php/lattice/ui/popover\";\nimport { Icon } from \"@lattice-php/lattice/icons\";\nimport { useT } from \"@lattice-php/lattice/i18n\";\nimport type { RendererComponent } from \"@lattice-php/lattice/core/types\";\nimport { useNotifications } from \"@lattice-php/lattice/notifications/store\";\nimport type { NotificationItem } from \"@lattice-php/lattice/notifications/types\";\nimport { NotificationList } from \"./notification-list\";\n\nconst NotificationsEcho = lazy(() =>\n import(\"./notifications-echo\").then((m) => ({ default: m.NotificationsEcho })),\n);\n\nclass EchoBoundary extends Component<{ children: ReactNode }, { failed: boolean }> {\n state = { failed: false };\n\n static getDerivedStateFromError(): { failed: boolean } {\n return { failed: true };\n }\n\n componentDidCatch(): void {\n console.warn(\n \"[lattice] The notifications bell declares a realtime channel but Echo is unavailable. Install @laravel/echo-react and call configureEcho().\",\n );\n }\n\n render(): ReactNode {\n return this.state.failed ? null : this.props.children;\n }\n}\n\nconst NotificationsComponent: RendererComponent<\"notifications\"> = ({ node }) => {\n const { t } = useT(\"lattice\");\n const store = useNotifications({\n endpoint: node.props.endpoint,\n pollingInterval: node.props.pollingInterval,\n });\n\n const label = t(\"notifications.label\", \"Notifications\");\n\n const trigger = (\n <span className=\"relative inline-flex items-center justify-center rounded-lt-sm p-2 hover:bg-lt-muted\">\n <Icon name=\"bell\" className=\"size-lt-icon-md\" />\n {store.unreadCount > 0 ? (\n <Badge\n variant=\"destructive\"\n data-test=\"notifications-badge\"\n className=\"absolute -right-0.5 -top-0.5 min-w-4 px-1 py-0 text-[10px]\"\n >\n {store.unreadCount}\n </Badge>\n ) : null}\n </span>\n );\n\n const panel = (\n <div className=\"w-80\" data-test=\"notifications-panel\">\n <div className=\"flex items-center justify-between border-b border-lt-border px-3 py-2\">\n <span className=\"text-sm font-medium\">{t(\"notifications.heading\", \"Notifications\")}</span>\n {store.unreadCount > 0 ? (\n <button\n type=\"button\"\n className=\"text-xs text-lt-muted-fg hover:text-lt-fg\"\n onClick={store.markAllRead}\n >\n {t(\"notifications.mark-all-read\", \"Mark all read\")}\n </button>\n ) : null}\n </div>\n <NotificationList\n notifications={store.notifications}\n status={store.status}\n hasMore={store.hasMore}\n onMarkRead={store.markRead}\n onDismiss={store.dismiss}\n onLoadMore={store.loadMore}\n />\n </div>\n );\n\n return (\n <>\n {node.props.channel ? (\n <EchoBoundary>\n <Suspense fallback={null}>\n <NotificationsEcho\n channel={node.props.channel}\n onReceive={(item: NotificationItem) => store.receive(item)}\n />\n </Suspense>\n </EchoBoundary>\n ) : null}\n\n {node.props.slideOut ? (\n <>\n <button\n type=\"button\"\n aria-label={label}\n data-test=\"notifications-trigger\"\n onClick={() => store.setOpen(true)}\n >\n {trigger}\n </button>\n <Dialog open={store.open} onOpenChange={store.setOpen}>\n <DialogContent aria-describedby={undefined} className=\"p-0\" placement=\"end\" width=\"sm\">\n <DialogTitle className=\"sr-only\">{label}</DialogTitle>\n {panel}\n </DialogContent>\n </Dialog>\n </>\n ) : (\n <PopoverRoot open={store.open} onOpenChange={store.setOpen}>\n <PopoverTrigger asChild>\n <button type=\"button\" aria-label={label} data-test=\"notifications-trigger\">\n {trigger}\n </button>\n </PopoverTrigger>\n <PopoverContent align=\"end\" className=\"p-0\">\n {panel}\n </PopoverContent>\n </PopoverRoot>\n )}\n </>\n );\n};\n\nexport default NotificationsComponent;\n"],"mappings":";;;;;;;;;;AAeA,IAAM,oBAAoB,WACxB,OAAO,2BAAwB,MAAM,OAAO,EAAE,SAAS,EAAE,kBAAkB,EAAE,CAC/E;AAEA,IAAM,eAAN,cAA2B,UAAwD;CACjF,QAAQ,EAAE,QAAQ,MAAM;CAExB,OAAO,2BAAgD;EACrD,OAAO,EAAE,QAAQ,KAAK;CACxB;CAEA,oBAA0B;EACxB,QAAQ,KACN,6IACF;CACF;CAEA,SAAoB;EAClB,OAAO,KAAK,MAAM,SAAS,OAAO,KAAK,MAAM;CAC/C;AACF;AAEA,IAAM,0BAA8D,EAAE,WAAW;CAC/E,MAAM,EAAE,MAAM,KAAK,SAAS;CAC5B,MAAM,QAAQ,iBAAiB;EAC7B,UAAU,KAAK,MAAM;EACrB,iBAAiB,KAAK,MAAM;CAC9B,CAAC;CAED,MAAM,QAAQ,EAAE,uBAAuB,eAAe;CAEtD,MAAM,UACJ,qBAAC,QAAD;EAAM,WAAU;YAAhB,CACE,oBAAC,MAAD;GAAM,MAAK;GAAO,WAAU;EAAmB,CAAA,GAC9C,MAAM,cAAc,IACnB,oBAAC,OAAD;GACE,SAAQ;GACR,aAAU;GACV,WAAU;aAET,MAAM;EACF,CAAA,IACL,IACA;;CAGR,MAAM,QACJ,qBAAC,OAAD;EAAK,WAAU;EAAO,aAAU;YAAhC,CACE,qBAAC,OAAD;GAAK,WAAU;aAAf,CACE,oBAAC,QAAD;IAAM,WAAU;cAAuB,EAAE,yBAAyB,eAAe;GAAQ,CAAA,GACxF,MAAM,cAAc,IACnB,oBAAC,UAAD;IACE,MAAK;IACL,WAAU;IACV,SAAS,MAAM;cAEd,EAAE,+BAA+B,eAAe;GAC3C,CAAA,IACN,IACD;MACL,oBAAC,kBAAD;GACE,eAAe,MAAM;GACrB,QAAQ,MAAM;GACd,SAAS,MAAM;GACf,YAAY,MAAM;GAClB,WAAW,MAAM;GACjB,YAAY,MAAM;EACnB,CAAA,CACE;;CAGP,OACE,qBAAA,YAAA,EAAA,UAAA,CACG,KAAK,MAAM,UACV,oBAAC,cAAD,EAAA,UACE,oBAAC,UAAD;EAAU,UAAU;YAClB,oBAAC,mBAAD;GACE,SAAS,KAAK,MAAM;GACpB,YAAY,SAA2B,MAAM,QAAQ,IAAI;EAC1D,CAAA;CACO,CAAA,EACE,CAAA,IACZ,MAEH,KAAK,MAAM,WACV,qBAAA,YAAA,EAAA,UAAA,CACE,oBAAC,UAAD;EACE,MAAK;EACL,cAAY;EACZ,aAAU;EACV,eAAe,MAAM,QAAQ,IAAI;YAEhC;CACK,CAAA,GACR,oBAAC,QAAD;EAAQ,MAAM,MAAM;EAAM,cAAc,MAAM;YAC5C,qBAAC,eAAD;GAAe,oBAAkB,KAAA;GAAW,WAAU;GAAM,WAAU;GAAM,OAAM;aAAlF,CACE,oBAAC,aAAD;IAAa,WAAU;cAAW;GAAmB,CAAA,GACpD,KACY;;CACT,CAAA,CACR,EAAA,CAAA,IAEF,qBAAC,SAAD;EAAa,MAAM,MAAM;EAAM,cAAc,MAAM;YAAnD,CACE,oBAAC,gBAAD;GAAgB,SAAA;aACd,oBAAC,UAAD;IAAQ,MAAK;IAAS,cAAY;IAAO,aAAU;cAChD;GACK,CAAA;EACM,CAAA,GAChB,oBAAC,gBAAD;GAAgB,OAAM;GAAM,WAAU;aACnC;EACa,CAAA,CACL;GAEf,EAAA,CAAA;AAEN"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"plugin.js","names":[],"sources":["../../resources/js/notifications/plugin.ts"],"sourcesContent":["import {\n createPlugin,\n eagerComponent,\n type ComponentRegistryFor,\n} from \"@lattice-php/lattice/core/registry\";\nimport
|
|
1
|
+
{"version":3,"file":"plugin.js","names":[],"sources":["../../resources/js/notifications/plugin.ts"],"sourcesContent":["import {\n createPlugin,\n eagerComponent,\n type ComponentRegistryFor,\n} from \"@lattice-php/lattice/core/registry\";\nimport type { NotificationNodeType } from \"@lattice-php/lattice/types/generated\";\nimport NotificationsComponent from \"./components/notifications\";\n\nexport const notificationsComponents = createPlugin({\n name: \"lattice/notifications\",\n components: {\n notifications: eagerComponent(NotificationsComponent),\n } satisfies ComponentRegistryFor<NotificationNodeType>,\n});\n"],"mappings":";;;AAQA,IAAa,0BAA0B,aAAa;CAClD,MAAM;CACN,YAAY,EACV,eAAe,eAAe,sBAAsB,EACtD;AACF,CAAC"}
|
package/dist/provider-base.js
CHANGED
|
@@ -2,9 +2,9 @@ import { updateAppearance } from "./appearance/index.js";
|
|
|
2
2
|
import { RegistryContext } from "./core/registry-context.js";
|
|
3
3
|
import { SpriteProvider } from "./icons/sprite.js";
|
|
4
4
|
import { Toaster } from "./toast/toaster.js";
|
|
5
|
-
import { EventBridge } from "./event-bridge.js";
|
|
6
5
|
import { ActionInteractionProvider } from "./action/components/action-trigger-provider.js";
|
|
7
6
|
import { useFlashEffects } from "./effects/use-flash-effects.js";
|
|
7
|
+
import { EventBridge } from "./event-bridge.js";
|
|
8
8
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
9
9
|
//#region resources/js/provider-base.tsx
|
|
10
10
|
var defaultSprite = { href: "" };
|
|
@@ -19,7 +19,7 @@ var EchoBoundary = class extends Component {
|
|
|
19
19
|
* is only fetched where it is actually needed.
|
|
20
20
|
*/
|
|
21
21
|
function RealtimeListeners({ listeners }) {
|
|
22
|
-
if (listeners
|
|
22
|
+
if (listeners.length === 0) return null;
|
|
23
23
|
return /* @__PURE__ */ jsx(EchoBoundary, { children: /* @__PURE__ */ jsx(Suspense, {
|
|
24
24
|
fallback: null,
|
|
25
25
|
children: /* @__PURE__ */ jsx(Subscriptions, { listeners })
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"listeners.js","names":[],"sources":["../../resources/js/realtime/listeners.tsx"],"sourcesContent":["import { Component, lazy, Suspense } from \"react\";\nimport type { ReactNode } from \"react\";\nimport type { Listen } from \"@lattice-php/lattice/types/generated\";\n\nconst Subscriptions = lazy(() => import(\"./subscriptions\"));\n\nclass EchoBoundary extends Component<{ children: ReactNode }, { failed: boolean }> {\n state = { failed: false };\n\n static getDerivedStateFromError(): { failed: boolean } {\n return { failed: true };\n }\n\n componentDidCatch(): void {\n console.warn(\n \"[lattice] Real-time listeners are declared but Echo is unavailable. Install @laravel/echo-react and call configureEcho().\",\n );\n }\n\n render(): ReactNode {\n return this.state.failed ? null : this.props.children;\n }\n}\n\n/**\n * Renders nothing when a page declares no listeners, so the echo-react chunk\n * is only fetched where it is actually needed.\n */\nexport function RealtimeListeners({ listeners }: { listeners
|
|
1
|
+
{"version":3,"file":"listeners.js","names":[],"sources":["../../resources/js/realtime/listeners.tsx"],"sourcesContent":["import { Component, lazy, Suspense } from \"react\";\nimport type { ReactNode } from \"react\";\nimport type { Listen } from \"@lattice-php/lattice/types/generated\";\n\nconst Subscriptions = lazy(() => import(\"./subscriptions\"));\n\nclass EchoBoundary extends Component<{ children: ReactNode }, { failed: boolean }> {\n state = { failed: false };\n\n static getDerivedStateFromError(): { failed: boolean } {\n return { failed: true };\n }\n\n componentDidCatch(): void {\n console.warn(\n \"[lattice] Real-time listeners are declared but Echo is unavailable. Install @laravel/echo-react and call configureEcho().\",\n );\n }\n\n render(): ReactNode {\n return this.state.failed ? null : this.props.children;\n }\n}\n\n/**\n * Renders nothing when a page declares no listeners, so the echo-react chunk\n * is only fetched where it is actually needed.\n */\nexport function RealtimeListeners({ listeners }: { listeners: Listen[] }) {\n if (listeners.length === 0) {\n return null;\n }\n\n return (\n <EchoBoundary>\n <Suspense fallback={null}>\n <Subscriptions listeners={listeners} />\n </Suspense>\n </EchoBoundary>\n );\n}\n"],"mappings":";;;AAIA,IAAM,gBAAgB,WAAW,OAAO,qBAAkB;AAE1D,IAAM,eAAN,cAA2B,UAAwD;CACjF,QAAQ,EAAE,QAAQ,MAAM;CAExB,OAAO,2BAAgD;EACrD,OAAO,EAAE,QAAQ,KAAK;CACxB;CAEA,oBAA0B;EACxB,QAAQ,KACN,2HACF;CACF;CAEA,SAAoB;EAClB,OAAO,KAAK,MAAM,SAAS,OAAO,KAAK,MAAM;CAC/C;AACF;;;;;AAMA,SAAgB,kBAAkB,EAAE,aAAsC;CACxE,IAAI,UAAU,WAAW,GACvB,OAAO;CAGT,OACE,oBAAC,cAAD,EAAA,UACE,oBAAC,UAAD;EAAU,UAAU;YAClB,oBAAC,eAAD,EAA0B,UAAY,CAAA;CAC9B,CAAA,EACE,CAAA;AAElB"}
|