@lattice-php/lattice 0.3.0 → 0.5.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 (195) hide show
  1. package/dist/action/components/action-form.js +3 -3
  2. package/dist/action/components/action-group.js +1 -1
  3. package/dist/action/components/action.js +10 -16
  4. package/dist/action/components/action.js.map +1 -1
  5. package/dist/action/run-action.d.ts +9 -0
  6. package/dist/action/run-action.js +22 -0
  7. package/dist/action/run-action.js.map +1 -0
  8. package/dist/chat/components/chat-box.js +31 -14
  9. package/dist/chat/components/chat-box.js.map +1 -1
  10. package/dist/chat/components/message.js +2 -2
  11. package/dist/chat/components/message.js.map +1 -1
  12. package/dist/chat/components/prompt-input.js +1 -1
  13. package/dist/chat/index.js +2 -0
  14. package/dist/chat/index.js.map +1 -1
  15. package/dist/chat/transport.d.ts +2 -0
  16. package/dist/chat/transport.js +23 -3
  17. package/dist/chat/transport.js.map +1 -1
  18. package/dist/core/api.d.ts +14 -7
  19. package/dist/core/api.js +77 -1
  20. package/dist/core/api.js.map +1 -1
  21. package/dist/core/components/badge.js +4 -4
  22. package/dist/core/components/badge.js.map +1 -1
  23. package/dist/core/components/button.js +31 -19
  24. package/dist/core/components/button.js.map +1 -1
  25. package/dist/core/components/card.js +3 -2
  26. package/dist/core/components/card.js.map +1 -1
  27. package/dist/core/components/chart.js +3 -2
  28. package/dist/core/components/chart.js.map +1 -1
  29. package/dist/core/components/checkbox.js +1 -1
  30. package/dist/core/components/checkbox.js.map +1 -1
  31. package/dist/core/components/control.js +4 -4
  32. package/dist/core/components/control.js.map +1 -1
  33. package/dist/core/components/dialog.d.ts +1 -1
  34. package/dist/core/components/dialog.js +3 -2
  35. package/dist/core/components/dialog.js.map +1 -1
  36. package/dist/core/components/floating-panel.js +5 -4
  37. package/dist/core/components/floating-panel.js.map +1 -1
  38. package/dist/core/components/fragment.js +3 -6
  39. package/dist/core/components/fragment.js.map +1 -1
  40. package/dist/core/components/grid.js +2 -1
  41. package/dist/core/components/grid.js.map +1 -1
  42. package/dist/core/components/heading.js +1 -1
  43. package/dist/core/components/heading.js.map +1 -1
  44. package/dist/core/components/index.js +0 -2
  45. package/dist/core/components/index.js.map +1 -1
  46. package/dist/core/components/popover.d.ts +1 -1
  47. package/dist/core/components/popover.js +1 -1
  48. package/dist/core/components/popover.js.map +1 -1
  49. package/dist/core/components/section.js +7 -11
  50. package/dist/core/components/section.js.map +1 -1
  51. package/dist/core/components/segmented-pills.js +1 -1
  52. package/dist/core/components/segmented-pills.js.map +1 -1
  53. package/dist/core/components/stack.js +9 -2
  54. package/dist/core/components/stack.js.map +1 -1
  55. package/dist/core/components/tabs.js +2 -2
  56. package/dist/core/components/tabs.js.map +1 -1
  57. package/dist/core/nodes.d.ts +6 -0
  58. package/dist/core/nodes.js +13 -0
  59. package/dist/core/nodes.js.map +1 -0
  60. package/dist/core/renderer.js +1 -1
  61. package/dist/core/types.d.ts +3 -1
  62. package/dist/create-app.d.ts +21 -0
  63. package/dist/create-app.js +31 -0
  64. package/dist/create-app.js.map +1 -0
  65. package/dist/effects/registry.js +2 -1
  66. package/dist/effects/registry.js.map +1 -1
  67. package/dist/effects/use-effect-dispatcher.js +1 -1
  68. package/dist/effects/use-flash-effects.js +1 -1
  69. package/dist/events/event-names.d.ts +3 -2
  70. package/dist/events/event-names.js +3 -2
  71. package/dist/events/event-names.js.map +1 -1
  72. package/dist/form/components/base/affix-group.d.ts +17 -0
  73. package/dist/form/components/base/affix-group.js +49 -0
  74. package/dist/form/components/base/affix-group.js.map +1 -0
  75. package/dist/form/components/base/input-otp.d.ts +7 -0
  76. package/dist/form/components/base/input-otp.js +30 -0
  77. package/dist/form/components/base/input-otp.js.map +1 -0
  78. package/dist/form/components/base/label.js +1 -1
  79. package/dist/form/components/base/label.js.map +1 -1
  80. package/dist/form/components/base/submit-button.js +1 -1
  81. package/dist/form/components/base/submit-button.js.map +1 -1
  82. package/dist/form/components/base/textarea.js +1 -1
  83. package/dist/form/components/base/textarea.js.map +1 -1
  84. package/dist/form/components/conditions.js +1 -1
  85. package/dist/form/components/conditions.js.map +1 -1
  86. package/dist/form/components/fields/file-upload.js +35 -3
  87. package/dist/form/components/fields/file-upload.js.map +1 -1
  88. package/dist/form/components/fields/number-input.js +21 -15
  89. package/dist/form/components/fields/number-input.js.map +1 -1
  90. package/dist/form/components/fields/otp-input.d.ts +2 -0
  91. package/dist/form/components/fields/otp-input.js +25 -0
  92. package/dist/form/components/fields/otp-input.js.map +1 -0
  93. package/dist/form/components/fields/password-input.js +21 -15
  94. package/dist/form/components/fields/password-input.js.map +1 -1
  95. package/dist/form/components/fields/rich-editor.js +2 -2
  96. package/dist/form/components/fields/rich-editor.js.map +1 -1
  97. package/dist/form/components/fields/row-item.js +1 -1
  98. package/dist/form/components/fields/table-rows.js +1 -1
  99. package/dist/form/components/fields/text-input.js +19 -13
  100. package/dist/form/components/fields/text-input.js.map +1 -1
  101. package/dist/form/components/form.js +2 -2
  102. package/dist/form/components/form.js.map +1 -1
  103. package/dist/form/components/index.d.ts +1 -0
  104. package/dist/form/components/index.js +2 -1
  105. package/dist/form/components/prefill-targets.d.ts +0 -1
  106. package/dist/form/components/prefill-targets.js +1 -4
  107. package/dist/form/components/prefill-targets.js.map +1 -1
  108. package/dist/form/components/use-form-resolver.js +2 -2
  109. package/dist/form/components/use-form-resolver.js.map +1 -1
  110. package/dist/form/index.js +1 -0
  111. package/dist/form/index.js.map +1 -1
  112. package/dist/form/skeleton.js +1 -1
  113. package/dist/form/skeleton.js.map +1 -1
  114. package/dist/i18n/locale-reload.js +1 -1
  115. package/dist/i18n/translatable.d.ts +4 -0
  116. package/dist/i18n/translatable.js +24 -0
  117. package/dist/i18n/translatable.js.map +1 -0
  118. package/dist/index.d.ts +3 -0
  119. package/dist/index.js +15 -13
  120. package/dist/lattice.css +99 -6
  121. package/dist/layout/breadcrumbs.js +3 -2
  122. package/dist/layout/breadcrumbs.js.map +1 -1
  123. package/dist/layout/callouts.js +2 -2
  124. package/dist/layout/callouts.js.map +1 -1
  125. package/dist/layout/components.js +4 -2
  126. package/dist/layout/components.js.map +1 -1
  127. package/dist/layout/dropdown.js +2 -1
  128. package/dist/layout/dropdown.js.map +1 -1
  129. package/dist/layout/menu-item.js +33 -12
  130. package/dist/layout/menu-item.js.map +1 -1
  131. package/dist/layout/menu.js +2 -1
  132. package/dist/layout/menu.js.map +1 -1
  133. package/dist/layout/popover.js +1 -1
  134. package/dist/layout/sidebar.js +69 -29
  135. package/dist/layout/sidebar.js.map +1 -1
  136. package/dist/layout/topbar.d.ts +3 -0
  137. package/dist/layout/topbar.js +16 -0
  138. package/dist/layout/topbar.js.map +1 -0
  139. package/dist/page.js +15 -10
  140. package/dist/page.js.map +1 -1
  141. package/dist/realtime/build-effects.d.ts +4 -0
  142. package/dist/realtime/build-effects.js +23 -0
  143. package/dist/realtime/build-effects.js.map +1 -0
  144. package/dist/realtime/listeners.d.ts +8 -0
  145. package/dist/realtime/listeners.js +31 -0
  146. package/dist/realtime/listeners.js.map +1 -0
  147. package/dist/realtime/subscriptions.d.ts +4 -0
  148. package/dist/realtime/subscriptions.js +45 -0
  149. package/dist/realtime/subscriptions.js.map +1 -0
  150. package/dist/registry.js +3 -2
  151. package/dist/registry.js.map +1 -1
  152. package/dist/remote/components/data-list.d.ts +10 -0
  153. package/dist/remote/components/data-list.js +106 -0
  154. package/dist/remote/components/data-list.js.map +1 -0
  155. package/dist/remote/index.d.ts +1 -0
  156. package/dist/remote/index.js +11 -0
  157. package/dist/remote/index.js.map +1 -0
  158. package/dist/table/components/bulk-bar.js +10 -15
  159. package/dist/table/components/bulk-bar.js.map +1 -1
  160. package/dist/table/components/cells/text-cell.js +38 -3
  161. package/dist/table/components/cells/text-cell.js.map +1 -1
  162. package/dist/table/components/column-filter-control.d.ts +2 -1
  163. package/dist/table/components/column-filter-control.js +28 -19
  164. package/dist/table/components/column-filter-control.js.map +1 -1
  165. package/dist/table/components/column-header.js +2 -2
  166. package/dist/table/components/column-header.js.map +1 -1
  167. package/dist/table/components/filter-bar.d.ts +7 -6
  168. package/dist/table/components/filter-bar.js +51 -28
  169. package/dist/table/components/filter-bar.js.map +1 -1
  170. package/dist/table/components/filter-controls.js +2 -2
  171. package/dist/table/components/filter-controls.js.map +1 -1
  172. package/dist/table/components/filter-stack-bar.js +4 -3
  173. package/dist/table/components/filter-stack-bar.js.map +1 -1
  174. package/dist/table/components/filter-value-input.js +1 -1
  175. package/dist/table/components/filter-value-input.js.map +1 -1
  176. package/dist/table/components/sort-bar.js +1 -1
  177. package/dist/table/components/sort-bar.js.map +1 -1
  178. package/dist/table/components/table.js +26 -17
  179. package/dist/table/components/table.js.map +1 -1
  180. package/dist/table/filter-values.d.ts +5 -0
  181. package/dist/table/filter-values.js +10 -3
  182. package/dist/table/filter-values.js.map +1 -1
  183. package/dist/table/query.js +5 -4
  184. package/dist/table/query.js.map +1 -1
  185. package/dist/table/use-table.d.ts +1 -0
  186. package/dist/table/use-table.js +4 -0
  187. package/dist/table/use-table.js.map +1 -1
  188. package/dist/toast/toast.js +5 -2
  189. package/dist/toast/toast.js.map +1 -1
  190. package/dist/toast/toaster.js +6 -5
  191. package/dist/toast/toaster.js.map +1 -1
  192. package/dist/types/generated.d.ts +122 -14
  193. package/dist/vite.js +32 -1
  194. package/dist/vite.js.map +1 -1
  195. package/package.json +33 -3
@@ -1 +1 @@
1
- {"version":3,"file":"breadcrumbs.js","names":[],"sources":["../../resources/js/layout/breadcrumbs.tsx"],"sourcesContent":["import { Link, usePage } from \"@inertiajs/react\";\nimport { Fragment } from \"react\";\nimport type { PagePayload, RendererComponent } from \"@lattice-php/lattice/core/types\";\n\nconst BreadcrumbsComponent: RendererComponent<\"breadcrumbs\"> = ({ node }) => {\n const page = usePage();\n const crumbs = (page.props.lattice as PagePayload | undefined)?.breadcrumbs ?? [];\n\n if (crumbs.length === 0) {\n return null;\n }\n\n return (\n <nav aria-label=\"Breadcrumb\" data-lattice-component={node.id}>\n <ol className=\"flex items-center gap-2 text-sm text-lt-muted-fg\">\n {crumbs.map((crumb, index) => {\n const isLast = index === crumbs.length - 1;\n\n return (\n <Fragment key={crumb.href}>\n <li>\n {isLast ? (\n <span aria-current=\"page\" className=\"text-lt-fg\">\n {crumb.title}\n </span>\n ) : (\n <Link className=\"hover:text-lt-fg\" href={crumb.href}>\n {crumb.title}\n </Link>\n )}\n </li>\n {isLast ? null : <li aria-hidden=\"true\">/</li>}\n </Fragment>\n );\n })}\n </ol>\n </nav>\n );\n};\n\nexport default BreadcrumbsComponent;\n"],"mappings":";;;;AAIA,IAAM,wBAA0D,EAAE,WAAW;CAE3E,MAAM,SADO,QACG,EAAK,MAAM,SAAqC,eAAe,CAAC;CAEhF,IAAI,OAAO,WAAW,GACpB,OAAO;CAGT,OACE,oBAAC,OAAD;EAAK,cAAW;EAAa,0BAAwB,KAAK;YACxD,oBAAC,MAAD;GAAI,WAAU;aACX,OAAO,KAAK,OAAO,UAAU;IAC5B,MAAM,SAAS,UAAU,OAAO,SAAS;IAEzC,OACE,qBAAC,UAAD,EAAA,UAAA,CACE,oBAAC,MAAD,EAAA,UACG,SACC,oBAAC,QAAD;KAAM,gBAAa;KAAO,WAAU;eACjC,MAAM;IACH,CAAA,IAEN,oBAAC,MAAD;KAAM,WAAU;KAAmB,MAAM,MAAM;eAC5C,MAAM;IACH,CAAA,EAEN,CAAA,GACH,SAAS,OAAO,oBAAC,MAAD;KAAI,eAAY;eAAO;IAAK,CAAA,CACrC,EAAA,GAbK,MAAM,IAaX;GAEd,CAAC;EACC,CAAA;CACD,CAAA;AAET"}
1
+ {"version":3,"file":"breadcrumbs.js","names":[],"sources":["../../resources/js/layout/breadcrumbs.tsx"],"sourcesContent":["import { Link, usePage } from \"@inertiajs/react\";\nimport { Fragment } from \"react\";\nimport type { PagePayload, RendererComponent } from \"@lattice-php/lattice/core/types\";\nimport { nodeIdentity } from \"@lattice-php/lattice/core/test-id\";\n\nconst BreadcrumbsComponent: RendererComponent<\"breadcrumbs\"> = ({ node }) => {\n const page = usePage();\n const crumbs = (page.props.lattice as PagePayload | undefined)?.breadcrumbs ?? [];\n\n if (crumbs.length === 0) {\n return null;\n }\n\n return (\n <nav aria-label=\"Breadcrumb\" data-lattice-component={nodeIdentity(node)}>\n <ol className=\"flex items-center gap-2 text-sm text-lt-muted-fg\">\n {crumbs.map((crumb, index) => {\n const isLast = index === crumbs.length - 1;\n\n return (\n <Fragment key={crumb.href}>\n <li>\n {isLast ? (\n <span aria-current=\"page\" className=\"text-lt-fg\">\n {crumb.title}\n </span>\n ) : (\n <Link className=\"hover:text-lt-fg\" href={crumb.href}>\n {crumb.title}\n </Link>\n )}\n </li>\n {isLast ? null : <li aria-hidden=\"true\">/</li>}\n </Fragment>\n );\n })}\n </ol>\n </nav>\n );\n};\n\nexport default BreadcrumbsComponent;\n"],"mappings":";;;;;AAKA,IAAM,wBAA0D,EAAE,WAAW;CAE3E,MAAM,SADO,QACG,EAAK,MAAM,SAAqC,eAAe,CAAC;CAEhF,IAAI,OAAO,WAAW,GACpB,OAAO;CAGT,OACE,oBAAC,OAAD;EAAK,cAAW;EAAa,0BAAwB,aAAa,IAAI;YACpE,oBAAC,MAAD;GAAI,WAAU;aACX,OAAO,KAAK,OAAO,UAAU;IAC5B,MAAM,SAAS,UAAU,OAAO,SAAS;IAEzC,OACE,qBAAC,UAAD,EAAA,UAAA,CACE,oBAAC,MAAD,EAAA,UACG,SACC,oBAAC,QAAD;KAAM,gBAAa;KAAO,WAAU;eACjC,MAAM;IACH,CAAA,IAEN,oBAAC,MAAD;KAAM,WAAU;KAAmB,MAAM,MAAM;eAC5C,MAAM;IACH,CAAA,EAEN,CAAA,GACH,SAAS,OAAO,oBAAC,MAAD;KAAI,eAAY;eAAO;IAAK,CAAA,CACrC,EAAA,GAbK,MAAM,IAaX;GAEd,CAAC;EACC,CAAA;CACD,CAAA;AAET"}
@@ -1,8 +1,8 @@
1
1
  import { cn } from "../lib/utils.js";
2
2
  import { Icon } from "../icons/sprite.js";
3
- import { useT } from "../i18n/instance.js";
4
3
  import { RenderNode } from "../core/renderer.js";
5
4
  import { onCallout } from "../toast/callout.js";
5
+ import { useT } from "../i18n/instance.js";
6
6
  import { variantStyles } from "../toast/variant-styles.js";
7
7
  import { useEffect, useState } from "react";
8
8
  import { jsx, jsxs } from "react/jsx-runtime";
@@ -50,7 +50,7 @@ var Callouts = () => {
50
50
  type: "button",
51
51
  "aria-label": t("a11y.dismiss", "Dismiss"),
52
52
  "data-test": "callout-dismiss",
53
- className: "shrink-0 rounded-md p-1 text-lt-muted-fg transition-colors hover:bg-lt-muted hover:text-lt-fg",
53
+ className: "shrink-0 rounded-lt-sm p-1 text-lt-muted-fg transition-colors hover:bg-lt-muted hover:text-lt-fg",
54
54
  onClick: () => dismiss(callout.id),
55
55
  children: /* @__PURE__ */ jsx(Icon, {
56
56
  name: "x",
@@ -1 +1 @@
1
- {"version":3,"file":"callouts.js","names":[],"sources":["../../resources/js/layout/callouts.tsx"],"sourcesContent":["import { Icon } from \"@lattice-php/lattice/icons\";\nimport { useEffect, useState } from \"react\";\nimport { RenderNode } from \"@lattice-php/lattice/core/renderer\";\nimport type { Callout } from \"@lattice-php/lattice/types/generated\";\nimport type { RendererComponent } from \"@lattice-php/lattice/core/types\";\nimport { onCallout } from \"@lattice-php/lattice/toast/callout\";\nimport { cn } from \"@lattice-php/lattice/lib/utils\";\nimport { useT } from \"@lattice-php/lattice/i18n\";\nimport { variantStyles } from \"@lattice-php/lattice/toast/variant-styles\";\n\ntype CalloutItem = Callout & { id: number };\n\nlet nextId = 0;\n\nconst Callouts: RendererComponent<\"callouts\"> = () => {\n const { t } = useT(\"lattice\");\n const [callouts, setCallouts] = useState<CalloutItem[]>([]);\n\n useEffect(\n () =>\n onCallout((callout) => {\n setCallouts((current) => [...current, { ...callout, id: nextId++ }]);\n }),\n [],\n );\n\n function dismiss(id: number): void {\n setCallouts((current) => current.filter((callout) => callout.id !== id));\n }\n\n if (callouts.length === 0) {\n return null;\n }\n\n return (\n <div className=\"flex w-full flex-col gap-2\">\n {callouts.map((callout) => (\n <div\n key={callout.id}\n role=\"status\"\n data-test={`callout-${callout.variant}`}\n className={cn(\n \"flex items-start gap-3 rounded-lt border border-l-4 border-lt-border bg-lt-popover p-4 text-lt-popover-fg\",\n variantStyles[callout.variant].accent,\n )}\n >\n {variantStyles[callout.variant].icon}\n <div className=\"flex min-w-0 flex-1 flex-col gap-2\">\n {callout.title ? (\n <p className=\"text-sm font-medium text-lt-fg\">{callout.title}</p>\n ) : null}\n <p className=\"text-sm text-lt-fg\">{callout.message}</p>\n {callout.action ? (\n <div className=\"flex flex-wrap gap-2\">\n <RenderNode node={callout.action} />\n </div>\n ) : null}\n </div>\n {callout.dismissible ? (\n <button\n type=\"button\"\n aria-label={t(\"a11y.dismiss\", \"Dismiss\")}\n data-test=\"callout-dismiss\"\n className=\"shrink-0 rounded-md p-1 text-lt-muted-fg transition-colors hover:bg-lt-muted hover:text-lt-fg\"\n onClick={() => dismiss(callout.id)}\n >\n <Icon name=\"x\" className=\"size-lt-icon-md\" />\n </button>\n ) : null}\n </div>\n ))}\n </div>\n );\n};\n\nexport default Callouts;\n"],"mappings":";;;;;;;;;AAYA,IAAI,SAAS;AAEb,IAAM,iBAAgD;CACpD,MAAM,EAAE,MAAM,KAAK,SAAS;CAC5B,MAAM,CAAC,UAAU,eAAe,SAAwB,CAAC,CAAC;CAE1D,gBAEI,WAAW,YAAY;EACrB,aAAa,YAAY,CAAC,GAAG,SAAS;GAAE,GAAG;GAAS,IAAI;EAAS,CAAC,CAAC;CACrE,CAAC,GACH,CAAC,CACH;CAEA,SAAS,QAAQ,IAAkB;EACjC,aAAa,YAAY,QAAQ,QAAQ,YAAY,QAAQ,OAAO,EAAE,CAAC;CACzE;CAEA,IAAI,SAAS,WAAW,GACtB,OAAO;CAGT,OACE,oBAAC,OAAD;EAAK,WAAU;YACZ,SAAS,KAAK,YACb,qBAAC,OAAD;GAEE,MAAK;GACL,aAAW,WAAW,QAAQ;GAC9B,WAAW,GACT,6GACA,cAAc,QAAQ,SAAS,MACjC;aAPF;IASG,cAAc,QAAQ,SAAS;IAChC,qBAAC,OAAD;KAAK,WAAU;eAAf;MACG,QAAQ,QACP,oBAAC,KAAD;OAAG,WAAU;iBAAkC,QAAQ;MAAS,CAAA,IAC9D;MACJ,oBAAC,KAAD;OAAG,WAAU;iBAAsB,QAAQ;MAAW,CAAA;MACrD,QAAQ,SACP,oBAAC,OAAD;OAAK,WAAU;iBACb,oBAAC,YAAD,EAAY,MAAM,QAAQ,OAAS,CAAA;MAChC,CAAA,IACH;KACD;;IACJ,QAAQ,cACP,oBAAC,UAAD;KACE,MAAK;KACL,cAAY,EAAE,gBAAgB,SAAS;KACvC,aAAU;KACV,WAAU;KACV,eAAe,QAAQ,QAAQ,EAAE;eAEjC,oBAAC,MAAD;MAAM,MAAK;MAAI,WAAU;KAAmB,CAAA;IACtC,CAAA,IACN;GACD;KA/BE,QAAQ,EA+BV,CACN;CACE,CAAA;AAET"}
1
+ {"version":3,"file":"callouts.js","names":[],"sources":["../../resources/js/layout/callouts.tsx"],"sourcesContent":["import { Icon } from \"@lattice-php/lattice/icons\";\nimport { useEffect, useState } from \"react\";\nimport { RenderNode } from \"@lattice-php/lattice/core/renderer\";\nimport type { Callout } from \"@lattice-php/lattice/types/generated\";\nimport type { RendererComponent } from \"@lattice-php/lattice/core/types\";\nimport { onCallout } from \"@lattice-php/lattice/toast/callout\";\nimport { cn } from \"@lattice-php/lattice/lib/utils\";\nimport { useT } from \"@lattice-php/lattice/i18n\";\nimport { variantStyles } from \"@lattice-php/lattice/toast/variant-styles\";\n\ntype CalloutItem = Callout & { id: number };\n\nlet nextId = 0;\n\nconst Callouts: RendererComponent<\"callouts\"> = () => {\n const { t } = useT(\"lattice\");\n const [callouts, setCallouts] = useState<CalloutItem[]>([]);\n\n useEffect(\n () =>\n onCallout((callout) => {\n setCallouts((current) => [...current, { ...callout, id: nextId++ }]);\n }),\n [],\n );\n\n function dismiss(id: number): void {\n setCallouts((current) => current.filter((callout) => callout.id !== id));\n }\n\n if (callouts.length === 0) {\n return null;\n }\n\n return (\n <div className=\"flex w-full flex-col gap-2\">\n {callouts.map((callout) => (\n <div\n key={callout.id}\n role=\"status\"\n data-test={`callout-${callout.variant}`}\n className={cn(\n \"flex items-start gap-3 rounded-lt border border-l-4 border-lt-border bg-lt-popover p-4 text-lt-popover-fg\",\n variantStyles[callout.variant].accent,\n )}\n >\n {variantStyles[callout.variant].icon}\n <div className=\"flex min-w-0 flex-1 flex-col gap-2\">\n {callout.title ? (\n <p className=\"text-sm font-medium text-lt-fg\">{callout.title}</p>\n ) : null}\n <p className=\"text-sm text-lt-fg\">{callout.message}</p>\n {callout.action ? (\n <div className=\"flex flex-wrap gap-2\">\n <RenderNode node={callout.action} />\n </div>\n ) : null}\n </div>\n {callout.dismissible ? (\n <button\n type=\"button\"\n aria-label={t(\"a11y.dismiss\", \"Dismiss\")}\n data-test=\"callout-dismiss\"\n className=\"shrink-0 rounded-lt-sm p-1 text-lt-muted-fg transition-colors hover:bg-lt-muted hover:text-lt-fg\"\n onClick={() => dismiss(callout.id)}\n >\n <Icon name=\"x\" className=\"size-lt-icon-md\" />\n </button>\n ) : null}\n </div>\n ))}\n </div>\n );\n};\n\nexport default Callouts;\n"],"mappings":";;;;;;;;;AAYA,IAAI,SAAS;AAEb,IAAM,iBAAgD;CACpD,MAAM,EAAE,MAAM,KAAK,SAAS;CAC5B,MAAM,CAAC,UAAU,eAAe,SAAwB,CAAC,CAAC;CAE1D,gBAEI,WAAW,YAAY;EACrB,aAAa,YAAY,CAAC,GAAG,SAAS;GAAE,GAAG;GAAS,IAAI;EAAS,CAAC,CAAC;CACrE,CAAC,GACH,CAAC,CACH;CAEA,SAAS,QAAQ,IAAkB;EACjC,aAAa,YAAY,QAAQ,QAAQ,YAAY,QAAQ,OAAO,EAAE,CAAC;CACzE;CAEA,IAAI,SAAS,WAAW,GACtB,OAAO;CAGT,OACE,oBAAC,OAAD;EAAK,WAAU;YACZ,SAAS,KAAK,YACb,qBAAC,OAAD;GAEE,MAAK;GACL,aAAW,WAAW,QAAQ;GAC9B,WAAW,GACT,6GACA,cAAc,QAAQ,SAAS,MACjC;aAPF;IASG,cAAc,QAAQ,SAAS;IAChC,qBAAC,OAAD;KAAK,WAAU;eAAf;MACG,QAAQ,QACP,oBAAC,KAAD;OAAG,WAAU;iBAAkC,QAAQ;MAAS,CAAA,IAC9D;MACJ,oBAAC,KAAD;OAAG,WAAU;iBAAsB,QAAQ;MAAW,CAAA;MACrD,QAAQ,SACP,oBAAC,OAAD;OAAK,WAAU;iBACb,oBAAC,YAAD,EAAY,MAAM,QAAQ,OAAS,CAAA;MAChC,CAAA,IACH;KACD;;IACJ,QAAQ,cACP,oBAAC,UAAD;KACE,MAAK;KACL,cAAY,EAAE,gBAAgB,SAAS;KACvC,aAAU;KACV,WAAU;KACV,eAAe,QAAQ,QAAQ,EAAE;eAEjC,oBAAC,MAAD;MAAM,MAAK;MAAI,WAAU;KAAmB,CAAA;IACtC,CAAA,IACN;GACD;KA/BE,QAAQ,EA+BV,CACN;CACE,CAAA;AAET"}
@@ -1,11 +1,12 @@
1
+ import Callouts from "./callouts.js";
1
2
  import { createPlugin, eagerComponent } from "../core/registry.js";
2
3
  import BreadcrumbsComponent from "./breadcrumbs.js";
3
- import Callouts from "./callouts.js";
4
4
  import DropdownComponent from "./dropdown.js";
5
5
  import MenuComponent from "./menu.js";
6
6
  import MenuItemComponent from "./menu-item.js";
7
7
  import OutletComponent from "./outlet.js";
8
8
  import SidebarComponent from "./sidebar.js";
9
+ import TopbarComponent from "./topbar.js";
9
10
  //#region resources/js/layout/components.ts
10
11
  var layoutComponents = createPlugin({
11
12
  components: {
@@ -15,7 +16,8 @@ var layoutComponents = createPlugin({
15
16
  menu: eagerComponent(MenuComponent),
16
17
  "menu-item": eagerComponent(MenuItemComponent),
17
18
  outlet: eagerComponent(OutletComponent),
18
- sidebar: eagerComponent(SidebarComponent)
19
+ sidebar: eagerComponent(SidebarComponent),
20
+ topbar: eagerComponent(TopbarComponent)
19
21
  },
20
22
  name: "lattice/layout"
21
23
  });
@@ -1 +1 @@
1
- {"version":3,"file":"components.js","names":[],"sources":["../../resources/js/layout/components.ts"],"sourcesContent":["import { createPlugin, eagerComponent } from \"@lattice-php/lattice/core/registry\";\nimport BreadcrumbsComponent from \"./breadcrumbs\";\nimport CalloutsComponent from \"./callouts\";\nimport DropdownComponent from \"./dropdown\";\nimport MenuComponent from \"./menu\";\nimport MenuItemComponent from \"./menu-item\";\nimport OutletComponent from \"./outlet\";\nimport SidebarComponent from \"./sidebar\";\n\nexport const layoutComponents = createPlugin({\n components: {\n breadcrumbs: eagerComponent(BreadcrumbsComponent),\n callouts: eagerComponent(CalloutsComponent),\n dropdown: eagerComponent(DropdownComponent),\n menu: eagerComponent(MenuComponent),\n \"menu-item\": eagerComponent(MenuItemComponent),\n outlet: eagerComponent(OutletComponent),\n sidebar: eagerComponent(SidebarComponent),\n },\n name: \"lattice/layout\",\n});\n"],"mappings":";;;;;;;;;AASA,IAAa,mBAAmB,aAAa;CAC3C,YAAY;EACV,aAAa,eAAe,oBAAoB;EAChD,UAAU,eAAe,QAAiB;EAC1C,UAAU,eAAe,iBAAiB;EAC1C,MAAM,eAAe,aAAa;EAClC,aAAa,eAAe,iBAAiB;EAC7C,QAAQ,eAAe,eAAe;EACtC,SAAS,eAAe,gBAAgB;CAC1C;CACA,MAAM;AACR,CAAC"}
1
+ {"version":3,"file":"components.js","names":[],"sources":["../../resources/js/layout/components.ts"],"sourcesContent":["import { createPlugin, eagerComponent } from \"@lattice-php/lattice/core/registry\";\nimport BreadcrumbsComponent from \"./breadcrumbs\";\nimport CalloutsComponent from \"./callouts\";\nimport DropdownComponent from \"./dropdown\";\nimport MenuComponent from \"./menu\";\nimport MenuItemComponent from \"./menu-item\";\nimport OutletComponent from \"./outlet\";\nimport SidebarComponent from \"./sidebar\";\nimport TopbarComponent from \"./topbar\";\n\nexport const layoutComponents = createPlugin({\n components: {\n breadcrumbs: eagerComponent(BreadcrumbsComponent),\n callouts: eagerComponent(CalloutsComponent),\n dropdown: eagerComponent(DropdownComponent),\n menu: eagerComponent(MenuComponent),\n \"menu-item\": eagerComponent(MenuItemComponent),\n outlet: eagerComponent(OutletComponent),\n sidebar: eagerComponent(SidebarComponent),\n topbar: eagerComponent(TopbarComponent),\n },\n name: \"lattice/layout\",\n});\n"],"mappings":";;;;;;;;;;AAUA,IAAa,mBAAmB,aAAa;CAC3C,YAAY;EACV,aAAa,eAAe,oBAAoB;EAChD,UAAU,eAAe,QAAiB;EAC1C,UAAU,eAAe,iBAAiB;EAC1C,MAAM,eAAe,aAAa;EAClC,aAAa,eAAe,iBAAiB;EAC7C,QAAQ,eAAe,eAAe;EACtC,SAAS,eAAe,gBAAgB;EACxC,QAAQ,eAAe,eAAe;CACxC;CACA,MAAM;AACR,CAAC"}
@@ -7,8 +7,9 @@ var DropdownComponent = ({ children, node }) => {
7
7
  return /* @__PURE__ */ jsx(Popover, {
8
8
  placement: node.props.placement,
9
9
  testId,
10
+ triggerClassName: "w-auto",
10
11
  trigger: /* @__PURE__ */ jsx("span", {
11
- className: "flex min-w-0 items-center rounded-md px-2 py-1.5 text-sm hover:bg-lt-muted",
12
+ className: "flex min-w-0 items-center rounded-lt-sm px-2 py-1.5 text-sm hover:bg-lt-muted",
12
13
  children: node.props.trigger.map((triggerNode, index) => /* @__PURE__ */ jsx(RenderNode, { node: triggerNode }, triggerNode.key ?? `${triggerNode.type}-${index}`))
13
14
  }),
14
15
  children: /* @__PURE__ */ jsx("ul", {
@@ -1 +1 @@
1
- {"version":3,"file":"dropdown.js","names":[],"sources":["../../resources/js/layout/dropdown.tsx"],"sourcesContent":["import type { RendererComponent } from \"@lattice-php/lattice/core/types\";\nimport { RenderNode } from \"@lattice-php/lattice/core/renderer\";\nimport { Popover } from \"./popover\";\n\nconst DropdownComponent: RendererComponent<\"dropdown\"> = ({ children, node }) => {\n const testId = node.key ?? \"dropdown\";\n\n return (\n <Popover\n placement={node.props.placement}\n testId={testId}\n trigger={\n <span className=\"flex min-w-0 items-center rounded-md px-2 py-1.5 text-sm hover:bg-lt-muted\">\n {node.props.trigger.map((triggerNode, index) => (\n <RenderNode\n key={triggerNode.key ?? `${triggerNode.type}-${index}`}\n node={triggerNode}\n />\n ))}\n </span>\n }\n >\n <ul className=\"flex flex-col gap-1\">{children}</ul>\n </Popover>\n );\n};\n\nexport default DropdownComponent;\n"],"mappings":";;;;AAIA,IAAM,qBAAoD,EAAE,UAAU,WAAW;CAC/E,MAAM,SAAS,KAAK,OAAO;CAE3B,OACE,oBAAC,SAAD;EACE,WAAW,KAAK,MAAM;EACd;EACR,SACE,oBAAC,QAAD;GAAM,WAAU;aACb,KAAK,MAAM,QAAQ,KAAK,aAAa,UACpC,oBAAC,YAAD,EAEE,MAAM,YACP,GAFM,YAAY,OAAO,GAAG,YAAY,KAAK,GAAG,OAEhD,CACF;EACG,CAAA;YAGR,oBAAC,MAAD;GAAI,WAAU;GAAuB;EAAa,CAAA;CAC3C,CAAA;AAEb"}
1
+ {"version":3,"file":"dropdown.js","names":[],"sources":["../../resources/js/layout/dropdown.tsx"],"sourcesContent":["import type { RendererComponent } from \"@lattice-php/lattice/core/types\";\nimport { RenderNode } from \"@lattice-php/lattice/core/renderer\";\nimport { Popover } from \"./popover\";\n\nconst DropdownComponent: RendererComponent<\"dropdown\"> = ({ children, node }) => {\n const testId = node.key ?? \"dropdown\";\n\n return (\n <Popover\n placement={node.props.placement}\n testId={testId}\n triggerClassName=\"w-auto\"\n trigger={\n <span className=\"flex min-w-0 items-center rounded-lt-sm px-2 py-1.5 text-sm hover:bg-lt-muted\">\n {node.props.trigger.map((triggerNode, index) => (\n <RenderNode\n key={triggerNode.key ?? `${triggerNode.type}-${index}`}\n node={triggerNode}\n />\n ))}\n </span>\n }\n >\n <ul className=\"flex flex-col gap-1\">{children}</ul>\n </Popover>\n );\n};\n\nexport default DropdownComponent;\n"],"mappings":";;;;AAIA,IAAM,qBAAoD,EAAE,UAAU,WAAW;CAC/E,MAAM,SAAS,KAAK,OAAO;CAE3B,OACE,oBAAC,SAAD;EACE,WAAW,KAAK,MAAM;EACd;EACR,kBAAiB;EACjB,SACE,oBAAC,QAAD;GAAM,WAAU;aACb,KAAK,MAAM,QAAQ,KAAK,aAAa,UACpC,oBAAC,YAAD,EAEE,MAAM,YACP,GAFM,YAAY,OAAO,GAAG,YAAY,KAAK,GAAG,OAEhD,CACF;EACG,CAAA;YAGR,oBAAC,MAAD;GAAI,WAAU;GAAuB;EAAa,CAAA;CAC3C,CAAA;AAEb"}
@@ -1,14 +1,24 @@
1
1
  import { cn } from "../lib/utils.js";
2
- import { prefixedNodeTestId } from "../core/test-id.js";
3
2
  import { Icon } from "../icons/sprite.js";
4
3
  import { IconRenderer } from "../icons/icon-renderer.js";
5
4
  import { useCollapsed } from "../core/collapsed-context.js";
5
+ import { prefixedNodeTestId } from "../core/test-id.js";
6
6
  import { Popover } from "./popover.js";
7
- import { useState } from "react";
8
7
  import { Link, usePage } from "@inertiajs/react";
8
+ import { useState } from "react";
9
9
  import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
10
10
  //#region resources/js/layout/menu-item.tsx
11
- var rowClass = "flex items-center gap-2 rounded-md px-3 py-2 text-sm text-lt-fg transition-colors hover:bg-lt-muted";
11
+ var rowClass = "flex items-center gap-2 rounded-lt-sm px-3 py-2 text-base font-medium text-lt-fg transition-colors hover:bg-lt-muted";
12
+ function MenuAffix({ affix, className }) {
13
+ if (affix.icon) return /* @__PURE__ */ jsx(IconRenderer, {
14
+ className: cn("size-lt-icon-md shrink-0", className),
15
+ icon: affix.icon
16
+ });
17
+ return /* @__PURE__ */ jsx("span", {
18
+ className: cn("shrink-0 text-sm text-lt-muted-fg", className),
19
+ children: affix.text
20
+ });
21
+ }
12
22
  function schemaContainsPath(schema, path) {
13
23
  return (schema ?? []).some((child) => child.props?.href === path || schemaContainsPath(child.schema, path));
14
24
  }
@@ -16,24 +26,35 @@ var MenuItemComponent = ({ children, node }) => {
16
26
  const collapsed = useCollapsed();
17
27
  const icon = node.props.icon;
18
28
  const label = node.props.label;
29
+ const prefix = node.props.prefix;
30
+ const suffix = node.props.suffix;
31
+ const iconOnly = Boolean(icon);
32
+ const flyoutIcon = icon ?? prefix?.icon ?? null;
19
33
  const href = node.props.href ?? "";
20
34
  const currentPath = usePage().url.split("?")[0];
21
35
  const testId = prefixedNodeTestId("menu", node);
22
- const content = /* @__PURE__ */ jsxs(Fragment$1, { children: [icon ? /* @__PURE__ */ jsx(IconRenderer, {
36
+ const content = icon ? /* @__PURE__ */ jsx(IconRenderer, {
23
37
  className: "size-lt-icon-md shrink-0",
24
38
  icon
25
- }) : null, collapsed ? /* @__PURE__ */ jsx("span", {
26
- className: "pointer-events-none absolute top-1/2 left-full z-50 ml-2 hidden -translate-y-1/2 rounded-md border border-lt-border bg-lt-popover px-2 py-1 text-sm whitespace-nowrap text-lt-popover-fg shadow-lg group-hover:block",
27
- role: "tooltip",
28
- children: label
29
- }) : /* @__PURE__ */ jsx("span", { children: label })] });
39
+ }) : /* @__PURE__ */ jsxs(Fragment$1, { children: [
40
+ prefix ? /* @__PURE__ */ jsx(MenuAffix, { affix: prefix }) : null,
41
+ collapsed ? /* @__PURE__ */ jsx("span", {
42
+ className: "pointer-events-none absolute top-1/2 left-full z-50 ml-2 hidden -translate-y-1/2 rounded-lt-sm border border-lt-border bg-lt-popover px-2 py-1 text-sm whitespace-nowrap text-lt-popover-fg shadow-lt-md group-hover:block",
43
+ role: "tooltip",
44
+ children: label
45
+ }) : /* @__PURE__ */ jsx("span", { children: label }),
46
+ suffix ? /* @__PURE__ */ jsx(MenuAffix, {
47
+ affix: suffix,
48
+ className: "ml-auto"
49
+ }) : null
50
+ ] });
30
51
  if (href === "") {
31
52
  if (!children) return collapsed ? null : /* @__PURE__ */ jsx("li", { children: /* @__PURE__ */ jsx("span", {
32
53
  className: "flex items-center gap-2 px-3 py-2 text-xs font-semibold tracking-wide text-lt-muted-fg uppercase",
33
54
  children: content
34
55
  }) });
35
56
  if (collapsed) return /* @__PURE__ */ jsx(FlyoutGroup, {
36
- icon,
57
+ icon: flyoutIcon,
37
58
  label,
38
59
  testId,
39
60
  children
@@ -49,9 +70,9 @@ var MenuItemComponent = ({ children, node }) => {
49
70
  const method = node.props.method ?? "get";
50
71
  return /* @__PURE__ */ jsx("li", { children: /* @__PURE__ */ jsx(Link, {
51
72
  "aria-current": active ? "page" : void 0,
52
- "aria-label": collapsed ? label : void 0,
73
+ "aria-label": collapsed || iconOnly ? label : void 0,
53
74
  as: method === "get" ? void 0 : "button",
54
- className: cn(rowClass, "w-full", collapsed && "group relative justify-center", active && "bg-lt-muted font-medium"),
75
+ className: cn(rowClass, "w-full", collapsed && "group relative justify-center", iconOnly && "justify-center", active && "bg-lt-muted font-medium"),
55
76
  "data-test": testId,
56
77
  href,
57
78
  method,
@@ -1 +1 @@
1
- {"version":3,"file":"menu-item.js","names":[],"sources":["../../resources/js/layout/menu-item.tsx"],"sourcesContent":["import { Link, usePage } from \"@inertiajs/react\";\nimport { useState } from \"react\";\nimport type { ReactNode } from \"react\";\nimport { prefixedNodeTestId } from \"@lattice-php/lattice/core/test-id\";\nimport type { RendererComponent, Schema } from \"@lattice-php/lattice/core/types\";\nimport { Icon, IconRenderer } from \"@lattice-php/lattice/icons\";\nimport { cn } from \"@lattice-php/lattice/lib/utils\";\nimport { useSidebarCollapsed } from \"./context\";\nimport { Popover } from \"./popover\";\n\nconst rowClass =\n \"flex items-center gap-2 rounded-md px-3 py-2 text-sm text-lt-fg transition-colors hover:bg-lt-muted\";\n\nfunction schemaContainsPath(schema: Schema | undefined, path: string): boolean {\n return (schema ?? []).some(\n (child) => child.props?.href === path || schemaContainsPath(child.schema, path),\n );\n}\n\nconst MenuItemComponent: RendererComponent<\"menu-item\"> = ({ children, node }) => {\n const collapsed = useSidebarCollapsed();\n const icon = node.props.icon;\n const label = node.props.label;\n const href = node.props.href ?? \"\";\n const currentPath = usePage().url.split(\"?\")[0];\n const testId = prefixedNodeTestId(\"menu\", node);\n\n const content = (\n <>\n {icon ? <IconRenderer className=\"size-lt-icon-md shrink-0\" icon={icon} /> : null}\n {collapsed ? (\n <span\n className=\"pointer-events-none absolute top-1/2 left-full z-50 ml-2 hidden -translate-y-1/2 rounded-md border border-lt-border bg-lt-popover px-2 py-1 text-sm whitespace-nowrap text-lt-popover-fg shadow-lg group-hover:block\"\n role=\"tooltip\"\n >\n {label}\n </span>\n ) : (\n <span>{label}</span>\n )}\n </>\n );\n\n if (href === \"\") {\n if (!children) {\n return collapsed ? null : (\n <li>\n <span className=\"flex items-center gap-2 px-3 py-2 text-xs font-semibold tracking-wide text-lt-muted-fg uppercase\">\n {content}\n </span>\n </li>\n );\n }\n\n if (collapsed) {\n return (\n <FlyoutGroup icon={icon} label={label} testId={testId}>\n {children}\n </FlyoutGroup>\n );\n }\n\n return (\n <CollapsibleItem\n content={content}\n defaultOpen={schemaContainsPath(node.schema, currentPath)}\n testId={testId}\n >\n {children}\n </CollapsibleItem>\n );\n }\n\n const active = currentPath === href;\n const method = node.props.method ?? \"get\";\n\n return (\n <li>\n <Link\n aria-current={active ? \"page\" : undefined}\n aria-label={collapsed ? label : undefined}\n as={method === \"get\" ? undefined : \"button\"}\n className={cn(\n rowClass,\n \"w-full\",\n collapsed && \"group relative justify-center\",\n active && \"bg-lt-muted font-medium\",\n )}\n data-test={testId}\n href={href}\n method={method}\n >\n {content}\n </Link>\n </li>\n );\n};\n\nfunction CollapsibleItem({\n children,\n content,\n defaultOpen,\n testId,\n}: {\n children: ReactNode;\n content: ReactNode;\n defaultOpen: boolean;\n testId?: string;\n}) {\n const [open, setOpen] = useState(defaultOpen);\n\n return (\n <li>\n <button\n aria-expanded={open}\n className={cn(rowClass, \"w-full\")}\n data-test={testId}\n onClick={() => setOpen((value) => !value)}\n type=\"button\"\n >\n {content}\n <Icon\n name=\"chevron-right\"\n className={cn(\n \"ml-auto size-lt-icon-md shrink-0 transition-transform\",\n open && \"rotate-90\",\n )}\n />\n </button>\n {open ? <ul className=\"mt-1 flex flex-col gap-1 pl-3\">{children}</ul> : null}\n </li>\n );\n}\n\nfunction FlyoutGroup({\n children,\n icon,\n label,\n testId,\n}: {\n children: ReactNode;\n icon?: string | null;\n label: string;\n testId?: string;\n}) {\n return (\n <li>\n <Popover\n className=\"min-w-48\"\n placement=\"right\"\n testId={testId}\n trigger={\n icon ? (\n <IconRenderer className=\"size-lt-icon-md shrink-0\" icon={icon} />\n ) : (\n <span>{label}</span>\n )\n }\n triggerClassName={cn(rowClass, \"justify-center\")}\n triggerLabel={label}\n >\n <ul className=\"flex flex-col gap-1\">\n <li className=\"px-3 py-1.5 text-xs font-semibold tracking-wide text-lt-muted-fg uppercase\">\n {label}\n </li>\n {children}\n </ul>\n </Popover>\n </li>\n );\n}\n\nexport default MenuItemComponent;\n"],"mappings":";;;;;;;;;;AAUA,IAAM,WACJ;AAEF,SAAS,mBAAmB,QAA4B,MAAuB;CAC7E,QAAQ,UAAU,CAAC,GAAG,MACnB,UAAU,MAAM,OAAO,SAAS,QAAQ,mBAAmB,MAAM,QAAQ,IAAI,CAChF;AACF;AAEA,IAAM,qBAAqD,EAAE,UAAU,WAAW;CAChF,MAAM,YAAY,aAAoB;CACtC,MAAM,OAAO,KAAK,MAAM;CACxB,MAAM,QAAQ,KAAK,MAAM;CACzB,MAAM,OAAO,KAAK,MAAM,QAAQ;CAChC,MAAM,cAAc,QAAQ,EAAE,IAAI,MAAM,GAAG,EAAE;CAC7C,MAAM,SAAS,mBAAmB,QAAQ,IAAI;CAE9C,MAAM,UACJ,qBAAA,YAAA,EAAA,UAAA,CACG,OAAO,oBAAC,cAAD;EAAc,WAAU;EAAiC;CAAO,CAAA,IAAI,MAC3E,YACC,oBAAC,QAAD;EACE,WAAU;EACV,MAAK;YAEJ;CACG,CAAA,IAEN,oBAAC,QAAD,EAAA,UAAO,MAAY,CAAA,CAErB,EAAA,CAAA;CAGJ,IAAI,SAAS,IAAI;EACf,IAAI,CAAC,UACH,OAAO,YAAY,OACjB,oBAAC,MAAD,EAAA,UACE,oBAAC,QAAD;GAAM,WAAU;aACb;EACG,CAAA,EACJ,CAAA;EAIR,IAAI,WACF,OACE,oBAAC,aAAD;GAAmB;GAAa;GAAe;GAC5C;EACU,CAAA;EAIjB,OACE,oBAAC,iBAAD;GACW;GACT,aAAa,mBAAmB,KAAK,QAAQ,WAAW;GAChD;GAEP;EACc,CAAA;CAErB;CAEA,MAAM,SAAS,gBAAgB;CAC/B,MAAM,SAAS,KAAK,MAAM,UAAU;CAEpC,OACE,oBAAC,MAAD,EAAA,UACE,oBAAC,MAAD;EACE,gBAAc,SAAS,SAAS,KAAA;EAChC,cAAY,YAAY,QAAQ,KAAA;EAChC,IAAI,WAAW,QAAQ,KAAA,IAAY;EACnC,WAAW,GACT,UACA,UACA,aAAa,iCACb,UAAU,yBACZ;EACA,aAAW;EACL;EACE;YAEP;CACG,CAAA,EACJ,CAAA;AAER;AAEA,SAAS,gBAAgB,EACvB,UACA,SACA,aACA,UAMC;CACD,MAAM,CAAC,MAAM,WAAW,SAAS,WAAW;CAE5C,OACE,qBAAC,MAAD,EAAA,UAAA,CACE,qBAAC,UAAD;EACE,iBAAe;EACf,WAAW,GAAG,UAAU,QAAQ;EAChC,aAAW;EACX,eAAe,SAAS,UAAU,CAAC,KAAK;EACxC,MAAK;YALP,CAOG,SACD,oBAAC,MAAD;GACE,MAAK;GACL,WAAW,GACT,yDACA,QAAQ,WACV;EACD,CAAA,CACK;KACP,OAAO,oBAAC,MAAD;EAAI,WAAU;EAAiC;CAAa,CAAA,IAAI,IACtE,EAAA,CAAA;AAER;AAEA,SAAS,YAAY,EACnB,UACA,MACA,OACA,UAMC;CACD,OACE,oBAAC,MAAD,EAAA,UACE,oBAAC,SAAD;EACE,WAAU;EACV,WAAU;EACF;EACR,SACE,OACE,oBAAC,cAAD;GAAc,WAAU;GAAiC;EAAO,CAAA,IAEhE,oBAAC,QAAD,EAAA,UAAO,MAAY,CAAA;EAGvB,kBAAkB,GAAG,UAAU,gBAAgB;EAC/C,cAAc;YAEd,qBAAC,MAAD;GAAI,WAAU;aAAd,CACE,oBAAC,MAAD;IAAI,WAAU;cACX;GACC,CAAA,GACH,QACC;;CACG,CAAA,EACP,CAAA;AAER"}
1
+ {"version":3,"file":"menu-item.js","names":[],"sources":["../../resources/js/layout/menu-item.tsx"],"sourcesContent":["import { Link, usePage } from \"@inertiajs/react\";\nimport { useState } from \"react\";\nimport type { ReactNode } from \"react\";\nimport { prefixedNodeTestId } from \"@lattice-php/lattice/core/test-id\";\nimport type { RendererComponent, Schema } from \"@lattice-php/lattice/core/types\";\nimport { Icon, IconRenderer } from \"@lattice-php/lattice/icons\";\nimport { cn } from \"@lattice-php/lattice/lib/utils\";\nimport type { Affix } from \"@lattice-php/lattice/types/generated\";\nimport { useSidebarCollapsed } from \"./context\";\nimport { Popover } from \"./popover\";\n\nconst rowClass =\n \"flex items-center gap-2 rounded-lt-sm px-3 py-2 text-base font-medium text-lt-fg transition-colors hover:bg-lt-muted\";\n\nfunction MenuAffix({ affix, className }: { affix: Affix; className?: string }) {\n if (affix.icon) {\n return <IconRenderer className={cn(\"size-lt-icon-md shrink-0\", className)} icon={affix.icon} />;\n }\n\n return <span className={cn(\"shrink-0 text-sm text-lt-muted-fg\", className)}>{affix.text}</span>;\n}\n\nfunction schemaContainsPath(schema: Schema | undefined, path: string): boolean {\n return (schema ?? []).some(\n (child) => child.props?.href === path || schemaContainsPath(child.schema, path),\n );\n}\n\nconst MenuItemComponent: RendererComponent<\"menu-item\"> = ({ children, node }) => {\n const collapsed = useSidebarCollapsed();\n const icon = node.props.icon;\n const label = node.props.label;\n const prefix = node.props.prefix;\n const suffix = node.props.suffix;\n const iconOnly = Boolean(icon);\n const flyoutIcon = icon ?? prefix?.icon ?? null;\n const href = node.props.href ?? \"\";\n const currentPath = usePage().url.split(\"?\")[0];\n const testId = prefixedNodeTestId(\"menu\", node);\n\n const content = icon ? (\n <IconRenderer className=\"size-lt-icon-md shrink-0\" icon={icon} />\n ) : (\n <>\n {prefix ? <MenuAffix affix={prefix} /> : null}\n {collapsed ? (\n <span\n className=\"pointer-events-none absolute top-1/2 left-full z-50 ml-2 hidden -translate-y-1/2 rounded-lt-sm border border-lt-border bg-lt-popover px-2 py-1 text-sm whitespace-nowrap text-lt-popover-fg shadow-lt-md group-hover:block\"\n role=\"tooltip\"\n >\n {label}\n </span>\n ) : (\n <span>{label}</span>\n )}\n {suffix ? <MenuAffix affix={suffix} className=\"ml-auto\" /> : null}\n </>\n );\n\n if (href === \"\") {\n if (!children) {\n return collapsed ? null : (\n <li>\n <span className=\"flex items-center gap-2 px-3 py-2 text-xs font-semibold tracking-wide text-lt-muted-fg uppercase\">\n {content}\n </span>\n </li>\n );\n }\n\n if (collapsed) {\n return (\n <FlyoutGroup icon={flyoutIcon} label={label} testId={testId}>\n {children}\n </FlyoutGroup>\n );\n }\n\n return (\n <CollapsibleItem\n content={content}\n defaultOpen={schemaContainsPath(node.schema, currentPath)}\n testId={testId}\n >\n {children}\n </CollapsibleItem>\n );\n }\n\n const active = currentPath === href;\n const method = node.props.method ?? \"get\";\n\n return (\n <li>\n <Link\n aria-current={active ? \"page\" : undefined}\n aria-label={collapsed || iconOnly ? label : undefined}\n as={method === \"get\" ? undefined : \"button\"}\n className={cn(\n rowClass,\n \"w-full\",\n collapsed && \"group relative justify-center\",\n iconOnly && \"justify-center\",\n active && \"bg-lt-muted font-medium\",\n )}\n data-test={testId}\n href={href}\n method={method}\n >\n {content}\n </Link>\n </li>\n );\n};\n\nfunction CollapsibleItem({\n children,\n content,\n defaultOpen,\n testId,\n}: {\n children: ReactNode;\n content: ReactNode;\n defaultOpen: boolean;\n testId?: string;\n}) {\n const [open, setOpen] = useState(defaultOpen);\n\n return (\n <li>\n <button\n aria-expanded={open}\n className={cn(rowClass, \"w-full\")}\n data-test={testId}\n onClick={() => setOpen((value) => !value)}\n type=\"button\"\n >\n {content}\n <Icon\n name=\"chevron-right\"\n className={cn(\n \"ml-auto size-lt-icon-md shrink-0 transition-transform\",\n open && \"rotate-90\",\n )}\n />\n </button>\n {open ? <ul className=\"mt-1 flex flex-col gap-1 pl-3\">{children}</ul> : null}\n </li>\n );\n}\n\nfunction FlyoutGroup({\n children,\n icon,\n label,\n testId,\n}: {\n children: ReactNode;\n icon?: string | null;\n label: string;\n testId?: string;\n}) {\n return (\n <li>\n <Popover\n className=\"min-w-48\"\n placement=\"right\"\n testId={testId}\n trigger={\n icon ? (\n <IconRenderer className=\"size-lt-icon-md shrink-0\" icon={icon} />\n ) : (\n <span>{label}</span>\n )\n }\n triggerClassName={cn(rowClass, \"justify-center\")}\n triggerLabel={label}\n >\n <ul className=\"flex flex-col gap-1\">\n <li className=\"px-3 py-1.5 text-xs font-semibold tracking-wide text-lt-muted-fg uppercase\">\n {label}\n </li>\n {children}\n </ul>\n </Popover>\n </li>\n );\n}\n\nexport default MenuItemComponent;\n"],"mappings":";;;;;;;;;;AAWA,IAAM,WACJ;AAEF,SAAS,UAAU,EAAE,OAAO,aAAmD;CAC7E,IAAI,MAAM,MACR,OAAO,oBAAC,cAAD;EAAc,WAAW,GAAG,4BAA4B,SAAS;EAAG,MAAM,MAAM;CAAO,CAAA;CAGhG,OAAO,oBAAC,QAAD;EAAM,WAAW,GAAG,qCAAqC,SAAS;YAAI,MAAM;CAAW,CAAA;AAChG;AAEA,SAAS,mBAAmB,QAA4B,MAAuB;CAC7E,QAAQ,UAAU,CAAC,GAAG,MACnB,UAAU,MAAM,OAAO,SAAS,QAAQ,mBAAmB,MAAM,QAAQ,IAAI,CAChF;AACF;AAEA,IAAM,qBAAqD,EAAE,UAAU,WAAW;CAChF,MAAM,YAAY,aAAoB;CACtC,MAAM,OAAO,KAAK,MAAM;CACxB,MAAM,QAAQ,KAAK,MAAM;CACzB,MAAM,SAAS,KAAK,MAAM;CAC1B,MAAM,SAAS,KAAK,MAAM;CAC1B,MAAM,WAAW,QAAQ,IAAI;CAC7B,MAAM,aAAa,QAAQ,QAAQ,QAAQ;CAC3C,MAAM,OAAO,KAAK,MAAM,QAAQ;CAChC,MAAM,cAAc,QAAQ,EAAE,IAAI,MAAM,GAAG,EAAE;CAC7C,MAAM,SAAS,mBAAmB,QAAQ,IAAI;CAE9C,MAAM,UAAU,OACd,oBAAC,cAAD;EAAc,WAAU;EAAiC;CAAO,CAAA,IAEhE,qBAAA,YAAA,EAAA,UAAA;EACG,SAAS,oBAAC,WAAD,EAAW,OAAO,OAAS,CAAA,IAAI;EACxC,YACC,oBAAC,QAAD;GACE,WAAU;GACV,MAAK;aAEJ;EACG,CAAA,IAEN,oBAAC,QAAD,EAAA,UAAO,MAAY,CAAA;EAEpB,SAAS,oBAAC,WAAD;GAAW,OAAO;GAAQ,WAAU;EAAW,CAAA,IAAI;CAC7D,EAAA,CAAA;CAGJ,IAAI,SAAS,IAAI;EACf,IAAI,CAAC,UACH,OAAO,YAAY,OACjB,oBAAC,MAAD,EAAA,UACE,oBAAC,QAAD;GAAM,WAAU;aACb;EACG,CAAA,EACJ,CAAA;EAIR,IAAI,WACF,OACE,oBAAC,aAAD;GAAa,MAAM;GAAmB;GAAe;GAClD;EACU,CAAA;EAIjB,OACE,oBAAC,iBAAD;GACW;GACT,aAAa,mBAAmB,KAAK,QAAQ,WAAW;GAChD;GAEP;EACc,CAAA;CAErB;CAEA,MAAM,SAAS,gBAAgB;CAC/B,MAAM,SAAS,KAAK,MAAM,UAAU;CAEpC,OACE,oBAAC,MAAD,EAAA,UACE,oBAAC,MAAD;EACE,gBAAc,SAAS,SAAS,KAAA;EAChC,cAAY,aAAa,WAAW,QAAQ,KAAA;EAC5C,IAAI,WAAW,QAAQ,KAAA,IAAY;EACnC,WAAW,GACT,UACA,UACA,aAAa,iCACb,YAAY,kBACZ,UAAU,yBACZ;EACA,aAAW;EACL;EACE;YAEP;CACG,CAAA,EACJ,CAAA;AAER;AAEA,SAAS,gBAAgB,EACvB,UACA,SACA,aACA,UAMC;CACD,MAAM,CAAC,MAAM,WAAW,SAAS,WAAW;CAE5C,OACE,qBAAC,MAAD,EAAA,UAAA,CACE,qBAAC,UAAD;EACE,iBAAe;EACf,WAAW,GAAG,UAAU,QAAQ;EAChC,aAAW;EACX,eAAe,SAAS,UAAU,CAAC,KAAK;EACxC,MAAK;YALP,CAOG,SACD,oBAAC,MAAD;GACE,MAAK;GACL,WAAW,GACT,yDACA,QAAQ,WACV;EACD,CAAA,CACK;KACP,OAAO,oBAAC,MAAD;EAAI,WAAU;EAAiC;CAAa,CAAA,IAAI,IACtE,EAAA,CAAA;AAER;AAEA,SAAS,YAAY,EACnB,UACA,MACA,OACA,UAMC;CACD,OACE,oBAAC,MAAD,EAAA,UACE,oBAAC,SAAD;EACE,WAAU;EACV,WAAU;EACF;EACR,SACE,OACE,oBAAC,cAAD;GAAc,WAAU;GAAiC;EAAO,CAAA,IAEhE,oBAAC,QAAD,EAAA,UAAO,MAAY,CAAA;EAGvB,kBAAkB,GAAG,UAAU,gBAAgB;EAC/C,cAAc;YAEd,qBAAC,MAAD;GAAI,WAAU;aAAd,CACE,oBAAC,MAAD;IAAI,WAAU;cACX;GACC,CAAA,GACH,QACC;;CACG,CAAA,EACP,CAAA;AAER"}
@@ -1,7 +1,8 @@
1
+ import { nodeIdentity } from "../core/test-id.js";
1
2
  import { jsx } from "react/jsx-runtime";
2
3
  //#region resources/js/layout/menu.tsx
3
4
  var MenuComponent = ({ children, node }) => /* @__PURE__ */ jsx("nav", {
4
- "data-lattice-component": node.id,
5
+ "data-lattice-component": nodeIdentity(node),
5
6
  children: /* @__PURE__ */ jsx("ul", {
6
7
  className: "flex flex-col gap-1",
7
8
  children
@@ -1 +1 @@
1
- {"version":3,"file":"menu.js","names":[],"sources":["../../resources/js/layout/menu.tsx"],"sourcesContent":["import type { RendererComponent } from \"@lattice-php/lattice/core/types\";\n\nconst MenuComponent: RendererComponent<\"menu\"> = ({ children, node }) => (\n <nav data-lattice-component={node.id}>\n <ul className=\"flex flex-col gap-1\">{children}</ul>\n </nav>\n);\n\nexport default MenuComponent;\n"],"mappings":";;AAEA,IAAM,iBAA4C,EAAE,UAAU,WAC5D,oBAAC,OAAD;CAAK,0BAAwB,KAAK;WAChC,oBAAC,MAAD;EAAI,WAAU;EAAuB;CAAa,CAAA;AAC/C,CAAA"}
1
+ {"version":3,"file":"menu.js","names":[],"sources":["../../resources/js/layout/menu.tsx"],"sourcesContent":["import type { RendererComponent } from \"@lattice-php/lattice/core/types\";\nimport { nodeIdentity } from \"@lattice-php/lattice/core/test-id\";\n\nconst MenuComponent: RendererComponent<\"menu\"> = ({ children, node }) => (\n <nav data-lattice-component={nodeIdentity(node)}>\n <ul className=\"flex flex-col gap-1\">{children}</ul>\n </nav>\n);\n\nexport default MenuComponent;\n"],"mappings":";;;AAGA,IAAM,iBAA4C,EAAE,UAAU,WAC5D,oBAAC,OAAD;CAAK,0BAAwB,aAAa,IAAI;WAC5C,oBAAC,MAAD;EAAI,WAAU;EAAuB;CAAa,CAAA;AAC/C,CAAA"}
@@ -1,8 +1,8 @@
1
1
  import { cn } from "../lib/utils.js";
2
2
  import { CollapsedContext } from "../core/collapsed-context.js";
3
3
  import { Popover as Popover$1, PopoverContent, PopoverTrigger } from "../core/components/popover.js";
4
- import { useEffect, useState } from "react";
5
4
  import { usePage } from "@inertiajs/react";
5
+ import { useEffect, useState } from "react";
6
6
  import { jsx, jsxs } from "react/jsx-runtime";
7
7
  //#region resources/js/layout/popover.tsx
8
8
  /**
@@ -1,45 +1,85 @@
1
+ import { LATTICE_EVENT } from "../events/event-names.js";
1
2
  import { cn } from "../lib/utils.js";
2
- import { Icon } from "../icons/sprite.js";
3
3
  import { CollapsedContext } from "../core/collapsed-context.js";
4
- import { useState } from "react";
4
+ import { nodeIdentity } from "../core/test-id.js";
5
+ import { router } from "@inertiajs/react";
6
+ import { useEffect, useState } from "react";
5
7
  import { jsx, jsxs } from "react/jsx-runtime";
6
8
  //#region resources/js/layout/sidebar.tsx
9
+ var DESKTOP_QUERY = "(min-width: 768px)";
7
10
  function readStored(key, remember) {
8
11
  if (!remember || typeof window === "undefined") return false;
9
12
  return window.localStorage.getItem(key) === "true";
10
13
  }
14
+ function matchesTarget(event, identity) {
15
+ const target = event.detail?.target;
16
+ return target == null || target === identity;
17
+ }
18
+ function useIsDesktop() {
19
+ const supported = () => typeof window !== "undefined" && typeof window.matchMedia === "function";
20
+ const [isDesktop, setIsDesktop] = useState(() => supported() ? window.matchMedia(DESKTOP_QUERY).matches : true);
21
+ useEffect(() => {
22
+ if (!supported()) return;
23
+ const query = window.matchMedia(DESKTOP_QUERY);
24
+ const update = () => setIsDesktop(query.matches);
25
+ update();
26
+ query.addEventListener("change", update);
27
+ return () => query.removeEventListener("change", update);
28
+ }, []);
29
+ return isDesktop;
30
+ }
11
31
  var SidebarComponent = ({ children, node }) => {
12
32
  const collapsible = node.props.collapsible;
13
33
  const rememberState = node.props.rememberState;
14
- const storageKey = `lattice:sidebar:${node.id ?? "default"}`;
34
+ const identity = nodeIdentity(node);
35
+ const storageKey = `lattice:sidebar:${identity ?? "default"}`;
36
+ const isDesktop = useIsDesktop();
15
37
  const [collapsed, setCollapsed] = useState(() => readStored(storageKey, collapsible && rememberState));
16
- function toggle() {
17
- setCollapsed((value) => {
18
- const next = !value;
19
- if (rememberState && typeof window !== "undefined") window.localStorage.setItem(storageKey, String(next));
20
- return next;
21
- });
22
- }
23
- const isCollapsed = collapsible && collapsed;
24
- return /* @__PURE__ */ jsx(CollapsedContext.Provider, {
38
+ const [mobileOpen, setMobileOpen] = useState(false);
39
+ useEffect(() => {
40
+ function toggle(event) {
41
+ if (!matchesTarget(event, identity)) return;
42
+ if (window.matchMedia?.(DESKTOP_QUERY).matches ?? true) {
43
+ if (!collapsible) return;
44
+ setCollapsed((value) => {
45
+ const next = !value;
46
+ if (rememberState && typeof window !== "undefined") window.localStorage.setItem(storageKey, String(next));
47
+ return next;
48
+ });
49
+ } else setMobileOpen((open) => !open);
50
+ }
51
+ window.addEventListener(LATTICE_EVENT.toggleSidebar, toggle);
52
+ return () => window.removeEventListener(LATTICE_EVENT.toggleSidebar, toggle);
53
+ }, [
54
+ identity,
55
+ collapsible,
56
+ rememberState,
57
+ storageKey
58
+ ]);
59
+ useEffect(() => router.on("navigate", () => setMobileOpen(false)), []);
60
+ useEffect(() => {
61
+ if (!mobileOpen) return;
62
+ function close(event) {
63
+ if (event.key === "Escape") setMobileOpen(false);
64
+ }
65
+ window.addEventListener("keydown", close);
66
+ return () => window.removeEventListener("keydown", close);
67
+ }, [mobileOpen]);
68
+ const isCollapsed = collapsible && collapsed && isDesktop;
69
+ return /* @__PURE__ */ jsxs(CollapsedContext.Provider, {
25
70
  value: isCollapsed,
26
- children: /* @__PURE__ */ jsxs("aside", {
27
- className: cn("sticky top-0 flex h-svh shrink-0 flex-col gap-4 border-r border-lt-border p-4 transition-[width]", isCollapsed ? "w-16 overflow-visible" : "w-64 overflow-x-hidden overflow-y-auto"),
28
- "data-lattice-component": node.id,
29
- children: [collapsible ? /* @__PURE__ */ jsx("button", {
30
- "aria-expanded": !isCollapsed,
31
- "aria-label": isCollapsed ? "Expand sidebar" : "Collapse sidebar",
32
- "data-test": "sidebar-toggle",
33
- className: cn("inline-flex items-center rounded-md p-2 text-lt-fg transition-colors hover:bg-lt-muted", isCollapsed ? "self-center" : "self-end"),
34
- onClick: toggle,
35
- type: "button",
36
- children: /* @__PURE__ */ jsx(Icon, {
37
- name: "panel-left",
38
- "aria-hidden": "true",
39
- className: "size-lt-icon-md shrink-0"
40
- })
41
- }) : null, children]
42
- })
71
+ children: [mobileOpen ? /* @__PURE__ */ jsx("div", {
72
+ "aria-hidden": "true",
73
+ className: "fixed inset-0 z-30 bg-black/50 md:hidden",
74
+ "data-test": "sidebar-backdrop",
75
+ onClick: () => setMobileOpen(false)
76
+ }) : null, /* @__PURE__ */ jsx("aside", {
77
+ className: cn("fixed inset-y-0 left-0 z-40 flex h-svh w-72 max-w-[80vw] shrink-0 flex-col gap-4 border-r border-lt-border bg-lt-bg p-4 transition-transform", "md:sticky md:top-0 md:z-auto md:max-w-none md:translate-x-0 md:transition-[width]", mobileOpen ? "translate-x-0" : "-translate-x-full", isCollapsed ? "md:w-16 md:overflow-visible" : "md:w-64 md:overflow-x-hidden md:overflow-y-auto"),
78
+ "data-collapsed": isCollapsed ? "true" : "false",
79
+ "data-lattice-component": identity,
80
+ "data-test": "sidebar",
81
+ children
82
+ })]
43
83
  });
44
84
  };
45
85
  //#endregion
@@ -1 +1 @@
1
- {"version":3,"file":"sidebar.js","names":[],"sources":["../../resources/js/layout/sidebar.tsx"],"sourcesContent":["import { Icon } from \"@lattice-php/lattice/icons\";\nimport { useState } from \"react\";\nimport type { RendererComponent } from \"@lattice-php/lattice/core/types\";\nimport { CollapsedContext } from \"../core/collapsed-context\";\nimport { cn } from \"@lattice-php/lattice/lib/utils\";\n\nfunction readStored(key: string, remember: boolean): boolean {\n if (!remember || typeof window === \"undefined\") {\n return false;\n }\n\n return window.localStorage.getItem(key) === \"true\";\n}\n\nconst SidebarComponent: RendererComponent<\"sidebar\"> = ({ children, node }) => {\n const collapsible = node.props.collapsible;\n const rememberState = node.props.rememberState;\n const storageKey = `lattice:sidebar:${node.id ?? \"default\"}`;\n\n const [collapsed, setCollapsed] = useState(() =>\n readStored(storageKey, collapsible && rememberState),\n );\n\n function toggle(): void {\n setCollapsed((value) => {\n const next = !value;\n\n if (rememberState && typeof window !== \"undefined\") {\n window.localStorage.setItem(storageKey, String(next));\n }\n\n return next;\n });\n }\n\n const isCollapsed = collapsible && collapsed;\n\n return (\n <CollapsedContext.Provider value={isCollapsed}>\n <aside\n className={cn(\n \"sticky top-0 flex h-svh shrink-0 flex-col gap-4 border-r border-lt-border p-4 transition-[width]\",\n isCollapsed ? \"w-16 overflow-visible\" : \"w-64 overflow-x-hidden overflow-y-auto\",\n )}\n data-lattice-component={node.id}\n >\n {collapsible ? (\n <button\n aria-expanded={!isCollapsed}\n aria-label={isCollapsed ? \"Expand sidebar\" : \"Collapse sidebar\"}\n data-test=\"sidebar-toggle\"\n className={cn(\n \"inline-flex items-center rounded-md p-2 text-lt-fg transition-colors hover:bg-lt-muted\",\n isCollapsed ? \"self-center\" : \"self-end\",\n )}\n onClick={toggle}\n type=\"button\"\n >\n <Icon name=\"panel-left\" aria-hidden=\"true\" className=\"size-lt-icon-md shrink-0\" />\n </button>\n ) : null}\n {children}\n </aside>\n </CollapsedContext.Provider>\n );\n};\n\nexport default SidebarComponent;\n"],"mappings":";;;;;;AAMA,SAAS,WAAW,KAAa,UAA4B;CAC3D,IAAI,CAAC,YAAY,OAAO,WAAW,aACjC,OAAO;CAGT,OAAO,OAAO,aAAa,QAAQ,GAAG,MAAM;AAC9C;AAEA,IAAM,oBAAkD,EAAE,UAAU,WAAW;CAC7E,MAAM,cAAc,KAAK,MAAM;CAC/B,MAAM,gBAAgB,KAAK,MAAM;CACjC,MAAM,aAAa,mBAAmB,KAAK,MAAM;CAEjD,MAAM,CAAC,WAAW,gBAAgB,eAChC,WAAW,YAAY,eAAe,aAAa,CACrD;CAEA,SAAS,SAAe;EACtB,cAAc,UAAU;GACtB,MAAM,OAAO,CAAC;GAEd,IAAI,iBAAiB,OAAO,WAAW,aACrC,OAAO,aAAa,QAAQ,YAAY,OAAO,IAAI,CAAC;GAGtD,OAAO;EACT,CAAC;CACH;CAEA,MAAM,cAAc,eAAe;CAEnC,OACE,oBAAC,iBAAiB,UAAlB;EAA2B,OAAO;YAChC,qBAAC,SAAD;GACE,WAAW,GACT,oGACA,cAAc,0BAA0B,wCAC1C;GACA,0BAAwB,KAAK;aAL/B,CAOG,cACC,oBAAC,UAAD;IACE,iBAAe,CAAC;IAChB,cAAY,cAAc,mBAAmB;IAC7C,aAAU;IACV,WAAW,GACT,0FACA,cAAc,gBAAgB,UAChC;IACA,SAAS;IACT,MAAK;cAEL,oBAAC,MAAD;KAAM,MAAK;KAAa,eAAY;KAAO,WAAU;IAA4B,CAAA;GAC3E,CAAA,IACN,MACH,QACI;;CACkB,CAAA;AAE/B"}
1
+ {"version":3,"file":"sidebar.js","names":[],"sources":["../../resources/js/layout/sidebar.tsx"],"sourcesContent":["import { router } from \"@inertiajs/react\";\nimport { useEffect, useState } from \"react\";\nimport type { RendererComponent } from \"@lattice-php/lattice/core/types\";\nimport { CollapsedContext } from \"../core/collapsed-context\";\nimport { LATTICE_EVENT } from \"@lattice-php/lattice/events/event-names\";\nimport { nodeIdentity } from \"@lattice-php/lattice/core/test-id\";\nimport { cn } from \"@lattice-php/lattice/lib/utils\";\n\nconst DESKTOP_QUERY = \"(min-width: 768px)\";\n\nfunction readStored(key: string, remember: boolean): boolean {\n if (!remember || typeof window === \"undefined\") {\n return false;\n }\n\n return window.localStorage.getItem(key) === \"true\";\n}\n\nfunction matchesTarget(event: Event, identity: string | undefined): boolean {\n const target = (event as CustomEvent<{ target?: string }>).detail?.target;\n\n return target == null || target === identity;\n}\n\nfunction useIsDesktop(): boolean {\n const supported = () => typeof window !== \"undefined\" && typeof window.matchMedia === \"function\";\n const [isDesktop, setIsDesktop] = useState(() =>\n supported() ? window.matchMedia(DESKTOP_QUERY).matches : true,\n );\n\n useEffect(() => {\n if (!supported()) {\n return;\n }\n\n const query = window.matchMedia(DESKTOP_QUERY);\n const update = (): void => setIsDesktop(query.matches);\n\n update();\n query.addEventListener(\"change\", update);\n\n return () => query.removeEventListener(\"change\", update);\n }, []);\n\n return isDesktop;\n}\n\nconst SidebarComponent: RendererComponent<\"sidebar\"> = ({ children, node }) => {\n const collapsible = node.props.collapsible;\n const rememberState = node.props.rememberState;\n const identity = nodeIdentity(node);\n const storageKey = `lattice:sidebar:${identity ?? \"default\"}`;\n const isDesktop = useIsDesktop();\n\n const [collapsed, setCollapsed] = useState(() =>\n readStored(storageKey, collapsible && rememberState),\n );\n const [mobileOpen, setMobileOpen] = useState(false);\n\n useEffect(() => {\n function toggle(event: Event): void {\n if (!matchesTarget(event, identity)) {\n return;\n }\n\n if (window.matchMedia?.(DESKTOP_QUERY).matches ?? true) {\n if (!collapsible) {\n return;\n }\n\n setCollapsed((value) => {\n const next = !value;\n\n if (rememberState && typeof window !== \"undefined\") {\n window.localStorage.setItem(storageKey, String(next));\n }\n\n return next;\n });\n } else {\n setMobileOpen((open) => !open);\n }\n }\n\n window.addEventListener(LATTICE_EVENT.toggleSidebar, toggle);\n\n return () => window.removeEventListener(LATTICE_EVENT.toggleSidebar, toggle);\n }, [identity, collapsible, rememberState, storageKey]);\n\n useEffect(() => router.on(\"navigate\", () => setMobileOpen(false)), []);\n\n useEffect(() => {\n if (!mobileOpen) {\n return;\n }\n\n function close(event: KeyboardEvent): void {\n if (event.key === \"Escape\") {\n setMobileOpen(false);\n }\n }\n\n window.addEventListener(\"keydown\", close);\n\n return () => window.removeEventListener(\"keydown\", close);\n }, [mobileOpen]);\n\n const isCollapsed = collapsible && collapsed && isDesktop;\n\n return (\n <CollapsedContext.Provider value={isCollapsed}>\n {mobileOpen ? (\n <div\n aria-hidden=\"true\"\n className=\"fixed inset-0 z-30 bg-black/50 md:hidden\"\n data-test=\"sidebar-backdrop\"\n onClick={() => setMobileOpen(false)}\n />\n ) : null}\n <aside\n className={cn(\n \"fixed inset-y-0 left-0 z-40 flex h-svh w-72 max-w-[80vw] shrink-0 flex-col gap-4 border-r border-lt-border bg-lt-bg p-4 transition-transform\",\n \"md:sticky md:top-0 md:z-auto md:max-w-none md:translate-x-0 md:transition-[width]\",\n mobileOpen ? \"translate-x-0\" : \"-translate-x-full\",\n isCollapsed\n ? \"md:w-16 md:overflow-visible\"\n : \"md:w-64 md:overflow-x-hidden md:overflow-y-auto\",\n )}\n data-collapsed={isCollapsed ? \"true\" : \"false\"}\n data-lattice-component={identity}\n data-test=\"sidebar\"\n >\n {children}\n </aside>\n </CollapsedContext.Provider>\n );\n};\n\nexport default SidebarComponent;\n"],"mappings":";;;;;;;;AAQA,IAAM,gBAAgB;AAEtB,SAAS,WAAW,KAAa,UAA4B;CAC3D,IAAI,CAAC,YAAY,OAAO,WAAW,aACjC,OAAO;CAGT,OAAO,OAAO,aAAa,QAAQ,GAAG,MAAM;AAC9C;AAEA,SAAS,cAAc,OAAc,UAAuC;CAC1E,MAAM,SAAU,MAA2C,QAAQ;CAEnE,OAAO,UAAU,QAAQ,WAAW;AACtC;AAEA,SAAS,eAAwB;CAC/B,MAAM,kBAAkB,OAAO,WAAW,eAAe,OAAO,OAAO,eAAe;CACtF,MAAM,CAAC,WAAW,gBAAgB,eAChC,UAAU,IAAI,OAAO,WAAW,aAAa,EAAE,UAAU,IAC3D;CAEA,gBAAgB;EACd,IAAI,CAAC,UAAU,GACb;EAGF,MAAM,QAAQ,OAAO,WAAW,aAAa;EAC7C,MAAM,eAAqB,aAAa,MAAM,OAAO;EAErD,OAAO;EACP,MAAM,iBAAiB,UAAU,MAAM;EAEvC,aAAa,MAAM,oBAAoB,UAAU,MAAM;CACzD,GAAG,CAAC,CAAC;CAEL,OAAO;AACT;AAEA,IAAM,oBAAkD,EAAE,UAAU,WAAW;CAC7E,MAAM,cAAc,KAAK,MAAM;CAC/B,MAAM,gBAAgB,KAAK,MAAM;CACjC,MAAM,WAAW,aAAa,IAAI;CAClC,MAAM,aAAa,mBAAmB,YAAY;CAClD,MAAM,YAAY,aAAa;CAE/B,MAAM,CAAC,WAAW,gBAAgB,eAChC,WAAW,YAAY,eAAe,aAAa,CACrD;CACA,MAAM,CAAC,YAAY,iBAAiB,SAAS,KAAK;CAElD,gBAAgB;EACd,SAAS,OAAO,OAAoB;GAClC,IAAI,CAAC,cAAc,OAAO,QAAQ,GAChC;GAGF,IAAI,OAAO,aAAa,aAAa,EAAE,WAAW,MAAM;IACtD,IAAI,CAAC,aACH;IAGF,cAAc,UAAU;KACtB,MAAM,OAAO,CAAC;KAEd,IAAI,iBAAiB,OAAO,WAAW,aACrC,OAAO,aAAa,QAAQ,YAAY,OAAO,IAAI,CAAC;KAGtD,OAAO;IACT,CAAC;GACH,OACE,eAAe,SAAS,CAAC,IAAI;EAEjC;EAEA,OAAO,iBAAiB,cAAc,eAAe,MAAM;EAE3D,aAAa,OAAO,oBAAoB,cAAc,eAAe,MAAM;CAC7E,GAAG;EAAC;EAAU;EAAa;EAAe;CAAU,CAAC;CAErD,gBAAgB,OAAO,GAAG,kBAAkB,cAAc,KAAK,CAAC,GAAG,CAAC,CAAC;CAErE,gBAAgB;EACd,IAAI,CAAC,YACH;EAGF,SAAS,MAAM,OAA4B;GACzC,IAAI,MAAM,QAAQ,UAChB,cAAc,KAAK;EAEvB;EAEA,OAAO,iBAAiB,WAAW,KAAK;EAExC,aAAa,OAAO,oBAAoB,WAAW,KAAK;CAC1D,GAAG,CAAC,UAAU,CAAC;CAEf,MAAM,cAAc,eAAe,aAAa;CAEhD,OACE,qBAAC,iBAAiB,UAAlB;EAA2B,OAAO;YAAlC,CACG,aACC,oBAAC,OAAD;GACE,eAAY;GACZ,WAAU;GACV,aAAU;GACV,eAAe,cAAc,KAAK;EACnC,CAAA,IACC,MACJ,oBAAC,SAAD;GACE,WAAW,GACT,gJACA,qFACA,aAAa,kBAAkB,qBAC/B,cACI,gCACA,iDACN;GACA,kBAAgB,cAAc,SAAS;GACvC,0BAAwB;GACxB,aAAU;GAET;EACI,CAAA,CACkB;;AAE/B"}
@@ -0,0 +1,3 @@
1
+ import { RendererComponent } from '../core/types';
2
+ declare const TopbarComponent: RendererComponent<"topbar">;
3
+ export default TopbarComponent;
@@ -0,0 +1,16 @@
1
+ import { cn } from "../lib/utils.js";
2
+ import { nodeIdentity } from "../core/test-id.js";
3
+ import { jsx } from "react/jsx-runtime";
4
+ //#region resources/js/layout/topbar.tsx
5
+ var TopbarComponent = ({ children, node }) => {
6
+ const sticky = node.props.sticky;
7
+ return /* @__PURE__ */ jsx("header", {
8
+ "data-lattice-component": nodeIdentity(node),
9
+ className: cn("flex h-14 w-full items-center gap-2 border-b border-lt-border bg-lt-bg px-4 text-lt-fg", sticky && "sticky top-0 z-30"),
10
+ children
11
+ });
12
+ };
13
+ //#endregion
14
+ export { TopbarComponent as default };
15
+
16
+ //# sourceMappingURL=topbar.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"topbar.js","names":[],"sources":["../../resources/js/layout/topbar.tsx"],"sourcesContent":["import type { RendererComponent } from \"@lattice-php/lattice/core/types\";\nimport { nodeIdentity } from \"@lattice-php/lattice/core/test-id\";\nimport { cn } from \"@lattice-php/lattice/lib/utils\";\n\nconst TopbarComponent: RendererComponent<\"topbar\"> = ({ children, node }) => {\n const sticky = node.props.sticky;\n\n return (\n <header\n data-lattice-component={nodeIdentity(node)}\n className={cn(\n \"flex h-14 w-full items-center gap-2 border-b border-lt-border bg-lt-bg px-4 text-lt-fg\",\n sticky && \"sticky top-0 z-30\",\n )}\n >\n {children}\n </header>\n );\n};\n\nexport default TopbarComponent;\n"],"mappings":";;;;AAIA,IAAM,mBAAgD,EAAE,UAAU,WAAW;CAC3E,MAAM,SAAS,KAAK,MAAM;CAE1B,OACE,oBAAC,UAAD;EACE,0BAAwB,aAAa,IAAI;EACzC,WAAW,GACT,0FACA,UAAU,mBACZ;EAEC;CACK,CAAA;AAEZ"}
package/dist/page.js CHANGED
@@ -1,22 +1,27 @@
1
1
  import { cn } from "./lib/utils.js";
2
2
  import { Renderer } from "./core/renderer.js";
3
+ import { RealtimeListeners } from "./realtime/listeners.js";
3
4
  import { Head } from "@inertiajs/react";
4
5
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
5
6
  //#region resources/js/page.tsx
6
7
  function Page({ lattice }) {
7
8
  const content = /* @__PURE__ */ jsx(Renderer, { nodes: lattice.schema });
8
- return /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(Head, { title: lattice.title ?? void 0 }), lattice.container === "centered" ? /* @__PURE__ */ jsx("main", {
9
- className: "min-h-svh bg-lt-bg text-lt-fg",
10
- children: /* @__PURE__ */ jsx("div", {
11
- "data-test": "lattice-centered-container",
12
- className: "mx-auto flex min-h-svh w-full max-w-6xl flex-col justify-center px-6 py-12 sm:px-8 lg:px-10",
9
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
10
+ /* @__PURE__ */ jsx(Head, { title: lattice.title ?? void 0 }),
11
+ /* @__PURE__ */ jsx(RealtimeListeners, { listeners: lattice.listeners }),
12
+ lattice.container === "centered" ? /* @__PURE__ */ jsx("main", {
13
+ className: "min-h-svh bg-lt-bg text-lt-fg",
14
+ children: /* @__PURE__ */ jsx("div", {
15
+ "data-test": "lattice-centered-container",
16
+ className: "mx-auto flex min-h-svh w-full max-w-6xl flex-col justify-center px-6 py-12 sm:px-8 lg:px-10",
17
+ children: content
18
+ })
19
+ }) : /* @__PURE__ */ jsx("div", {
20
+ "data-test": "lattice-default-container",
21
+ className: cn("w-full", { "px-4 py-6": lattice.layout !== null }),
13
22
  children: content
14
23
  })
15
- }) : /* @__PURE__ */ jsx("div", {
16
- "data-test": "lattice-default-container",
17
- className: cn("w-full", { "px-4 py-6": lattice.layout !== null }),
18
- children: content
19
- })] });
24
+ ] });
20
25
  }
21
26
  //#endregion
22
27
  export { Page as default };
package/dist/page.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"page.js","names":[],"sources":["../resources/js/page.tsx"],"sourcesContent":["import { Head } from \"@inertiajs/react\";\nimport { Renderer } from \"@lattice-php/lattice/core/renderer\";\nimport type { PagePayload } from \"@lattice-php/lattice\";\nimport { cn } from \"@lattice-php/lattice/lib/utils\";\n\ntype Props = {\n lattice: PagePayload;\n};\n\nexport default function Page({ lattice }: Props) {\n const content = <Renderer nodes={lattice.schema} />;\n\n return (\n <>\n <Head title={lattice.title ?? undefined} />\n\n {lattice.container === \"centered\" ? (\n <main className=\"min-h-svh bg-lt-bg text-lt-fg\">\n <div\n data-test=\"lattice-centered-container\"\n className=\"mx-auto flex min-h-svh w-full max-w-6xl flex-col justify-center px-6 py-12 sm:px-8 lg:px-10\"\n >\n {content}\n </div>\n </main>\n ) : (\n <div\n data-test=\"lattice-default-container\"\n className={cn(\"w-full\", {\n \"px-4 py-6\": lattice.layout !== null,\n })}\n >\n {content}\n </div>\n )}\n </>\n );\n}\n"],"mappings":";;;;;AASA,SAAwB,KAAK,EAAE,WAAkB;CAC/C,MAAM,UAAU,oBAAC,UAAD,EAAU,OAAO,QAAQ,OAAS,CAAA;CAElD,OACE,qBAAA,UAAA,EAAA,UAAA,CACE,oBAAC,MAAD,EAAM,OAAO,QAAQ,SAAS,KAAA,EAAY,CAAA,GAEzC,QAAQ,cAAc,aACrB,oBAAC,QAAD;EAAM,WAAU;YACd,oBAAC,OAAD;GACE,aAAU;GACV,WAAU;aAET;EACE,CAAA;CACD,CAAA,IAEN,oBAAC,OAAD;EACE,aAAU;EACV,WAAW,GAAG,UAAU,EACtB,aAAa,QAAQ,WAAW,KAClC,CAAC;YAEA;CACE,CAAA,CAEP,EAAA,CAAA;AAEN"}
1
+ {"version":3,"file":"page.js","names":[],"sources":["../resources/js/page.tsx"],"sourcesContent":["import { Head } from \"@inertiajs/react\";\nimport { Renderer } from \"@lattice-php/lattice/core/renderer\";\nimport type { PagePayload } from \"@lattice-php/lattice\";\nimport { cn } from \"@lattice-php/lattice/lib/utils\";\nimport { RealtimeListeners } from \"@lattice-php/lattice/realtime/listeners\";\n\ntype Props = {\n lattice: PagePayload;\n};\n\nexport default function Page({ lattice }: Props) {\n const content = <Renderer nodes={lattice.schema} />;\n\n return (\n <>\n <Head title={lattice.title ?? undefined} />\n\n <RealtimeListeners listeners={lattice.listeners} />\n\n {lattice.container === \"centered\" ? (\n <main className=\"min-h-svh bg-lt-bg text-lt-fg\">\n <div\n data-test=\"lattice-centered-container\"\n className=\"mx-auto flex min-h-svh w-full max-w-6xl flex-col justify-center px-6 py-12 sm:px-8 lg:px-10\"\n >\n {content}\n </div>\n </main>\n ) : (\n <div\n data-test=\"lattice-default-container\"\n className={cn(\"w-full\", {\n \"px-4 py-6\": lattice.layout !== null,\n })}\n >\n {content}\n </div>\n )}\n </>\n );\n}\n"],"mappings":";;;;;;AAUA,SAAwB,KAAK,EAAE,WAAkB;CAC/C,MAAM,UAAU,oBAAC,UAAD,EAAU,OAAO,QAAQ,OAAS,CAAA;CAElD,OACE,qBAAA,UAAA,EAAA,UAAA;EACE,oBAAC,MAAD,EAAM,OAAO,QAAQ,SAAS,KAAA,EAAY,CAAA;EAE1C,oBAAC,mBAAD,EAAmB,WAAW,QAAQ,UAAY,CAAA;EAEjD,QAAQ,cAAc,aACrB,oBAAC,QAAD;GAAM,WAAU;aACd,oBAAC,OAAD;IACE,aAAU;IACV,WAAU;cAET;GACE,CAAA;EACD,CAAA,IAEN,oBAAC,OAAD;GACE,aAAU;GACV,WAAW,GAAG,UAAU,EACtB,aAAa,QAAQ,WAAW,KAClC,CAAC;aAEA;EACE,CAAA;CAEP,EAAA,CAAA;AAEN"}
@@ -0,0 +1,4 @@
1
+ import { Effect } from '../types/generated';
2
+ import { Translate } from '../i18n/translatable';
3
+ export type RawEffect = Record<string, unknown>;
4
+ export declare function buildEffects(effects: readonly RawEffect[], payload: Record<string, unknown>, t: Translate): Effect[];
@@ -0,0 +1,23 @@
1
+ import { isTranslatable, resolveTranslatable } from "../i18n/translatable.js";
2
+ //#region resources/js/realtime/build-effects.ts
3
+ function buildEffects(effects, payload, t) {
4
+ return effects.map((effect) => resolveEffect(effect, payload, t));
5
+ }
6
+ function resolveEffect(effect, payload, t) {
7
+ if (effect.type !== "toast") return effect;
8
+ const toast = effect.toast;
9
+ if (typeof toast !== "object" || toast === null) return effect;
10
+ const message = toast.message;
11
+ if (!isTranslatable(message)) return effect;
12
+ return {
13
+ ...effect,
14
+ toast: {
15
+ ...toast,
16
+ message: resolveTranslatable(message, payload, t)
17
+ }
18
+ };
19
+ }
20
+ //#endregion
21
+ export { buildEffects };
22
+
23
+ //# sourceMappingURL=build-effects.js.map
@@ -0,0 +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"}
@@ -0,0 +1,8 @@
1
+ import { ListenerPayload } from '../types/generated';
2
+ /**
3
+ * Renders nothing when a page declares no listeners, so the echo-react chunk
4
+ * is only fetched where it is actually needed.
5
+ */
6
+ export declare function RealtimeListeners({ listeners }: {
7
+ listeners?: ListenerPayload[];
8
+ }): import("react").JSX.Element | null;
@@ -0,0 +1,31 @@
1
+ import { Component, Suspense, lazy } from "react";
2
+ import { jsx } from "react/jsx-runtime";
3
+ //#region resources/js/realtime/listeners.tsx
4
+ var Subscriptions = lazy(() => import("./subscriptions.js"));
5
+ var EchoBoundary = class extends Component {
6
+ state = { failed: false };
7
+ static getDerivedStateFromError() {
8
+ return { failed: true };
9
+ }
10
+ componentDidCatch() {
11
+ console.warn("[lattice] Real-time listeners are declared but Echo is unavailable. Install @laravel/echo-react and call configureEcho().");
12
+ }
13
+ render() {
14
+ return this.state.failed ? null : this.props.children;
15
+ }
16
+ };
17
+ /**
18
+ * Renders nothing when a page declares no listeners, so the echo-react chunk
19
+ * is only fetched where it is actually needed.
20
+ */
21
+ function RealtimeListeners({ listeners }) {
22
+ if (listeners === void 0 || listeners.length === 0) return null;
23
+ return /* @__PURE__ */ jsx(EchoBoundary, { children: /* @__PURE__ */ jsx(Suspense, {
24
+ fallback: null,
25
+ children: /* @__PURE__ */ jsx(Subscriptions, { listeners })
26
+ }) });
27
+ }
28
+ //#endregion
29
+ export { RealtimeListeners };
30
+
31
+ //# sourceMappingURL=listeners.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"listeners.js","names":[],"sources":["../../resources/js/realtime/listeners.tsx"],"sourcesContent":["import { Component, lazy, Suspense } from \"react\";\nimport type { ReactNode } from \"react\";\nimport type { ListenerPayload } from \"@lattice-php/lattice/types/generated\";\n\nconst Subscriptions = lazy(() => import(\"./subscriptions\"));\n\nclass EchoBoundary extends Component<{ children: ReactNode }, { failed: boolean }> {\n state = { failed: false };\n\n static getDerivedStateFromError(): { failed: boolean } {\n return { failed: true };\n }\n\n componentDidCatch(): void {\n console.warn(\n \"[lattice] Real-time listeners are declared but Echo is unavailable. Install @laravel/echo-react and call configureEcho().\",\n );\n }\n\n render(): ReactNode {\n return this.state.failed ? null : this.props.children;\n }\n}\n\n/**\n * Renders nothing when a page declares no listeners, so the echo-react chunk\n * is only fetched where it is actually needed.\n */\nexport function RealtimeListeners({ listeners }: { listeners?: ListenerPayload[] }) {\n if (listeners === undefined || listeners.length === 0) {\n return null;\n }\n\n return (\n <EchoBoundary>\n <Suspense fallback={null}>\n <Subscriptions listeners={listeners} />\n </Suspense>\n </EchoBoundary>\n );\n}\n"],"mappings":";;;AAIA,IAAM,gBAAgB,WAAW,OAAO,qBAAkB;AAE1D,IAAM,eAAN,cAA2B,UAAwD;CACjF,QAAQ,EAAE,QAAQ,MAAM;CAExB,OAAO,2BAAgD;EACrD,OAAO,EAAE,QAAQ,KAAK;CACxB;CAEA,oBAA0B;EACxB,QAAQ,KACN,2HACF;CACF;CAEA,SAAoB;EAClB,OAAO,KAAK,MAAM,SAAS,OAAO,KAAK,MAAM;CAC/C;AACF;;;;;AAMA,SAAgB,kBAAkB,EAAE,aAAgD;CAClF,IAAI,cAAc,KAAA,KAAa,UAAU,WAAW,GAClD,OAAO;CAGT,OACE,oBAAC,cAAD,EAAA,UACE,oBAAC,UAAD;EAAU,UAAU;YAClB,oBAAC,eAAD,EAA0B,UAAY,CAAA;CAC9B,CAAA,EACE,CAAA;AAElB"}
@@ -0,0 +1,4 @@
1
+ import { ListenerPayload } from '../types/generated';
2
+ export default function Subscriptions({ listeners }: {
3
+ listeners: ListenerPayload[];
4
+ }): import("react").JSX.Element;