@lattice-php/lattice 0.20.0 → 0.21.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 (199) hide show
  1. package/dist/action/components/action-form.d.ts +6 -1
  2. package/dist/action/components/action-form.js +34 -49
  3. package/dist/action/components/action-form.js.map +1 -1
  4. package/dist/action/components/action-trigger-provider.d.ts +1 -1
  5. package/dist/action/components/action-trigger-provider.js.map +1 -1
  6. package/dist/action/hooks/use-action.d.ts +1 -1
  7. package/dist/action/hooks/use-action.js +3 -1
  8. package/dist/action/hooks/use-action.js.map +1 -1
  9. package/dist/action/index.d.ts +0 -2
  10. package/dist/action/index.js +1 -2
  11. package/dist/chat/plugin.d.ts +0 -1
  12. package/dist/chat/plugin.js.map +1 -1
  13. package/dist/clipboard/index.d.ts +0 -4
  14. package/dist/clipboard/index.js +1 -15
  15. package/dist/{events → core}/event-names.js +1 -1
  16. package/dist/core/event-names.js.map +1 -0
  17. package/dist/core/hooks/use-window-event.d.ts +8 -0
  18. package/dist/core/hooks/use-window-event.js +22 -0
  19. package/dist/core/hooks/use-window-event.js.map +1 -0
  20. package/dist/core/index.js +3 -3
  21. package/dist/core/types.d.ts +8 -73
  22. package/dist/create-app.js +1 -1
  23. package/dist/effects/dispatch.js +1 -1
  24. package/dist/effects/dispatch.js.map +1 -1
  25. package/dist/effects/registry.d.ts +2 -18
  26. package/dist/effects/registry.js +4 -8
  27. package/dist/effects/registry.js.map +1 -1
  28. package/dist/event-bridge.js +10 -23
  29. package/dist/event-bridge.js.map +1 -1
  30. package/dist/form/components/fields/date-picker-field.js +1 -1
  31. package/dist/form/components/fields/file-upload.js +4 -6
  32. package/dist/form/components/fields/file-upload.js.map +1 -1
  33. package/dist/form/components/fields/select.js +2 -2
  34. package/dist/form/components/fields/select.js.map +1 -1
  35. package/dist/form/components/fields/table-rows.js +3 -15
  36. package/dist/form/components/fields/table-rows.js.map +1 -1
  37. package/dist/form/components/form.js +8 -23
  38. package/dist/form/components/form.js.map +1 -1
  39. package/dist/form/embed.d.ts +4 -0
  40. package/dist/form/embed.js +3 -1
  41. package/dist/form/lib/collect-fields.d.ts +7 -0
  42. package/dist/form/lib/collect-fields.js +19 -0
  43. package/dist/form/lib/collect-fields.js.map +1 -0
  44. package/dist/form/lib/field-errors.d.ts +3 -0
  45. package/dist/form/lib/field-errors.js +11 -0
  46. package/dist/form/lib/field-errors.js.map +1 -0
  47. package/dist/format/format-context.d.ts +6 -0
  48. package/dist/format/format-context.js +17 -0
  49. package/dist/format/format-context.js.map +1 -0
  50. package/dist/i18n/backend.js +1 -1
  51. package/dist/i18n/index.js +2 -2
  52. package/dist/i18n/instance.js +1 -1
  53. package/dist/i18n/locale-reload.d.ts +1 -1
  54. package/dist/i18n/locale-reload.js +7 -6
  55. package/dist/i18n/locale-reload.js.map +1 -1
  56. package/dist/i18n/locale.js +1 -1
  57. package/dist/i18n/locale.js.map +1 -1
  58. package/dist/i18n/page-props.js +1 -1
  59. package/dist/i18n/shared-props.js +1 -3
  60. package/dist/i18n/shared-props.js.map +1 -1
  61. package/dist/i18n/timezone.js +1 -1
  62. package/dist/i18n/timezone.js.map +1 -1
  63. package/dist/index.d.ts +6 -7
  64. package/dist/index.js +7 -8
  65. package/dist/lattice.css +105 -0
  66. package/dist/layout/components/callouts.js +1 -1
  67. package/dist/layout/components/sidebar.js +15 -48
  68. package/dist/layout/components/sidebar.js.map +1 -1
  69. package/dist/layout/plugin.d.ts +0 -1
  70. package/dist/layout/plugin.js.map +1 -1
  71. package/dist/lib/is-truthy.d.ts +2 -0
  72. package/dist/lib/is-truthy.js +9 -0
  73. package/dist/lib/is-truthy.js.map +1 -0
  74. package/dist/lib/use-debounced-callback.d.ts +10 -0
  75. package/dist/lib/use-debounced-callback.js +34 -0
  76. package/dist/lib/use-debounced-callback.js.map +1 -0
  77. package/dist/lib/use-media-query.d.ts +5 -0
  78. package/dist/lib/use-media-query.js +26 -0
  79. package/dist/lib/use-media-query.js.map +1 -0
  80. package/dist/lib/use-persistent-state.d.ts +13 -0
  81. package/dist/lib/use-persistent-state.js +62 -0
  82. package/dist/lib/use-persistent-state.js.map +1 -0
  83. package/dist/notifications/components/notifications.js +3 -1
  84. package/dist/notifications/components/notifications.js.map +1 -1
  85. package/dist/notifications/plugin.d.ts +0 -1
  86. package/dist/notifications/plugin.js.map +1 -1
  87. package/dist/provider-base.js +1 -1
  88. package/dist/realtime/listeners.d.ts +1 -1
  89. package/dist/realtime/listeners.js +1 -1
  90. package/dist/realtime/listeners.js.map +1 -1
  91. package/dist/registry.d.ts +5 -0
  92. package/dist/registry.js.map +1 -1
  93. package/dist/remote/components/data-list.js +1 -1
  94. package/dist/remote/plugin.d.ts +0 -1
  95. package/dist/remote/plugin.js.map +1 -1
  96. package/dist/table/components/bulk-bar.js +4 -2
  97. package/dist/table/components/bulk-bar.js.map +1 -1
  98. package/dist/table/components/cells/boolean-cell.js +1 -3
  99. package/dist/table/components/cells/boolean-cell.js.map +1 -1
  100. package/dist/table/components/cells/copyable-cell.d.ts +9 -0
  101. package/dist/table/components/cells/copyable-cell.js +17 -0
  102. package/dist/table/components/cells/copyable-cell.js.map +1 -0
  103. package/dist/table/components/cells/money-cell.js +7 -18
  104. package/dist/table/components/cells/money-cell.js.map +1 -1
  105. package/dist/table/components/cells/number-cell.js +14 -27
  106. package/dist/table/components/cells/number-cell.js.map +1 -1
  107. package/dist/table/components/cells/numeric-cell.d.ts +10 -0
  108. package/dist/table/components/cells/numeric-cell.js +25 -0
  109. package/dist/table/components/cells/numeric-cell.js.map +1 -0
  110. package/dist/table/components/cells/stack-cell.js +1 -1
  111. package/dist/table/components/cells/text-cell.js +4 -5
  112. package/dist/table/components/cells/text-cell.js.map +1 -1
  113. package/dist/table/components/filter-controls.js +1 -3
  114. package/dist/table/components/filter-controls.js.map +1 -1
  115. package/dist/table/components/table-cell.js.map +1 -1
  116. package/dist/table/components/table-search.js +4 -7
  117. package/dist/table/components/table-search.js.map +1 -1
  118. package/dist/table/components/table.js +2 -3
  119. package/dist/table/components/table.js.map +1 -1
  120. package/dist/table/hooks/use-column-visibility.js +29 -58
  121. package/dist/table/hooks/use-column-visibility.js.map +1 -1
  122. package/dist/table/hooks/use-table.js +5 -13
  123. package/dist/table/hooks/use-table.js.map +1 -1
  124. package/dist/table/lib/bulk.d.ts +2 -0
  125. package/dist/table/lib/bulk.js +3 -1
  126. package/dist/table/lib/bulk.js.map +1 -1
  127. package/dist/table/lib/query.js +1 -1
  128. package/dist/table/lib/query.js.map +1 -1
  129. package/dist/table/plugin.d.ts +0 -1
  130. package/dist/table/plugin.js.map +1 -1
  131. package/dist/table/types.d.ts +4 -57
  132. package/dist/toast/callout.js +1 -1
  133. package/dist/toast/callout.js.map +1 -1
  134. package/dist/toast/index.d.ts +1 -1
  135. package/dist/toast/index.js +2 -2
  136. package/dist/toast/toast.d.ts +0 -2
  137. package/dist/toast/toast.js +3 -10
  138. package/dist/toast/toast.js.map +1 -1
  139. package/dist/toast/toaster.js +2 -2
  140. package/dist/types/generated.d.ts +224 -80
  141. package/dist/types/index.d.ts +1 -1
  142. package/dist/ui/button.d.ts +2 -2
  143. package/dist/ui/chart-view.js +7 -30
  144. package/dist/ui/chart-view.js.map +1 -1
  145. package/dist/ui/click-behavior.d.ts +4 -4
  146. package/dist/ui/click-behavior.js.map +1 -1
  147. package/dist/ui/collapsible.js +3 -15
  148. package/dist/ui/collapsible.js.map +1 -1
  149. package/dist/ui/combobox.js +6 -3
  150. package/dist/ui/combobox.js.map +1 -1
  151. package/dist/ui/confirm-dialog.js +1 -1
  152. package/dist/ui/confirm-dialog.js.map +1 -1
  153. package/dist/ui/control.d.ts +1 -1
  154. package/dist/ui/dialog.d.ts +6 -2
  155. package/dist/ui/dialog.js +29 -5
  156. package/dist/ui/dialog.js.map +1 -1
  157. package/dist/ui/fragment.js +1 -1
  158. package/dist/ui/fragment.js.map +1 -1
  159. package/dist/ui/icon-button.d.ts +1 -1
  160. package/dist/ui/image-preview.js +1 -1
  161. package/dist/ui/image-preview.js.map +1 -1
  162. package/dist/ui/modal.js +3 -2
  163. package/dist/ui/modal.js.map +1 -1
  164. package/dist/ui/pill.d.ts +2 -0
  165. package/dist/ui/pill.js +10 -0
  166. package/dist/ui/pill.js.map +1 -0
  167. package/dist/ui/plugin.js.map +1 -1
  168. package/dist/ui/progress.js +1 -1
  169. package/dist/ui/section.js +2 -15
  170. package/dist/ui/section.js.map +1 -1
  171. package/dist/ui/segmented-pills.js +2 -1
  172. package/dist/ui/segmented-pills.js.map +1 -1
  173. package/dist/ui/tabs.js +12 -10
  174. package/dist/ui/tabs.js.map +1 -1
  175. package/dist/ui/tree-context.js +11 -13
  176. package/dist/ui/tree-context.js.map +1 -1
  177. package/dist/ui/tree.js +1 -1
  178. package/dist/ui/tree.js.map +1 -1
  179. package/dist/ui/use-collapsible-state.d.ts +7 -0
  180. package/dist/ui/use-collapsible-state.js +21 -0
  181. package/dist/ui/use-collapsible-state.js.map +1 -0
  182. package/dist-standalone/chunks/chart-view-C6R5iPra.js +36 -0
  183. package/dist-standalone/chunks/{date-picker-field-VbH9xrQO.js → date-picker-field-DhhEB-Mh.js} +1 -1
  184. package/dist-standalone/chunks/{page-props-AIa5UR6n.js → page-props-DOfg30l5.js} +1 -1
  185. package/dist-standalone/chunks/{rich-editor-field-DLQTyt36.js → rich-editor-field-DORXTHPw.js} +2 -2
  186. package/dist-standalone/chunks/{subscriptions-DY2tj9Im.js → subscriptions-B_ISgA7V.js} +1 -1
  187. package/dist-standalone/chunks/use-effect-dispatcher-D1wPPwHj.js +97 -0
  188. package/dist-standalone/lattice.css +1 -1
  189. package/dist-standalone/lattice.js +15 -15
  190. package/dist-standalone/manifest.json +8 -8
  191. package/package.json +1 -1
  192. package/dist/clipboard/index.js.map +0 -1
  193. package/dist/events/event-names.js.map +0 -1
  194. package/dist/table/components/table-action-node.d.ts +0 -4
  195. package/dist/table/components/table-action-node.js +0 -24
  196. package/dist/table/components/table-action-node.js.map +0 -1
  197. package/dist-standalone/chunks/chart-view-wJmnVu7L.js +0 -36
  198. package/dist-standalone/chunks/use-effect-dispatcher-feEs0GCP.js +0 -97
  199. /package/dist/{events → core}/event-names.d.ts +0 -0
@@ -0,0 +1,17 @@
1
+ import { useLocale } from "../i18n/locale.js";
2
+ import { useTimezone } from "../i18n/timezone.js";
3
+ import { useMemo } from "react";
4
+ //#region resources/js/format/format-context.ts
5
+ /** The `{ locale, timezone }` pair every `formatValue` call needs. */
6
+ function useFormatContext() {
7
+ const { locale } = useLocale();
8
+ const { timezone } = useTimezone();
9
+ return useMemo(() => ({
10
+ locale,
11
+ timezone
12
+ }), [locale, timezone]);
13
+ }
14
+ //#endregion
15
+ export { useFormatContext };
16
+
17
+ //# sourceMappingURL=format-context.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"format-context.js","names":[],"sources":["../../resources/js/format/format-context.ts"],"sourcesContent":["import { useMemo } from \"react\";\nimport { useLocale } from \"@lattice-php/lattice/i18n/locale\";\nimport { useTimezone } from \"@lattice-php/lattice/i18n/timezone\";\n\nexport type FormatContext = { locale: string; timezone: string };\n\n/** The `{ locale, timezone }` pair every `formatValue` call needs. */\nexport function useFormatContext(): FormatContext {\n const { locale } = useLocale();\n const { timezone } = useTimezone();\n\n return useMemo(() => ({ locale, timezone }), [locale, timezone]);\n}\n"],"mappings":";;;;;AAOA,SAAgB,mBAAkC;CAChD,MAAM,EAAE,WAAW,UAAU;CAC7B,MAAM,EAAE,aAAa,YAAY;CAEjC,OAAO,eAAe;EAAE;EAAQ;CAAS,IAAI,CAAC,QAAQ,QAAQ,CAAC;AACjE"}
@@ -1,5 +1,5 @@
1
- import { setConfig } from "./config.js";
2
1
  import { localeHeader } from "./locale.js";
2
+ import { setConfig } from "./config.js";
3
3
  import { ensureI18n, i18n, preloadLanguages } from "./instance.js";
4
4
  import HttpBackend from "i18next-http-backend";
5
5
  //#region resources/js/i18n/backend.ts
@@ -1,10 +1,10 @@
1
+ import { LocaleReload } from "./locale-reload.js";
2
+ import { i18nConfigFromPageProps } from "./shared-props.js";
1
3
  import { currentLocale, localeHeader, setLocale, useLocale } from "./locale.js";
2
4
  import { i18n, translate, useT } from "./instance.js";
3
5
  import { configureI18n, enableBackend } from "./backend.js";
4
6
  import { LocaleSwitcher, useLocaleOptions } from "./locale-switcher.js";
5
- import { i18nConfigFromPageProps } from "./shared-props.js";
6
7
  import { configureI18nFromPageProps } from "./page-props.js";
7
8
  import { currentTimezone, setTimezone, useTimezone } from "./timezone.js";
8
9
  import { DateTime } from "./date-time.js";
9
- import { LocaleReload } from "./locale-reload.js";
10
10
  export { DateTime, LocaleReload, LocaleSwitcher, configureI18n, configureI18nFromPageProps, currentLocale, currentTimezone, enableBackend, i18n, i18nConfigFromPageProps, localeHeader, setLocale, setTimezone, translate, useLocale, useLocaleOptions, useT, useTimezone };
@@ -1,5 +1,5 @@
1
- import { useConfig } from "./config.js";
2
1
  import { currentLocale, subscribeLocale, useLocale } from "./locale.js";
2
+ import { useConfig } from "./config.js";
3
3
  import { useCallback, useSyncExternalStore } from "react";
4
4
  import i18next from "i18next";
5
5
  //#region resources/js/i18n/instance.ts
@@ -1,4 +1,4 @@
1
1
  import { VisitOptions } from '@inertiajs/core';
2
2
  type LocaleReloadProps = Pick<VisitOptions, "preserveScroll" | "preserveState">;
3
- export declare function LocaleReload({ preserveScroll, preserveState }: LocaleReloadProps): import("react").JSX.Element;
3
+ export declare function LocaleReload({ preserveScroll, preserveState }: LocaleReloadProps): null;
4
4
  export {};
@@ -1,15 +1,16 @@
1
- import { EventBridge } from "../event-bridge.js";
1
+ import { LATTICE_EVENT } from "../core/event-names.js";
2
+ import { useWindowEvent } from "../core/hooks/use-window-event.js";
2
3
  import { router } from "@inertiajs/react";
3
- import { useCallback } from "react";
4
- import { jsx } from "react/jsx-runtime";
5
4
  //#region resources/js/i18n/locale-reload.tsx
6
5
  function LocaleReload({ preserveScroll = true, preserveState = true }) {
7
- return /* @__PURE__ */ jsx(EventBridge, { onLocaleChange: useCallback(() => {
8
- router.visit(window.location.href, {
6
+ useWindowEvent(LATTICE_EVENT.localeChange, (event) => {
7
+ const locale = event.detail?.locale;
8
+ if (typeof locale === "string" && locale !== "") router.visit(window.location.href, {
9
9
  preserveScroll,
10
10
  preserveState
11
11
  });
12
- }, [preserveScroll, preserveState]) });
12
+ });
13
+ return null;
13
14
  }
14
15
  //#endregion
15
16
  export { LocaleReload };
@@ -1 +1 @@
1
- {"version":3,"file":"locale-reload.js","names":[],"sources":["../../resources/js/i18n/locale-reload.tsx"],"sourcesContent":["import type { VisitOptions } from \"@inertiajs/core\";\nimport { router } from \"@inertiajs/react\";\nimport { useCallback } from \"react\";\nimport { EventBridge } from \"@lattice-php/lattice/event-bridge\";\n\ntype LocaleReloadProps = Pick<VisitOptions, \"preserveScroll\" | \"preserveState\">;\n\n// preserveState by default: the visit only re-fetches the re-localized props,\n// so keeping the page mounted avoids remounting the whole tree (and losing\n// table sort/filter, form input, focus) on every locale switch.\nexport function LocaleReload({ preserveScroll = true, preserveState = true }: LocaleReloadProps) {\n const reload = useCallback(() => {\n router.visit(window.location.href, { preserveScroll, preserveState });\n }, [preserveScroll, preserveState]);\n\n return <EventBridge onLocaleChange={reload} />;\n}\n"],"mappings":";;;;;AAUA,SAAgB,aAAa,EAAE,iBAAiB,MAAM,gBAAgB,QAA2B;CAK/F,OAAO,oBAAC,aAAD,EAAa,gBAJL,kBAAkB;EAC/B,OAAO,MAAM,OAAO,SAAS,MAAM;GAAE;GAAgB;EAAc,CAAC;CACtE,GAAG,CAAC,gBAAgB,aAAa,CAEG,EAAS,CAAA;AAC/C"}
1
+ {"version":3,"file":"locale-reload.js","names":[],"sources":["../../resources/js/i18n/locale-reload.tsx"],"sourcesContent":["import type { VisitOptions } from \"@inertiajs/core\";\nimport { router } from \"@inertiajs/react\";\nimport { LATTICE_EVENT } from \"@lattice-php/lattice/core/event-names\";\nimport { useWindowEvent } from \"@lattice-php/lattice/core/hooks/use-window-event\";\n\ntype LocaleReloadProps = Pick<VisitOptions, \"preserveScroll\" | \"preserveState\">;\n\n// preserveState by default: the visit only re-fetches the re-localized props,\n// so keeping the page mounted avoids remounting the whole tree (and losing\n// table sort/filter, form input, focus) on every locale switch.\nexport function LocaleReload({ preserveScroll = true, preserveState = true }: LocaleReloadProps) {\n useWindowEvent(LATTICE_EVENT.localeChange, (event) => {\n const locale = (event as CustomEvent<{ locale?: unknown }>).detail?.locale;\n\n if (typeof locale === \"string\" && locale !== \"\") {\n router.visit(window.location.href, { preserveScroll, preserveState });\n }\n });\n\n return null;\n}\n"],"mappings":";;;;AAUA,SAAgB,aAAa,EAAE,iBAAiB,MAAM,gBAAgB,QAA2B;CAC/F,eAAe,cAAc,eAAe,UAAU;EACpD,MAAM,SAAU,MAA4C,QAAQ;EAEpE,IAAI,OAAO,WAAW,YAAY,WAAW,IAC3C,OAAO,MAAM,OAAO,SAAS,MAAM;GAAE;GAAgB;EAAc,CAAC;CAExE,CAAC;CAED,OAAO;AACT"}
@@ -1,4 +1,4 @@
1
- import { LATTICE_EVENT } from "../events/event-names.js";
1
+ import { LATTICE_EVENT } from "../core/event-names.js";
2
2
  import { useSyncExternalStore } from "react";
3
3
  //#region resources/js/i18n/locale.ts
4
4
  var key = "locale";
@@ -1 +1 @@
1
- {"version":3,"file":"locale.js","names":[],"sources":["../../resources/js/i18n/locale.ts"],"sourcesContent":["import { useSyncExternalStore } from \"react\";\nimport { LATTICE_EVENT } from \"@lattice-php/lattice/events/event-names\";\n\nexport type UseLocaleReturn = {\n readonly locale: string;\n readonly setLocale: (locale: string) => void;\n};\n\nconst key = \"locale\";\nconst fallback = \"en\";\nconst maxAge = 365 * 24 * 60 * 60;\nconst listeners = new Set<() => void>();\n\nlet active: string | undefined;\n\nfunction normalize(value: string): string {\n const next = value.trim();\n\n return next === \"\" ? fallback : next;\n}\n\nfunction storedValue(): string | null {\n if (typeof window === \"undefined\") {\n return null;\n }\n\n try {\n return localStorage.getItem(key);\n } catch {\n return null;\n }\n}\n\nfunction cookieValue(): string | null {\n if (typeof document === \"undefined\") {\n return null;\n }\n\n const item = document.cookie\n .split(\";\")\n .map((cookie) => cookie.trim())\n .find((cookie) => cookie.startsWith(`${key}=`));\n\n if (!item) {\n return null;\n }\n\n try {\n return decodeURIComponent(item.slice(key.length + 1));\n } catch {\n return null;\n }\n}\n\nfunction documentValue(): string | null {\n if (typeof document === \"undefined\") {\n return null;\n }\n\n return document.documentElement.lang || null;\n}\n\nfunction detectedLocale(): string {\n return normalize(storedValue() ?? cookieValue() ?? documentValue() ?? fallback);\n}\n\nfunction persist(locale: string): void {\n if (typeof document !== \"undefined\") {\n document.cookie = `${key}=${encodeURIComponent(locale)};path=/;max-age=${maxAge};SameSite=Lax`;\n document.documentElement.lang = locale;\n }\n\n if (typeof window !== \"undefined\") {\n try {\n localStorage.setItem(key, locale);\n } catch {\n return;\n }\n }\n}\n\nfunction snapshot(): string {\n active ??= detectedLocale();\n\n return active;\n}\n\nfunction subscribe(callback: () => void): () => void {\n listeners.add(callback);\n\n return () => {\n listeners.delete(callback);\n };\n}\n\nfunction notify(): void {\n listeners.forEach((listener) => listener());\n}\n\nfunction dispatch(locale: string): void {\n if (typeof window === \"undefined\") {\n return;\n }\n\n window.dispatchEvent(new CustomEvent(LATTICE_EVENT.localeChange, { detail: { locale } }));\n}\n\nexport function currentLocale(): string {\n return snapshot();\n}\n\nexport function localeHeader(): Record<string, string> {\n return { \"Accept-Language\": currentLocale() };\n}\n\nexport function subscribeLocale(callback: (locale: string) => void): () => void {\n return subscribe(() => callback(currentLocale()));\n}\n\nexport function setLocale(locale: string): void {\n const previous = currentLocale();\n const next = normalize(locale);\n\n active = next;\n persist(next);\n\n if (next === previous) {\n return;\n }\n\n notify();\n dispatch(next);\n}\n\nexport function useLocale(): UseLocaleReturn {\n const locale = useSyncExternalStore(subscribe, snapshot, () => fallback);\n\n return { locale, setLocale } as const;\n}\n"],"mappings":";;;AAQA,IAAM,MAAM;AACZ,IAAM,WAAW;AACjB,IAAM,SAAS,MAAM,KAAK,KAAK;AAC/B,IAAM,4BAAY,IAAI,IAAgB;AAEtC,IAAI;AAEJ,SAAS,UAAU,OAAuB;CACxC,MAAM,OAAO,MAAM,KAAK;CAExB,OAAO,SAAS,KAAK,WAAW;AAClC;AAEA,SAAS,cAA6B;CACpC,IAAI,OAAO,WAAW,aACpB,OAAO;CAGT,IAAI;EACF,OAAO,aAAa,QAAQ,GAAG;CACjC,QAAQ;EACN,OAAO;CACT;AACF;AAEA,SAAS,cAA6B;CACpC,IAAI,OAAO,aAAa,aACtB,OAAO;CAGT,MAAM,OAAO,SAAS,OACnB,MAAM,GAAG,EACT,KAAK,WAAW,OAAO,KAAK,CAAC,EAC7B,MAAM,WAAW,OAAO,WAAW,GAAG,IAAI,EAAE,CAAC;CAEhD,IAAI,CAAC,MACH,OAAO;CAGT,IAAI;EACF,OAAO,mBAAmB,KAAK,MAAM,CAAc,CAAC;CACtD,QAAQ;EACN,OAAO;CACT;AACF;AAEA,SAAS,gBAA+B;CACtC,IAAI,OAAO,aAAa,aACtB,OAAO;CAGT,OAAO,SAAS,gBAAgB,QAAQ;AAC1C;AAEA,SAAS,iBAAyB;CAChC,OAAO,UAAU,YAAY,KAAK,YAAY,KAAK,cAAc,KAAK,QAAQ;AAChF;AAEA,SAAS,QAAQ,QAAsB;CACrC,IAAI,OAAO,aAAa,aAAa;EACnC,SAAS,SAAS,GAAG,IAAI,GAAG,mBAAmB,MAAM,EAAE,kBAAkB,OAAO;EAChF,SAAS,gBAAgB,OAAO;CAClC;CAEA,IAAI,OAAO,WAAW,aACpB,IAAI;EACF,aAAa,QAAQ,KAAK,MAAM;CAClC,QAAQ;EACN;CACF;AAEJ;AAEA,SAAS,WAAmB;CAC1B,WAAW,eAAe;CAE1B,OAAO;AACT;AAEA,SAAS,UAAU,UAAkC;CACnD,UAAU,IAAI,QAAQ;CAEtB,aAAa;EACX,UAAU,OAAO,QAAQ;CAC3B;AACF;AAEA,SAAS,SAAe;CACtB,UAAU,SAAS,aAAa,SAAS,CAAC;AAC5C;AAEA,SAAS,SAAS,QAAsB;CACtC,IAAI,OAAO,WAAW,aACpB;CAGF,OAAO,cAAc,IAAI,YAAY,cAAc,cAAc,EAAE,QAAQ,EAAE,OAAO,EAAE,CAAC,CAAC;AAC1F;AAEA,SAAgB,gBAAwB;CACtC,OAAO,SAAS;AAClB;AAEA,SAAgB,eAAuC;CACrD,OAAO,EAAE,mBAAmB,cAAc,EAAE;AAC9C;AAEA,SAAgB,gBAAgB,UAAgD;CAC9E,OAAO,gBAAgB,SAAS,cAAc,CAAC,CAAC;AAClD;AAEA,SAAgB,UAAU,QAAsB;CAC9C,MAAM,WAAW,cAAc;CAC/B,MAAM,OAAO,UAAU,MAAM;CAE7B,SAAS;CACT,QAAQ,IAAI;CAEZ,IAAI,SAAS,UACX;CAGF,OAAO;CACP,SAAS,IAAI;AACf;AAEA,SAAgB,YAA6B;CAG3C,OAAO;EAAE,QAFM,qBAAqB,WAAW,gBAAgB,QAEtD;EAAQ;CAAU;AAC7B"}
1
+ {"version":3,"file":"locale.js","names":[],"sources":["../../resources/js/i18n/locale.ts"],"sourcesContent":["import { useSyncExternalStore } from \"react\";\nimport { LATTICE_EVENT } from \"@lattice-php/lattice/core/event-names\";\n\nexport type UseLocaleReturn = {\n readonly locale: string;\n readonly setLocale: (locale: string) => void;\n};\n\nconst key = \"locale\";\nconst fallback = \"en\";\nconst maxAge = 365 * 24 * 60 * 60;\nconst listeners = new Set<() => void>();\n\nlet active: string | undefined;\n\nfunction normalize(value: string): string {\n const next = value.trim();\n\n return next === \"\" ? fallback : next;\n}\n\nfunction storedValue(): string | null {\n if (typeof window === \"undefined\") {\n return null;\n }\n\n try {\n return localStorage.getItem(key);\n } catch {\n return null;\n }\n}\n\nfunction cookieValue(): string | null {\n if (typeof document === \"undefined\") {\n return null;\n }\n\n const item = document.cookie\n .split(\";\")\n .map((cookie) => cookie.trim())\n .find((cookie) => cookie.startsWith(`${key}=`));\n\n if (!item) {\n return null;\n }\n\n try {\n return decodeURIComponent(item.slice(key.length + 1));\n } catch {\n return null;\n }\n}\n\nfunction documentValue(): string | null {\n if (typeof document === \"undefined\") {\n return null;\n }\n\n return document.documentElement.lang || null;\n}\n\nfunction detectedLocale(): string {\n return normalize(storedValue() ?? cookieValue() ?? documentValue() ?? fallback);\n}\n\nfunction persist(locale: string): void {\n if (typeof document !== \"undefined\") {\n document.cookie = `${key}=${encodeURIComponent(locale)};path=/;max-age=${maxAge};SameSite=Lax`;\n document.documentElement.lang = locale;\n }\n\n if (typeof window !== \"undefined\") {\n try {\n localStorage.setItem(key, locale);\n } catch {\n return;\n }\n }\n}\n\nfunction snapshot(): string {\n active ??= detectedLocale();\n\n return active;\n}\n\nfunction subscribe(callback: () => void): () => void {\n listeners.add(callback);\n\n return () => {\n listeners.delete(callback);\n };\n}\n\nfunction notify(): void {\n listeners.forEach((listener) => listener());\n}\n\nfunction dispatch(locale: string): void {\n if (typeof window === \"undefined\") {\n return;\n }\n\n window.dispatchEvent(new CustomEvent(LATTICE_EVENT.localeChange, { detail: { locale } }));\n}\n\nexport function currentLocale(): string {\n return snapshot();\n}\n\nexport function localeHeader(): Record<string, string> {\n return { \"Accept-Language\": currentLocale() };\n}\n\nexport function subscribeLocale(callback: (locale: string) => void): () => void {\n return subscribe(() => callback(currentLocale()));\n}\n\nexport function setLocale(locale: string): void {\n const previous = currentLocale();\n const next = normalize(locale);\n\n active = next;\n persist(next);\n\n if (next === previous) {\n return;\n }\n\n notify();\n dispatch(next);\n}\n\nexport function useLocale(): UseLocaleReturn {\n const locale = useSyncExternalStore(subscribe, snapshot, () => fallback);\n\n return { locale, setLocale } as const;\n}\n"],"mappings":";;;AAQA,IAAM,MAAM;AACZ,IAAM,WAAW;AACjB,IAAM,SAAS,MAAM,KAAK,KAAK;AAC/B,IAAM,4BAAY,IAAI,IAAgB;AAEtC,IAAI;AAEJ,SAAS,UAAU,OAAuB;CACxC,MAAM,OAAO,MAAM,KAAK;CAExB,OAAO,SAAS,KAAK,WAAW;AAClC;AAEA,SAAS,cAA6B;CACpC,IAAI,OAAO,WAAW,aACpB,OAAO;CAGT,IAAI;EACF,OAAO,aAAa,QAAQ,GAAG;CACjC,QAAQ;EACN,OAAO;CACT;AACF;AAEA,SAAS,cAA6B;CACpC,IAAI,OAAO,aAAa,aACtB,OAAO;CAGT,MAAM,OAAO,SAAS,OACnB,MAAM,GAAG,EACT,KAAK,WAAW,OAAO,KAAK,CAAC,EAC7B,MAAM,WAAW,OAAO,WAAW,GAAG,IAAI,EAAE,CAAC;CAEhD,IAAI,CAAC,MACH,OAAO;CAGT,IAAI;EACF,OAAO,mBAAmB,KAAK,MAAM,CAAc,CAAC;CACtD,QAAQ;EACN,OAAO;CACT;AACF;AAEA,SAAS,gBAA+B;CACtC,IAAI,OAAO,aAAa,aACtB,OAAO;CAGT,OAAO,SAAS,gBAAgB,QAAQ;AAC1C;AAEA,SAAS,iBAAyB;CAChC,OAAO,UAAU,YAAY,KAAK,YAAY,KAAK,cAAc,KAAK,QAAQ;AAChF;AAEA,SAAS,QAAQ,QAAsB;CACrC,IAAI,OAAO,aAAa,aAAa;EACnC,SAAS,SAAS,GAAG,IAAI,GAAG,mBAAmB,MAAM,EAAE,kBAAkB,OAAO;EAChF,SAAS,gBAAgB,OAAO;CAClC;CAEA,IAAI,OAAO,WAAW,aACpB,IAAI;EACF,aAAa,QAAQ,KAAK,MAAM;CAClC,QAAQ;EACN;CACF;AAEJ;AAEA,SAAS,WAAmB;CAC1B,WAAW,eAAe;CAE1B,OAAO;AACT;AAEA,SAAS,UAAU,UAAkC;CACnD,UAAU,IAAI,QAAQ;CAEtB,aAAa;EACX,UAAU,OAAO,QAAQ;CAC3B;AACF;AAEA,SAAS,SAAe;CACtB,UAAU,SAAS,aAAa,SAAS,CAAC;AAC5C;AAEA,SAAS,SAAS,QAAsB;CACtC,IAAI,OAAO,WAAW,aACpB;CAGF,OAAO,cAAc,IAAI,YAAY,cAAc,cAAc,EAAE,QAAQ,EAAE,OAAO,EAAE,CAAC,CAAC;AAC1F;AAEA,SAAgB,gBAAwB;CACtC,OAAO,SAAS;AAClB;AAEA,SAAgB,eAAuC;CACrD,OAAO,EAAE,mBAAmB,cAAc,EAAE;AAC9C;AAEA,SAAgB,gBAAgB,UAAgD;CAC9E,OAAO,gBAAgB,SAAS,cAAc,CAAC,CAAC;AAClD;AAEA,SAAgB,UAAU,QAAsB;CAC9C,MAAM,WAAW,cAAc;CAC/B,MAAM,OAAO,UAAU,MAAM;CAE7B,SAAS;CACT,QAAQ,IAAI;CAEZ,IAAI,SAAS,UACX;CAGF,OAAO;CACP,SAAS,IAAI;AACf;AAEA,SAAgB,YAA6B;CAG3C,OAAO;EAAE,QAFM,qBAAqB,WAAW,gBAAgB,QAEtD;EAAQ;CAAU;AAC7B"}
@@ -1,5 +1,5 @@
1
- import { configureI18n } from "./backend.js";
2
1
  import { i18nConfigFromPageProps } from "./shared-props.js";
2
+ import { configureI18n } from "./backend.js";
3
3
  //#region resources/js/i18n/page-props.ts
4
4
  function configureI18nFromPageProps(props, options = {}) {
5
5
  return configureI18n(i18nConfigFromPageProps(props), options);
@@ -1,7 +1,5 @@
1
+ import { isRecord } from "../core/materialize.js";
1
2
  //#region resources/js/i18n/shared-props.ts
2
- function isRecord(value) {
3
- return typeof value === "object" && value !== null;
4
- }
5
3
  function isStringArray(value) {
6
4
  return Array.isArray(value) && value.every((item) => typeof item === "string");
7
5
  }
@@ -1 +1 @@
1
- {"version":3,"file":"shared-props.js","names":[],"sources":["../../resources/js/i18n/shared-props.ts"],"sourcesContent":["import type { I18nConfig } from \"@lattice-php/lattice/types/generated\";\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null;\n}\n\nfunction isStringArray(value: unknown): value is string[] {\n return Array.isArray(value) && value.every((item) => typeof item === \"string\");\n}\n\nfunction isI18nConfig(value: unknown): value is I18nConfig {\n return (\n isRecord(value) &&\n typeof value.enabled === \"boolean\" &&\n typeof value.saveMissing === \"boolean\" &&\n isStringArray(value.locales) &&\n isStringArray(value.preloadLocales) &&\n (value.timezone === undefined || value.timezone === null || typeof value.timezone === \"string\")\n );\n}\n\n/**\n * Parse the backend-shared `lattice.i18n` Inertia prop. Lives apart from the\n * configure entrypoint so callers can inspect the prop without pulling the\n * i18next backend into their bundle.\n */\nexport function i18nConfigFromPageProps(props: unknown): I18nConfig | undefined {\n if (!isRecord(props)) {\n return undefined;\n }\n\n const shared = props.lattice;\n const config = isRecord(shared) ? shared.i18n : undefined;\n\n return isI18nConfig(config) ? config : undefined;\n}\n"],"mappings":";AAEA,SAAS,SAAS,OAAkD;CAClE,OAAO,OAAO,UAAU,YAAY,UAAU;AAChD;AAEA,SAAS,cAAc,OAAmC;CACxD,OAAO,MAAM,QAAQ,KAAK,KAAK,MAAM,OAAO,SAAS,OAAO,SAAS,QAAQ;AAC/E;AAEA,SAAS,aAAa,OAAqC;CACzD,OACE,SAAS,KAAK,KACd,OAAO,MAAM,YAAY,aACzB,OAAO,MAAM,gBAAgB,aAC7B,cAAc,MAAM,OAAO,KAC3B,cAAc,MAAM,cAAc,MACjC,MAAM,aAAa,KAAA,KAAa,MAAM,aAAa,QAAQ,OAAO,MAAM,aAAa;AAE1F;;;;;;AAOA,SAAgB,wBAAwB,OAAwC;CAC9E,IAAI,CAAC,SAAS,KAAK,GACjB;CAGF,MAAM,SAAS,MAAM;CACrB,MAAM,SAAS,SAAS,MAAM,IAAI,OAAO,OAAO,KAAA;CAEhD,OAAO,aAAa,MAAM,IAAI,SAAS,KAAA;AACzC"}
1
+ {"version":3,"file":"shared-props.js","names":[],"sources":["../../resources/js/i18n/shared-props.ts"],"sourcesContent":["import { isRecord } from \"@lattice-php/lattice/core/materialize\";\nimport type { I18nConfig } from \"@lattice-php/lattice/types/generated\";\n\nfunction isStringArray(value: unknown): value is string[] {\n return Array.isArray(value) && value.every((item) => typeof item === \"string\");\n}\n\nfunction isI18nConfig(value: unknown): value is I18nConfig {\n return (\n isRecord(value) &&\n typeof value.enabled === \"boolean\" &&\n typeof value.saveMissing === \"boolean\" &&\n isStringArray(value.locales) &&\n isStringArray(value.preloadLocales) &&\n (value.timezone === undefined || value.timezone === null || typeof value.timezone === \"string\")\n );\n}\n\n/**\n * Parse the backend-shared `lattice.i18n` Inertia prop. Lives apart from the\n * configure entrypoint so callers can inspect the prop without pulling the\n * i18next backend into their bundle.\n */\nexport function i18nConfigFromPageProps(props: unknown): I18nConfig | undefined {\n if (!isRecord(props)) {\n return undefined;\n }\n\n const shared = props.lattice;\n const config = isRecord(shared) ? shared.i18n : undefined;\n\n return isI18nConfig(config) ? config : undefined;\n}\n"],"mappings":";;AAGA,SAAS,cAAc,OAAmC;CACxD,OAAO,MAAM,QAAQ,KAAK,KAAK,MAAM,OAAO,SAAS,OAAO,SAAS,QAAQ;AAC/E;AAEA,SAAS,aAAa,OAAqC;CACzD,OACE,SAAS,KAAK,KACd,OAAO,MAAM,YAAY,aACzB,OAAO,MAAM,gBAAgB,aAC7B,cAAc,MAAM,OAAO,KAC3B,cAAc,MAAM,cAAc,MACjC,MAAM,aAAa,KAAA,KAAa,MAAM,aAAa,QAAQ,OAAO,MAAM,aAAa;AAE1F;;;;;;AAOA,SAAgB,wBAAwB,OAAwC;CAC9E,IAAI,CAAC,SAAS,KAAK,GACjB;CAGF,MAAM,SAAS,MAAM;CACrB,MAAM,SAAS,SAAS,MAAM,IAAI,OAAO,OAAO,KAAA;CAEhD,OAAO,aAAa,MAAM,IAAI,SAAS,KAAA;AACzC"}
@@ -1,4 +1,4 @@
1
- import { LATTICE_EVENT } from "../events/event-names.js";
1
+ import { LATTICE_EVENT } from "../core/event-names.js";
2
2
  import { configTimezone, subscribeConfig } from "./config.js";
3
3
  import { useSyncExternalStore } from "react";
4
4
  //#region resources/js/i18n/timezone.ts
@@ -1 +1 @@
1
- {"version":3,"file":"timezone.js","names":[],"sources":["../../resources/js/i18n/timezone.ts"],"sourcesContent":["import { useSyncExternalStore } from \"react\";\nimport { LATTICE_EVENT } from \"@lattice-php/lattice/events/event-names\";\nimport { configTimezone, subscribeConfig } from \"./config\";\n\nexport type UseTimezoneReturn = {\n readonly timezone: string;\n readonly setTimezone: (timezone: string) => void;\n};\n\nconst fallback = \"UTC\";\nconst listeners = new Set<() => void>();\n\nlet override: string | undefined;\n\nfunction detectedTimezone(): string {\n if (typeof Intl === \"undefined\") {\n return fallback;\n }\n\n try {\n return Intl.DateTimeFormat().resolvedOptions().timeZone || fallback;\n } catch {\n return fallback;\n }\n}\n\nfunction snapshot(): string {\n return override ?? configTimezone() ?? detectedTimezone();\n}\n\nfunction subscribe(callback: () => void): () => void {\n listeners.add(callback);\n\n return () => {\n listeners.delete(callback);\n };\n}\n\nfunction notify(): void {\n listeners.forEach((listener) => listener());\n}\n\nsubscribeConfig(() => notify());\n\nfunction dispatch(timezone: string): void {\n if (typeof window === \"undefined\") {\n return;\n }\n\n window.dispatchEvent(new CustomEvent(LATTICE_EVENT.timezoneChange, { detail: { timezone } }));\n}\n\nexport function currentTimezone(): string {\n return snapshot();\n}\n\nexport function setTimezone(timezone: string): void {\n const previous = currentTimezone();\n const next = timezone.trim();\n\n override = next === \"\" ? undefined : next;\n\n if (currentTimezone() === previous) {\n return;\n }\n\n notify();\n dispatch(currentTimezone());\n}\n\nexport function useTimezone(): UseTimezoneReturn {\n const timezone = useSyncExternalStore(subscribe, snapshot, () => fallback);\n\n return { timezone, setTimezone } as const;\n}\n"],"mappings":";;;;AASA,IAAM,WAAW;AACjB,IAAM,4BAAY,IAAI,IAAgB;AAEtC,IAAI;AAEJ,SAAS,mBAA2B;CAClC,IAAI,OAAO,SAAS,aAClB,OAAO;CAGT,IAAI;EACF,OAAO,KAAK,eAAe,EAAE,gBAAgB,EAAE,YAAY;CAC7D,QAAQ;EACN,OAAO;CACT;AACF;AAEA,SAAS,WAAmB;CAC1B,OAAO,YAAY,eAAe,KAAK,iBAAiB;AAC1D;AAEA,SAAS,UAAU,UAAkC;CACnD,UAAU,IAAI,QAAQ;CAEtB,aAAa;EACX,UAAU,OAAO,QAAQ;CAC3B;AACF;AAEA,SAAS,SAAe;CACtB,UAAU,SAAS,aAAa,SAAS,CAAC;AAC5C;AAEA,sBAAsB,OAAO,CAAC;AAE9B,SAAS,SAAS,UAAwB;CACxC,IAAI,OAAO,WAAW,aACpB;CAGF,OAAO,cAAc,IAAI,YAAY,cAAc,gBAAgB,EAAE,QAAQ,EAAE,SAAS,EAAE,CAAC,CAAC;AAC9F;AAEA,SAAgB,kBAA0B;CACxC,OAAO,SAAS;AAClB;AAEA,SAAgB,YAAY,UAAwB;CAClD,MAAM,WAAW,gBAAgB;CACjC,MAAM,OAAO,SAAS,KAAK;CAE3B,WAAW,SAAS,KAAK,KAAA,IAAY;CAErC,IAAI,gBAAgB,MAAM,UACxB;CAGF,OAAO;CACP,SAAS,gBAAgB,CAAC;AAC5B;AAEA,SAAgB,cAAiC;CAG/C,OAAO;EAAE,UAFQ,qBAAqB,WAAW,gBAAgB,QAExD;EAAU;CAAY;AACjC"}
1
+ {"version":3,"file":"timezone.js","names":[],"sources":["../../resources/js/i18n/timezone.ts"],"sourcesContent":["import { useSyncExternalStore } from \"react\";\nimport { LATTICE_EVENT } from \"@lattice-php/lattice/core/event-names\";\nimport { configTimezone, subscribeConfig } from \"./config\";\n\nexport type UseTimezoneReturn = {\n readonly timezone: string;\n readonly setTimezone: (timezone: string) => void;\n};\n\nconst fallback = \"UTC\";\nconst listeners = new Set<() => void>();\n\nlet override: string | undefined;\n\nfunction detectedTimezone(): string {\n if (typeof Intl === \"undefined\") {\n return fallback;\n }\n\n try {\n return Intl.DateTimeFormat().resolvedOptions().timeZone || fallback;\n } catch {\n return fallback;\n }\n}\n\nfunction snapshot(): string {\n return override ?? configTimezone() ?? detectedTimezone();\n}\n\nfunction subscribe(callback: () => void): () => void {\n listeners.add(callback);\n\n return () => {\n listeners.delete(callback);\n };\n}\n\nfunction notify(): void {\n listeners.forEach((listener) => listener());\n}\n\nsubscribeConfig(() => notify());\n\nfunction dispatch(timezone: string): void {\n if (typeof window === \"undefined\") {\n return;\n }\n\n window.dispatchEvent(new CustomEvent(LATTICE_EVENT.timezoneChange, { detail: { timezone } }));\n}\n\nexport function currentTimezone(): string {\n return snapshot();\n}\n\nexport function setTimezone(timezone: string): void {\n const previous = currentTimezone();\n const next = timezone.trim();\n\n override = next === \"\" ? undefined : next;\n\n if (currentTimezone() === previous) {\n return;\n }\n\n notify();\n dispatch(currentTimezone());\n}\n\nexport function useTimezone(): UseTimezoneReturn {\n const timezone = useSyncExternalStore(subscribe, snapshot, () => fallback);\n\n return { timezone, setTimezone } as const;\n}\n"],"mappings":";;;;AASA,IAAM,WAAW;AACjB,IAAM,4BAAY,IAAI,IAAgB;AAEtC,IAAI;AAEJ,SAAS,mBAA2B;CAClC,IAAI,OAAO,SAAS,aAClB,OAAO;CAGT,IAAI;EACF,OAAO,KAAK,eAAe,EAAE,gBAAgB,EAAE,YAAY;CAC7D,QAAQ;EACN,OAAO;CACT;AACF;AAEA,SAAS,WAAmB;CAC1B,OAAO,YAAY,eAAe,KAAK,iBAAiB;AAC1D;AAEA,SAAS,UAAU,UAAkC;CACnD,UAAU,IAAI,QAAQ;CAEtB,aAAa;EACX,UAAU,OAAO,QAAQ;CAC3B;AACF;AAEA,SAAS,SAAe;CACtB,UAAU,SAAS,aAAa,SAAS,CAAC;AAC5C;AAEA,sBAAsB,OAAO,CAAC;AAE9B,SAAS,SAAS,UAAwB;CACxC,IAAI,OAAO,WAAW,aACpB;CAGF,OAAO,cAAc,IAAI,YAAY,cAAc,gBAAgB,EAAE,QAAQ,EAAE,SAAS,EAAE,CAAC,CAAC;AAC9F;AAEA,SAAgB,kBAA0B;CACxC,OAAO,SAAS;AAClB;AAEA,SAAgB,YAAY,UAAwB;CAClD,MAAM,WAAW,gBAAgB;CACjC,MAAM,OAAO,SAAS,KAAK;CAE3B,WAAW,SAAS,KAAK,KAAA,IAAY;CAErC,IAAI,gBAAgB,MAAM,UACxB;CAGF,OAAO;CACP,SAAS,gBAAgB,CAAC;AAC5B;AAEA,SAAgB,cAAiC;CAG/C,OAAO;EAAE,UAFQ,qBAAqB,WAAW,gBAAgB,QAExD;EAAU;CAAY;AACjC"}
package/dist/index.d.ts CHANGED
@@ -6,14 +6,14 @@ export { useEffectDispatcher } from './effects/use-effect-dispatcher.js';
6
6
  export { builtinEffectHandlers, effectHandler, mergeEffectHandlers } from './effects/registry.js';
7
7
  export { registerRichEditorExtension } from './form/rich-editor/registry.js';
8
8
  export { initializeTheme, updateAppearance, useAppearance } from './appearance/index.js';
9
- export { copyToClipboard, useClipboard } from './clipboard/index.js';
9
+ export { copyToClipboard } from './clipboard/index.js';
10
10
  export { createLatticeApp, type CreateLatticeAppI18nOptions, type CreateLatticeAppOptions, } from './create-app.js';
11
11
  export { EventBridge } from './event-bridge.js';
12
12
  export { Icon, IconRenderer, IconRendererProvider, SpriteProvider } from './icons/index.js';
13
13
  export { createLayoutResolver, createPageResolver, pageComponentName, withVisitHeaders, } from './inertia.js';
14
14
  export { Callouts, layoutComponents, OutletContext, SchemaLayout, SidebarCollapsedContext, useSidebarCollapsed, } from './layout/index.js';
15
15
  export { Provider, useColumnRegistry, useComponentRegistry } from './provider.js';
16
- export { onCallout, onToast, showToast, Toaster } from './toast/index.js';
16
+ export { onCallout, onToast, Toaster } from './toast/index.js';
17
17
  export { createPlugin, createRegistry, eagerComponent, extendRegistry, lazyComponent, } from './core/registry.js';
18
18
  export type { Plugin, Registry } from './core/registry.js';
19
19
  export type { UseChatOptions } from './chat/hooks/use-chat.js';
@@ -21,20 +21,19 @@ export type { ChatFrame, ChatMessage, ChatRole, ChatStatus, ChatTransport, ChatT
21
21
  export { Renderer } from './core/renderer.js';
22
22
  export { LATTICE_REF_HEADER, withRefHeader } from './core/component-ref.js';
23
23
  export { withHeaders } from './core/headers.js';
24
- export { LATTICE_EVENT } from './events/event-names.js';
24
+ export { LATTICE_EVENT } from './core/event-names.js';
25
25
  export type { ButtonVariant } from './ui/button.js';
26
- export type { ReloadComponentEvent } from './events/event-names.js';
27
- export type { ComponentProps, KnownPageContainer, LayoutPayload, Node, NodeOfType, NodeProps, NodeType, PageContainer, PageBreadcrumb, PagePayload, PropsOf, RendererComponent, RendererComponentModule, RendererComponentProps, Schema, UnknownComponent, WireNode, } from './core/types.js';
26
+ export type { ReloadComponentEvent } from './core/event-names.js';
27
+ export type { ComponentProps, KnownPageContainer, LayoutPayload, Node, NodeProps, NodeType, PageContainer, PageBreadcrumb, PagePayload, ComponentPropsOf, RendererComponent, RendererComponentModule, RendererComponentProps, Schema, UnknownComponent, } from './core/types.js';
28
28
  export { RealtimeListeners } from './realtime/listeners.js';
29
29
  export type { ChannelVisibility, DateFormat, Listen, NumberFormat } from './types/generated.js';
30
30
  export { columnCell } from './table/registry.js';
31
31
  export type { ColumnCellArgs, ColumnCellComponent, ColumnRegistry } from './table/registry.js';
32
- export type { ColumnProps, ColumnPropsOf } from './table/types.js';
32
+ export type { ColumnNode, ColumnProps, ColumnPropsOf, FilterNode, FilterProps, FilterPropsOf, } from './table/types.js';
33
33
  export type { Method } from '@inertiajs/core';
34
34
  export type { ActionEffect, ActionResponse } from './effects/dispatch.js';
35
35
  export type { EffectHandler, EffectHandlerRegistry, EffectOf, EffectProps, EffectPropsOf, } from './effects/registry.js';
36
36
  export type { EditorExtensionPayloadOf, EditorExtensionProps, RichEditorExtensionDefinition, ToolbarButton, ToolbarControl, ToolbarItem, } from './form/rich-editor/registry.js';
37
37
  export type { Appearance, ResolvedAppearance, UseAppearanceReturn } from './appearance/index.js';
38
- export type { CopiedValue, CopyFn, UseClipboardReturn } from './clipboard/index.js';
39
38
  export type { Callout, ToastMessage, Variant } from './toast/index.js';
40
39
  export type { IconName, IconRendererFunction, IconRendererProps, KnownIcons, SpriteValue, } from './icons/index.js';
package/dist/index.js CHANGED
@@ -1,17 +1,16 @@
1
1
  import { initializeTheme, updateAppearance, useAppearance } from "./appearance/index.js";
2
2
  import { createPlugin, createRegistry, eagerComponent, extendRegistry, lazyComponent } from "./core/registry.js";
3
3
  import { useColumnRegistry, useComponentRegistry } from "./core/registry-context.js";
4
- import { LATTICE_EVENT } from "./events/event-names.js";
5
- import { onToast, showToast } from "./toast/toast.js";
6
- import { onCallout } from "./toast/callout.js";
4
+ import { LATTICE_EVENT } from "./core/event-names.js";
5
+ import { LATTICE_REF_HEADER, withRefHeader } from "./core/component-ref.js";
6
+ import { withHeaders } from "./core/headers.js";
7
7
  import { Icon, SpriteProvider } from "./icons/sprite.js";
8
8
  import { IconRenderer, IconRendererProvider } from "./icons/icon-renderer.js";
9
9
  import { CollapsedContext, useCollapsed } from "./core/collapsed-context.js";
10
10
  import { Renderer } from "./core/renderer.js";
11
+ import { onToast } from "./toast/toast.js";
12
+ import { onCallout } from "./toast/callout.js";
11
13
  import { Toaster } from "./toast/toaster.js";
12
- import { EventBridge } from "./event-bridge.js";
13
- import { LATTICE_REF_HEADER, withRefHeader } from "./core/component-ref.js";
14
- import { withHeaders } from "./core/headers.js";
15
14
  import Callouts from "./layout/components/callouts.js";
16
15
  import { builtinEffectHandlers, effectHandler, mergeEffectHandlers } from "./effects/registry.js";
17
16
  import { dispatchActionError, dispatchEffects, getActionEffects, isActionEffect } from "./effects/dispatch.js";
@@ -21,6 +20,7 @@ import { layoutComponents } from "./layout/plugin.js";
21
20
  import SchemaLayout from "./layout/components/schema-layout.js";
22
21
  import { RealtimeListeners } from "./realtime/listeners.js";
23
22
  import { createLayoutResolver, createPageResolver, pageComponentName, withVisitHeaders } from "./inertia.js";
23
+ import { EventBridge } from "./event-bridge.js";
24
24
  import { useChat } from "./chat/hooks/use-chat.js";
25
25
  import { chatComponents } from "./chat/plugin.js";
26
26
  import { copyToClipboard } from "./ui/copyable-text.js";
@@ -28,6 +28,5 @@ import { columnCell } from "./table/registry.js";
28
28
  import { registry } from "./registry.js";
29
29
  import { createLatticeApp } from "./create-app.js";
30
30
  import { registerRichEditorExtension } from "./form/rich-editor/registry.js";
31
- import { useClipboard } from "./clipboard/index.js";
32
31
  import { Provider } from "./provider.js";
33
- export { Callouts, EventBridge, Icon, IconRenderer, IconRendererProvider, LATTICE_EVENT, LATTICE_REF_HEADER, OutletContext, Provider, RealtimeListeners, Renderer, SchemaLayout, CollapsedContext as SidebarCollapsedContext, SpriteProvider, Toaster, builtinEffectHandlers, chatComponents, columnCell, copyToClipboard, createLatticeApp, createLayoutResolver, createPageResolver, createPlugin, createRegistry, dispatchActionError, dispatchEffects, eagerComponent, effectHandler, extendRegistry, getActionEffects, initializeTheme, isActionEffect, layoutComponents, lazyComponent, mergeEffectHandlers, onCallout, onToast, pageComponentName, registerRichEditorExtension, registry, showToast, updateAppearance, useAppearance, useChat, useClipboard, useColumnRegistry, useComponentRegistry, useEffectDispatcher, useCollapsed as useSidebarCollapsed, withHeaders, withRefHeader, withVisitHeaders };
32
+ export { Callouts, EventBridge, Icon, IconRenderer, IconRendererProvider, LATTICE_EVENT, LATTICE_REF_HEADER, OutletContext, Provider, RealtimeListeners, Renderer, SchemaLayout, CollapsedContext as SidebarCollapsedContext, SpriteProvider, Toaster, builtinEffectHandlers, chatComponents, columnCell, copyToClipboard, createLatticeApp, createLayoutResolver, createPageResolver, createPlugin, createRegistry, dispatchActionError, dispatchEffects, eagerComponent, effectHandler, extendRegistry, getActionEffects, initializeTheme, isActionEffect, layoutComponents, lazyComponent, mergeEffectHandlers, onCallout, onToast, pageComponentName, registerRichEditorExtension, registry, updateAppearance, useAppearance, useChat, useColumnRegistry, useComponentRegistry, useEffectDispatcher, useCollapsed as useSidebarCollapsed, withHeaders, withRefHeader, withVisitHeaders };
package/dist/lattice.css CHANGED
@@ -85,6 +85,7 @@
85
85
 
86
86
  --lt-duration-fast: 120ms;
87
87
  --lt-duration-base: 160ms;
88
+ --lt-duration-slow: 240ms;
88
89
 
89
90
  --lt-sidebar-w: 16rem;
90
91
  --lt-sidebar-w-collapsed: 4rem;
@@ -96,6 +97,20 @@
96
97
  color-scheme: light;
97
98
  }
98
99
 
100
+ /*
101
+ * Radix keeps dialogs mounted until their exit animation ends, so reduced
102
+ * motion zeroes the durations instead of removing the animations — the
103
+ * animation events still fire and close stays instant.
104
+ */
105
+ @media (prefers-reduced-motion: reduce) {
106
+ :root,
107
+ [data-theme="light"] {
108
+ --lt-duration-fast: 0ms;
109
+ --lt-duration-base: 0ms;
110
+ --lt-duration-slow: 0ms;
111
+ }
112
+ }
113
+
99
114
  [data-theme="dark"],
100
115
  .dark {
101
116
  --lt-bg: var(--background, oklch(0.145 0 0));
@@ -205,6 +220,14 @@
205
220
  --font-weight-lt-bold: var(--lt-font-weight-bold);
206
221
  --animate-lt-toast-in: lt-toast-in var(--lt-duration-base) ease-out;
207
222
  --animate-lt-toast-out: lt-toast-out var(--lt-duration-fast) ease-in;
223
+ --animate-lt-fade-in: lt-fade-in var(--lt-duration-base) ease-out;
224
+ --animate-lt-fade-out: lt-fade-out var(--lt-duration-fast) ease-in;
225
+ --animate-lt-dialog-in: lt-dialog-in var(--lt-duration-base) ease-out;
226
+ --animate-lt-dialog-out: lt-dialog-out var(--lt-duration-fast) ease-in;
227
+ --animate-lt-sheet-in-start: lt-sheet-in-start var(--lt-duration-slow) ease-out;
228
+ --animate-lt-sheet-out-start: lt-sheet-out-start var(--lt-duration-fast) ease-in;
229
+ --animate-lt-sheet-in-end: lt-sheet-in-end var(--lt-duration-slow) ease-out;
230
+ --animate-lt-sheet-out-end: lt-sheet-out-end var(--lt-duration-fast) ease-in;
208
231
  }
209
232
 
210
233
  @theme {
@@ -285,6 +308,88 @@
285
308
  }
286
309
  }
287
310
 
311
+ @keyframes lt-fade-in {
312
+ from {
313
+ opacity: 0;
314
+ }
315
+ to {
316
+ opacity: 1;
317
+ }
318
+ }
319
+
320
+ @keyframes lt-fade-out {
321
+ from {
322
+ opacity: 1;
323
+ }
324
+ to {
325
+ opacity: 0;
326
+ }
327
+ }
328
+
329
+ /* Centering uses Tailwind's standalone translate property, which composes
330
+ with transform — so these keyframes may only animate opacity and scale,
331
+ never a translate of their own. */
332
+ @keyframes lt-dialog-in {
333
+ from {
334
+ opacity: 0;
335
+ transform: scale(0.98);
336
+ }
337
+ to {
338
+ opacity: 1;
339
+ transform: scale(1);
340
+ }
341
+ }
342
+
343
+ @keyframes lt-dialog-out {
344
+ from {
345
+ opacity: 1;
346
+ transform: scale(1);
347
+ }
348
+ to {
349
+ opacity: 0;
350
+ transform: scale(0.98);
351
+ }
352
+ }
353
+
354
+ /* Sheet slides are physical (translateX): under RTL a sheet docks to the
355
+ correct logical edge but enters from the mirrored side. Shipped locales
356
+ are LTR. */
357
+ @keyframes lt-sheet-in-start {
358
+ from {
359
+ transform: translateX(-100%);
360
+ }
361
+ to {
362
+ transform: translateX(0);
363
+ }
364
+ }
365
+
366
+ @keyframes lt-sheet-out-start {
367
+ from {
368
+ transform: translateX(0);
369
+ }
370
+ to {
371
+ transform: translateX(-100%);
372
+ }
373
+ }
374
+
375
+ @keyframes lt-sheet-in-end {
376
+ from {
377
+ transform: translateX(100%);
378
+ }
379
+ to {
380
+ transform: translateX(0);
381
+ }
382
+ }
383
+
384
+ @keyframes lt-sheet-out-end {
385
+ from {
386
+ transform: translateX(0);
387
+ }
388
+ to {
389
+ transform: translateX(100%);
390
+ }
391
+ }
392
+
288
393
  /*
289
394
  * Named colours. Semantic names alias the theme tokens; hue names carry their
290
395
  * own oklch values with `.dark` overrides. Renderers resolve a named colour to
@@ -1,7 +1,7 @@
1
- import { onCallout } from "../../toast/callout.js";
2
1
  import { cn } from "../../lib/utils.js";
3
2
  import { Icon } from "../../icons/sprite.js";
4
3
  import { RenderNode } from "../../core/renderer.js";
4
+ import { onCallout } from "../../toast/callout.js";
5
5
  import { useT } from "../../i18n/instance.js";
6
6
  import { variantStyles } from "../../toast/variant-styles.js";
7
7
  import { useEffect, useState } from "react";
@@ -1,70 +1,37 @@
1
- import { LATTICE_EVENT } from "../../events/event-names.js";
1
+ import { LATTICE_EVENT } from "../../core/event-names.js";
2
+ import { useWindowEvent } from "../../core/hooks/use-window-event.js";
2
3
  import { cn } from "../../lib/utils.js";
3
4
  import { CollapsedContext } from "../../core/collapsed-context.js";
4
5
  import { nodeIdentity } from "../../core/test-id.js";
6
+ import { useMediaQuery } from "../../lib/use-media-query.js";
7
+ import { useCollapsibleState } from "../../ui/use-collapsible-state.js";
5
8
  import { router } from "@inertiajs/react";
6
9
  import { useEffect, useState } from "react";
7
10
  import { jsx, jsxs } from "react/jsx-runtime";
8
11
  //#region resources/js/layout/components/sidebar.tsx
9
12
  var DESKTOP_QUERY = "(min-width: 768px)";
10
- function readStored(key, remember) {
11
- if (!remember || typeof window === "undefined") return false;
12
- return window.localStorage.getItem(key) === "true";
13
- }
14
13
  function matchesTarget(event, identity) {
15
14
  const target = event.detail?.target;
16
15
  return target == null || target === identity;
17
16
  }
18
- function useIsDesktop() {
19
- const supported = () => typeof window !== "undefined" && typeof window.matchMedia === "function";
20
- const [isDesktop, setIsDesktop] = useState(() => supported() ? window.matchMedia(DESKTOP_QUERY).matches : true);
21
- useEffect(() => {
22
- if (!supported()) return;
23
- const query = window.matchMedia(DESKTOP_QUERY);
24
- const update = () => setIsDesktop(query.matches);
25
- update();
26
- query.addEventListener("change", update);
27
- return () => query.removeEventListener("change", update);
28
- }, []);
29
- return isDesktop;
30
- }
31
17
  var SidebarComponent = ({ children, node }) => {
32
18
  const collapsible = node.props.collapsible;
33
19
  const rememberState = node.props.rememberState;
34
20
  const identity = nodeIdentity(node);
35
21
  const storageKey = `lattice:sidebar:${identity ?? "default"}`;
36
- const isDesktop = useIsDesktop();
37
- const [collapsed, setCollapsed] = useState(() => readStored(storageKey, collapsible && rememberState));
22
+ const isDesktop = useMediaQuery(DESKTOP_QUERY, true);
23
+ const [collapsed, toggleCollapsed] = useCollapsibleState(storageKey, false, collapsible && rememberState);
38
24
  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
- ]);
25
+ useWindowEvent(LATTICE_EVENT.toggleSidebar, (event) => {
26
+ if (!matchesTarget(event, identity)) return;
27
+ if (window.matchMedia?.(DESKTOP_QUERY).matches ?? true) {
28
+ if (collapsible) toggleCollapsed();
29
+ } else setMobileOpen((open) => !open);
30
+ });
59
31
  useEffect(() => router.on("navigate", () => setMobileOpen(false)), []);
60
- 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]);
32
+ useWindowEvent("keydown", (event) => {
33
+ if (event.key === "Escape") setMobileOpen(false);
34
+ }, { enabled: mobileOpen });
68
35
  const isCollapsed = collapsible && collapsed && isDesktop;
69
36
  return /* @__PURE__ */ jsxs(CollapsedContext.Provider, {
70
37
  value: isCollapsed,
@@ -1 +1 @@
1
- {"version":3,"file":"sidebar.js","names":[],"sources":["../../../resources/js/layout/components/sidebar.tsx"],"sourcesContent":["import { router } from \"@inertiajs/react\";\nimport { useEffect, useState } from \"react\";\nimport type { RendererComponent } from \"@lattice-php/lattice/core/types\";\nimport { CollapsedContext } from \"@lattice-php/lattice/core/collapsed-context\";\nimport { LATTICE_EVENT } from \"@lattice-php/lattice/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-lt-overlay bg-lt-overlay md:hidden\"\n data-test=\"sidebar-backdrop\"\n onClick={() => setMobileOpen(false)}\n />\n ) : null}\n <aside\n className={cn(\n \"fixed inset-y-0 left-0 z-lt-modal flex h-svh w-72 max-w-[80vw] shrink-0 flex-col gap-4 border-r border-lt-border bg-lt-bg p-4 transition-transform\",\n \"md:sticky md:top-0 md:z-auto md:max-w-none md:translate-x-0 md:transition-[width]\",\n mobileOpen ? \"translate-x-0\" : \"-translate-x-full\",\n isCollapsed\n ? \"md:w-16 md:overflow-visible\"\n : \"md:w-64 md:overflow-x-hidden md:overflow-y-auto\",\n )}\n data-collapsed={isCollapsed ? \"true\" : \"false\"}\n data-lattice-component={identity}\n data-test=\"sidebar\"\n >\n {children}\n </aside>\n </CollapsedContext.Provider>\n );\n};\n\nexport default SidebarComponent;\n"],"mappings":";;;;;;;;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,sJACA,qFACA,aAAa,kBAAkB,qBAC/B,cACI,gCACA,iDACN;GACA,kBAAgB,cAAc,SAAS;GACvC,0BAAwB;GACxB,aAAU;GAET;EACI,CAAA,CACkB;;AAE/B"}
1
+ {"version":3,"file":"sidebar.js","names":[],"sources":["../../../resources/js/layout/components/sidebar.tsx"],"sourcesContent":["import { router } from \"@inertiajs/react\";\nimport { useEffect, useState } from \"react\";\nimport type { RendererComponent } from \"@lattice-php/lattice/core/types\";\nimport { CollapsedContext } from \"@lattice-php/lattice/core/collapsed-context\";\nimport { LATTICE_EVENT } from \"@lattice-php/lattice/core/event-names\";\nimport { useWindowEvent } from \"@lattice-php/lattice/core/hooks/use-window-event\";\nimport { nodeIdentity } from \"@lattice-php/lattice/core/test-id\";\nimport { cn } from \"@lattice-php/lattice/lib/utils\";\nimport { useMediaQuery } from \"@lattice-php/lattice/lib/use-media-query\";\nimport { useCollapsibleState } from \"@lattice-php/lattice/ui/use-collapsible-state\";\n\nconst DESKTOP_QUERY = \"(min-width: 768px)\";\n\nfunction matchesTarget(event: Event, identity: string | undefined): boolean {\n const target = (event as CustomEvent<{ target?: string }>).detail?.target;\n\n return target == null || target === identity;\n}\n\nconst SidebarComponent: RendererComponent<\"sidebar\"> = ({ children, node }) => {\n const collapsible = node.props.collapsible;\n const rememberState = node.props.rememberState;\n const identity = nodeIdentity(node);\n const storageKey = `lattice:sidebar:${identity ?? \"default\"}`;\n const isDesktop = useMediaQuery(DESKTOP_QUERY, true);\n\n const [collapsed, toggleCollapsed] = useCollapsibleState(\n storageKey,\n false,\n collapsible && rememberState,\n );\n const [mobileOpen, setMobileOpen] = useState(false);\n\n useWindowEvent(LATTICE_EVENT.toggleSidebar, (event) => {\n if (!matchesTarget(event, identity)) {\n return;\n }\n\n if (window.matchMedia?.(DESKTOP_QUERY).matches ?? true) {\n if (collapsible) {\n toggleCollapsed();\n }\n } else {\n setMobileOpen((open) => !open);\n }\n });\n\n useEffect(() => router.on(\"navigate\", () => setMobileOpen(false)), []);\n\n useWindowEvent(\n \"keydown\",\n (event) => {\n if ((event as KeyboardEvent).key === \"Escape\") {\n setMobileOpen(false);\n }\n },\n { enabled: mobileOpen },\n );\n\n const isCollapsed = collapsible && collapsed && isDesktop;\n\n return (\n <CollapsedContext.Provider value={isCollapsed}>\n {mobileOpen ? (\n <div\n aria-hidden=\"true\"\n className=\"fixed inset-0 z-lt-overlay bg-lt-overlay md:hidden\"\n data-test=\"sidebar-backdrop\"\n onClick={() => setMobileOpen(false)}\n />\n ) : null}\n <aside\n className={cn(\n \"fixed inset-y-0 left-0 z-lt-modal flex h-svh w-72 max-w-[80vw] shrink-0 flex-col gap-4 border-r border-lt-border bg-lt-bg p-4 transition-transform\",\n \"md:sticky md:top-0 md:z-auto md:max-w-none md:translate-x-0 md:transition-[width]\",\n mobileOpen ? \"translate-x-0\" : \"-translate-x-full\",\n isCollapsed\n ? \"md:w-16 md:overflow-visible\"\n : \"md:w-64 md:overflow-x-hidden md:overflow-y-auto\",\n )}\n data-collapsed={isCollapsed ? \"true\" : \"false\"}\n data-lattice-component={identity}\n data-test=\"sidebar\"\n >\n {children}\n </aside>\n </CollapsedContext.Provider>\n );\n};\n\nexport default SidebarComponent;\n"],"mappings":";;;;;;;;;;;AAWA,IAAM,gBAAgB;AAEtB,SAAS,cAAc,OAAc,UAAuC;CAC1E,MAAM,SAAU,MAA2C,QAAQ;CAEnE,OAAO,UAAU,QAAQ,WAAW;AACtC;AAEA,IAAM,oBAAkD,EAAE,UAAU,WAAW;CAC7E,MAAM,cAAc,KAAK,MAAM;CAC/B,MAAM,gBAAgB,KAAK,MAAM;CACjC,MAAM,WAAW,aAAa,IAAI;CAClC,MAAM,aAAa,mBAAmB,YAAY;CAClD,MAAM,YAAY,cAAc,eAAe,IAAI;CAEnD,MAAM,CAAC,WAAW,mBAAmB,oBACnC,YACA,OACA,eAAe,aACjB;CACA,MAAM,CAAC,YAAY,iBAAiB,SAAS,KAAK;CAElD,eAAe,cAAc,gBAAgB,UAAU;EACrD,IAAI,CAAC,cAAc,OAAO,QAAQ,GAChC;EAGF,IAAI,OAAO,aAAa,aAAa,EAAE,WAAW;OAC5C,aACF,gBAAgB;EAAA,OAGlB,eAAe,SAAS,CAAC,IAAI;CAEjC,CAAC;CAED,gBAAgB,OAAO,GAAG,kBAAkB,cAAc,KAAK,CAAC,GAAG,CAAC,CAAC;CAErE,eACE,YACC,UAAU;EACT,IAAK,MAAwB,QAAQ,UACnC,cAAc,KAAK;CAEvB,GACA,EAAE,SAAS,WAAW,CACxB;CAEA,MAAM,cAAc,eAAe,aAAa;CAEhD,OACE,qBAAC,iBAAiB,UAAlB;EAA2B,OAAO;YAAlC,CACG,aACC,oBAAC,OAAD;GACE,eAAY;GACZ,WAAU;GACV,aAAU;GACV,eAAe,cAAc,KAAK;EACnC,CAAA,IACC,MACJ,oBAAC,SAAD;GACE,WAAW,GACT,sJACA,qFACA,aAAa,kBAAkB,qBAC/B,cACI,gCACA,iDACN;GACA,kBAAgB,cAAc,SAAS;GACvC,0BAAwB;GACxB,aAAU;GAET;EACI,CAAA,CACkB;;AAE/B"}
@@ -1,2 +1 @@
1
- export type LayoutComponentType = "breadcrumbs" | "callouts" | "dropdown" | "menu" | "menu-item" | "outlet" | "sidebar" | "topbar";
2
1
  export declare const layoutComponents: import('../core/registry.js').Plugin;
@@ -1 +1 @@
1
- {"version":3,"file":"plugin.js","names":[],"sources":["../../resources/js/layout/plugin.ts"],"sourcesContent":["import {\n createPlugin,\n eagerComponent,\n type ComponentRegistryFor,\n} from \"@lattice-php/lattice/core/registry\";\nimport BreadcrumbsComponent from \"./components/breadcrumbs\";\nimport CalloutsComponent from \"./components/callouts\";\nimport DropdownComponent from \"./components/dropdown\";\nimport MenuComponent from \"./components/menu\";\nimport MenuItemComponent from \"./components/menu-item\";\nimport OutletComponent from \"./components/outlet\";\nimport SidebarComponent from \"./components/sidebar\";\nimport TopbarComponent from \"./components/topbar\";\n\nexport type LayoutComponentType =\n | \"breadcrumbs\"\n | \"callouts\"\n | \"dropdown\"\n | \"menu\"\n | \"menu-item\"\n | \"outlet\"\n | \"sidebar\"\n | \"topbar\";\n\nexport const layoutComponents = createPlugin({\n components: {\n breadcrumbs: eagerComponent(BreadcrumbsComponent),\n callouts: eagerComponent(CalloutsComponent),\n dropdown: eagerComponent(DropdownComponent),\n menu: eagerComponent(MenuComponent),\n \"menu-item\": eagerComponent(MenuItemComponent),\n outlet: eagerComponent(OutletComponent),\n sidebar: eagerComponent(SidebarComponent),\n topbar: eagerComponent(TopbarComponent),\n } satisfies ComponentRegistryFor<LayoutComponentType>,\n name: \"lattice/layout\",\n});\n"],"mappings":";;;;;;;;;;AAwBA,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"}
1
+ {"version":3,"file":"plugin.js","names":[],"sources":["../../resources/js/layout/plugin.ts"],"sourcesContent":["import {\n createPlugin,\n eagerComponent,\n type ComponentRegistryFor,\n} from \"@lattice-php/lattice/core/registry\";\nimport type { LayoutNodeType } from \"@lattice-php/lattice/types/generated\";\nimport BreadcrumbsComponent from \"./components/breadcrumbs\";\nimport CalloutsComponent from \"./components/callouts\";\nimport DropdownComponent from \"./components/dropdown\";\nimport MenuComponent from \"./components/menu\";\nimport MenuItemComponent from \"./components/menu-item\";\nimport OutletComponent from \"./components/outlet\";\nimport SidebarComponent from \"./components/sidebar\";\nimport TopbarComponent from \"./components/topbar\";\n\nexport const layoutComponents = createPlugin({\n components: {\n breadcrumbs: eagerComponent(BreadcrumbsComponent),\n callouts: eagerComponent(CalloutsComponent),\n dropdown: eagerComponent(DropdownComponent),\n menu: eagerComponent(MenuComponent),\n \"menu-item\": eagerComponent(MenuItemComponent),\n outlet: eagerComponent(OutletComponent),\n sidebar: eagerComponent(SidebarComponent),\n topbar: eagerComponent(TopbarComponent),\n } satisfies ComponentRegistryFor<LayoutNodeType>,\n name: \"lattice/layout\",\n});\n"],"mappings":";;;;;;;;;;AAeA,IAAa,mBAAmB,aAAa;CAC3C,YAAY;EACV,aAAa,eAAe,oBAAoB;EAChD,UAAU,eAAe,QAAiB;EAC1C,UAAU,eAAe,iBAAiB;EAC1C,MAAM,eAAe,aAAa;EAClC,aAAa,eAAe,iBAAiB;EAC7C,QAAQ,eAAe,eAAe;EACtC,SAAS,eAAe,gBAAgB;EACxC,QAAQ,eAAe,eAAe;CACxC;CACA,MAAM;AACR,CAAC"}
@@ -0,0 +1,2 @@
1
+ /** Coerce a wire value (boolean, `1`/`0`, `"1"`/`"true"`) to a boolean. */
2
+ export declare function isTruthy(value: unknown): boolean;
@@ -0,0 +1,9 @@
1
+ //#region resources/js/lib/is-truthy.ts
2
+ /** Coerce a wire value (boolean, `1`/`0`, `"1"`/`"true"`) to a boolean. */
3
+ function isTruthy(value) {
4
+ return value === true || value === 1 || value === "1" || value === "true";
5
+ }
6
+ //#endregion
7
+ export { isTruthy };
8
+
9
+ //# sourceMappingURL=is-truthy.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"is-truthy.js","names":[],"sources":["../../resources/js/lib/is-truthy.ts"],"sourcesContent":["/** Coerce a wire value (boolean, `1`/`0`, `\"1\"`/`\"true\"`) to a boolean. */\nexport function isTruthy(value: unknown): boolean {\n return value === true || value === 1 || value === \"1\" || value === \"true\";\n}\n"],"mappings":";;AACA,SAAgB,SAAS,OAAyB;CAChD,OAAO,UAAU,QAAQ,UAAU,KAAK,UAAU,OAAO,UAAU;AACrE"}
@@ -0,0 +1,10 @@
1
+ export type DebouncedCallback<A extends unknown[]> = {
2
+ (...args: A): void;
3
+ cancel: () => void;
4
+ };
5
+ /**
6
+ * A debounced wrapper around `callback` that is stable across renders (it reads
7
+ * the latest callback via a ref) and clears its pending timer on unmount, so a
8
+ * late fire can never run against a torn-down component.
9
+ */
10
+ export declare function useDebouncedCallback<A extends unknown[]>(callback: (...args: A) => void, delayMs: number): DebouncedCallback<A>;
@@ -0,0 +1,34 @@
1
+ import { useCallback, useEffect, useMemo, useRef } from "react";
2
+ //#region resources/js/lib/use-debounced-callback.ts
3
+ /**
4
+ * A debounced wrapper around `callback` that is stable across renders (it reads
5
+ * the latest callback via a ref) and clears its pending timer on unmount, so a
6
+ * late fire can never run against a torn-down component.
7
+ */
8
+ function useDebouncedCallback(callback, delayMs) {
9
+ const callbackRef = useRef(callback);
10
+ callbackRef.current = callback;
11
+ const timerRef = useRef(null);
12
+ const cancel = useCallback(() => {
13
+ if (timerRef.current !== null) {
14
+ clearTimeout(timerRef.current);
15
+ timerRef.current = null;
16
+ }
17
+ }, []);
18
+ useEffect(() => cancel, [cancel]);
19
+ return useMemo(() => {
20
+ const debounced = (...args) => {
21
+ cancel();
22
+ timerRef.current = setTimeout(() => {
23
+ timerRef.current = null;
24
+ callbackRef.current(...args);
25
+ }, delayMs);
26
+ };
27
+ debounced.cancel = cancel;
28
+ return debounced;
29
+ }, [cancel, delayMs]);
30
+ }
31
+ //#endregion
32
+ export { useDebouncedCallback };
33
+
34
+ //# sourceMappingURL=use-debounced-callback.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-debounced-callback.js","names":[],"sources":["../../resources/js/lib/use-debounced-callback.ts"],"sourcesContent":["import { useCallback, useEffect, useMemo, useRef } from \"react\";\n\nexport type DebouncedCallback<A extends unknown[]> = {\n (...args: A): void;\n cancel: () => void;\n};\n\n/**\n * A debounced wrapper around `callback` that is stable across renders (it reads\n * the latest callback via a ref) and clears its pending timer on unmount, so a\n * late fire can never run against a torn-down component.\n */\nexport function useDebouncedCallback<A extends unknown[]>(\n callback: (...args: A) => void,\n delayMs: number,\n): DebouncedCallback<A> {\n const callbackRef = useRef(callback);\n callbackRef.current = callback;\n\n const timerRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n\n const cancel = useCallback(() => {\n if (timerRef.current !== null) {\n clearTimeout(timerRef.current);\n timerRef.current = null;\n }\n }, []);\n\n useEffect(() => cancel, [cancel]);\n\n return useMemo(() => {\n const debounced = (...args: A): void => {\n cancel();\n timerRef.current = setTimeout(() => {\n timerRef.current = null;\n callbackRef.current(...args);\n }, delayMs);\n };\n\n debounced.cancel = cancel;\n\n return debounced;\n }, [cancel, delayMs]);\n}\n"],"mappings":";;;;;;;AAYA,SAAgB,qBACd,UACA,SACsB;CACtB,MAAM,cAAc,OAAO,QAAQ;CACnC,YAAY,UAAU;CAEtB,MAAM,WAAW,OAA6C,IAAI;CAElE,MAAM,SAAS,kBAAkB;EAC/B,IAAI,SAAS,YAAY,MAAM;GAC7B,aAAa,SAAS,OAAO;GAC7B,SAAS,UAAU;EACrB;CACF,GAAG,CAAC,CAAC;CAEL,gBAAgB,QAAQ,CAAC,MAAM,CAAC;CAEhC,OAAO,cAAc;EACnB,MAAM,aAAa,GAAG,SAAkB;GACtC,OAAO;GACP,SAAS,UAAU,iBAAiB;IAClC,SAAS,UAAU;IACnB,YAAY,QAAQ,GAAG,IAAI;GAC7B,GAAG,OAAO;EACZ;EAEA,UAAU,SAAS;EAEnB,OAAO;CACT,GAAG,CAAC,QAAQ,OAAO,CAAC;AACtB"}