@lattice-php/lattice 0.16.0 → 0.17.1

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 (124) 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/renderer.js +42 -2
  11. package/dist/core/renderer.js.map +1 -1
  12. package/dist/core/types.d.ts +22 -42
  13. package/dist/core/use-click-behavior.d.ts +42 -0
  14. package/dist/core/use-click-behavior.js +46 -0
  15. package/dist/core/use-click-behavior.js.map +1 -0
  16. package/dist/create-app.d.ts +8 -2
  17. package/dist/create-app.js +4 -2
  18. package/dist/create-app.js.map +1 -1
  19. package/dist/effects/registry.d.ts +9 -20
  20. package/dist/effects/registry.js +4 -6
  21. package/dist/effects/registry.js.map +1 -1
  22. package/dist/events/event-bridge.d.ts +1 -1
  23. package/dist/events/event-bridge.js +1 -1
  24. package/dist/events/event-bridge.js.map +1 -1
  25. package/dist/form/components/base/input-otp.d.ts +2 -1
  26. package/dist/form/components/base/input-otp.js.map +1 -1
  27. package/dist/form/components/conditions.d.ts +1 -1
  28. package/dist/form/components/conditions.js.map +1 -1
  29. package/dist/form/components/field-props.d.ts +2 -1
  30. package/dist/form/components/field-props.js.map +1 -1
  31. package/dist/form/components/field-scope.d.ts +2 -1
  32. package/dist/form/components/field-scope.js.map +1 -1
  33. package/dist/form/components/fields/row-action-menu.d.ts +2 -1
  34. package/dist/form/components/fields/row-action-menu.js.map +1 -1
  35. package/dist/form/components/fields/row-item.d.ts +2 -1
  36. package/dist/form/components/fields/row-item.js.map +1 -1
  37. package/dist/form/components/fields/table-rows.d.ts +2 -1
  38. package/dist/form/components/fields/table-rows.js.map +1 -1
  39. package/dist/form/components/fields/time-picker-columns.d.ts +2 -1
  40. package/dist/form/components/fields/time-picker-columns.js.map +1 -1
  41. package/dist/form/components/fields/time-picker.d.ts +2 -1
  42. package/dist/form/components/fields/time-picker.js.map +1 -1
  43. package/dist/form/components/fields/use-row-collection.d.ts +2 -1
  44. package/dist/form/components/fields/use-row-collection.js.map +1 -1
  45. package/dist/form/components/form-path.d.ts +0 -1
  46. package/dist/form/components/form-path.js +1 -1
  47. package/dist/form/components/form-path.js.map +1 -1
  48. package/dist/form/components/prefill-targets.d.ts +1 -1
  49. package/dist/form/components/prefill-targets.js.map +1 -1
  50. package/dist/form/components/types.d.ts +5 -1
  51. package/dist/form/components/use-field-commit.d.ts +2 -1
  52. package/dist/form/components/use-field-commit.js.map +1 -1
  53. package/dist/form/components/use-form-resolver.d.ts +2 -1
  54. package/dist/form/components/use-form-resolver.js.map +1 -1
  55. package/dist/format/date-time.d.ts +12 -0
  56. package/dist/format/date-time.js +30 -0
  57. package/dist/format/date-time.js.map +1 -0
  58. package/dist/format/value.js +1 -1
  59. package/dist/format/value.js.map +1 -1
  60. package/dist/i18n/config.d.ts +2 -1
  61. package/dist/i18n/config.js.map +1 -1
  62. package/dist/i18n/date-time.js +1 -1
  63. package/dist/i18n/date-time.js.map +1 -1
  64. package/dist/i18n/instance.d.ts +1 -1
  65. package/dist/i18n/instance.js.map +1 -1
  66. package/dist/i18n/locale-reload.d.ts +2 -1
  67. package/dist/i18n/locale-reload.js.map +1 -1
  68. package/dist/index.js +1 -1
  69. package/dist/layout/components.js +1 -1
  70. package/dist/layout/menu-item.js +43 -49
  71. package/dist/layout/menu-item.js.map +1 -1
  72. package/dist/notifications/api.d.ts +6 -0
  73. package/dist/notifications/api.js +21 -0
  74. package/dist/notifications/api.js.map +1 -0
  75. package/dist/notifications/components/empty-state.d.ts +1 -0
  76. package/dist/notifications/components/empty-state.js +21 -0
  77. package/dist/notifications/components/empty-state.js.map +1 -0
  78. package/dist/notifications/components/notification-item.d.ts +6 -0
  79. package/dist/notifications/components/notification-item.js +65 -0
  80. package/dist/notifications/components/notification-item.js.map +1 -0
  81. package/dist/notifications/components/notification-list.d.ts +10 -0
  82. package/dist/notifications/components/notification-list.js +38 -0
  83. package/dist/notifications/components/notification-list.js.map +1 -0
  84. package/dist/notifications/components/notifications-echo.d.ts +5 -0
  85. package/dist/notifications/components/notifications-echo.js +22 -0
  86. package/dist/notifications/components/notifications-echo.js.map +1 -0
  87. package/dist/notifications/components/notifications.d.ts +3 -0
  88. package/dist/notifications/components/notifications.js +109 -0
  89. package/dist/notifications/components/notifications.js.map +1 -0
  90. package/dist/notifications/index.d.ts +1 -0
  91. package/dist/notifications/index.js +11 -0
  92. package/dist/notifications/index.js.map +1 -0
  93. package/dist/notifications/store.d.ts +25 -0
  94. package/dist/notifications/store.js +100 -0
  95. package/dist/notifications/store.js.map +1 -0
  96. package/dist/notifications/types.d.ts +10 -0
  97. package/dist/notifications/types.js +0 -0
  98. package/dist/realtime/build-effects.d.ts +2 -1
  99. package/dist/realtime/build-effects.js.map +1 -1
  100. package/dist/realtime/subscriptions.js.map +1 -1
  101. package/dist/registry/eager.js +2 -1
  102. package/dist/registry/eager.js.map +1 -1
  103. package/dist/registry/lazy.js +2 -1
  104. package/dist/registry/lazy.js.map +1 -1
  105. package/dist/table/bulk.d.ts +2 -1
  106. package/dist/table/bulk.js.map +1 -1
  107. package/dist/table/components/bulk-bar.js +2 -2
  108. package/dist/table/components/cells/money-cell.js +1 -1
  109. package/dist/table/components/cells/number-cell.js +1 -1
  110. package/dist/table/components/cells/text-cell.js +1 -1
  111. package/dist/table/components/filter-controls.d.ts +0 -4
  112. package/dist/table/components/filter-controls.js.map +1 -1
  113. package/dist/table/components/table-cell.js.map +1 -1
  114. package/dist/table/format.d.ts +1 -12
  115. package/dist/table/format.js +2 -26
  116. package/dist/table/format.js.map +1 -1
  117. package/dist/table/types.d.ts +7 -17
  118. package/dist/types/generated.d.ts +119 -290
  119. package/dist/vite-client.d.ts +8 -0
  120. package/dist/vite.d.ts +35 -1
  121. package/dist/vite.js +60 -2
  122. package/dist/vite.js.map +1 -1
  123. package/package.json +17 -2
  124. package/resources/icons/bell.svg +16 -0
@@ -0,0 +1,21 @@
1
+ import { Icon } from "../../icons/sprite.js";
2
+ import { useT } from "../../i18n/instance.js";
3
+ import { jsx, jsxs } from "react/jsx-runtime";
4
+ //#region resources/js/notifications/components/empty-state.tsx
5
+ function EmptyState() {
6
+ const { t } = useT("lattice");
7
+ return /* @__PURE__ */ jsxs("div", {
8
+ className: "flex flex-col items-center gap-2 px-4 py-10 text-lt-muted-fg",
9
+ children: [/* @__PURE__ */ jsx(Icon, {
10
+ name: "bell",
11
+ className: "size-lt-icon-lg"
12
+ }), /* @__PURE__ */ jsx("p", {
13
+ className: "text-sm",
14
+ children: t("notifications.empty", "No notifications yet")
15
+ })]
16
+ });
17
+ }
18
+ //#endregion
19
+ export { EmptyState };
20
+
21
+ //# sourceMappingURL=empty-state.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"empty-state.js","names":[],"sources":["../../../resources/js/notifications/components/empty-state.tsx"],"sourcesContent":["import { Icon } from \"@lattice-php/lattice/icons\";\nimport { useT } from \"@lattice-php/lattice/i18n\";\n\nexport function EmptyState() {\n const { t } = useT(\"lattice\");\n return (\n <div className=\"flex flex-col items-center gap-2 px-4 py-10 text-lt-muted-fg\">\n <Icon name=\"bell\" className=\"size-lt-icon-lg\" />\n <p className=\"text-sm\">{t(\"notifications.empty\", \"No notifications yet\")}</p>\n </div>\n );\n}\n"],"mappings":";;;;AAGA,SAAgB,aAAa;CAC3B,MAAM,EAAE,MAAM,KAAK,SAAS;CAC5B,OACE,qBAAC,OAAD;EAAK,WAAU;YAAf,CACE,oBAAC,MAAD;GAAM,MAAK;GAAO,WAAU;EAAmB,CAAA,GAC/C,oBAAC,KAAD;GAAG,WAAU;aAAW,EAAE,uBAAuB,sBAAsB;EAAK,CAAA,CACzE;;AAET"}
@@ -0,0 +1,6 @@
1
+ import { NotificationItem } from '../types';
2
+ export declare function NotificationItemRow({ notification, onMarkRead, onDismiss, }: {
3
+ notification: NotificationItem;
4
+ onMarkRead: (id: string) => void;
5
+ onDismiss: (id: string) => void;
6
+ }): import("react").JSX.Element;
@@ -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"}