@lattice-php/lattice 0.16.0 → 0.17.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (122) hide show
  1. package/dist/action/components/action-form.js +1 -1
  2. package/dist/action/use-action.js +1 -1
  3. package/dist/chat/types.d.ts +2 -10
  4. package/dist/core/components/button.js +34 -18
  5. package/dist/core/components/button.js.map +1 -1
  6. package/dist/core/components/control.d.ts +0 -2
  7. package/dist/core/components/control.js.map +1 -1
  8. package/dist/core/components/link.js +25 -29
  9. package/dist/core/components/link.js.map +1 -1
  10. package/dist/core/types.d.ts +22 -42
  11. package/dist/core/use-click-behavior.d.ts +42 -0
  12. package/dist/core/use-click-behavior.js +46 -0
  13. package/dist/core/use-click-behavior.js.map +1 -0
  14. package/dist/create-app.d.ts +8 -2
  15. package/dist/create-app.js +4 -2
  16. package/dist/create-app.js.map +1 -1
  17. package/dist/effects/registry.d.ts +9 -20
  18. package/dist/effects/registry.js +4 -6
  19. package/dist/effects/registry.js.map +1 -1
  20. package/dist/events/event-bridge.d.ts +1 -1
  21. package/dist/events/event-bridge.js +1 -1
  22. package/dist/events/event-bridge.js.map +1 -1
  23. package/dist/form/components/base/input-otp.d.ts +2 -1
  24. package/dist/form/components/base/input-otp.js.map +1 -1
  25. package/dist/form/components/conditions.d.ts +1 -1
  26. package/dist/form/components/conditions.js.map +1 -1
  27. package/dist/form/components/field-props.d.ts +2 -1
  28. package/dist/form/components/field-props.js.map +1 -1
  29. package/dist/form/components/field-scope.d.ts +2 -1
  30. package/dist/form/components/field-scope.js.map +1 -1
  31. package/dist/form/components/fields/row-action-menu.d.ts +2 -1
  32. package/dist/form/components/fields/row-action-menu.js.map +1 -1
  33. package/dist/form/components/fields/row-item.d.ts +2 -1
  34. package/dist/form/components/fields/row-item.js.map +1 -1
  35. package/dist/form/components/fields/table-rows.d.ts +2 -1
  36. package/dist/form/components/fields/table-rows.js.map +1 -1
  37. package/dist/form/components/fields/time-picker-columns.d.ts +2 -1
  38. package/dist/form/components/fields/time-picker-columns.js.map +1 -1
  39. package/dist/form/components/fields/time-picker.d.ts +2 -1
  40. package/dist/form/components/fields/time-picker.js.map +1 -1
  41. package/dist/form/components/fields/use-row-collection.d.ts +2 -1
  42. package/dist/form/components/fields/use-row-collection.js.map +1 -1
  43. package/dist/form/components/form-path.d.ts +0 -1
  44. package/dist/form/components/form-path.js +1 -1
  45. package/dist/form/components/form-path.js.map +1 -1
  46. package/dist/form/components/prefill-targets.d.ts +1 -1
  47. package/dist/form/components/prefill-targets.js.map +1 -1
  48. package/dist/form/components/types.d.ts +5 -1
  49. package/dist/form/components/use-field-commit.d.ts +2 -1
  50. package/dist/form/components/use-field-commit.js.map +1 -1
  51. package/dist/form/components/use-form-resolver.d.ts +2 -1
  52. package/dist/form/components/use-form-resolver.js.map +1 -1
  53. package/dist/format/date-time.d.ts +12 -0
  54. package/dist/format/date-time.js +30 -0
  55. package/dist/format/date-time.js.map +1 -0
  56. package/dist/format/value.js +1 -1
  57. package/dist/format/value.js.map +1 -1
  58. package/dist/i18n/config.d.ts +2 -1
  59. package/dist/i18n/config.js.map +1 -1
  60. package/dist/i18n/date-time.js +1 -1
  61. package/dist/i18n/date-time.js.map +1 -1
  62. package/dist/i18n/instance.d.ts +1 -1
  63. package/dist/i18n/instance.js.map +1 -1
  64. package/dist/i18n/locale-reload.d.ts +2 -1
  65. package/dist/i18n/locale-reload.js.map +1 -1
  66. package/dist/index.js +1 -1
  67. package/dist/layout/components.js +1 -1
  68. package/dist/layout/menu-item.js +43 -49
  69. package/dist/layout/menu-item.js.map +1 -1
  70. package/dist/notifications/api.d.ts +6 -0
  71. package/dist/notifications/api.js +21 -0
  72. package/dist/notifications/api.js.map +1 -0
  73. package/dist/notifications/components/empty-state.d.ts +1 -0
  74. package/dist/notifications/components/empty-state.js +21 -0
  75. package/dist/notifications/components/empty-state.js.map +1 -0
  76. package/dist/notifications/components/notification-item.d.ts +6 -0
  77. package/dist/notifications/components/notification-item.js +65 -0
  78. package/dist/notifications/components/notification-item.js.map +1 -0
  79. package/dist/notifications/components/notification-list.d.ts +10 -0
  80. package/dist/notifications/components/notification-list.js +38 -0
  81. package/dist/notifications/components/notification-list.js.map +1 -0
  82. package/dist/notifications/components/notifications-echo.d.ts +5 -0
  83. package/dist/notifications/components/notifications-echo.js +22 -0
  84. package/dist/notifications/components/notifications-echo.js.map +1 -0
  85. package/dist/notifications/components/notifications.d.ts +3 -0
  86. package/dist/notifications/components/notifications.js +109 -0
  87. package/dist/notifications/components/notifications.js.map +1 -0
  88. package/dist/notifications/index.d.ts +1 -0
  89. package/dist/notifications/index.js +11 -0
  90. package/dist/notifications/index.js.map +1 -0
  91. package/dist/notifications/store.d.ts +25 -0
  92. package/dist/notifications/store.js +100 -0
  93. package/dist/notifications/store.js.map +1 -0
  94. package/dist/notifications/types.d.ts +10 -0
  95. package/dist/notifications/types.js +0 -0
  96. package/dist/realtime/build-effects.d.ts +2 -1
  97. package/dist/realtime/build-effects.js.map +1 -1
  98. package/dist/realtime/subscriptions.js.map +1 -1
  99. package/dist/registry/eager.js +2 -1
  100. package/dist/registry/eager.js.map +1 -1
  101. package/dist/registry/lazy.js +2 -1
  102. package/dist/registry/lazy.js.map +1 -1
  103. package/dist/table/bulk.d.ts +2 -1
  104. package/dist/table/bulk.js.map +1 -1
  105. package/dist/table/components/bulk-bar.js +2 -2
  106. package/dist/table/components/cells/money-cell.js +1 -1
  107. package/dist/table/components/cells/number-cell.js +1 -1
  108. package/dist/table/components/cells/text-cell.js +1 -1
  109. package/dist/table/components/filter-controls.d.ts +0 -4
  110. package/dist/table/components/filter-controls.js.map +1 -1
  111. package/dist/table/components/table-cell.js.map +1 -1
  112. package/dist/table/format.d.ts +1 -12
  113. package/dist/table/format.js +2 -26
  114. package/dist/table/format.js.map +1 -1
  115. package/dist/table/types.d.ts +7 -17
  116. package/dist/types/generated.d.ts +119 -290
  117. package/dist/vite-client.d.ts +8 -0
  118. package/dist/vite.d.ts +35 -1
  119. package/dist/vite.js +60 -2
  120. package/dist/vite.js.map +1 -1
  121. package/package.json +13 -2
  122. package/resources/icons/bell.svg +16 -0
@@ -0,0 +1,65 @@
1
+ import { cn } from "../../lib/utils.js";
2
+ import { IconRenderer } from "../../icons/icon-renderer.js";
3
+ import { RenderNode } from "../../core/renderer.js";
4
+ import { useT } from "../../i18n/instance.js";
5
+ import { Link } from "@inertiajs/react";
6
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
7
+ //#region resources/js/notifications/components/notification-item.tsx
8
+ var variantIconClass = {
9
+ success: "text-lt-success",
10
+ info: "text-lt-info",
11
+ warning: "text-lt-warning",
12
+ error: "text-lt-danger"
13
+ };
14
+ function NotificationItemRow({ notification, onMarkRead, onDismiss }) {
15
+ const { t } = useT("lattice");
16
+ const content = /* @__PURE__ */ jsxs(Fragment, { children: [notification.title ? /* @__PURE__ */ jsx("p", {
17
+ className: "truncate text-sm font-medium text-lt-fg",
18
+ children: notification.title
19
+ }) : null, notification.body ? /* @__PURE__ */ jsx("p", {
20
+ className: "text-sm text-lt-muted-fg",
21
+ children: notification.body
22
+ }) : null] });
23
+ return /* @__PURE__ */ jsxs("li", {
24
+ className: cn("flex gap-3 px-3 py-3", !notification.isRead && "bg-lt-muted/40"),
25
+ "data-test": "notification",
26
+ children: [
27
+ notification.icon ? /* @__PURE__ */ jsx(IconRenderer, {
28
+ icon: notification.icon,
29
+ className: cn("mt-0.5 size-lt-icon-md", notification.variant ? variantIconClass[notification.variant] : void 0)
30
+ }) : null,
31
+ /* @__PURE__ */ jsxs("div", {
32
+ className: "min-w-0 flex-1",
33
+ children: [notification.href ? /* @__PURE__ */ jsx(Link, {
34
+ href: notification.href,
35
+ className: "block",
36
+ "data-test": "notification-link",
37
+ onClick: () => onMarkRead(notification.id),
38
+ children: content
39
+ }) : content, notification.actions.length > 0 ? /* @__PURE__ */ jsx("div", {
40
+ className: "mt-2 flex flex-wrap gap-2",
41
+ children: notification.actions.map((node, index) => /* @__PURE__ */ jsx(RenderNode, { node }, node.key ?? node.id ?? `action-${index}`))
42
+ }) : null]
43
+ }),
44
+ /* @__PURE__ */ jsxs("div", {
45
+ className: "flex shrink-0 flex-col gap-1",
46
+ children: [!notification.isRead ? /* @__PURE__ */ jsx("button", {
47
+ type: "button",
48
+ className: "text-xs text-lt-muted-fg hover:text-lt-fg",
49
+ onClick: () => onMarkRead(notification.id),
50
+ children: t("notifications.mark-read", "Mark read")
51
+ }) : null, /* @__PURE__ */ jsx("button", {
52
+ type: "button",
53
+ "aria-label": t("notifications.dismiss", "Dismiss"),
54
+ className: "text-xs text-lt-muted-fg hover:text-lt-fg",
55
+ onClick: () => onDismiss(notification.id),
56
+ children: t("notifications.dismiss", "Dismiss")
57
+ })]
58
+ })
59
+ ]
60
+ });
61
+ }
62
+ //#endregion
63
+ export { NotificationItemRow };
64
+
65
+ //# sourceMappingURL=notification-item.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"notification-item.js","names":[],"sources":["../../../resources/js/notifications/components/notification-item.tsx"],"sourcesContent":["import { Link } from \"@inertiajs/react\";\nimport { RenderNode } from \"@lattice-php/lattice/core/renderer\";\nimport { IconRenderer } from \"@lattice-php/lattice/icons\";\nimport { useT } from \"@lattice-php/lattice/i18n\";\nimport { cn } from \"@lattice-php/lattice/lib/utils\";\nimport type { NotificationItem } from \"../types\";\n\nconst variantIconClass: Record<NonNullable<NotificationItem[\"variant\"]>, string> = {\n success: \"text-lt-success\",\n info: \"text-lt-info\",\n warning: \"text-lt-warning\",\n error: \"text-lt-danger\",\n};\n\nexport function NotificationItemRow({\n notification,\n onMarkRead,\n onDismiss,\n}: {\n notification: NotificationItem;\n onMarkRead: (id: string) => void;\n onDismiss: (id: string) => void;\n}) {\n const { t } = useT(\"lattice\");\n\n const content = (\n <>\n {notification.title ? (\n <p className=\"truncate text-sm font-medium text-lt-fg\">{notification.title}</p>\n ) : null}\n {notification.body ? <p className=\"text-sm text-lt-muted-fg\">{notification.body}</p> : null}\n </>\n );\n\n return (\n <li\n className={cn(\"flex gap-3 px-3 py-3\", !notification.isRead && \"bg-lt-muted/40\")}\n data-test=\"notification\"\n >\n {notification.icon ? (\n <IconRenderer\n icon={notification.icon}\n className={cn(\n \"mt-0.5 size-lt-icon-md\",\n notification.variant ? variantIconClass[notification.variant] : undefined,\n )}\n />\n ) : null}\n <div className=\"min-w-0 flex-1\">\n {notification.href ? (\n <Link\n href={notification.href}\n className=\"block\"\n data-test=\"notification-link\"\n onClick={() => onMarkRead(notification.id)}\n >\n {content}\n </Link>\n ) : (\n content\n )}\n {notification.actions.length > 0 ? (\n <div className=\"mt-2 flex flex-wrap gap-2\">\n {notification.actions.map((node, index) => (\n <RenderNode key={node.key ?? node.id ?? `action-${index}`} node={node} />\n ))}\n </div>\n ) : null}\n </div>\n <div className=\"flex shrink-0 flex-col gap-1\">\n {!notification.isRead ? (\n <button\n type=\"button\"\n className=\"text-xs text-lt-muted-fg hover:text-lt-fg\"\n onClick={() => onMarkRead(notification.id)}\n >\n {t(\"notifications.mark-read\", \"Mark read\")}\n </button>\n ) : null}\n <button\n type=\"button\"\n aria-label={t(\"notifications.dismiss\", \"Dismiss\")}\n className=\"text-xs text-lt-muted-fg hover:text-lt-fg\"\n onClick={() => onDismiss(notification.id)}\n >\n {t(\"notifications.dismiss\", \"Dismiss\")}\n </button>\n </div>\n </li>\n );\n}\n"],"mappings":";;;;;;;AAOA,IAAM,mBAA6E;CACjF,SAAS;CACT,MAAM;CACN,SAAS;CACT,OAAO;AACT;AAEA,SAAgB,oBAAoB,EAClC,cACA,YACA,aAKC;CACD,MAAM,EAAE,MAAM,KAAK,SAAS;CAE5B,MAAM,UACJ,qBAAA,UAAA,EAAA,UAAA,CACG,aAAa,QACZ,oBAAC,KAAD;EAAG,WAAU;YAA2C,aAAa;CAAS,CAAA,IAC5E,MACH,aAAa,OAAO,oBAAC,KAAD;EAAG,WAAU;YAA4B,aAAa;CAAQ,CAAA,IAAI,IACvF,EAAA,CAAA;CAGJ,OACE,qBAAC,MAAD;EACE,WAAW,GAAG,wBAAwB,CAAC,aAAa,UAAU,gBAAgB;EAC9E,aAAU;YAFZ;GAIG,aAAa,OACZ,oBAAC,cAAD;IACE,MAAM,aAAa;IACnB,WAAW,GACT,0BACA,aAAa,UAAU,iBAAiB,aAAa,WAAW,KAAA,CAClE;GACD,CAAA,IACC;GACJ,qBAAC,OAAD;IAAK,WAAU;cAAf,CACG,aAAa,OACZ,oBAAC,MAAD;KACE,MAAM,aAAa;KACnB,WAAU;KACV,aAAU;KACV,eAAe,WAAW,aAAa,EAAE;eAExC;IACG,CAAA,IAEN,SAED,aAAa,QAAQ,SAAS,IAC7B,oBAAC,OAAD;KAAK,WAAU;eACZ,aAAa,QAAQ,KAAK,MAAM,UAC/B,oBAAC,YAAD,EAAiE,KAAO,GAAvD,KAAK,OAAO,KAAK,MAAM,UAAU,OAAsB,CACzE;IACE,CAAA,IACH,IACD;;GACL,qBAAC,OAAD;IAAK,WAAU;cAAf,CACG,CAAC,aAAa,SACb,oBAAC,UAAD;KACE,MAAK;KACL,WAAU;KACV,eAAe,WAAW,aAAa,EAAE;eAExC,EAAE,2BAA2B,WAAW;IACnC,CAAA,IACN,MACJ,oBAAC,UAAD;KACE,MAAK;KACL,cAAY,EAAE,yBAAyB,SAAS;KAChD,WAAU;KACV,eAAe,UAAU,aAAa,EAAE;eAEvC,EAAE,yBAAyB,SAAS;IAC/B,CAAA,CACL;;EACH;;AAER"}
@@ -0,0 +1,10 @@
1
+ import { NotificationItem } from '../types';
2
+ import { NotificationsStatus } from '../store';
3
+ export declare function NotificationList({ notifications, status, hasMore, onMarkRead, onDismiss, onLoadMore, }: {
4
+ notifications: NotificationItem[];
5
+ status: NotificationsStatus;
6
+ hasMore: boolean;
7
+ onMarkRead: (id: string) => void;
8
+ onDismiss: (id: string) => void;
9
+ onLoadMore: () => void;
10
+ }): import("react").JSX.Element;
@@ -0,0 +1,38 @@
1
+ import { useT } from "../../i18n/instance.js";
2
+ import { Skeleton } from "../../core/components/skeleton.js";
3
+ import { EmptyState } from "./empty-state.js";
4
+ import { NotificationItemRow } from "./notification-item.js";
5
+ import { jsx, jsxs } from "react/jsx-runtime";
6
+ //#region resources/js/notifications/components/notification-list.tsx
7
+ function NotificationList({ notifications, status, hasMore, onMarkRead, onDismiss, onLoadMore }) {
8
+ const { t } = useT("lattice");
9
+ if (status === "loading" && notifications.length === 0) return /* @__PURE__ */ jsxs("div", {
10
+ className: "space-y-2 p-3",
11
+ children: [
12
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-12 w-full" }),
13
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-12 w-full" }),
14
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-12 w-full" })
15
+ ]
16
+ });
17
+ if (notifications.length === 0) return /* @__PURE__ */ jsx(EmptyState, {});
18
+ return /* @__PURE__ */ jsxs("div", {
19
+ className: "max-h-96 overflow-y-auto",
20
+ children: [/* @__PURE__ */ jsx("ul", {
21
+ className: "divide-y divide-lt-border",
22
+ children: notifications.map((notification) => /* @__PURE__ */ jsx(NotificationItemRow, {
23
+ notification,
24
+ onMarkRead,
25
+ onDismiss
26
+ }, notification.id))
27
+ }), hasMore ? /* @__PURE__ */ jsx("button", {
28
+ type: "button",
29
+ className: "w-full py-2 text-sm text-lt-muted-fg hover:text-lt-fg",
30
+ onClick: onLoadMore,
31
+ children: t("notifications.load-more", "Load more")
32
+ }) : null]
33
+ });
34
+ }
35
+ //#endregion
36
+ export { NotificationList };
37
+
38
+ //# sourceMappingURL=notification-list.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"notification-list.js","names":[],"sources":["../../../resources/js/notifications/components/notification-list.tsx"],"sourcesContent":["import { Skeleton } from \"@lattice-php/lattice/core/components/skeleton\";\nimport { useT } from \"@lattice-php/lattice/i18n\";\nimport type { NotificationItem } from \"../types\";\nimport type { NotificationsStatus } from \"../store\";\nimport { EmptyState } from \"./empty-state\";\nimport { NotificationItemRow } from \"./notification-item\";\n\nexport function NotificationList({\n notifications,\n status,\n hasMore,\n onMarkRead,\n onDismiss,\n onLoadMore,\n}: {\n notifications: NotificationItem[];\n status: NotificationsStatus;\n hasMore: boolean;\n onMarkRead: (id: string) => void;\n onDismiss: (id: string) => void;\n onLoadMore: () => void;\n}) {\n const { t } = useT(\"lattice\");\n\n if (status === \"loading\" && notifications.length === 0) {\n return (\n <div className=\"space-y-2 p-3\">\n <Skeleton className=\"h-12 w-full\" />\n <Skeleton className=\"h-12 w-full\" />\n <Skeleton className=\"h-12 w-full\" />\n </div>\n );\n }\n\n if (notifications.length === 0) {\n return <EmptyState />;\n }\n\n return (\n <div className=\"max-h-96 overflow-y-auto\">\n <ul className=\"divide-y divide-lt-border\">\n {notifications.map((notification) => (\n <NotificationItemRow\n key={notification.id}\n notification={notification}\n onMarkRead={onMarkRead}\n onDismiss={onDismiss}\n />\n ))}\n </ul>\n {hasMore ? (\n <button\n type=\"button\"\n className=\"w-full py-2 text-sm text-lt-muted-fg hover:text-lt-fg\"\n onClick={onLoadMore}\n >\n {t(\"notifications.load-more\", \"Load more\")}\n </button>\n ) : null}\n </div>\n );\n}\n"],"mappings":";;;;;;AAOA,SAAgB,iBAAiB,EAC/B,eACA,QACA,SACA,YACA,WACA,cAQC;CACD,MAAM,EAAE,MAAM,KAAK,SAAS;CAE5B,IAAI,WAAW,aAAa,cAAc,WAAW,GACnD,OACE,qBAAC,OAAD;EAAK,WAAU;YAAf;GACE,oBAAC,UAAD,EAAU,WAAU,cAAe,CAAA;GACnC,oBAAC,UAAD,EAAU,WAAU,cAAe,CAAA;GACnC,oBAAC,UAAD,EAAU,WAAU,cAAe,CAAA;EAChC;;CAIT,IAAI,cAAc,WAAW,GAC3B,OAAO,oBAAC,YAAD,CAAa,CAAA;CAGtB,OACE,qBAAC,OAAD;EAAK,WAAU;YAAf,CACE,oBAAC,MAAD;GAAI,WAAU;aACX,cAAc,KAAK,iBAClB,oBAAC,qBAAD;IAEgB;IACF;IACD;GACZ,GAJM,aAAa,EAInB,CACF;EACC,CAAA,GACH,UACC,oBAAC,UAAD;GACE,MAAK;GACL,WAAU;GACV,SAAS;aAER,EAAE,2BAA2B,WAAW;EACnC,CAAA,IACN,IACD;;AAET"}
@@ -0,0 +1,5 @@
1
+ import { NotificationItem } from '../types';
2
+ export declare function NotificationsEcho({ channel, onReceive, }: {
3
+ channel: string;
4
+ onReceive: (item: NotificationItem) => void;
5
+ }): null;
@@ -0,0 +1,22 @@
1
+ import { useEchoNotification } from "@laravel/echo-react";
2
+ //#region resources/js/notifications/components/notifications-echo.tsx
3
+ function NotificationsEcho({ channel, onReceive }) {
4
+ useEchoNotification(channel, (payload) => {
5
+ onReceive({
6
+ id: payload.id,
7
+ title: payload.title ?? null,
8
+ body: payload.body ?? null,
9
+ icon: payload.icon ?? null,
10
+ variant: payload.variant ?? null,
11
+ href: payload.href ?? null,
12
+ isRead: false,
13
+ createdAt: null,
14
+ actions: []
15
+ });
16
+ });
17
+ return null;
18
+ }
19
+ //#endregion
20
+ export { NotificationsEcho };
21
+
22
+ //# sourceMappingURL=notifications-echo.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"notifications-echo.js","names":[],"sources":["../../../resources/js/notifications/components/notifications-echo.tsx"],"sourcesContent":["import { useEchoNotification } from \"@laravel/echo-react\";\nimport type { NotificationItem } from \"../types\";\n\nexport function NotificationsEcho({\n channel,\n onReceive,\n}: {\n channel: string;\n onReceive: (item: NotificationItem) => void;\n}) {\n useEchoNotification<Partial<NotificationItem>>(channel, (payload) => {\n onReceive({\n id: payload.id,\n title: payload.title ?? null,\n body: payload.body ?? null,\n icon: payload.icon ?? null,\n variant: payload.variant ?? null,\n href: payload.href ?? null,\n isRead: false,\n createdAt: null,\n actions: [],\n });\n });\n\n return null;\n}\n"],"mappings":";;AAGA,SAAgB,kBAAkB,EAChC,SACA,aAIC;CACD,oBAA+C,UAAU,YAAY;EACnE,UAAU;GACR,IAAI,QAAQ;GACZ,OAAO,QAAQ,SAAS;GACxB,MAAM,QAAQ,QAAQ;GACtB,MAAM,QAAQ,QAAQ;GACtB,SAAS,QAAQ,WAAW;GAC5B,MAAM,QAAQ,QAAQ;GACtB,QAAQ;GACR,WAAW;GACX,SAAS,CAAC;EACZ,CAAC;CACH,CAAC;CAED,OAAO;AACT"}
@@ -0,0 +1,3 @@
1
+ import { RendererComponent } from '../../core/types';
2
+ declare const NotificationsComponent: RendererComponent<"notifications">;
3
+ export default NotificationsComponent;
@@ -0,0 +1,109 @@
1
+ import { Icon } from "../../icons/sprite.js";
2
+ import { useT } from "../../i18n/instance.js";
3
+ import { Popover, PopoverContent, PopoverTrigger } from "../../core/components/popover.js";
4
+ import { Dialog, DialogContent, DialogTitle } from "../../core/components/dialog.js";
5
+ import { Badge } from "../../core/components/badge.js";
6
+ import { useNotifications } from "../store.js";
7
+ import { NotificationList } from "./notification-list.js";
8
+ import { Component, Suspense, lazy } from "react";
9
+ import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
10
+ //#region resources/js/notifications/components/notifications.tsx
11
+ var NotificationsEcho = lazy(() => import("./notifications-echo.js").then((m) => ({ default: m.NotificationsEcho })));
12
+ var EchoBoundary = class extends Component {
13
+ state = { failed: false };
14
+ static getDerivedStateFromError() {
15
+ return { failed: true };
16
+ }
17
+ componentDidCatch() {
18
+ console.warn("[lattice] The notifications bell declares a realtime channel but Echo is unavailable. Install @laravel/echo-react and call configureEcho().");
19
+ }
20
+ render() {
21
+ return this.state.failed ? null : this.props.children;
22
+ }
23
+ };
24
+ var NotificationsComponent = ({ node }) => {
25
+ const { t } = useT("lattice");
26
+ const store = useNotifications({
27
+ endpoint: node.props.endpoint,
28
+ pollingInterval: node.props.pollingInterval
29
+ });
30
+ const label = t("notifications.label", "Notifications");
31
+ const trigger = /* @__PURE__ */ jsxs("span", {
32
+ className: "relative inline-flex items-center justify-center rounded-lt-sm p-2 hover:bg-lt-muted",
33
+ children: [/* @__PURE__ */ jsx(Icon, {
34
+ name: "bell",
35
+ className: "size-lt-icon-md"
36
+ }), store.unreadCount > 0 ? /* @__PURE__ */ jsx(Badge, {
37
+ variant: "destructive",
38
+ "data-test": "notifications-badge",
39
+ className: "absolute -right-0.5 -top-0.5 min-w-4 px-1 py-0 text-[10px]",
40
+ children: store.unreadCount
41
+ }) : null]
42
+ });
43
+ const panel = /* @__PURE__ */ jsxs("div", {
44
+ className: "w-80",
45
+ "data-test": "notifications-panel",
46
+ children: [/* @__PURE__ */ jsxs("div", {
47
+ className: "flex items-center justify-between border-b border-lt-border px-3 py-2",
48
+ children: [/* @__PURE__ */ jsx("span", {
49
+ className: "text-sm font-medium",
50
+ children: t("notifications.heading", "Notifications")
51
+ }), store.unreadCount > 0 ? /* @__PURE__ */ jsx("button", {
52
+ type: "button",
53
+ className: "text-xs text-lt-muted-fg hover:text-lt-fg",
54
+ onClick: store.markAllRead,
55
+ children: t("notifications.mark-all-read", "Mark all read")
56
+ }) : null]
57
+ }), /* @__PURE__ */ jsx(NotificationList, {
58
+ notifications: store.notifications,
59
+ status: store.status,
60
+ hasMore: store.hasMore,
61
+ onMarkRead: store.markRead,
62
+ onDismiss: store.dismiss,
63
+ onLoadMore: store.loadMore
64
+ })]
65
+ });
66
+ return /* @__PURE__ */ jsxs(Fragment$1, { children: [node.props.channel ? /* @__PURE__ */ jsx(EchoBoundary, { children: /* @__PURE__ */ jsx(Suspense, {
67
+ fallback: null,
68
+ children: /* @__PURE__ */ jsx(NotificationsEcho, {
69
+ channel: node.props.channel,
70
+ onReceive: (item) => store.receive(item)
71
+ })
72
+ }) }) : null, node.props.slideOut ? /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx("button", {
73
+ type: "button",
74
+ "aria-label": label,
75
+ "data-test": "notifications-trigger",
76
+ onClick: () => store.setOpen(true),
77
+ children: trigger
78
+ }), /* @__PURE__ */ jsx(Dialog, {
79
+ open: store.open,
80
+ onOpenChange: store.setOpen,
81
+ children: /* @__PURE__ */ jsxs(DialogContent, {
82
+ className: "fixed left-auto right-0 top-0 h-full w-96 max-w-full translate-x-0 translate-y-0 overflow-y-auto p-0",
83
+ children: [/* @__PURE__ */ jsx(DialogTitle, {
84
+ className: "sr-only",
85
+ children: label
86
+ }), panel]
87
+ })
88
+ })] }) : /* @__PURE__ */ jsxs(Popover, {
89
+ open: store.open,
90
+ onOpenChange: store.setOpen,
91
+ children: [/* @__PURE__ */ jsx(PopoverTrigger, {
92
+ asChild: true,
93
+ children: /* @__PURE__ */ jsx("button", {
94
+ type: "button",
95
+ "aria-label": label,
96
+ "data-test": "notifications-trigger",
97
+ children: trigger
98
+ })
99
+ }), /* @__PURE__ */ jsx(PopoverContent, {
100
+ align: "end",
101
+ className: "p-0",
102
+ children: panel
103
+ })]
104
+ })] });
105
+ };
106
+ //#endregion
107
+ export { NotificationsComponent as default };
108
+
109
+ //# sourceMappingURL=notifications.js.map
@@ -0,0 +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/core/components/badge\";\nimport { Dialog, DialogContent, DialogTitle } from \"@lattice-php/lattice/core/components/dialog\";\nimport {\n Popover as PopoverRoot,\n PopoverContent,\n PopoverTrigger,\n} from \"@lattice-php/lattice/core/components/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 \"../store\";\nimport type { NotificationItem } from \"../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=\"fixed left-auto right-0 top-0 h-full w-96 max-w-full translate-x-0 translate-y-0 overflow-y-auto p-0\">\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,WAAU;aAAzB,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"}
@@ -0,0 +1 @@
1
+ export declare const notificationsPlugin: import('../core/registry').Plugin;
@@ -0,0 +1,11 @@
1
+ import { createPlugin, eagerComponent } from "../core/registry.js";
2
+ import NotificationsComponent from "./components/notifications.js";
3
+ //#region resources/js/notifications/index.ts
4
+ var notificationsPlugin = createPlugin({
5
+ name: "lattice/notifications",
6
+ components: { notifications: eagerComponent(NotificationsComponent) }
7
+ });
8
+ //#endregion
9
+ export { notificationsPlugin };
10
+
11
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","names":[],"sources":["../../resources/js/notifications/index.ts"],"sourcesContent":["import { createPlugin, eagerComponent } from \"@lattice-php/lattice/core/registry\";\nimport NotificationsComponent from \"./components/notifications\";\n\nexport const notificationsPlugin = createPlugin({\n name: \"lattice/notifications\",\n components: {\n notifications: eagerComponent(NotificationsComponent),\n },\n});\n"],"mappings":";;;AAGA,IAAa,sBAAsB,aAAa;CAC9C,MAAM;CACN,YAAY,EACV,eAAe,eAAe,sBAAsB,EACtD;AACF,CAAC"}
@@ -0,0 +1,25 @@
1
+ import { NotificationItem } from './types';
2
+ export declare function prependIncoming(list: NotificationItem[], item: NotificationItem): NotificationItem[];
3
+ export declare function markReadIn(list: NotificationItem[], id: string): NotificationItem[];
4
+ export declare function removeIn(list: NotificationItem[], id: string): NotificationItem[];
5
+ export type NotificationsStatus = "loading" | "idle" | "error";
6
+ type UseNotificationsOptions = {
7
+ endpoint: string;
8
+ pollingInterval?: number | null;
9
+ };
10
+ type UseNotificationsReturn = {
11
+ notifications: NotificationItem[];
12
+ unreadCount: number;
13
+ status: NotificationsStatus;
14
+ hasMore: boolean;
15
+ open: boolean;
16
+ setOpen: (open: boolean) => void;
17
+ loadMore: () => void;
18
+ markRead: (id: string) => void;
19
+ markAllRead: () => void;
20
+ dismiss: (id: string) => void;
21
+ clearAll: () => void;
22
+ receive: (item: NotificationItem) => void;
23
+ };
24
+ export declare function useNotifications({ endpoint, pollingInterval, }: UseNotificationsOptions): UseNotificationsReturn;
25
+ export {};
@@ -0,0 +1,100 @@
1
+ import { clearAll, dismiss, fetchNotifications, markAllRead, markRead } from "./api.js";
2
+ import { useCallback, useEffect, useRef, useState } from "react";
3
+ //#region resources/js/notifications/store.ts
4
+ function prependIncoming(list, item) {
5
+ if (list.some((n) => n.id === item.id)) return list;
6
+ return [item, ...list];
7
+ }
8
+ function markReadIn(list, id) {
9
+ return list.map((n) => n.id === id ? {
10
+ ...n,
11
+ isRead: true
12
+ } : n);
13
+ }
14
+ function removeIn(list, id) {
15
+ return list.filter((n) => n.id !== id);
16
+ }
17
+ function useNotifications({ endpoint, pollingInterval }) {
18
+ const [notifications, setNotifications] = useState([]);
19
+ const [unreadCount, setUnreadCount] = useState(0);
20
+ const [status, setStatus] = useState("loading");
21
+ const [hasMore, setHasMore] = useState(false);
22
+ const [open, setOpen] = useState(false);
23
+ const pageRef = useRef(1);
24
+ const hasMoreRef = useRef(hasMore);
25
+ hasMoreRef.current = hasMore;
26
+ const loadingMoreRef = useRef(false);
27
+ const hydrate = useCallback(async () => {
28
+ try {
29
+ const result = await fetchNotifications(endpoint, 1);
30
+ pageRef.current = 1;
31
+ setNotifications(result.notifications);
32
+ setUnreadCount(result.unreadCount);
33
+ setHasMore(result.hasMore);
34
+ setStatus("idle");
35
+ } catch {
36
+ setStatus("error");
37
+ }
38
+ }, [endpoint]);
39
+ useEffect(() => {
40
+ hydrate();
41
+ }, [hydrate]);
42
+ useEffect(() => {
43
+ if (!pollingInterval || pollingInterval <= 0) return;
44
+ const timer = setInterval(() => void hydrate(), pollingInterval * 1e3);
45
+ return () => clearInterval(timer);
46
+ }, [hydrate, pollingInterval]);
47
+ return {
48
+ notifications,
49
+ unreadCount,
50
+ status,
51
+ hasMore,
52
+ open,
53
+ setOpen,
54
+ loadMore: useCallback(() => {
55
+ if (loadingMoreRef.current || !hasMoreRef.current) return;
56
+ loadingMoreRef.current = true;
57
+ const next = pageRef.current + 1;
58
+ fetchNotifications(endpoint, next).then((result) => {
59
+ pageRef.current = next;
60
+ setNotifications((current) => [...current, ...result.notifications]);
61
+ setHasMore(result.hasMore);
62
+ }).catch(() => void hydrate()).finally(() => {
63
+ loadingMoreRef.current = false;
64
+ });
65
+ }, [endpoint, hydrate]),
66
+ markRead: useCallback((id) => {
67
+ setNotifications((current) => markReadIn(current, id));
68
+ setUnreadCount((count) => Math.max(0, count - 1));
69
+ markRead(endpoint, id).then((r) => setUnreadCount(r.unreadCount)).catch(() => void hydrate());
70
+ }, [endpoint, hydrate]),
71
+ markAllRead: useCallback(() => {
72
+ setNotifications((current) => current.map((n) => ({
73
+ ...n,
74
+ isRead: true
75
+ })));
76
+ setUnreadCount(0);
77
+ markAllRead(endpoint).then((r) => setUnreadCount(r.unreadCount)).catch(() => void hydrate());
78
+ }, [endpoint, hydrate]),
79
+ dismiss: useCallback((id) => {
80
+ setNotifications((current) => removeIn(current, id));
81
+ dismiss(endpoint, id).then((r) => setUnreadCount(r.unreadCount)).catch(() => void hydrate());
82
+ }, [endpoint, hydrate]),
83
+ clearAll: useCallback(() => {
84
+ setNotifications([]);
85
+ setUnreadCount(0);
86
+ clearAll(endpoint).then((r) => setUnreadCount(r.unreadCount)).catch(() => void hydrate());
87
+ }, [endpoint, hydrate]),
88
+ receive: useCallback((item) => {
89
+ setNotifications((current) => {
90
+ const next = prependIncoming(current, item);
91
+ if (next !== current) setUnreadCount((count) => count + 1);
92
+ return next;
93
+ });
94
+ }, [])
95
+ };
96
+ }
97
+ //#endregion
98
+ export { markReadIn, prependIncoming, removeIn, useNotifications };
99
+
100
+ //# sourceMappingURL=store.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"store.js","names":[],"sources":["../../resources/js/notifications/store.ts"],"sourcesContent":["import { useCallback, useEffect, useRef, useState } from \"react\";\nimport {\n clearAll as apiClearAll,\n dismiss as apiDismiss,\n fetchNotifications,\n markAllRead as apiMarkAllRead,\n markRead as apiMarkRead,\n} from \"./api\";\nimport type { NotificationItem } from \"./types\";\n\nexport function prependIncoming(\n list: NotificationItem[],\n item: NotificationItem,\n): NotificationItem[] {\n if (list.some((n) => n.id === item.id)) {\n return list;\n }\n\n return [item, ...list];\n}\n\nexport function markReadIn(list: NotificationItem[], id: string): NotificationItem[] {\n return list.map((n) => (n.id === id ? { ...n, isRead: true } : n));\n}\n\nexport function removeIn(list: NotificationItem[], id: string): NotificationItem[] {\n return list.filter((n) => n.id !== id);\n}\n\nexport type NotificationsStatus = \"loading\" | \"idle\" | \"error\";\n\ntype UseNotificationsOptions = {\n endpoint: string;\n pollingInterval?: number | null;\n};\n\ntype UseNotificationsReturn = {\n notifications: NotificationItem[];\n unreadCount: number;\n status: NotificationsStatus;\n hasMore: boolean;\n open: boolean;\n setOpen: (open: boolean) => void;\n loadMore: () => void;\n markRead: (id: string) => void;\n markAllRead: () => void;\n dismiss: (id: string) => void;\n clearAll: () => void;\n receive: (item: NotificationItem) => void;\n};\n\nexport function useNotifications({\n endpoint,\n pollingInterval,\n}: UseNotificationsOptions): UseNotificationsReturn {\n const [notifications, setNotifications] = useState<NotificationItem[]>([]);\n const [unreadCount, setUnreadCount] = useState(0);\n const [status, setStatus] = useState<NotificationsStatus>(\"loading\");\n const [hasMore, setHasMore] = useState(false);\n const [open, setOpen] = useState(false);\n const pageRef = useRef(1);\n const hasMoreRef = useRef(hasMore);\n hasMoreRef.current = hasMore;\n const loadingMoreRef = useRef(false);\n\n const hydrate = useCallback(async (): Promise<void> => {\n try {\n const result = await fetchNotifications(endpoint, 1);\n pageRef.current = 1;\n setNotifications(result.notifications);\n setUnreadCount(result.unreadCount);\n setHasMore(result.hasMore);\n setStatus(\"idle\");\n } catch {\n setStatus(\"error\");\n }\n }, [endpoint]);\n\n useEffect(() => {\n void hydrate();\n }, [hydrate]);\n\n useEffect(() => {\n if (!pollingInterval || pollingInterval <= 0) {\n return;\n }\n\n const timer = setInterval(() => void hydrate(), pollingInterval * 1000);\n\n return () => clearInterval(timer);\n }, [hydrate, pollingInterval]);\n\n const loadMore = useCallback((): void => {\n if (loadingMoreRef.current || !hasMoreRef.current) {\n return;\n }\n\n loadingMoreRef.current = true;\n const next = pageRef.current + 1;\n void fetchNotifications(endpoint, next)\n .then((result) => {\n pageRef.current = next;\n setNotifications((current) => [...current, ...result.notifications]);\n setHasMore(result.hasMore);\n })\n .catch(() => void hydrate())\n .finally(() => {\n loadingMoreRef.current = false;\n });\n }, [endpoint, hydrate]);\n\n const markRead = useCallback(\n (id: string): void => {\n setNotifications((current) => markReadIn(current, id));\n setUnreadCount((count) => Math.max(0, count - 1));\n void apiMarkRead(endpoint, id)\n .then((r) => setUnreadCount(r.unreadCount))\n .catch(() => void hydrate());\n },\n [endpoint, hydrate],\n );\n\n const markAllRead = useCallback((): void => {\n setNotifications((current) => current.map((n) => ({ ...n, isRead: true })));\n setUnreadCount(0);\n void apiMarkAllRead(endpoint)\n .then((r) => setUnreadCount(r.unreadCount))\n .catch(() => void hydrate());\n }, [endpoint, hydrate]);\n\n const dismiss = useCallback(\n (id: string): void => {\n setNotifications((current) => removeIn(current, id));\n void apiDismiss(endpoint, id)\n .then((r) => setUnreadCount(r.unreadCount))\n .catch(() => void hydrate());\n },\n [endpoint, hydrate],\n );\n\n const clearAll = useCallback((): void => {\n setNotifications([]);\n setUnreadCount(0);\n void apiClearAll(endpoint)\n .then((r) => setUnreadCount(r.unreadCount))\n .catch(() => void hydrate());\n }, [endpoint, hydrate]);\n\n const receive = useCallback((item: NotificationItem): void => {\n setNotifications((current) => {\n const next = prependIncoming(current, item);\n if (next !== current) {\n setUnreadCount((count) => count + 1);\n }\n return next;\n });\n }, []);\n\n return {\n notifications,\n unreadCount,\n status,\n hasMore,\n open,\n setOpen,\n loadMore,\n markRead,\n markAllRead,\n dismiss,\n clearAll,\n receive,\n };\n}\n"],"mappings":";;;AAUA,SAAgB,gBACd,MACA,MACoB;CACpB,IAAI,KAAK,MAAM,MAAM,EAAE,OAAO,KAAK,EAAE,GACnC,OAAO;CAGT,OAAO,CAAC,MAAM,GAAG,IAAI;AACvB;AAEA,SAAgB,WAAW,MAA0B,IAAgC;CACnF,OAAO,KAAK,KAAK,MAAO,EAAE,OAAO,KAAK;EAAE,GAAG;EAAG,QAAQ;CAAK,IAAI,CAAE;AACnE;AAEA,SAAgB,SAAS,MAA0B,IAAgC;CACjF,OAAO,KAAK,QAAQ,MAAM,EAAE,OAAO,EAAE;AACvC;AAwBA,SAAgB,iBAAiB,EAC/B,UACA,mBACkD;CAClD,MAAM,CAAC,eAAe,oBAAoB,SAA6B,CAAC,CAAC;CACzE,MAAM,CAAC,aAAa,kBAAkB,SAAS,CAAC;CAChD,MAAM,CAAC,QAAQ,aAAa,SAA8B,SAAS;CACnE,MAAM,CAAC,SAAS,cAAc,SAAS,KAAK;CAC5C,MAAM,CAAC,MAAM,WAAW,SAAS,KAAK;CACtC,MAAM,UAAU,OAAO,CAAC;CACxB,MAAM,aAAa,OAAO,OAAO;CACjC,WAAW,UAAU;CACrB,MAAM,iBAAiB,OAAO,KAAK;CAEnC,MAAM,UAAU,YAAY,YAA2B;EACrD,IAAI;GACF,MAAM,SAAS,MAAM,mBAAmB,UAAU,CAAC;GACnD,QAAQ,UAAU;GAClB,iBAAiB,OAAO,aAAa;GACrC,eAAe,OAAO,WAAW;GACjC,WAAW,OAAO,OAAO;GACzB,UAAU,MAAM;EAClB,QAAQ;GACN,UAAU,OAAO;EACnB;CACF,GAAG,CAAC,QAAQ,CAAC;CAEb,gBAAgB;EACd,QAAa;CACf,GAAG,CAAC,OAAO,CAAC;CAEZ,gBAAgB;EACd,IAAI,CAAC,mBAAmB,mBAAmB,GACzC;EAGF,MAAM,QAAQ,kBAAkB,KAAK,QAAQ,GAAG,kBAAkB,GAAI;EAEtE,aAAa,cAAc,KAAK;CAClC,GAAG,CAAC,SAAS,eAAe,CAAC;CAoE7B,OAAO;EACL;EACA;EACA;EACA;EACA;EACA;EACA,UAzEe,kBAAwB;GACvC,IAAI,eAAe,WAAW,CAAC,WAAW,SACxC;GAGF,eAAe,UAAU;GACzB,MAAM,OAAO,QAAQ,UAAU;GAC/B,mBAAwB,UAAU,IAAI,EACnC,MAAM,WAAW;IAChB,QAAQ,UAAU;IAClB,kBAAkB,YAAY,CAAC,GAAG,SAAS,GAAG,OAAO,aAAa,CAAC;IACnE,WAAW,OAAO,OAAO;GAC3B,CAAC,EACA,YAAY,KAAK,QAAQ,CAAC,EAC1B,cAAc;IACb,eAAe,UAAU;GAC3B,CAAC;EACL,GAAG,CAAC,UAAU,OAAO,CAwDnB;EACA,UAvDe,aACd,OAAqB;GACpB,kBAAkB,YAAY,WAAW,SAAS,EAAE,CAAC;GACrD,gBAAgB,UAAU,KAAK,IAAI,GAAG,QAAQ,CAAC,CAAC;GAChD,SAAiB,UAAU,EAAE,EAC1B,MAAM,MAAM,eAAe,EAAE,WAAW,CAAC,EACzC,YAAY,KAAK,QAAQ,CAAC;EAC/B,GACA,CAAC,UAAU,OAAO,CA+ClB;EACA,aA7CkB,kBAAwB;GAC1C,kBAAkB,YAAY,QAAQ,KAAK,OAAO;IAAE,GAAG;IAAG,QAAQ;GAAK,EAAE,CAAC;GAC1E,eAAe,CAAC;GAChB,YAAoB,QAAQ,EACzB,MAAM,MAAM,eAAe,EAAE,WAAW,CAAC,EACzC,YAAY,KAAK,QAAQ,CAAC;EAC/B,GAAG,CAAC,UAAU,OAAO,CAuCnB;EACA,SAtCc,aACb,OAAqB;GACpB,kBAAkB,YAAY,SAAS,SAAS,EAAE,CAAC;GACnD,QAAgB,UAAU,EAAE,EACzB,MAAM,MAAM,eAAe,EAAE,WAAW,CAAC,EACzC,YAAY,KAAK,QAAQ,CAAC;EAC/B,GACA,CAAC,UAAU,OAAO,CA+BlB;EACA,UA7Be,kBAAwB;GACvC,iBAAiB,CAAC,CAAC;GACnB,eAAe,CAAC;GAChB,SAAiB,QAAQ,EACtB,MAAM,MAAM,eAAe,EAAE,WAAW,CAAC,EACzC,YAAY,KAAK,QAAQ,CAAC;EAC/B,GAAG,CAAC,UAAU,OAAO,CAuBnB;EACA,SAtBc,aAAa,SAAiC;GAC5D,kBAAkB,YAAY;IAC5B,MAAM,OAAO,gBAAgB,SAAS,IAAI;IAC1C,IAAI,SAAS,SACX,gBAAgB,UAAU,QAAQ,CAAC;IAErC,OAAO;GACT,CAAC;EACH,GAAG,CAAC,CAcF;CACF;AACF"}
@@ -0,0 +1,10 @@
1
+ import { NotificationItem } from '../types/generated';
2
+ export type { NotificationItem };
3
+ export type NotificationsResponse = {
4
+ notifications: NotificationItem[];
5
+ unreadCount: number;
6
+ hasMore: boolean;
7
+ };
8
+ export type UnreadCountResponse = {
9
+ unreadCount: number;
10
+ };
File without changes
@@ -1,4 +1,5 @@
1
1
  import { Effect } from '../types/generated';
2
2
  import { Translate } from '../i18n/translatable';
3
- export type RawEffect = Record<string, unknown>;
3
+ type RawEffect = Record<string, unknown>;
4
4
  export declare function buildEffects(effects: readonly RawEffect[], payload: Record<string, unknown>, t: Translate): Effect[];
5
+ export {};
@@ -1 +1 @@
1
- {"version":3,"file":"build-effects.js","names":[],"sources":["../../resources/js/realtime/build-effects.ts"],"sourcesContent":["import type { Effect } from \"@lattice-php/lattice/types/generated\";\nimport { isTranslatable, resolveTranslatable } from \"@lattice-php/lattice/i18n/translatable\";\nimport type { Translate } from \"@lattice-php/lattice/i18n/translatable\";\n\nexport type RawEffect = Record<string, unknown>;\n\nexport function buildEffects(\n effects: readonly RawEffect[],\n payload: Record<string, unknown>,\n t: Translate,\n): Effect[] {\n return effects.map((effect) => resolveEffect(effect, payload, t)) as Effect[];\n}\n\nfunction resolveEffect(\n effect: RawEffect,\n payload: Record<string, unknown>,\n t: Translate,\n): RawEffect {\n if (effect.type !== \"toast\") {\n return effect;\n }\n\n const toast = effect.toast;\n\n if (typeof toast !== \"object\" || toast === null) {\n return effect;\n }\n\n const message = (toast as Record<string, unknown>).message;\n\n if (!isTranslatable(message)) {\n return effect;\n }\n\n return {\n ...effect,\n toast: {\n ...(toast as Record<string, unknown>),\n message: resolveTranslatable(message, payload, t),\n },\n };\n}\n"],"mappings":";;AAMA,SAAgB,aACd,SACA,SACA,GACU;CACV,OAAO,QAAQ,KAAK,WAAW,cAAc,QAAQ,SAAS,CAAC,CAAC;AAClE;AAEA,SAAS,cACP,QACA,SACA,GACW;CACX,IAAI,OAAO,SAAS,SAClB,OAAO;CAGT,MAAM,QAAQ,OAAO;CAErB,IAAI,OAAO,UAAU,YAAY,UAAU,MACzC,OAAO;CAGT,MAAM,UAAW,MAAkC;CAEnD,IAAI,CAAC,eAAe,OAAO,GACzB,OAAO;CAGT,OAAO;EACL,GAAG;EACH,OAAO;GACL,GAAI;GACJ,SAAS,oBAAoB,SAAS,SAAS,CAAC;EAClD;CACF;AACF"}
1
+ {"version":3,"file":"build-effects.js","names":[],"sources":["../../resources/js/realtime/build-effects.ts"],"sourcesContent":["import type { Effect } from \"@lattice-php/lattice/types/generated\";\nimport { isTranslatable, resolveTranslatable } from \"@lattice-php/lattice/i18n/translatable\";\nimport type { Translate } from \"@lattice-php/lattice/i18n/translatable\";\n\ntype RawEffect = Record<string, unknown>;\n\nexport function buildEffects(\n effects: readonly RawEffect[],\n payload: Record<string, unknown>,\n t: Translate,\n): Effect[] {\n return effects.map((effect) => resolveEffect(effect, payload, t)) as Effect[];\n}\n\nfunction resolveEffect(\n effect: RawEffect,\n payload: Record<string, unknown>,\n t: Translate,\n): RawEffect {\n if (effect.type !== \"toast\") {\n return effect;\n }\n\n const toast = effect.toast;\n\n if (typeof toast !== \"object\" || toast === null) {\n return effect;\n }\n\n const message = (toast as Record<string, unknown>).message;\n\n if (!isTranslatable(message)) {\n return effect;\n }\n\n return {\n ...effect,\n toast: {\n ...(toast as Record<string, unknown>),\n message: resolveTranslatable(message, payload, t),\n },\n };\n}\n"],"mappings":";;AAMA,SAAgB,aACd,SACA,SACA,GACU;CACV,OAAO,QAAQ,KAAK,WAAW,cAAc,QAAQ,SAAS,CAAC,CAAC;AAClE;AAEA,SAAS,cACP,QACA,SACA,GACW;CACX,IAAI,OAAO,SAAS,SAClB,OAAO;CAGT,MAAM,QAAQ,OAAO;CAErB,IAAI,OAAO,UAAU,YAAY,UAAU,MACzC,OAAO;CAGT,MAAM,UAAW,MAAkC;CAEnD,IAAI,CAAC,eAAe,OAAO,GACzB,OAAO;CAGT,OAAO;EACL,GAAG;EACH,OAAO;GACL,GAAI;GACJ,SAAS,oBAAoB,SAAS,SAAS,CAAC;EAClD;CACF;AACF"}
@@ -1 +1 @@
1
- {"version":3,"file":"subscriptions.js","names":[],"sources":["../../resources/js/realtime/subscriptions.tsx"],"sourcesContent":["import { useEcho, useEchoPresence, useEchoPublic } from \"@laravel/echo-react\";\nimport { useCallback } from \"react\";\nimport { useEffectDispatcher } from \"@lattice-php/lattice/effects/use-effect-dispatcher\";\nimport { useT } from \"@lattice-php/lattice/i18n\";\nimport { buildEffects } from \"./build-effects\";\nimport type { RawEffect } from \"./build-effects\";\nimport type { ListenerPayload } from \"@lattice-php/lattice/types/generated\";\n\nfunction useListenerHandler(listener: ListenerPayload): (payload: unknown) => void {\n const { t } = useT(\"lattice\");\n const dispatch = useEffectDispatcher();\n\n return useCallback(\n (payload: unknown) => {\n const data = (typeof payload === \"object\" && payload !== null ? payload : {}) as Record<\n string,\n unknown\n >;\n dispatch(buildEffects(listener.effects as unknown as RawEffect[], data, t));\n },\n [dispatch, listener, t],\n );\n}\n\nfunction PublicListener({ listener }: { listener: ListenerPayload }) {\n useEchoPublic(listener.channel, listener.events, useListenerHandler(listener));\n return null;\n}\n\nfunction PrivateListener({ listener }: { listener: ListenerPayload }) {\n useEcho(listener.channel, listener.events, useListenerHandler(listener));\n return null;\n}\n\nfunction PresenceListener({ listener }: { listener: ListenerPayload }) {\n useEchoPresence(listener.channel, listener.events, useListenerHandler(listener));\n return null;\n}\n\nfunction Listener({ listener }: { listener: ListenerPayload }) {\n switch (listener.visibility) {\n case \"private\":\n return <PrivateListener listener={listener} />;\n case \"presence\":\n return <PresenceListener listener={listener} />;\n default:\n return <PublicListener listener={listener} />;\n }\n}\n\nexport default function Subscriptions({ listeners }: { listeners: ListenerPayload[] }) {\n return (\n <>\n {listeners.map((listener, index) => (\n <Listener key={`${listener.visibility}:${listener.channel}:${index}`} listener={listener} />\n ))}\n </>\n );\n}\n"],"mappings":";;;;;;;AAQA,SAAS,mBAAmB,UAAuD;CACjF,MAAM,EAAE,MAAM,KAAK,SAAS;CAC5B,MAAM,WAAW,oBAAoB;CAErC,OAAO,aACJ,YAAqB;EACpB,MAAM,OAAQ,OAAO,YAAY,YAAY,YAAY,OAAO,UAAU,CAAC;EAI3E,SAAS,aAAa,SAAS,SAAmC,MAAM,CAAC,CAAC;CAC5E,GACA;EAAC;EAAU;EAAU;CAAC,CACxB;AACF;AAEA,SAAS,eAAe,EAAE,YAA2C;CACnE,cAAc,SAAS,SAAS,SAAS,QAAQ,mBAAmB,QAAQ,CAAC;CAC7E,OAAO;AACT;AAEA,SAAS,gBAAgB,EAAE,YAA2C;CACpE,QAAQ,SAAS,SAAS,SAAS,QAAQ,mBAAmB,QAAQ,CAAC;CACvE,OAAO;AACT;AAEA,SAAS,iBAAiB,EAAE,YAA2C;CACrE,gBAAgB,SAAS,SAAS,SAAS,QAAQ,mBAAmB,QAAQ,CAAC;CAC/E,OAAO;AACT;AAEA,SAAS,SAAS,EAAE,YAA2C;CAC7D,QAAQ,SAAS,YAAjB;EACE,KAAK,WACH,OAAO,oBAAC,iBAAD,EAA2B,SAAW,CAAA;EAC/C,KAAK,YACH,OAAO,oBAAC,kBAAD,EAA4B,SAAW,CAAA;EAChD,SACE,OAAO,oBAAC,gBAAD,EAA0B,SAAW,CAAA;CAChD;AACF;AAEA,SAAwB,cAAc,EAAE,aAA+C;CACrF,OACE,oBAAA,YAAA,EAAA,UACG,UAAU,KAAK,UAAU,UACxB,oBAAC,UAAD,EAAgF,SAAW,GAA5E,GAAG,SAAS,WAAW,GAAG,SAAS,QAAQ,GAAG,OAA8B,CAC5F,EACD,CAAA;AAEN"}
1
+ {"version":3,"file":"subscriptions.js","names":[],"sources":["../../resources/js/realtime/subscriptions.tsx"],"sourcesContent":["import { useEcho, useEchoPresence, useEchoPublic } from \"@laravel/echo-react\";\nimport { useCallback } from \"react\";\nimport { useEffectDispatcher } from \"@lattice-php/lattice/effects/use-effect-dispatcher\";\nimport { useT } from \"@lattice-php/lattice/i18n\";\nimport { buildEffects } from \"./build-effects\";\nimport type { ListenerPayload } from \"@lattice-php/lattice/types/generated\";\n\nfunction useListenerHandler(listener: ListenerPayload): (payload: unknown) => void {\n const { t } = useT(\"lattice\");\n const dispatch = useEffectDispatcher();\n\n return useCallback(\n (payload: unknown) => {\n const data = (typeof payload === \"object\" && payload !== null ? payload : {}) as Record<\n string,\n unknown\n >;\n dispatch(buildEffects(listener.effects, data, t));\n },\n [dispatch, listener, t],\n );\n}\n\nfunction PublicListener({ listener }: { listener: ListenerPayload }) {\n useEchoPublic(listener.channel, listener.events, useListenerHandler(listener));\n return null;\n}\n\nfunction PrivateListener({ listener }: { listener: ListenerPayload }) {\n useEcho(listener.channel, listener.events, useListenerHandler(listener));\n return null;\n}\n\nfunction PresenceListener({ listener }: { listener: ListenerPayload }) {\n useEchoPresence(listener.channel, listener.events, useListenerHandler(listener));\n return null;\n}\n\nfunction Listener({ listener }: { listener: ListenerPayload }) {\n switch (listener.visibility) {\n case \"private\":\n return <PrivateListener listener={listener} />;\n case \"presence\":\n return <PresenceListener listener={listener} />;\n default:\n return <PublicListener listener={listener} />;\n }\n}\n\nexport default function Subscriptions({ listeners }: { listeners: ListenerPayload[] }) {\n return (\n <>\n {listeners.map((listener, index) => (\n <Listener key={`${listener.visibility}:${listener.channel}:${index}`} listener={listener} />\n ))}\n </>\n );\n}\n"],"mappings":";;;;;;;AAOA,SAAS,mBAAmB,UAAuD;CACjF,MAAM,EAAE,MAAM,KAAK,SAAS;CAC5B,MAAM,WAAW,oBAAoB;CAErC,OAAO,aACJ,YAAqB;EACpB,MAAM,OAAQ,OAAO,YAAY,YAAY,YAAY,OAAO,UAAU,CAAC;EAI3E,SAAS,aAAa,SAAS,SAAS,MAAM,CAAC,CAAC;CAClD,GACA;EAAC;EAAU;EAAU;CAAC,CACxB;AACF;AAEA,SAAS,eAAe,EAAE,YAA2C;CACnE,cAAc,SAAS,SAAS,SAAS,QAAQ,mBAAmB,QAAQ,CAAC;CAC7E,OAAO;AACT;AAEA,SAAS,gBAAgB,EAAE,YAA2C;CACpE,QAAQ,SAAS,SAAS,SAAS,QAAQ,mBAAmB,QAAQ,CAAC;CACvE,OAAO;AACT;AAEA,SAAS,iBAAiB,EAAE,YAA2C;CACrE,gBAAgB,SAAS,SAAS,SAAS,QAAQ,mBAAmB,QAAQ,CAAC;CAC/E,OAAO;AACT;AAEA,SAAS,SAAS,EAAE,YAA2C;CAC7D,QAAQ,SAAS,YAAjB;EACE,KAAK,WACH,OAAO,oBAAC,iBAAD,EAA2B,SAAW,CAAA;EAC/C,KAAK,YACH,OAAO,oBAAC,kBAAD,EAA4B,SAAW,CAAA;EAChD,SACE,OAAO,oBAAC,gBAAD,EAA0B,SAAW,CAAA;CAChD;AACF;AAEA,SAAwB,cAAc,EAAE,aAA+C;CACrF,OACE,oBAAA,YAAA,EAAA,UACG,UAAU,KAAK,UAAU,UACxB,oBAAC,UAAD,EAAgF,SAAW,GAA5E,GAAG,SAAS,WAAW,GAAG,SAAS,QAAQ,GAAG,OAA8B,CAC5F,EACD,CAAA;AAEN"}
@@ -2,12 +2,13 @@ import { createRegistry } from "../core/registry.js";
2
2
  import { layoutComponents } from "../layout/components.js";
3
3
  import { actionComponents } from "../action/index.js";
4
4
  import { chatPlugin } from "../chat/index.js";
5
+ import { notificationsPlugin } from "../notifications/index.js";
5
6
  import { remoteComponents } from "../remote/index.js";
6
7
  import { eagerFormComponents } from "../form/eager.js";
7
8
  import { eagerCoreComponents } from "../core/components/eager.js";
8
9
  import { eagerTableComponents } from "../table/eager.js";
9
10
  //#region resources/js/registry/eager.ts
10
- var eagerRegistry = createRegistry(eagerCoreComponents, actionComponents, eagerFormComponents, layoutComponents, eagerTableComponents, chatPlugin, remoteComponents);
11
+ var eagerRegistry = createRegistry(eagerCoreComponents, actionComponents, eagerFormComponents, layoutComponents, eagerTableComponents, chatPlugin, notificationsPlugin, remoteComponents);
11
12
  //#endregion
12
13
  export { eagerRegistry };
13
14
 
@@ -1 +1 @@
1
- {"version":3,"file":"eager.js","names":[],"sources":["../../resources/js/registry/eager.ts"],"sourcesContent":["import { createRegistry } from \"@lattice-php/lattice/core/registry\";\nimport { actionComponents } from \"../action\";\nimport { chatPlugin } from \"../chat\";\nimport { eagerCoreComponents } from \"../core/components/eager\";\nimport { eagerFormComponents } from \"../form/eager\";\nimport { layoutComponents } from \"../layout/components\";\nimport { remoteComponents } from \"../remote\";\nimport { eagerTableComponents } from \"../table/eager\";\n\nexport const eagerRegistry = createRegistry(\n eagerCoreComponents,\n actionComponents,\n eagerFormComponents,\n layoutComponents,\n eagerTableComponents,\n chatPlugin,\n remoteComponents,\n);\n"],"mappings":";;;;;;;;;AASA,IAAa,gBAAgB,eAC3B,qBACA,kBACA,qBACA,kBACA,sBACA,YACA,gBACF"}
1
+ {"version":3,"file":"eager.js","names":[],"sources":["../../resources/js/registry/eager.ts"],"sourcesContent":["import { createRegistry } from \"@lattice-php/lattice/core/registry\";\nimport { actionComponents } from \"../action\";\nimport { chatPlugin } from \"../chat\";\nimport { eagerCoreComponents } from \"../core/components/eager\";\nimport { eagerFormComponents } from \"../form/eager\";\nimport { layoutComponents } from \"../layout/components\";\nimport { notificationsPlugin } from \"../notifications\";\nimport { remoteComponents } from \"../remote\";\nimport { eagerTableComponents } from \"../table/eager\";\n\nexport const eagerRegistry = createRegistry(\n eagerCoreComponents,\n actionComponents,\n eagerFormComponents,\n layoutComponents,\n eagerTableComponents,\n chatPlugin,\n notificationsPlugin,\n remoteComponents,\n);\n"],"mappings":";;;;;;;;;;AAUA,IAAa,gBAAgB,eAC3B,qBACA,kBACA,qBACA,kBACA,sBACA,YACA,qBACA,gBACF"}
@@ -4,10 +4,11 @@ import { actionComponents } from "../action/index.js";
4
4
  import { chatPlugin } from "../chat/index.js";
5
5
  import { coreComponents } from "../core/components/index.js";
6
6
  import { formComponents } from "../form/index.js";
7
+ import { notificationsPlugin } from "../notifications/index.js";
7
8
  import { remoteComponents } from "../remote/index.js";
8
9
  import { tableComponents } from "../table/index.js";
9
10
  //#region resources/js/registry/lazy.ts
10
- var lazyRegistry = createRegistry(coreComponents, actionComponents, formComponents, layoutComponents, tableComponents, chatPlugin, remoteComponents);
11
+ var lazyRegistry = createRegistry(coreComponents, actionComponents, formComponents, layoutComponents, tableComponents, chatPlugin, notificationsPlugin, remoteComponents);
11
12
  //#endregion
12
13
  export { lazyRegistry };
13
14
 
@@ -1 +1 @@
1
- {"version":3,"file":"lazy.js","names":[],"sources":["../../resources/js/registry/lazy.ts"],"sourcesContent":["import { createRegistry } from \"@lattice-php/lattice/core/registry\";\nimport { actionComponents } from \"../action\";\nimport { chatPlugin } from \"../chat\";\nimport { coreComponents } from \"../core/components\";\nimport { formComponents } from \"../form\";\nimport { layoutComponents } from \"../layout/components\";\nimport { remoteComponents } from \"../remote\";\nimport { tableComponents } from \"../table\";\n\nexport const lazyRegistry = createRegistry(\n coreComponents,\n actionComponents,\n formComponents,\n layoutComponents,\n tableComponents,\n chatPlugin,\n remoteComponents,\n);\n"],"mappings":";;;;;;;;;AASA,IAAa,eAAe,eAC1B,gBACA,kBACA,gBACA,kBACA,iBACA,YACA,gBACF"}
1
+ {"version":3,"file":"lazy.js","names":[],"sources":["../../resources/js/registry/lazy.ts"],"sourcesContent":["import { createRegistry } from \"@lattice-php/lattice/core/registry\";\nimport { actionComponents } from \"../action\";\nimport { chatPlugin } from \"../chat\";\nimport { coreComponents } from \"../core/components\";\nimport { formComponents } from \"../form\";\nimport { layoutComponents } from \"../layout/components\";\nimport { notificationsPlugin } from \"../notifications\";\nimport { remoteComponents } from \"../remote\";\nimport { tableComponents } from \"../table\";\n\nexport const lazyRegistry = createRegistry(\n coreComponents,\n actionComponents,\n formComponents,\n layoutComponents,\n tableComponents,\n chatPlugin,\n notificationsPlugin,\n remoteComponents,\n);\n"],"mappings":";;;;;;;;;;AAUA,IAAa,eAAe,eAC1B,gBACA,kBACA,gBACA,kBACA,iBACA,YACA,qBACA,gBACF"}
@@ -1,6 +1,7 @@
1
1
  import { Method } from '@inertiajs/core';
2
2
  import { Node } from '../core/types';
3
- import { Action, ActionNode, ButtonVariant } from '../types/generated';
3
+ import { Action, ButtonVariant } from '../types/generated';
4
+ import { ActionNode } from './types';
4
5
  export type BulkAction = {
5
6
  id: string;
6
7
  label: string;
@@ -1 +1 @@
1
- {"version":3,"file":"bulk.js","names":[],"sources":["../../resources/js/table/bulk.ts"],"sourcesContent":["import type { Method } from \"@inertiajs/core\";\nimport type { Node } from \"@lattice-php/lattice/core/types\";\nimport type { Action, ActionNode, ButtonVariant } from \"@lattice-php/lattice/types/generated\";\n\nexport type BulkAction = {\n id: string;\n label: string;\n method: Method;\n endpoint: string;\n ref: string;\n variant: ButtonVariant;\n confirmation: Action[\"confirmation\"];\n form: Node | null;\n};\n\nexport function getBulkActions(actions: ActionNode[] | undefined): BulkAction[] {\n return (actions ?? []).flatMap((node): BulkAction[] => {\n if (node.type === \"action.group\") {\n return [];\n }\n\n const props = node.props;\n\n if (!props.endpoint) {\n return [];\n }\n\n return [\n {\n id: node.id ?? \"\",\n label: props.label ?? \"Run action\",\n method: props.method ?? \"post\",\n endpoint: props.endpoint,\n ref: props.ref ?? \"\",\n variant: props.variant ?? \"default\",\n confirmation: props.confirmation,\n form: props.form,\n },\n ];\n });\n}\n"],"mappings":";AAeA,SAAgB,eAAe,SAAiD;CAC9E,QAAQ,WAAW,CAAC,GAAG,SAAS,SAAuB;EACrD,IAAI,KAAK,SAAS,gBAChB,OAAO,CAAC;EAGV,MAAM,QAAQ,KAAK;EAEnB,IAAI,CAAC,MAAM,UACT,OAAO,CAAC;EAGV,OAAO,CACL;GACE,IAAI,KAAK,MAAM;GACf,OAAO,MAAM,SAAS;GACtB,QAAQ,MAAM,UAAU;GACxB,UAAU,MAAM;GAChB,KAAK,MAAM,OAAO;GAClB,SAAS,MAAM,WAAW;GAC1B,cAAc,MAAM;GACpB,MAAM,MAAM;EACd,CACF;CACF,CAAC;AACH"}
1
+ {"version":3,"file":"bulk.js","names":[],"sources":["../../resources/js/table/bulk.ts"],"sourcesContent":["import type { Method } from \"@inertiajs/core\";\nimport type { Node } from \"@lattice-php/lattice/core/types\";\nimport type { Action, ButtonVariant } from \"@lattice-php/lattice/types/generated\";\nimport type { ActionNode } from \"./types\";\n\nexport type BulkAction = {\n id: string;\n label: string;\n method: Method;\n endpoint: string;\n ref: string;\n variant: ButtonVariant;\n confirmation: Action[\"confirmation\"];\n form: Node | null;\n};\n\nexport function getBulkActions(actions: ActionNode[] | undefined): BulkAction[] {\n return (actions ?? []).flatMap((node): BulkAction[] => {\n if (node.type === \"action.group\") {\n return [];\n }\n\n const props = node.props;\n\n if (!props.endpoint) {\n return [];\n }\n\n return [\n {\n id: node.id ?? \"\",\n label: props.label ?? \"Run action\",\n method: props.method ?? \"post\",\n endpoint: props.endpoint,\n ref: props.ref ?? \"\",\n variant: props.variant ?? \"default\",\n confirmation: props.confirmation,\n form: props.form,\n },\n ];\n });\n}\n"],"mappings":";AAgBA,SAAgB,eAAe,SAAiD;CAC9E,QAAQ,WAAW,CAAC,GAAG,SAAS,SAAuB;EACrD,IAAI,KAAK,SAAS,gBAChB,OAAO,CAAC;EAGV,MAAM,QAAQ,KAAK;EAEnB,IAAI,CAAC,MAAM,UACT,OAAO,CAAC;EAGV,OAAO,CACL;GACE,IAAI,KAAK,MAAM;GACf,OAAO,MAAM,SAAS;GACtB,QAAQ,MAAM,UAAU;GACxB,UAAU,MAAM;GAChB,KAAK,MAAM,OAAO;GAClB,SAAS,MAAM,WAAW;GAC1B,cAAc,MAAM;GACpB,MAAM,MAAM;EACd,CACF;CACF,CAAC;AACH"}
@@ -1,11 +1,11 @@
1
1
  import { withHeaders } from "../../core/headers.js";
2
2
  import { useT } from "../../i18n/instance.js";
3
3
  import { prefixedTestId } from "../../core/test-id.js";
4
- import { getActionEffects } from "../../effects/dispatch.js";
5
- import { useEffectDispatcher } from "../../effects/use-effect-dispatcher.js";
6
4
  import { Button } from "../../core/components/button.js";
7
5
  import { Spinner } from "../../core/components/spinner.js";
8
6
  import { ConfirmDialog } from "../../core/components/confirm-dialog.js";
7
+ import { getActionEffects } from "../../effects/dispatch.js";
8
+ import { useEffectDispatcher } from "../../effects/use-effect-dispatcher.js";
9
9
  import { runAction } from "../../action/run-action.js";
10
10
  import { ActionForm } from "../../action/components/action-form.js";
11
11
  import { useHttp } from "@inertiajs/react";
@@ -1,7 +1,7 @@
1
1
  import { useLocale } from "../../../i18n/locale.js";
2
- import { formatCell } from "../../format.js";
3
2
  import { numericValue } from "../../../format/numeric.js";
4
3
  import { formatNumber } from "../../../format/number.js";
4
+ import { formatCell } from "../../format.js";
5
5
  import { jsx } from "react/jsx-runtime";
6
6
  //#region resources/js/table/components/cells/money-cell.tsx
7
7
  var MoneyCell = ({ column, props, row, value }) => {
@@ -1,7 +1,7 @@
1
1
  import { useLocale } from "../../../i18n/locale.js";
2
- import { formatCell } from "../../format.js";
3
2
  import { numericValue } from "../../../format/numeric.js";
4
3
  import { formatNumber } from "../../../format/number.js";
4
+ import { formatCell } from "../../format.js";
5
5
  import { jsx } from "react/jsx-runtime";
6
6
  //#region resources/js/table/components/cells/number-cell.tsx
7
7
  var NumberCell = ({ column, props, value }) => {