@lattice-php/lattice 0.16.0 → 0.17.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (124) hide show
  1. package/dist/action/components/action-form.js +1 -1
  2. package/dist/action/use-action.js +1 -1
  3. package/dist/chat/types.d.ts +2 -10
  4. package/dist/core/components/button.js +34 -18
  5. package/dist/core/components/button.js.map +1 -1
  6. package/dist/core/components/control.d.ts +0 -2
  7. package/dist/core/components/control.js.map +1 -1
  8. package/dist/core/components/link.js +25 -29
  9. package/dist/core/components/link.js.map +1 -1
  10. package/dist/core/renderer.js +42 -2
  11. package/dist/core/renderer.js.map +1 -1
  12. package/dist/core/types.d.ts +22 -42
  13. package/dist/core/use-click-behavior.d.ts +42 -0
  14. package/dist/core/use-click-behavior.js +46 -0
  15. package/dist/core/use-click-behavior.js.map +1 -0
  16. package/dist/create-app.d.ts +8 -2
  17. package/dist/create-app.js +4 -2
  18. package/dist/create-app.js.map +1 -1
  19. package/dist/effects/registry.d.ts +9 -20
  20. package/dist/effects/registry.js +4 -6
  21. package/dist/effects/registry.js.map +1 -1
  22. package/dist/events/event-bridge.d.ts +1 -1
  23. package/dist/events/event-bridge.js +1 -1
  24. package/dist/events/event-bridge.js.map +1 -1
  25. package/dist/form/components/base/input-otp.d.ts +2 -1
  26. package/dist/form/components/base/input-otp.js.map +1 -1
  27. package/dist/form/components/conditions.d.ts +1 -1
  28. package/dist/form/components/conditions.js.map +1 -1
  29. package/dist/form/components/field-props.d.ts +2 -1
  30. package/dist/form/components/field-props.js.map +1 -1
  31. package/dist/form/components/field-scope.d.ts +2 -1
  32. package/dist/form/components/field-scope.js.map +1 -1
  33. package/dist/form/components/fields/row-action-menu.d.ts +2 -1
  34. package/dist/form/components/fields/row-action-menu.js.map +1 -1
  35. package/dist/form/components/fields/row-item.d.ts +2 -1
  36. package/dist/form/components/fields/row-item.js.map +1 -1
  37. package/dist/form/components/fields/table-rows.d.ts +2 -1
  38. package/dist/form/components/fields/table-rows.js.map +1 -1
  39. package/dist/form/components/fields/time-picker-columns.d.ts +2 -1
  40. package/dist/form/components/fields/time-picker-columns.js.map +1 -1
  41. package/dist/form/components/fields/time-picker.d.ts +2 -1
  42. package/dist/form/components/fields/time-picker.js.map +1 -1
  43. package/dist/form/components/fields/use-row-collection.d.ts +2 -1
  44. package/dist/form/components/fields/use-row-collection.js.map +1 -1
  45. package/dist/form/components/form-path.d.ts +0 -1
  46. package/dist/form/components/form-path.js +1 -1
  47. package/dist/form/components/form-path.js.map +1 -1
  48. package/dist/form/components/prefill-targets.d.ts +1 -1
  49. package/dist/form/components/prefill-targets.js.map +1 -1
  50. package/dist/form/components/types.d.ts +5 -1
  51. package/dist/form/components/use-field-commit.d.ts +2 -1
  52. package/dist/form/components/use-field-commit.js.map +1 -1
  53. package/dist/form/components/use-form-resolver.d.ts +2 -1
  54. package/dist/form/components/use-form-resolver.js.map +1 -1
  55. package/dist/format/date-time.d.ts +12 -0
  56. package/dist/format/date-time.js +30 -0
  57. package/dist/format/date-time.js.map +1 -0
  58. package/dist/format/value.js +1 -1
  59. package/dist/format/value.js.map +1 -1
  60. package/dist/i18n/config.d.ts +2 -1
  61. package/dist/i18n/config.js.map +1 -1
  62. package/dist/i18n/date-time.js +1 -1
  63. package/dist/i18n/date-time.js.map +1 -1
  64. package/dist/i18n/instance.d.ts +1 -1
  65. package/dist/i18n/instance.js.map +1 -1
  66. package/dist/i18n/locale-reload.d.ts +2 -1
  67. package/dist/i18n/locale-reload.js.map +1 -1
  68. package/dist/index.js +1 -1
  69. package/dist/layout/components.js +1 -1
  70. package/dist/layout/menu-item.js +43 -49
  71. package/dist/layout/menu-item.js.map +1 -1
  72. package/dist/notifications/api.d.ts +6 -0
  73. package/dist/notifications/api.js +21 -0
  74. package/dist/notifications/api.js.map +1 -0
  75. package/dist/notifications/components/empty-state.d.ts +1 -0
  76. package/dist/notifications/components/empty-state.js +21 -0
  77. package/dist/notifications/components/empty-state.js.map +1 -0
  78. package/dist/notifications/components/notification-item.d.ts +6 -0
  79. package/dist/notifications/components/notification-item.js +65 -0
  80. package/dist/notifications/components/notification-item.js.map +1 -0
  81. package/dist/notifications/components/notification-list.d.ts +10 -0
  82. package/dist/notifications/components/notification-list.js +38 -0
  83. package/dist/notifications/components/notification-list.js.map +1 -0
  84. package/dist/notifications/components/notifications-echo.d.ts +5 -0
  85. package/dist/notifications/components/notifications-echo.js +22 -0
  86. package/dist/notifications/components/notifications-echo.js.map +1 -0
  87. package/dist/notifications/components/notifications.d.ts +3 -0
  88. package/dist/notifications/components/notifications.js +109 -0
  89. package/dist/notifications/components/notifications.js.map +1 -0
  90. package/dist/notifications/index.d.ts +1 -0
  91. package/dist/notifications/index.js +11 -0
  92. package/dist/notifications/index.js.map +1 -0
  93. package/dist/notifications/store.d.ts +25 -0
  94. package/dist/notifications/store.js +100 -0
  95. package/dist/notifications/store.js.map +1 -0
  96. package/dist/notifications/types.d.ts +10 -0
  97. package/dist/notifications/types.js +0 -0
  98. package/dist/realtime/build-effects.d.ts +2 -1
  99. package/dist/realtime/build-effects.js.map +1 -1
  100. package/dist/realtime/subscriptions.js.map +1 -1
  101. package/dist/registry/eager.js +2 -1
  102. package/dist/registry/eager.js.map +1 -1
  103. package/dist/registry/lazy.js +2 -1
  104. package/dist/registry/lazy.js.map +1 -1
  105. package/dist/table/bulk.d.ts +2 -1
  106. package/dist/table/bulk.js.map +1 -1
  107. package/dist/table/components/bulk-bar.js +2 -2
  108. package/dist/table/components/cells/money-cell.js +1 -1
  109. package/dist/table/components/cells/number-cell.js +1 -1
  110. package/dist/table/components/cells/text-cell.js +1 -1
  111. package/dist/table/components/filter-controls.d.ts +0 -4
  112. package/dist/table/components/filter-controls.js.map +1 -1
  113. package/dist/table/components/table-cell.js.map +1 -1
  114. package/dist/table/format.d.ts +1 -12
  115. package/dist/table/format.js +2 -26
  116. package/dist/table/format.js.map +1 -1
  117. package/dist/table/types.d.ts +7 -17
  118. package/dist/types/generated.d.ts +119 -290
  119. package/dist/vite-client.d.ts +8 -0
  120. package/dist/vite.d.ts +35 -1
  121. package/dist/vite.js +60 -2
  122. package/dist/vite.js.map +1 -1
  123. package/package.json +17 -2
  124. package/resources/icons/bell.svg +16 -0
@@ -1 +1 @@
1
- {"version":3,"file":"create-app.js","names":[],"sources":["../resources/js/create-app.tsx"],"sourcesContent":["import { createInertiaApp } from \"@inertiajs/react\";\nimport type { ReactElement } from \"react\";\nimport { initializeTheme } from \"./appearance\";\nimport type { Registry } from \"./core/registry\";\nimport { setDefaultRegistry } from \"./core/registry-context\";\nimport type { SpriteValue } from \"./icons/sprite\";\nimport {\n createLayoutResolver,\n createPageResolver,\n type CreateLayoutResolverOptions,\n type PageModules,\n} from \"./inertia\";\nimport { ProviderBase } from \"./provider-base\";\nimport { registry as defaultRegistry } from \"./registry\";\n\ntype InertiaAppOptions = NonNullable<Parameters<typeof createInertiaApp>[0]>;\n\nexport type CreateLatticeAppOptions = Omit<\n InertiaAppOptions,\n \"resolve\" | \"layout\" | \"setup\" | \"withApp\" | \"pages\"\n> & {\n registry?: Registry;\n sprite?: SpriteValue;\n /** Normal Inertia page modules, e.g. `import.meta.glob('./pages/**\\/*.tsx')`. */\n pages?: PageModules;\n defaultLayout?: CreateLayoutResolverOptions[\"defaultLayout\"];\n};\n\n/**\n * Bootstrap an Inertia app with the Lattice shell: the page/layout resolvers\n * (server-driven Lattice pages and normal Inertia pages alike), the Provider —\n * registry, sprite, flash toasts via Lattice's own Toaster — and theme\n * initialization. Forwards any other createInertiaApp option.\n */\nexport function createLatticeApp({\n registry,\n sprite,\n pages = {},\n defaultLayout,\n strictMode = true,\n ...inertiaOptions\n}: CreateLatticeAppOptions = {}) {\n const activeRegistry = registry ?? defaultRegistry;\n\n setDefaultRegistry(activeRegistry);\n\n const app = createInertiaApp({\n ...inertiaOptions,\n strictMode,\n resolve: createPageResolver(pages),\n layout: createLayoutResolver({ defaultLayout }),\n withApp: (node: ReactElement): ReactElement => (\n <ProviderBase registry={activeRegistry} sprite={sprite}>\n {node}\n </ProviderBase>\n ),\n });\n\n initializeTheme();\n\n return app;\n}\n"],"mappings":";;;;;;;;;;;;;;AAkCA,SAAgB,iBAAiB,EAC/B,UACA,QACA,QAAQ,CAAC,GACT,eACA,aAAa,MACb,GAAG,mBACwB,CAAC,GAAG;CAC/B,MAAM,iBAAiB,YAAY;CAEnC,mBAAmB,cAAc;CAEjC,MAAM,MAAM,iBAAiB;EAC3B,GAAG;EACH;EACA,SAAS,mBAAmB,KAAK;EACjC,QAAQ,qBAAqB,EAAE,cAAc,CAAC;EAC9C,UAAU,SACR,oBAAC,cAAD;GAAc,UAAU;GAAwB;aAC7C;EACW,CAAA;CAElB,CAAC;CAED,gBAAgB;CAEhB,OAAO;AACT"}
1
+ {"version":3,"file":"create-app.js","names":[],"sources":["../resources/js/create-app.tsx"],"sourcesContent":["import { createInertiaApp } from \"@inertiajs/react\";\nimport type { ReactElement } from \"react\";\nimport { initializeTheme } from \"./appearance\";\nimport { extendRegistry, type Plugin, type Registry } from \"./core/registry\";\nimport { setDefaultRegistry } from \"./core/registry-context\";\nimport type { SpriteValue } from \"./icons/sprite\";\nimport {\n createLayoutResolver,\n createPageResolver,\n type CreateLayoutResolverOptions,\n type PageModules,\n} from \"./inertia\";\nimport { ProviderBase } from \"./provider-base\";\nimport { registry as defaultRegistry } from \"./registry\";\n\ntype InertiaAppOptions = NonNullable<Parameters<typeof createInertiaApp>[0]>;\n\nexport type CreateLatticeAppOptions = Omit<\n InertiaAppOptions,\n \"resolve\" | \"layout\" | \"setup\" | \"withApp\" | \"pages\"\n> & {\n registry?: Registry;\n /**\n * Component-package plugins to merge onto the registry — pass the\n * Composer-discovered `virtual:lattice/plugins` here to register vendor\n * components with no manual `extendRegistry` call.\n */\n plugins?: Plugin[];\n sprite?: SpriteValue;\n /** Normal Inertia page modules, e.g. `import.meta.glob('./pages/**\\/*.tsx')`. */\n pages?: PageModules;\n defaultLayout?: CreateLayoutResolverOptions[\"defaultLayout\"];\n};\n\n/**\n * Bootstrap an Inertia app with the Lattice shell: the page/layout resolvers\n * (server-driven Lattice pages and normal Inertia pages alike), the Provider —\n * registry, sprite, flash toasts via Lattice's own Toaster — and theme\n * initialization. Forwards any other createInertiaApp option.\n */\nexport function createLatticeApp({\n registry,\n plugins,\n sprite,\n pages = {},\n defaultLayout,\n strictMode = true,\n ...inertiaOptions\n}: CreateLatticeAppOptions = {}) {\n const baseRegistry = registry ?? defaultRegistry;\n const activeRegistry =\n plugins && plugins.length > 0 ? extendRegistry(baseRegistry, ...plugins) : baseRegistry;\n\n setDefaultRegistry(activeRegistry);\n\n const app = createInertiaApp({\n ...inertiaOptions,\n strictMode,\n resolve: createPageResolver(pages),\n layout: createLayoutResolver({ defaultLayout }),\n withApp: (node: ReactElement): ReactElement => (\n <ProviderBase registry={activeRegistry} sprite={sprite}>\n {node}\n </ProviderBase>\n ),\n });\n\n initializeTheme();\n\n return app;\n}\n"],"mappings":";;;;;;;;;;;;;;;AAwCA,SAAgB,iBAAiB,EAC/B,UACA,SACA,QACA,QAAQ,CAAC,GACT,eACA,aAAa,MACb,GAAG,mBACwB,CAAC,GAAG;CAC/B,MAAM,eAAe,YAAY;CACjC,MAAM,iBACJ,WAAW,QAAQ,SAAS,IAAI,eAAe,cAAc,GAAG,OAAO,IAAI;CAE7E,mBAAmB,cAAc;CAEjC,MAAM,MAAM,iBAAiB;EAC3B,GAAG;EACH;EACA,SAAS,mBAAmB,KAAK;EACjC,QAAQ,qBAAqB,EAAE,cAAc,CAAC;EAC9C,UAAU,SACR,oBAAC,cAAD;GAAc,UAAU;GAAwB;aAC7C;EACW,CAAA;CAElB,CAAC;CAED,gBAAgB;CAEhB,OAAO;AACT"}
@@ -1,37 +1,26 @@
1
1
  import { ResolveProps } from '../core/types';
2
- import { Effect } from '../types/generated';
2
+ import { Effect, EffectPropsMap } from '../types/generated';
3
3
  /**
4
- * Augmentable map of effect `type` payload (the effect's fields minus `type`).
5
- * Consumer apps extend it via `declare module "@lattice-php/lattice"` so their
6
- * custom effects type their handler's payload; built-ins resolve through the
7
- * generated `Effect` union.
4
+ * Consumer apps augment this via `declare module "@lattice-php/lattice"` to type
5
+ * their custom effects' payloads; built-ins resolve through `EffectPropsMap`. The
6
+ * effect counterpart of `ComponentProps`.
8
7
  */
9
8
  export interface EffectProps {
10
9
  }
11
- type EffectPayloads = {
12
- [TEffect in Effect as TEffect["type"]]: Omit<TEffect, "type">;
13
- };
14
- type EffectPayloadOf<TType extends string> = ResolveProps<EffectProps, EffectPayloads, TType, Record<string, unknown>>;
15
- /**
16
- * Resolves an effect `type` to its full shape — `{ type, ...payload }` — the way
17
- * `Node<T>` pairs a type with its props, so built-ins and consumer effects alike
18
- * always carry `type`. An unknown type falls back to the loose `Effect` union.
19
- */
10
+ type EffectPayloadOf<TType extends string> = ResolveProps<EffectProps, EffectPropsMap, TType, Record<string, unknown>>;
20
11
  export type EffectOf<TType extends string> = string extends TType ? Effect : {
21
12
  type: TType;
22
13
  } & EffectPayloadOf<TType>;
23
14
  export type EffectHandler<TType extends string = string> = (effect: EffectOf<TType>) => void;
24
15
  export type EffectHandlerRegistry = Record<string, EffectHandler>;
25
16
  /**
26
- * Registers a typed effect handler, erasing the type parameter for the registry.
27
- * Mirrors `eagerComponent`/`columnCell`: author against `EffectHandler<"my.type">`
28
- * for a typed payload, register through this.
17
+ * Author a handler against `EffectHandler<"my.type">` for a typed payload, then
18
+ * register it through this — it erases the type parameter for the loose registry.
29
19
  */
30
20
  export declare function effectHandler<TType extends string>(_type: TType, fn: EffectHandler<TType>): EffectHandler;
31
21
  /**
32
- * Built-in effect handlers. Imperative effects act directly; the rest bridge to
33
- * the `lattice:*` DOM events that toast/callout/modal/fragment/form subscribe to
34
- * — preserving today's behavior exactly.
22
+ * Imperative effects act directly; the rest bridge to the `lattice:*` DOM events
23
+ * that toast/callout/modal/fragment/form subscribe to.
35
24
  */
36
25
  export declare const builtinEffectHandlers: EffectHandlerRegistry;
37
26
  export declare function mergeEffectHandlers(...registries: Array<EffectHandlerRegistry | undefined>): EffectHandlerRegistry;
@@ -3,9 +3,8 @@ import { setLocale } from "../i18n/locale.js";
3
3
  import { router } from "@inertiajs/react";
4
4
  //#region resources/js/effects/registry.ts
5
5
  /**
6
- * Registers a typed effect handler, erasing the type parameter for the registry.
7
- * Mirrors `eagerComponent`/`columnCell`: author against `EffectHandler<"my.type">`
8
- * for a typed payload, register through this.
6
+ * Author a handler against `EffectHandler<"my.type">` for a typed payload, then
7
+ * register it through this — it erases the type parameter for the loose registry.
9
8
  */
10
9
  function effectHandler(_type, fn) {
11
10
  return fn;
@@ -22,9 +21,8 @@ function bridge(event) {
22
21
  return (effect) => window.dispatchEvent(new CustomEvent(event, { detail: effect }));
23
22
  }
24
23
  /**
25
- * Built-in effect handlers. Imperative effects act directly; the rest bridge to
26
- * the `lattice:*` DOM events that toast/callout/modal/fragment/form subscribe to
27
- * — preserving today's behavior exactly.
24
+ * Imperative effects act directly; the rest bridge to the `lattice:*` DOM events
25
+ * that toast/callout/modal/fragment/form subscribe to.
28
26
  */
29
27
  var builtinEffectHandlers = {
30
28
  reloadPage: () => router.reload(),
@@ -1 +1 @@
1
- {"version":3,"file":"registry.js","names":[],"sources":["../../resources/js/effects/registry.ts"],"sourcesContent":["import { router } from \"@inertiajs/react\";\nimport type { ResolveProps } from \"@lattice-php/lattice/core/types\";\nimport type { Effect } from \"@lattice-php/lattice/types/generated\";\nimport { LATTICE_EVENT } from \"@lattice-php/lattice/events/event-names\";\nimport { setLocale } from \"@lattice-php/lattice/i18n/locale\";\n\n/**\n * Augmentable map of effect `type` → payload (the effect's fields minus `type`).\n * Consumer apps extend it via `declare module \"@lattice-php/lattice\"` so their\n * custom effects type their handler's payload; built-ins resolve through the\n * generated `Effect` union.\n */\nexport interface EffectProps {}\n\ntype EffectPayloads = { [TEffect in Effect as TEffect[\"type\"]]: Omit<TEffect, \"type\"> };\n\ntype EffectPayloadOf<TType extends string> = ResolveProps<\n EffectProps,\n EffectPayloads,\n TType,\n Record<string, unknown>\n>;\n\n/**\n * Resolves an effect `type` to its full shape — `{ type, ...payload }` — the way\n * `Node<T>` pairs a type with its props, so built-ins and consumer effects alike\n * always carry `type`. An unknown type falls back to the loose `Effect` union.\n */\nexport type EffectOf<TType extends string> = string extends TType\n ? Effect\n : { type: TType } & EffectPayloadOf<TType>;\n\nexport type EffectHandler<TType extends string = string> = (effect: EffectOf<TType>) => void;\n\nexport type EffectHandlerRegistry = Record<string, EffectHandler>;\n\n/**\n * Registers a typed effect handler, erasing the type parameter for the registry.\n * Mirrors `eagerComponent`/`columnCell`: author against `EffectHandler<\"my.type\">`\n * for a typed payload, register through this.\n */\nexport function effectHandler<TType extends string>(\n _type: TType,\n fn: EffectHandler<TType>,\n): EffectHandler {\n return fn as unknown as EffectHandler;\n}\n\nfunction triggerDownload(url: string): void {\n const link = document.createElement(\"a\");\n link.href = url;\n link.rel = \"noopener\";\n document.body.appendChild(link);\n link.click();\n link.remove();\n}\n\nfunction bridge(event: string): EffectHandler {\n return (effect) => window.dispatchEvent(new CustomEvent(event, { detail: effect }));\n}\n\n/**\n * Built-in effect handlers. Imperative effects act directly; the rest bridge to\n * the `lattice:*` DOM events that toast/callout/modal/fragment/form subscribe to\n * — preserving today's behavior exactly.\n */\nexport const builtinEffectHandlers: EffectHandlerRegistry = {\n reloadPage: () => router.reload(),\n redirect: effectHandler(\"redirect\", (effect) => router.visit(effect.url)),\n download: effectHandler(\"download\", (effect) => triggerDownload(effect.url)),\n localeChange: effectHandler(\"localeChange\", (effect) => setLocale(effect.locale)),\n toast: bridge(LATTICE_EVENT.toast),\n callout: bridge(LATTICE_EVENT.callout),\n reloadComponent: bridge(LATTICE_EVENT.reloadComponent),\n openModal: bridge(LATTICE_EVENT.openModal),\n closeModal: bridge(LATTICE_EVENT.closeModal),\n resetForm: bridge(LATTICE_EVENT.resetForm),\n toggleSidebar: bridge(LATTICE_EVENT.toggleSidebar),\n};\n\nexport function mergeEffectHandlers(\n ...registries: Array<EffectHandlerRegistry | undefined>\n): EffectHandlerRegistry {\n return registries.reduce<EffectHandlerRegistry>(\n (merged, registry) => ({ ...merged, ...registry }),\n {},\n );\n}\n"],"mappings":";;;;;;;;;AAyCA,SAAgB,cACd,OACA,IACe;CACf,OAAO;AACT;AAEA,SAAS,gBAAgB,KAAmB;CAC1C,MAAM,OAAO,SAAS,cAAc,GAAG;CACvC,KAAK,OAAO;CACZ,KAAK,MAAM;CACX,SAAS,KAAK,YAAY,IAAI;CAC9B,KAAK,MAAM;CACX,KAAK,OAAO;AACd;AAEA,SAAS,OAAO,OAA8B;CAC5C,QAAQ,WAAW,OAAO,cAAc,IAAI,YAAY,OAAO,EAAE,QAAQ,OAAO,CAAC,CAAC;AACpF;;;;;;AAOA,IAAa,wBAA+C;CAC1D,kBAAkB,OAAO,OAAO;CAChC,UAAU,cAAc,aAAa,WAAW,OAAO,MAAM,OAAO,GAAG,CAAC;CACxE,UAAU,cAAc,aAAa,WAAW,gBAAgB,OAAO,GAAG,CAAC;CAC3E,cAAc,cAAc,iBAAiB,WAAW,UAAU,OAAO,MAAM,CAAC;CAChF,OAAO,OAAO,cAAc,KAAK;CACjC,SAAS,OAAO,cAAc,OAAO;CACrC,iBAAiB,OAAO,cAAc,eAAe;CACrD,WAAW,OAAO,cAAc,SAAS;CACzC,YAAY,OAAO,cAAc,UAAU;CAC3C,WAAW,OAAO,cAAc,SAAS;CACzC,eAAe,OAAO,cAAc,aAAa;AACnD;AAEA,SAAgB,oBACd,GAAG,YACoB;CACvB,OAAO,WAAW,QACf,QAAQ,cAAc;EAAE,GAAG;EAAQ,GAAG;CAAS,IAChD,CAAC,CACH;AACF"}
1
+ {"version":3,"file":"registry.js","names":[],"sources":["../../resources/js/effects/registry.ts"],"sourcesContent":["import { router } from \"@inertiajs/react\";\nimport type { ResolveProps } from \"@lattice-php/lattice/core/types\";\nimport type { Effect, EffectPropsMap } from \"@lattice-php/lattice/types/generated\";\nimport { LATTICE_EVENT } from \"@lattice-php/lattice/events/event-names\";\nimport { setLocale } from \"@lattice-php/lattice/i18n/locale\";\n\n/**\n * Consumer apps augment this via `declare module \"@lattice-php/lattice\"` to type\n * their custom effects' payloads; built-ins resolve through `EffectPropsMap`. The\n * effect counterpart of `ComponentProps`.\n */\nexport interface EffectProps {}\n\ntype EffectPayloadOf<TType extends string> = ResolveProps<\n EffectProps,\n EffectPropsMap,\n TType,\n Record<string, unknown>\n>;\n\nexport type EffectOf<TType extends string> = string extends TType\n ? Effect\n : { type: TType } & EffectPayloadOf<TType>;\n\nexport type EffectHandler<TType extends string = string> = (effect: EffectOf<TType>) => void;\n\nexport type EffectHandlerRegistry = Record<string, EffectHandler>;\n\n/**\n * Author a handler against `EffectHandler<\"my.type\">` for a typed payload, then\n * register it through this — it erases the type parameter for the loose registry.\n */\nexport function effectHandler<TType extends string>(\n _type: TType,\n fn: EffectHandler<TType>,\n): EffectHandler {\n return fn as unknown as EffectHandler;\n}\n\nfunction triggerDownload(url: string): void {\n const link = document.createElement(\"a\");\n link.href = url;\n link.rel = \"noopener\";\n document.body.appendChild(link);\n link.click();\n link.remove();\n}\n\nfunction bridge(event: string): EffectHandler {\n return (effect) => window.dispatchEvent(new CustomEvent(event, { detail: effect }));\n}\n\n/**\n * Imperative effects act directly; the rest bridge to the `lattice:*` DOM events\n * that toast/callout/modal/fragment/form subscribe to.\n */\nexport const builtinEffectHandlers: EffectHandlerRegistry = {\n reloadPage: () => router.reload(),\n redirect: effectHandler(\"redirect\", (effect) => router.visit(effect.url)),\n download: effectHandler(\"download\", (effect) => triggerDownload(effect.url)),\n localeChange: effectHandler(\"localeChange\", (effect) => setLocale(effect.locale)),\n toast: bridge(LATTICE_EVENT.toast),\n callout: bridge(LATTICE_EVENT.callout),\n reloadComponent: bridge(LATTICE_EVENT.reloadComponent),\n openModal: bridge(LATTICE_EVENT.openModal),\n closeModal: bridge(LATTICE_EVENT.closeModal),\n resetForm: bridge(LATTICE_EVENT.resetForm),\n toggleSidebar: bridge(LATTICE_EVENT.toggleSidebar),\n};\n\nexport function mergeEffectHandlers(\n ...registries: Array<EffectHandlerRegistry | undefined>\n): EffectHandlerRegistry {\n return registries.reduce<EffectHandlerRegistry>(\n (merged, registry) => ({ ...merged, ...registry }),\n {},\n );\n}\n"],"mappings":";;;;;;;;AAgCA,SAAgB,cACd,OACA,IACe;CACf,OAAO;AACT;AAEA,SAAS,gBAAgB,KAAmB;CAC1C,MAAM,OAAO,SAAS,cAAc,GAAG;CACvC,KAAK,OAAO;CACZ,KAAK,MAAM;CACX,SAAS,KAAK,YAAY,IAAI;CAC9B,KAAK,MAAM;CACX,KAAK,OAAO;AACd;AAEA,SAAS,OAAO,OAA8B;CAC5C,QAAQ,WAAW,OAAO,cAAc,IAAI,YAAY,OAAO,EAAE,QAAQ,OAAO,CAAC,CAAC;AACpF;;;;;AAMA,IAAa,wBAA+C;CAC1D,kBAAkB,OAAO,OAAO;CAChC,UAAU,cAAc,aAAa,WAAW,OAAO,MAAM,OAAO,GAAG,CAAC;CACxE,UAAU,cAAc,aAAa,WAAW,gBAAgB,OAAO,GAAG,CAAC;CAC3E,cAAc,cAAc,iBAAiB,WAAW,UAAU,OAAO,MAAM,CAAC;CAChF,OAAO,OAAO,cAAc,KAAK;CACjC,SAAS,OAAO,cAAc,OAAO;CACrC,iBAAiB,OAAO,cAAc,eAAe;CACrD,WAAW,OAAO,cAAc,SAAS;CACzC,YAAY,OAAO,cAAc,UAAU;CAC3C,WAAW,OAAO,cAAc,SAAS;CACzC,eAAe,OAAO,cAAc,aAAa;AACnD;AAEA,SAAgB,oBACd,GAAG,YACoB;CACvB,OAAO,WAAW,QACf,QAAQ,cAAc;EAAE,GAAG;EAAQ,GAAG;CAAS,IAChD,CAAC,CACH;AACF"}
@@ -1,5 +1,5 @@
1
1
  import { ToastMessage } from '../toast/toast';
2
- export declare const appearances: readonly ["light", "dark", "system"];
2
+ declare const appearances: readonly ["light", "dark", "system"];
3
3
  export type Appearance = (typeof appearances)[number];
4
4
  type EventBridgeProps = {
5
5
  onAppearanceChange?: (appearance: Appearance) => void;
@@ -40,6 +40,6 @@ function EventBridge({ onAppearanceChange, onLocaleChange, onToast: onToast$1 })
40
40
  return null;
41
41
  }
42
42
  //#endregion
43
- export { EventBridge, appearances };
43
+ export { EventBridge };
44
44
 
45
45
  //# sourceMappingURL=event-bridge.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"event-bridge.js","names":[],"sources":["../../resources/js/events/event-bridge.tsx"],"sourcesContent":["import { useEffect } from \"react\";\nimport { onToast as subscribeToToasts } from \"@lattice-php/lattice/toast/toast\";\nimport type { ToastMessage } from \"@lattice-php/lattice/toast/toast\";\nimport { LATTICE_EVENT } from \"./event-names\";\n\nexport const appearances = [\"light\", \"dark\", \"system\"] as const;\n\nexport type Appearance = (typeof appearances)[number];\n\ntype EventBridgeProps = {\n onAppearanceChange?: (appearance: Appearance) => void;\n onLocaleChange?: (locale: string) => void;\n onToast?: (toast: ToastMessage) => void;\n};\n\ntype AppearanceEvent = CustomEvent<{\n value?: unknown;\n}>;\n\ntype LocaleEvent = CustomEvent<{\n locale?: unknown;\n}>;\n\nfunction isAppearance(value: unknown): value is Appearance {\n return appearances.some((appearance) => appearance === value);\n}\n\nexport function EventBridge({ onAppearanceChange, onLocaleChange, onToast }: EventBridgeProps) {\n useEffect(() => {\n if (!onToast) {\n return;\n }\n\n return subscribeToToasts(onToast);\n }, [onToast]);\n\n useEffect(() => {\n if (!onAppearanceChange) {\n return;\n }\n\n const listener = (event: Event): void => {\n const value = (event as AppearanceEvent).detail?.value;\n\n if (isAppearance(value)) {\n onAppearanceChange(value);\n }\n };\n\n window.addEventListener(LATTICE_EVENT.appearanceChange, listener);\n\n return () => {\n window.removeEventListener(LATTICE_EVENT.appearanceChange, listener);\n };\n }, [onAppearanceChange]);\n\n useEffect(() => {\n if (!onLocaleChange) {\n return;\n }\n\n const listener = (event: Event): void => {\n const locale = (event as LocaleEvent).detail?.locale;\n\n if (typeof locale === \"string\" && locale !== \"\") {\n onLocaleChange(locale);\n }\n };\n\n window.addEventListener(LATTICE_EVENT.localeChange, listener);\n\n return () => {\n window.removeEventListener(LATTICE_EVENT.localeChange, listener);\n };\n }, [onLocaleChange]);\n\n return null;\n}\n"],"mappings":";;;;AAKA,IAAa,cAAc;CAAC;CAAS;CAAQ;AAAQ;AAkBrD,SAAS,aAAa,OAAqC;CACzD,OAAO,YAAY,MAAM,eAAe,eAAe,KAAK;AAC9D;AAEA,SAAgB,YAAY,EAAE,oBAAoB,gBAAgB,SAAA,aAA6B;CAC7F,gBAAgB;EACd,IAAI,CAAC,WACH;EAGF,OAAO,QAAkB,SAAO;CAClC,GAAG,CAAC,SAAO,CAAC;CAEZ,gBAAgB;EACd,IAAI,CAAC,oBACH;EAGF,MAAM,YAAY,UAAuB;GACvC,MAAM,QAAS,MAA0B,QAAQ;GAEjD,IAAI,aAAa,KAAK,GACpB,mBAAmB,KAAK;EAE5B;EAEA,OAAO,iBAAiB,cAAc,kBAAkB,QAAQ;EAEhE,aAAa;GACX,OAAO,oBAAoB,cAAc,kBAAkB,QAAQ;EACrE;CACF,GAAG,CAAC,kBAAkB,CAAC;CAEvB,gBAAgB;EACd,IAAI,CAAC,gBACH;EAGF,MAAM,YAAY,UAAuB;GACvC,MAAM,SAAU,MAAsB,QAAQ;GAE9C,IAAI,OAAO,WAAW,YAAY,WAAW,IAC3C,eAAe,MAAM;EAEzB;EAEA,OAAO,iBAAiB,cAAc,cAAc,QAAQ;EAE5D,aAAa;GACX,OAAO,oBAAoB,cAAc,cAAc,QAAQ;EACjE;CACF,GAAG,CAAC,cAAc,CAAC;CAEnB,OAAO;AACT"}
1
+ {"version":3,"file":"event-bridge.js","names":[],"sources":["../../resources/js/events/event-bridge.tsx"],"sourcesContent":["import { useEffect } from \"react\";\nimport { onToast as subscribeToToasts } from \"@lattice-php/lattice/toast/toast\";\nimport type { ToastMessage } from \"@lattice-php/lattice/toast/toast\";\nimport { LATTICE_EVENT } from \"./event-names\";\n\nconst appearances = [\"light\", \"dark\", \"system\"] as const;\n\nexport type Appearance = (typeof appearances)[number];\n\ntype EventBridgeProps = {\n onAppearanceChange?: (appearance: Appearance) => void;\n onLocaleChange?: (locale: string) => void;\n onToast?: (toast: ToastMessage) => void;\n};\n\ntype AppearanceEvent = CustomEvent<{\n value?: unknown;\n}>;\n\ntype LocaleEvent = CustomEvent<{\n locale?: unknown;\n}>;\n\nfunction isAppearance(value: unknown): value is Appearance {\n return appearances.some((appearance) => appearance === value);\n}\n\nexport function EventBridge({ onAppearanceChange, onLocaleChange, onToast }: EventBridgeProps) {\n useEffect(() => {\n if (!onToast) {\n return;\n }\n\n return subscribeToToasts(onToast);\n }, [onToast]);\n\n useEffect(() => {\n if (!onAppearanceChange) {\n return;\n }\n\n const listener = (event: Event): void => {\n const value = (event as AppearanceEvent).detail?.value;\n\n if (isAppearance(value)) {\n onAppearanceChange(value);\n }\n };\n\n window.addEventListener(LATTICE_EVENT.appearanceChange, listener);\n\n return () => {\n window.removeEventListener(LATTICE_EVENT.appearanceChange, listener);\n };\n }, [onAppearanceChange]);\n\n useEffect(() => {\n if (!onLocaleChange) {\n return;\n }\n\n const listener = (event: Event): void => {\n const locale = (event as LocaleEvent).detail?.locale;\n\n if (typeof locale === \"string\" && locale !== \"\") {\n onLocaleChange(locale);\n }\n };\n\n window.addEventListener(LATTICE_EVENT.localeChange, listener);\n\n return () => {\n window.removeEventListener(LATTICE_EVENT.localeChange, listener);\n };\n }, [onLocaleChange]);\n\n return null;\n}\n"],"mappings":";;;;AAKA,IAAM,cAAc;CAAC;CAAS;CAAQ;AAAQ;AAkB9C,SAAS,aAAa,OAAqC;CACzD,OAAO,YAAY,MAAM,eAAe,eAAe,KAAK;AAC9D;AAEA,SAAgB,YAAY,EAAE,oBAAoB,gBAAgB,SAAA,aAA6B;CAC7F,gBAAgB;EACd,IAAI,CAAC,WACH;EAGF,OAAO,QAAkB,SAAO;CAClC,GAAG,CAAC,SAAO,CAAC;CAEZ,gBAAgB;EACd,IAAI,CAAC,oBACH;EAGF,MAAM,YAAY,UAAuB;GACvC,MAAM,QAAS,MAA0B,QAAQ;GAEjD,IAAI,aAAa,KAAK,GACpB,mBAAmB,KAAK;EAE5B;EAEA,OAAO,iBAAiB,cAAc,kBAAkB,QAAQ;EAEhE,aAAa;GACX,OAAO,oBAAoB,cAAc,kBAAkB,QAAQ;EACrE;CACF,GAAG,CAAC,kBAAkB,CAAC;CAEvB,gBAAgB;EACd,IAAI,CAAC,gBACH;EAGF,MAAM,YAAY,UAAuB;GACvC,MAAM,SAAU,MAAsB,QAAQ;GAE9C,IAAI,OAAO,WAAW,YAAY,WAAW,IAC3C,eAAe,MAAM;EAEzB;EAEA,OAAO,iBAAiB,cAAc,cAAc,QAAQ;EAE5D,aAAa;GACX,OAAO,oBAAoB,cAAc,cAAc,QAAQ;EACjE;CACF,GAAG,CAAC,cAAc,CAAC;CAEnB,OAAO;AACT"}
@@ -1,6 +1,7 @@
1
1
  import { OTPInput } from 'input-otp';
2
2
  import { ComponentProps } from 'react';
3
- export type InputOTPProps = Omit<ComponentProps<typeof OTPInput>, "children" | "maxLength" | "render"> & {
3
+ type InputOTPProps = Omit<ComponentProps<typeof OTPInput>, "children" | "maxLength" | "render"> & {
4
4
  length: number;
5
5
  };
6
6
  export declare function InputOTP({ length, containerClassName, pattern, ...props }: InputOTPProps): import("react").JSX.Element;
7
+ export {};
@@ -1 +1 @@
1
- {"version":3,"file":"input-otp.js","names":[],"sources":["../../../../resources/js/form/components/base/input-otp.tsx"],"sourcesContent":["import { OTPInput, REGEXP_ONLY_DIGITS, type SlotProps } from \"input-otp\";\nimport type { ComponentProps } from \"react\";\nimport { cn } from \"@lattice-php/lattice/lib/utils\";\n\nfunction Slot({ char, hasFakeCaret, isActive }: SlotProps) {\n return (\n <div\n className={cn(\n \"relative flex h-lt-control-md w-10 items-center justify-center border-y border-r border-lt-input text-base shadow-lt-xs transition-all first:rounded-l-lt-sm first:border-l last:rounded-r-lt-sm\",\n isActive && \"z-10 border-lt-ring ring-lt-ring/50 ring-[3px]\",\n )}\n >\n {char}\n {hasFakeCaret ? (\n <div className=\"pointer-events-none absolute inset-0 flex items-center justify-center\">\n <div className=\"bg-lt-fg h-5 w-px animate-pulse\" />\n </div>\n ) : null}\n </div>\n );\n}\n\nexport type InputOTPProps = Omit<\n ComponentProps<typeof OTPInput>,\n \"children\" | \"maxLength\" | \"render\"\n> & {\n length: number;\n};\n\nexport function InputOTP({\n length,\n containerClassName,\n pattern = REGEXP_ONLY_DIGITS,\n ...props\n}: InputOTPProps) {\n return (\n <OTPInput\n maxLength={length}\n pattern={pattern}\n containerClassName={cn(\n \"flex items-center gap-2 has-[:disabled]:opacity-50\",\n containerClassName,\n )}\n render={({ slots }) => (\n <div className=\"flex items-center\">\n {slots.map((slot, index) => (\n <Slot key={index} {...slot} />\n ))}\n </div>\n )}\n {...props}\n />\n );\n}\n"],"mappings":";;;;AAIA,SAAS,KAAK,EAAE,MAAM,cAAc,YAAuB;CACzD,OACE,qBAAC,OAAD;EACE,WAAW,GACT,oMACA,YAAY,gDACd;YAJF,CAMG,MACA,eACC,oBAAC,OAAD;GAAK,WAAU;aACb,oBAAC,OAAD,EAAK,WAAU,kCAAmC,CAAA;EAC/C,CAAA,IACH,IACD;;AAET;AASA,SAAgB,SAAS,EACvB,QACA,oBACA,UAAU,oBACV,GAAG,SACa;CAChB,OACE,oBAAC,UAAD;EACE,WAAW;EACF;EACT,oBAAoB,GAClB,sDACA,kBACF;EACA,SAAS,EAAE,YACT,oBAAC,OAAD;GAAK,WAAU;aACZ,MAAM,KAAK,MAAM,UAChB,oBAAC,MAAD,EAAkB,GAAI,KAAO,GAAlB,KAAkB,CAC9B;EACE,CAAA;EAEP,GAAI;CACL,CAAA;AAEL"}
1
+ {"version":3,"file":"input-otp.js","names":[],"sources":["../../../../resources/js/form/components/base/input-otp.tsx"],"sourcesContent":["import { OTPInput, REGEXP_ONLY_DIGITS, type SlotProps } from \"input-otp\";\nimport type { ComponentProps } from \"react\";\nimport { cn } from \"@lattice-php/lattice/lib/utils\";\n\nfunction Slot({ char, hasFakeCaret, isActive }: SlotProps) {\n return (\n <div\n className={cn(\n \"relative flex h-lt-control-md w-10 items-center justify-center border-y border-r border-lt-input text-base shadow-lt-xs transition-all first:rounded-l-lt-sm first:border-l last:rounded-r-lt-sm\",\n isActive && \"z-10 border-lt-ring ring-lt-ring/50 ring-[3px]\",\n )}\n >\n {char}\n {hasFakeCaret ? (\n <div className=\"pointer-events-none absolute inset-0 flex items-center justify-center\">\n <div className=\"bg-lt-fg h-5 w-px animate-pulse\" />\n </div>\n ) : null}\n </div>\n );\n}\n\ntype InputOTPProps = Omit<ComponentProps<typeof OTPInput>, \"children\" | \"maxLength\" | \"render\"> & {\n length: number;\n};\n\nexport function InputOTP({\n length,\n containerClassName,\n pattern = REGEXP_ONLY_DIGITS,\n ...props\n}: InputOTPProps) {\n return (\n <OTPInput\n maxLength={length}\n pattern={pattern}\n containerClassName={cn(\n \"flex items-center gap-2 has-[:disabled]:opacity-50\",\n containerClassName,\n )}\n render={({ slots }) => (\n <div className=\"flex items-center\">\n {slots.map((slot, index) => (\n <Slot key={index} {...slot} />\n ))}\n </div>\n )}\n {...props}\n />\n );\n}\n"],"mappings":";;;;AAIA,SAAS,KAAK,EAAE,MAAM,cAAc,YAAuB;CACzD,OACE,qBAAC,OAAD;EACE,WAAW,GACT,oMACA,YAAY,gDACd;YAJF,CAMG,MACA,eACC,oBAAC,OAAD;GAAK,WAAU;aACb,oBAAC,OAAD,EAAK,WAAU,kCAAmC,CAAA;EAC/C,CAAA,IACH,IACD;;AAET;AAMA,SAAgB,SAAS,EACvB,QACA,oBACA,UAAU,oBACV,GAAG,SACa;CAChB,OACE,oBAAC,UAAD;EACE,WAAW;EACF;EACT,oBAAoB,GAClB,sDACA,kBACF;EACA,SAAS,EAAE,YACT,oBAAC,OAAD;GAAK,WAAU;aACZ,MAAM,KAAK,MAAM,UAChB,oBAAC,MAAD,EAAkB,GAAI,KAAO,GAAlB,KAAkB,CAC9B;EACE,CAAA;EAEP,GAAI;CACL,CAAA;AAEL"}
@@ -6,7 +6,7 @@ export type FieldConditions = {
6
6
  readOnly?: Condition[];
7
7
  disabled?: Condition[];
8
8
  };
9
- export type FieldFlags = {
9
+ type FieldFlags = {
10
10
  hidden?: boolean;
11
11
  required?: boolean;
12
12
  readOnly?: boolean;
@@ -1 +1 @@
1
- {"version":3,"file":"conditions.js","names":[],"sources":["../../../resources/js/form/components/conditions.ts"],"sourcesContent":["import type { Condition, Op } from \"@lattice-php/lattice/types/generated\";\n\nexport type { Condition };\n\nexport type FieldConditions = {\n visible?: Condition[];\n required?: Condition[];\n readOnly?: Condition[];\n disabled?: Condition[];\n};\n\nexport type FieldFlags = {\n hidden?: boolean;\n required?: boolean;\n readOnly?: boolean;\n disabled?: boolean;\n};\n\nexport type FieldState = {\n hidden: boolean;\n required: boolean;\n readOnly: boolean;\n disabled: boolean;\n};\n\nconst BOOLEAN_TRUE_VALUES = new Set([\"1\", \"true\", \"on\", \"yes\"]);\n\n// Mirrors PHP filter_var(FILTER_VALIDATE_BOOLEAN) so conditions evaluate\n// identically on the server and the client.\nexport function toBoolean(value: unknown): boolean {\n if (typeof value === \"boolean\") {\n return value;\n }\n\n if (typeof value === \"number\") {\n return value === 1;\n }\n\n return BOOLEAN_TRUE_VALUES.has(String(value).toLowerCase());\n}\n\nfunction equals(actual: unknown, expected: unknown): boolean {\n if (typeof expected === \"boolean\") {\n return toBoolean(actual) === expected;\n }\n return String(actual ?? \"\") === String(expected ?? \"\");\n}\n\nfunction isIn(actual: unknown, expected: unknown): boolean {\n const needles = (Array.isArray(expected) ? expected : [expected]).map((value) => String(value));\n return needles.includes(String(actual ?? \"\"));\n}\n\nfunction isBlank(value: unknown): boolean {\n return value == null || String(value).trim() === \"\";\n}\n\n// Null when either value can't be parsed, so before/after never matches a bad date. Mirrors PHP strtotime.\nfunction compareDates(actual: unknown, expected: unknown): number | null {\n const left = Date.parse(String(actual));\n const right = Date.parse(String(expected));\n\n if (Number.isNaN(left) || Number.isNaN(right)) {\n return null;\n }\n\n return left === right ? 0 : left < right ? -1 : 1;\n}\n\n// Unknown operators from untrusted payloads fail open (the condition matches).\n// The `never` parameter makes an Op value added without a case above a\n// compile error rather than a silent fall-through.\nfunction evaluateUnknownOperator(_operator: never): boolean {\n return true;\n}\n\nfunction evaluateOp(operator: Op, actual: unknown, expected: unknown): boolean {\n switch (operator) {\n case \"eq\":\n return equals(actual, expected);\n case \"neq\":\n return !equals(actual, expected);\n case \"gt\":\n return Number(actual) > Number(expected);\n case \"lt\":\n return Number(actual) < Number(expected);\n case \"gte\":\n return Number(actual) >= Number(expected);\n case \"lte\":\n return Number(actual) <= Number(expected);\n case \"contains\":\n return String(actual ?? \"\").includes(String(expected ?? \"\"));\n case \"starts_with\":\n return String(actual ?? \"\").startsWith(String(expected ?? \"\"));\n case \"ends_with\":\n return String(actual ?? \"\").endsWith(String(expected ?? \"\"));\n case \"in\":\n return isIn(actual, expected);\n case \"not_in\":\n return !isIn(actual, expected);\n case \"before\":\n return compareDates(actual, expected) === -1;\n case \"after\":\n return compareDates(actual, expected) === 1;\n case \"empty\":\n return isBlank(actual);\n case \"filled\":\n return !isBlank(actual);\n default:\n return evaluateUnknownOperator(operator);\n }\n}\n\nfunction allMatch(conditions: Condition[], values: Record<string, unknown>): boolean {\n return conditions.every((condition) =>\n evaluateOp(condition.operator, values[condition.field], condition.value),\n );\n}\n\nfunction anyMatch(conditions: Condition[] | undefined, values: Record<string, unknown>): boolean {\n return Boolean(\n conditions?.some((condition) =>\n evaluateOp(condition.operator, values[condition.field], condition.value),\n ),\n );\n}\n\nexport function evaluateConditions(\n conditions: FieldConditions | undefined,\n values: Record<string, unknown>,\n flags: FieldFlags,\n): FieldState {\n const visible = !conditions?.visible?.length || allMatch(conditions.visible, values);\n\n return {\n hidden: Boolean(flags.hidden) || !visible,\n required: Boolean(flags.required) || anyMatch(conditions?.required, values),\n readOnly: Boolean(flags.readOnly) || anyMatch(conditions?.readOnly, values),\n disabled: Boolean(flags.disabled) || anyMatch(conditions?.disabled, values),\n };\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"conditions.js","names":[],"sources":["../../../resources/js/form/components/conditions.ts"],"sourcesContent":["import type { Condition, Op } from \"@lattice-php/lattice/types/generated\";\n\nexport type { Condition };\n\nexport type FieldConditions = {\n visible?: Condition[];\n required?: Condition[];\n readOnly?: Condition[];\n disabled?: Condition[];\n};\n\ntype FieldFlags = {\n hidden?: boolean;\n required?: boolean;\n readOnly?: boolean;\n disabled?: boolean;\n};\n\nexport type FieldState = {\n hidden: boolean;\n required: boolean;\n readOnly: boolean;\n disabled: boolean;\n};\n\nconst BOOLEAN_TRUE_VALUES = new Set([\"1\", \"true\", \"on\", \"yes\"]);\n\n// Mirrors PHP filter_var(FILTER_VALIDATE_BOOLEAN) so conditions evaluate\n// identically on the server and the client.\nexport function toBoolean(value: unknown): boolean {\n if (typeof value === \"boolean\") {\n return value;\n }\n\n if (typeof value === \"number\") {\n return value === 1;\n }\n\n return BOOLEAN_TRUE_VALUES.has(String(value).toLowerCase());\n}\n\nfunction equals(actual: unknown, expected: unknown): boolean {\n if (typeof expected === \"boolean\") {\n return toBoolean(actual) === expected;\n }\n return String(actual ?? \"\") === String(expected ?? \"\");\n}\n\nfunction isIn(actual: unknown, expected: unknown): boolean {\n const needles = (Array.isArray(expected) ? expected : [expected]).map((value) => String(value));\n return needles.includes(String(actual ?? \"\"));\n}\n\nfunction isBlank(value: unknown): boolean {\n return value == null || String(value).trim() === \"\";\n}\n\n// Null when either value can't be parsed, so before/after never matches a bad date. Mirrors PHP strtotime.\nfunction compareDates(actual: unknown, expected: unknown): number | null {\n const left = Date.parse(String(actual));\n const right = Date.parse(String(expected));\n\n if (Number.isNaN(left) || Number.isNaN(right)) {\n return null;\n }\n\n return left === right ? 0 : left < right ? -1 : 1;\n}\n\n// Unknown operators from untrusted payloads fail open (the condition matches).\n// The `never` parameter makes an Op value added without a case above a\n// compile error rather than a silent fall-through.\nfunction evaluateUnknownOperator(_operator: never): boolean {\n return true;\n}\n\nfunction evaluateOp(operator: Op, actual: unknown, expected: unknown): boolean {\n switch (operator) {\n case \"eq\":\n return equals(actual, expected);\n case \"neq\":\n return !equals(actual, expected);\n case \"gt\":\n return Number(actual) > Number(expected);\n case \"lt\":\n return Number(actual) < Number(expected);\n case \"gte\":\n return Number(actual) >= Number(expected);\n case \"lte\":\n return Number(actual) <= Number(expected);\n case \"contains\":\n return String(actual ?? \"\").includes(String(expected ?? \"\"));\n case \"starts_with\":\n return String(actual ?? \"\").startsWith(String(expected ?? \"\"));\n case \"ends_with\":\n return String(actual ?? \"\").endsWith(String(expected ?? \"\"));\n case \"in\":\n return isIn(actual, expected);\n case \"not_in\":\n return !isIn(actual, expected);\n case \"before\":\n return compareDates(actual, expected) === -1;\n case \"after\":\n return compareDates(actual, expected) === 1;\n case \"empty\":\n return isBlank(actual);\n case \"filled\":\n return !isBlank(actual);\n default:\n return evaluateUnknownOperator(operator);\n }\n}\n\nfunction allMatch(conditions: Condition[], values: Record<string, unknown>): boolean {\n return conditions.every((condition) =>\n evaluateOp(condition.operator, values[condition.field], condition.value),\n );\n}\n\nfunction anyMatch(conditions: Condition[] | undefined, values: Record<string, unknown>): boolean {\n return Boolean(\n conditions?.some((condition) =>\n evaluateOp(condition.operator, values[condition.field], condition.value),\n ),\n );\n}\n\nexport function evaluateConditions(\n conditions: FieldConditions | undefined,\n values: Record<string, unknown>,\n flags: FieldFlags,\n): FieldState {\n const visible = !conditions?.visible?.length || allMatch(conditions.visible, values);\n\n return {\n hidden: Boolean(flags.hidden) || !visible,\n required: Boolean(flags.required) || anyMatch(conditions?.required, values),\n readOnly: Boolean(flags.readOnly) || anyMatch(conditions?.readOnly, values),\n disabled: Boolean(flags.disabled) || anyMatch(conditions?.disabled, values),\n };\n}\n"],"mappings":"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"}
@@ -6,7 +6,7 @@ import { FieldConditions } from './conditions';
6
6
  * lens the shared hooks read them through. Everything is optional because the
7
7
  * lens is also applied to non-field nodes while walking the schema.
8
8
  */
9
- export type FieldProps = {
9
+ type FieldProps = {
10
10
  conditions?: FieldConditions | null;
11
11
  dependsOnAny?: boolean | null;
12
12
  dependsOnKeys?: string[] | null;
@@ -25,3 +25,4 @@ export type FieldProps = {
25
25
  };
26
26
  export declare function fieldProps(node: Node): FieldProps;
27
27
  export declare function walkFields(nodes: Node[] | undefined, visit: (props: FieldProps, node: Node) => void): void;
28
+ export {};
@@ -1 +1 @@
1
- {"version":3,"file":"field-props.js","names":[],"sources":["../../../resources/js/form/components/field-props.ts"],"sourcesContent":["import type { Node } from \"@lattice-php/lattice/core/types\";\nimport type { FieldConditions } from \"./conditions\";\n\n/**\n * The props every form-field node shares (the PHP Field base). Nodes flow through\n * the form framework loosely typed via the generic schema, so this is the typed\n * lens the shared hooks read them through. Everything is optional because the\n * lens is also applied to non-field nodes while walking the schema.\n */\nexport type FieldProps = {\n conditions?: FieldConditions | null;\n dependsOnAny?: boolean | null;\n dependsOnKeys?: string[] | null;\n disabled?: boolean | null;\n helperText?: string | null;\n hidden?: boolean | null;\n label?: string | null;\n name?: string;\n editablePrefill?: boolean | null;\n prefillRefreshOn?: string[] | null;\n prefillResetOn?: string[] | null;\n readOnly?: boolean | null;\n required?: boolean | null;\n tooltip?: string | null;\n value?: unknown;\n};\n\nexport function fieldProps(node: Node): FieldProps {\n return node.props as FieldProps;\n}\n\nexport function walkFields(\n nodes: Node[] | undefined,\n visit: (props: FieldProps, node: Node) => void,\n): void {\n for (const child of nodes ?? []) {\n visit(fieldProps(child), child);\n walkFields(child.schema, visit);\n }\n}\n"],"mappings":";AA2BA,SAAgB,WAAW,MAAwB;CACjD,OAAO,KAAK;AACd;AAEA,SAAgB,WACd,OACA,OACM;CACN,KAAK,MAAM,SAAS,SAAS,CAAC,GAAG;EAC/B,MAAM,WAAW,KAAK,GAAG,KAAK;EAC9B,WAAW,MAAM,QAAQ,KAAK;CAChC;AACF"}
1
+ {"version":3,"file":"field-props.js","names":[],"sources":["../../../resources/js/form/components/field-props.ts"],"sourcesContent":["import type { Node } from \"@lattice-php/lattice/core/types\";\nimport type { FieldConditions } from \"./conditions\";\n\n/**\n * The props every form-field node shares (the PHP Field base). Nodes flow through\n * the form framework loosely typed via the generic schema, so this is the typed\n * lens the shared hooks read them through. Everything is optional because the\n * lens is also applied to non-field nodes while walking the schema.\n */\ntype FieldProps = {\n conditions?: FieldConditions | null;\n dependsOnAny?: boolean | null;\n dependsOnKeys?: string[] | null;\n disabled?: boolean | null;\n helperText?: string | null;\n hidden?: boolean | null;\n label?: string | null;\n name?: string;\n editablePrefill?: boolean | null;\n prefillRefreshOn?: string[] | null;\n prefillResetOn?: string[] | null;\n readOnly?: boolean | null;\n required?: boolean | null;\n tooltip?: string | null;\n value?: unknown;\n};\n\nexport function fieldProps(node: Node): FieldProps {\n return node.props as FieldProps;\n}\n\nexport function walkFields(\n nodes: Node[] | undefined,\n visit: (props: FieldProps, node: Node) => void,\n): void {\n for (const child of nodes ?? []) {\n visit(fieldProps(child), child);\n walkFields(child.schema, visit);\n }\n}\n"],"mappings":";AA2BA,SAAgB,WAAW,MAAwB;CACjD,OAAO,KAAK;AACd;AAEA,SAAgB,WACd,OACA,OACM;CACN,KAAK,MAAM,SAAS,SAAS,CAAC,GAAG;EAC/B,MAAM,WAAW,KAAK,GAAG,KAAK;EAC9B,WAAW,MAAM,QAAQ,KAAK;CAChC;AACF"}
@@ -1,4 +1,4 @@
1
- export type FieldScopeValue = {
1
+ type FieldScopeValue = {
2
2
  row: Record<string, unknown>;
3
3
  rowId: string | null;
4
4
  path: string;
@@ -19,3 +19,4 @@ export declare function FieldScopeProvider({ base, index, row, onChange, childre
19
19
  }): import("react").JSX.Element;
20
20
  /** Null outside a row so callers can preserve top-level behavior without a wrapper. */
21
21
  export declare function useFieldScope(): FieldScopeValue | null;
22
+ export {};
@@ -1 +1 @@
1
- {"version":3,"file":"field-scope.js","names":[],"sources":["../../../resources/js/form/components/field-scope.tsx"],"sourcesContent":["import { createContext, useContext, useMemo } from \"react\";\nimport { appendPath, getPath, toHtmlName } from \"./form-path\";\nimport { buildOverrideKey, rowIdFrom } from \"./override-keys\";\n\nexport type FieldScopeValue = {\n row: Record<string, unknown>;\n rowId: string | null;\n path: string;\n values: Record<string, unknown>;\n identityPath: string;\n getValue: (name: string) => unknown;\n setValue: (name: string, value: unknown) => void;\n scopedName: (name: string) => string;\n errorKey: (name: string) => string;\n overrideKey: (name: string) => string;\n};\n\nconst FieldScopeContext = createContext<FieldScopeValue | null>(null);\n\nfunction childCollectionIdentity(base: string, parent: FieldScopeValue | null): string {\n if (!parent) {\n return base;\n }\n\n const local = base.startsWith(`${parent.path}.`) ? base.slice(parent.path.length + 1) : base;\n\n return appendPath(parent.identityPath, local);\n}\n\nexport function FieldScopeProvider({\n base,\n index,\n row,\n onChange,\n children,\n}: {\n base: string;\n index: number;\n row: Record<string, unknown>;\n onChange: (name: string, value: unknown) => void;\n children: React.ReactNode;\n}) {\n const parent = useContext(FieldScopeContext);\n\n const value = useMemo<FieldScopeValue>(() => {\n const scopedRow = row ?? {};\n const rowId = rowIdFrom(scopedRow);\n const path = appendPath(base, index);\n const identityCollection = childCollectionIdentity(base, parent);\n const identityPath = appendPath(identityCollection, rowId ?? index);\n\n return {\n row: scopedRow,\n rowId,\n path,\n values: parent ? { ...parent.values, ...scopedRow } : scopedRow,\n identityPath,\n getValue: (name) => getPath(scopedRow, name),\n setValue: onChange,\n scopedName: (name) => toHtmlName(appendPath(path, name)),\n errorKey: (name) => appendPath(path, name),\n overrideKey: (name) => buildOverrideKey(identityCollection, rowId, index, name),\n };\n }, [base, index, row, onChange, parent]);\n\n return <FieldScopeContext.Provider value={value}>{children}</FieldScopeContext.Provider>;\n}\n\n/** Null outside a row so callers can preserve top-level behavior without a wrapper. */\nexport function useFieldScope(): FieldScopeValue | null {\n return useContext(FieldScopeContext);\n}\n"],"mappings":";;;;;AAiBA,IAAM,oBAAoB,cAAsC,IAAI;AAEpE,SAAS,wBAAwB,MAAc,QAAwC;CACrF,IAAI,CAAC,QACH,OAAO;CAGT,MAAM,QAAQ,KAAK,WAAW,GAAG,OAAO,KAAK,EAAE,IAAI,KAAK,MAAM,OAAO,KAAK,SAAS,CAAC,IAAI;CAExF,OAAO,WAAW,OAAO,cAAc,KAAK;AAC9C;AAEA,SAAgB,mBAAmB,EACjC,MACA,OACA,KACA,UACA,YAOC;CACD,MAAM,SAAS,WAAW,iBAAiB;CAE3C,MAAM,QAAQ,cAA+B;EAC3C,MAAM,YAAY,OAAO,CAAC;EAC1B,MAAM,QAAQ,UAAU,SAAS;EACjC,MAAM,OAAO,WAAW,MAAM,KAAK;EACnC,MAAM,qBAAqB,wBAAwB,MAAM,MAAM;EAC/D,MAAM,eAAe,WAAW,oBAAoB,SAAS,KAAK;EAElE,OAAO;GACL,KAAK;GACL;GACA;GACA,QAAQ,SAAS;IAAE,GAAG,OAAO;IAAQ,GAAG;GAAU,IAAI;GACtD;GACA,WAAW,SAAS,QAAQ,WAAW,IAAI;GAC3C,UAAU;GACV,aAAa,SAAS,WAAW,WAAW,MAAM,IAAI,CAAC;GACvD,WAAW,SAAS,WAAW,MAAM,IAAI;GACzC,cAAc,SAAS,iBAAiB,oBAAoB,OAAO,OAAO,IAAI;EAChF;CACF,GAAG;EAAC;EAAM;EAAO;EAAK;EAAU;CAAM,CAAC;CAEvC,OAAO,oBAAC,kBAAkB,UAAnB;EAAmC;EAAQ;CAAqC,CAAA;AACzF;;AAGA,SAAgB,gBAAwC;CACtD,OAAO,WAAW,iBAAiB;AACrC"}
1
+ {"version":3,"file":"field-scope.js","names":[],"sources":["../../../resources/js/form/components/field-scope.tsx"],"sourcesContent":["import { createContext, useContext, useMemo } from \"react\";\nimport { appendPath, getPath, toHtmlName } from \"./form-path\";\nimport { buildOverrideKey, rowIdFrom } from \"./override-keys\";\n\ntype FieldScopeValue = {\n row: Record<string, unknown>;\n rowId: string | null;\n path: string;\n values: Record<string, unknown>;\n identityPath: string;\n getValue: (name: string) => unknown;\n setValue: (name: string, value: unknown) => void;\n scopedName: (name: string) => string;\n errorKey: (name: string) => string;\n overrideKey: (name: string) => string;\n};\n\nconst FieldScopeContext = createContext<FieldScopeValue | null>(null);\n\nfunction childCollectionIdentity(base: string, parent: FieldScopeValue | null): string {\n if (!parent) {\n return base;\n }\n\n const local = base.startsWith(`${parent.path}.`) ? base.slice(parent.path.length + 1) : base;\n\n return appendPath(parent.identityPath, local);\n}\n\nexport function FieldScopeProvider({\n base,\n index,\n row,\n onChange,\n children,\n}: {\n base: string;\n index: number;\n row: Record<string, unknown>;\n onChange: (name: string, value: unknown) => void;\n children: React.ReactNode;\n}) {\n const parent = useContext(FieldScopeContext);\n\n const value = useMemo<FieldScopeValue>(() => {\n const scopedRow = row ?? {};\n const rowId = rowIdFrom(scopedRow);\n const path = appendPath(base, index);\n const identityCollection = childCollectionIdentity(base, parent);\n const identityPath = appendPath(identityCollection, rowId ?? index);\n\n return {\n row: scopedRow,\n rowId,\n path,\n values: parent ? { ...parent.values, ...scopedRow } : scopedRow,\n identityPath,\n getValue: (name) => getPath(scopedRow, name),\n setValue: onChange,\n scopedName: (name) => toHtmlName(appendPath(path, name)),\n errorKey: (name) => appendPath(path, name),\n overrideKey: (name) => buildOverrideKey(identityCollection, rowId, index, name),\n };\n }, [base, index, row, onChange, parent]);\n\n return <FieldScopeContext.Provider value={value}>{children}</FieldScopeContext.Provider>;\n}\n\n/** Null outside a row so callers can preserve top-level behavior without a wrapper. */\nexport function useFieldScope(): FieldScopeValue | null {\n return useContext(FieldScopeContext);\n}\n"],"mappings":";;;;;AAiBA,IAAM,oBAAoB,cAAsC,IAAI;AAEpE,SAAS,wBAAwB,MAAc,QAAwC;CACrF,IAAI,CAAC,QACH,OAAO;CAGT,MAAM,QAAQ,KAAK,WAAW,GAAG,OAAO,KAAK,EAAE,IAAI,KAAK,MAAM,OAAO,KAAK,SAAS,CAAC,IAAI;CAExF,OAAO,WAAW,OAAO,cAAc,KAAK;AAC9C;AAEA,SAAgB,mBAAmB,EACjC,MACA,OACA,KACA,UACA,YAOC;CACD,MAAM,SAAS,WAAW,iBAAiB;CAE3C,MAAM,QAAQ,cAA+B;EAC3C,MAAM,YAAY,OAAO,CAAC;EAC1B,MAAM,QAAQ,UAAU,SAAS;EACjC,MAAM,OAAO,WAAW,MAAM,KAAK;EACnC,MAAM,qBAAqB,wBAAwB,MAAM,MAAM;EAC/D,MAAM,eAAe,WAAW,oBAAoB,SAAS,KAAK;EAElE,OAAO;GACL,KAAK;GACL;GACA;GACA,QAAQ,SAAS;IAAE,GAAG,OAAO;IAAQ,GAAG;GAAU,IAAI;GACtD;GACA,WAAW,SAAS,QAAQ,WAAW,IAAI;GAC3C,UAAU;GACV,aAAa,SAAS,WAAW,WAAW,MAAM,IAAI,CAAC;GACvD,WAAW,SAAS,WAAW,MAAM,IAAI;GACzC,cAAc,SAAS,iBAAiB,oBAAoB,OAAO,OAAO,IAAI;EAChF;CACF,GAAG;EAAC;EAAM;EAAO;EAAK;EAAU;CAAM,CAAC;CAEvC,OAAO,oBAAC,kBAAkB,UAAnB;EAAmC;EAAQ;CAAqC,CAAA;AACzF;;AAGA,SAAgB,gBAAwC;CACtD,OAAO,WAAW,iBAAiB;AACrC"}
@@ -1,6 +1,6 @@
1
1
  import { RowAction as WireRowAction } from '../../../types/generated';
2
2
  import { RowAction } from './row-actions';
3
- export type RowActionTranslate = (key: string, fallback: string) => string;
3
+ type RowActionTranslate = (key: string, fallback: string) => string;
4
4
  export type RowActionContext = {
5
5
  index: number;
6
6
  removable: boolean;
@@ -15,3 +15,4 @@ export type RowActionContext = {
15
15
  * minimum, and built-in labels resolve through i18n when the server sends none.
16
16
  */
17
17
  export declare function buildRowActions(declared: WireRowAction[] | null, ctx: RowActionContext): RowAction[];
18
+ export {};
@@ -1 +1 @@
1
- {"version":3,"file":"row-action-menu.js","names":[],"sources":["../../../../resources/js/form/components/fields/row-action-menu.ts"],"sourcesContent":["import type { RowAction as WireRowAction } from \"@lattice-php/lattice/types/generated\";\nimport type { RowAction } from \"./row-actions\";\n\nexport type RowActionTranslate = (key: string, fallback: string) => string;\n\n/** Translation key + fallback and icon for each built-in; the server sends null labels. */\nconst BUILT_IN: Record<\"duplicate\" | \"remove\", { key: string; fallback: string; icon: string }> = {\n duplicate: { key: \"table.rowActions.duplicate\", fallback: \"Duplicate\", icon: \"copy\" },\n remove: { key: \"table.rowActions.remove\", fallback: \"Remove\", icon: \"trash-2\" },\n};\n\nexport type RowActionContext = {\n index: number;\n removable: boolean;\n onRemove: (index: number) => void;\n onDuplicate: (index: number) => void;\n t: RowActionTranslate;\n};\n\n/**\n * Resolves the declared wire row actions into the click-wired client actions the\n * kebab renders. `null` (undeclared) falls back to the built-in remove; an empty\n * array disables row actions entirely. Remove is dropped while the row is at its\n * minimum, and built-in labels resolve through i18n when the server sends none.\n */\nexport function buildRowActions(\n declared: WireRowAction[] | null,\n ctx: RowActionContext,\n): RowAction[] {\n const source = declared ?? defaultActions(ctx.removable);\n\n return source\n .map((action) => toClientAction(action, ctx))\n .filter((action): action is RowAction => action !== null);\n}\n\nfunction defaultActions(removable: boolean): WireRowAction[] {\n if (!removable) {\n return [];\n }\n\n return [{ type: \"remove\", key: \"remove\", label: null, icon: null, destructive: true }];\n}\n\nfunction toClientAction(action: WireRowAction, ctx: RowActionContext): RowAction | null {\n if (action.type === \"duplicate\") {\n const builtIn = BUILT_IN.duplicate;\n\n return {\n key: action.key,\n label: action.label ?? ctx.t(builtIn.key, builtIn.fallback),\n icon: action.icon ?? builtIn.icon,\n destructive: action.destructive,\n onClick: () => ctx.onDuplicate(ctx.index),\n };\n }\n\n if (action.type === \"remove\") {\n if (!ctx.removable) {\n return null;\n }\n\n const builtIn = BUILT_IN.remove;\n\n return {\n key: action.key,\n label: action.label ?? ctx.t(builtIn.key, builtIn.fallback),\n icon: action.icon ?? builtIn.icon,\n destructive: action.destructive,\n onClick: () => ctx.onRemove(ctx.index),\n };\n }\n\n return null;\n}\n"],"mappings":";;AAMA,IAAM,WAA4F;CAChG,WAAW;EAAE,KAAK;EAA8B,UAAU;EAAa,MAAM;CAAO;CACpF,QAAQ;EAAE,KAAK;EAA2B,UAAU;EAAU,MAAM;CAAU;AAChF;;;;;;;AAgBA,SAAgB,gBACd,UACA,KACa;CAGb,QAFe,YAAY,eAAe,IAAI,SAAS,GAGpD,KAAK,WAAW,eAAe,QAAQ,GAAG,CAAC,EAC3C,QAAQ,WAAgC,WAAW,IAAI;AAC5D;AAEA,SAAS,eAAe,WAAqC;CAC3D,IAAI,CAAC,WACH,OAAO,CAAC;CAGV,OAAO,CAAC;EAAE,MAAM;EAAU,KAAK;EAAU,OAAO;EAAM,MAAM;EAAM,aAAa;CAAK,CAAC;AACvF;AAEA,SAAS,eAAe,QAAuB,KAAyC;CACtF,IAAI,OAAO,SAAS,aAAa;EAC/B,MAAM,UAAU,SAAS;EAEzB,OAAO;GACL,KAAK,OAAO;GACZ,OAAO,OAAO,SAAS,IAAI,EAAE,QAAQ,KAAK,QAAQ,QAAQ;GAC1D,MAAM,OAAO,QAAQ,QAAQ;GAC7B,aAAa,OAAO;GACpB,eAAe,IAAI,YAAY,IAAI,KAAK;EAC1C;CACF;CAEA,IAAI,OAAO,SAAS,UAAU;EAC5B,IAAI,CAAC,IAAI,WACP,OAAO;EAGT,MAAM,UAAU,SAAS;EAEzB,OAAO;GACL,KAAK,OAAO;GACZ,OAAO,OAAO,SAAS,IAAI,EAAE,QAAQ,KAAK,QAAQ,QAAQ;GAC1D,MAAM,OAAO,QAAQ,QAAQ;GAC7B,aAAa,OAAO;GACpB,eAAe,IAAI,SAAS,IAAI,KAAK;EACvC;CACF;CAEA,OAAO;AACT"}
1
+ {"version":3,"file":"row-action-menu.js","names":[],"sources":["../../../../resources/js/form/components/fields/row-action-menu.ts"],"sourcesContent":["import type { RowAction as WireRowAction } from \"@lattice-php/lattice/types/generated\";\nimport type { RowAction } from \"./row-actions\";\n\ntype RowActionTranslate = (key: string, fallback: string) => string;\n\n/** Translation key + fallback and icon for each built-in; the server sends null labels. */\nconst BUILT_IN: Record<\"duplicate\" | \"remove\", { key: string; fallback: string; icon: string }> = {\n duplicate: { key: \"table.rowActions.duplicate\", fallback: \"Duplicate\", icon: \"copy\" },\n remove: { key: \"table.rowActions.remove\", fallback: \"Remove\", icon: \"trash-2\" },\n};\n\nexport type RowActionContext = {\n index: number;\n removable: boolean;\n onRemove: (index: number) => void;\n onDuplicate: (index: number) => void;\n t: RowActionTranslate;\n};\n\n/**\n * Resolves the declared wire row actions into the click-wired client actions the\n * kebab renders. `null` (undeclared) falls back to the built-in remove; an empty\n * array disables row actions entirely. Remove is dropped while the row is at its\n * minimum, and built-in labels resolve through i18n when the server sends none.\n */\nexport function buildRowActions(\n declared: WireRowAction[] | null,\n ctx: RowActionContext,\n): RowAction[] {\n const source = declared ?? defaultActions(ctx.removable);\n\n return source\n .map((action) => toClientAction(action, ctx))\n .filter((action): action is RowAction => action !== null);\n}\n\nfunction defaultActions(removable: boolean): WireRowAction[] {\n if (!removable) {\n return [];\n }\n\n return [{ type: \"remove\", key: \"remove\", label: null, icon: null, destructive: true }];\n}\n\nfunction toClientAction(action: WireRowAction, ctx: RowActionContext): RowAction | null {\n if (action.type === \"duplicate\") {\n const builtIn = BUILT_IN.duplicate;\n\n return {\n key: action.key,\n label: action.label ?? ctx.t(builtIn.key, builtIn.fallback),\n icon: action.icon ?? builtIn.icon,\n destructive: action.destructive,\n onClick: () => ctx.onDuplicate(ctx.index),\n };\n }\n\n if (action.type === \"remove\") {\n if (!ctx.removable) {\n return null;\n }\n\n const builtIn = BUILT_IN.remove;\n\n return {\n key: action.key,\n label: action.label ?? ctx.t(builtIn.key, builtIn.fallback),\n icon: action.icon ?? builtIn.icon,\n destructive: action.destructive,\n onClick: () => ctx.onRemove(ctx.index),\n };\n }\n\n return null;\n}\n"],"mappings":";;AAMA,IAAM,WAA4F;CAChG,WAAW;EAAE,KAAK;EAA8B,UAAU;EAAa,MAAM;CAAO;CACpF,QAAQ;EAAE,KAAK;EAA2B,UAAU;EAAU,MAAM;CAAU;AAChF;;;;;;;AAgBA,SAAgB,gBACd,UACA,KACa;CAGb,QAFe,YAAY,eAAe,IAAI,SAAS,GAGpD,KAAK,WAAW,eAAe,QAAQ,GAAG,CAAC,EAC3C,QAAQ,WAAgC,WAAW,IAAI;AAC5D;AAEA,SAAS,eAAe,WAAqC;CAC3D,IAAI,CAAC,WACH,OAAO,CAAC;CAGV,OAAO,CAAC;EAAE,MAAM;EAAU,KAAK;EAAU,OAAO;EAAM,MAAM;EAAM,aAAa;CAAK,CAAC;AACvF;AAEA,SAAS,eAAe,QAAuB,KAAyC;CACtF,IAAI,OAAO,SAAS,aAAa;EAC/B,MAAM,UAAU,SAAS;EAEzB,OAAO;GACL,KAAK,OAAO;GACZ,OAAO,OAAO,SAAS,IAAI,EAAE,QAAQ,KAAK,QAAQ,QAAQ;GAC1D,MAAM,OAAO,QAAQ,QAAQ;GAC7B,aAAa,OAAO;GACpB,eAAe,IAAI,YAAY,IAAI,KAAK;EAC1C;CACF;CAEA,IAAI,OAAO,SAAS,UAAU;EAC5B,IAAI,CAAC,IAAI,WACP,OAAO;EAGT,MAAM,UAAU,SAAS;EAEzB,OAAO;GACL,KAAK,OAAO;GACZ,OAAO,OAAO,SAAS,IAAI,EAAE,QAAQ,KAAK,QAAQ,QAAQ;GAC1D,MAAM,OAAO,QAAQ,QAAQ;GAC7B,aAAa,OAAO;GACpB,eAAe,IAAI,SAAS,IAAI,KAAK;EACvC;CACF;CAEA,OAAO;AACT"}
@@ -8,7 +8,7 @@ export declare function RowButton({ label, testId, onClick, children, }: {
8
8
  onClick: () => void;
9
9
  children: ReactNode;
10
10
  }): import("react").JSX.Element;
11
- export type RowItemProps = {
11
+ type RowItemProps = {
12
12
  base: string;
13
13
  index: number;
14
14
  row: RepeaterRow;
@@ -25,3 +25,4 @@ export type RowItemProps = {
25
25
  onDuplicate: (index: number) => void;
26
26
  };
27
27
  export declare const RowItem: import('react').MemoExoticComponent<({ base, index, row, template, heading, reorderable, isFirst, isLast, removable, rowActions, onField, onRemove, onMove, onDuplicate, }: RowItemProps) => import("react").JSX.Element>;
28
+ export {};
@@ -1 +1 @@
1
- {"version":3,"file":"row-item.js","names":[],"sources":["../../../../resources/js/form/components/fields/row-item.tsx"],"sourcesContent":["import { Icon } from \"@lattice-php/lattice/icons\";\nimport type { ReactNode } from \"react\";\nimport { memo } from \"react\";\nimport type { Node } from \"@lattice-php/lattice/core/types\";\nimport { RenderNode } from \"@lattice-php/lattice/core/renderer\";\nimport { useT } from \"@lattice-php/lattice/i18n\";\nimport type { RowAction as WireRowAction } from \"@lattice-php/lattice/types/generated\";\nimport { FieldScopeProvider } from \"../field-scope\";\nimport { buildRowActions } from \"./row-action-menu\";\nimport { RowActions } from \"./row-actions\";\nimport type { RepeaterRow } from \"./repeater-rows\";\n\nexport function RowButton({\n label,\n testId,\n onClick,\n children,\n}: {\n label: string;\n testId: string;\n onClick: () => void;\n children: ReactNode;\n}) {\n return (\n <button\n type=\"button\"\n aria-label={label}\n data-test={testId}\n className=\"text-lt-muted-fg hover:text-lt-fg\"\n onClick={onClick}\n >\n {children}\n </button>\n );\n}\n\nexport type RowItemProps = {\n base: string;\n index: number;\n row: RepeaterRow;\n template: Node[];\n heading: string;\n reorderable: boolean;\n isFirst: boolean;\n isLast: boolean;\n removable: boolean;\n rowActions: WireRowAction[] | null;\n onField: (index: number, field: string, value: unknown) => void;\n onRemove: (index: number) => void;\n onMove: (index: number, delta: number) => void;\n onDuplicate: (index: number) => void;\n};\n\n// Memoised so editing one row doesn't re-render its siblings. Its props are kept\n// referentially stable by the parent: `row` survives untouched via functional\n// store updates, and the handlers are `useCallback`-stable.\nexport const RowItem = memo(function RowItem({\n base,\n index,\n row,\n template,\n heading,\n reorderable,\n isFirst,\n isLast,\n removable,\n rowActions,\n onField,\n onRemove,\n onMove,\n onDuplicate,\n}: RowItemProps) {\n const { t } = useT(\"lattice\");\n\n return (\n <div\n data-test={`repeater-${base}-row-${index}`}\n className=\"rounded-lt border border-lt-border bg-lt-surface p-4\"\n >\n <div className=\"mb-2 flex items-center justify-between\">\n <span className=\"text-sm font-medium text-lt-muted-fg\">{heading}</span>\n <div className=\"flex items-center gap-1 [&_svg]:size-lt-icon-sm\">\n {reorderable && !isFirst && (\n <RowButton\n label=\"Move up\"\n testId={`repeater-${base}-up-${index}`}\n onClick={() => onMove(index, -1)}\n >\n <Icon name=\"arrow-up\" />\n </RowButton>\n )}\n {reorderable && !isLast && (\n <RowButton\n label=\"Move down\"\n testId={`repeater-${base}-down-${index}`}\n onClick={() => onMove(index, 1)}\n >\n <Icon name=\"arrow-down\" />\n </RowButton>\n )}\n <RowActions\n actions={buildRowActions(rowActions, { index, removable, onRemove, onDuplicate, t })}\n />\n </div>\n </div>\n\n <FieldScopeProvider\n base={base}\n index={index}\n row={row}\n onChange={(field, value) => onField(index, field, value)}\n >\n <div className=\"flex flex-col gap-4\">\n {template.map((child) => (\n <RenderNode key={child.key ?? child.id} node={child} />\n ))}\n </div>\n </FieldScopeProvider>\n </div>\n );\n});\n"],"mappings":";;;;;;;;;AAYA,SAAgB,UAAU,EACxB,OACA,QACA,SACA,YAMC;CACD,OACE,oBAAC,UAAD;EACE,MAAK;EACL,cAAY;EACZ,aAAW;EACX,WAAU;EACD;EAER;CACK,CAAA;AAEZ;AAsBA,IAAa,UAAU,KAAK,SAAS,QAAQ,EAC3C,MACA,OACA,KACA,UACA,SACA,aACA,SACA,QACA,WACA,YACA,SACA,UACA,QACA,eACe;CACf,MAAM,EAAE,MAAM,KAAK,SAAS;CAE5B,OACE,qBAAC,OAAD;EACE,aAAW,YAAY,KAAK,OAAO;EACnC,WAAU;YAFZ,CAIE,qBAAC,OAAD;GAAK,WAAU;aAAf,CACE,oBAAC,QAAD;IAAM,WAAU;cAAwC;GAAc,CAAA,GACtE,qBAAC,OAAD;IAAK,WAAU;cAAf;KACG,eAAe,CAAC,WACf,oBAAC,WAAD;MACE,OAAM;MACN,QAAQ,YAAY,KAAK,MAAM;MAC/B,eAAe,OAAO,OAAO,EAAE;gBAE/B,oBAAC,MAAD,EAAM,MAAK,WAAY,CAAA;KACd,CAAA;KAEZ,eAAe,CAAC,UACf,oBAAC,WAAD;MACE,OAAM;MACN,QAAQ,YAAY,KAAK,QAAQ;MACjC,eAAe,OAAO,OAAO,CAAC;gBAE9B,oBAAC,MAAD,EAAM,MAAK,aAAc,CAAA;KAChB,CAAA;KAEb,oBAAC,YAAD,EACE,SAAS,gBAAgB,YAAY;MAAE;MAAO;MAAW;MAAU;MAAa;KAAE,CAAC,EACpF,CAAA;IACE;KACF;MAEL,oBAAC,oBAAD;GACQ;GACC;GACF;GACL,WAAW,OAAO,UAAU,QAAQ,OAAO,OAAO,KAAK;aAEvD,oBAAC,OAAD;IAAK,WAAU;cACZ,SAAS,KAAK,UACb,oBAAC,YAAD,EAAwC,MAAM,MAAQ,GAArC,MAAM,OAAO,MAAM,EAAkB,CACvD;GACE,CAAA;EACa,CAAA,CACjB;;AAET,CAAC"}
1
+ {"version":3,"file":"row-item.js","names":[],"sources":["../../../../resources/js/form/components/fields/row-item.tsx"],"sourcesContent":["import { Icon } from \"@lattice-php/lattice/icons\";\nimport type { ReactNode } from \"react\";\nimport { memo } from \"react\";\nimport type { Node } from \"@lattice-php/lattice/core/types\";\nimport { RenderNode } from \"@lattice-php/lattice/core/renderer\";\nimport { useT } from \"@lattice-php/lattice/i18n\";\nimport type { RowAction as WireRowAction } from \"@lattice-php/lattice/types/generated\";\nimport { FieldScopeProvider } from \"../field-scope\";\nimport { buildRowActions } from \"./row-action-menu\";\nimport { RowActions } from \"./row-actions\";\nimport type { RepeaterRow } from \"./repeater-rows\";\n\nexport function RowButton({\n label,\n testId,\n onClick,\n children,\n}: {\n label: string;\n testId: string;\n onClick: () => void;\n children: ReactNode;\n}) {\n return (\n <button\n type=\"button\"\n aria-label={label}\n data-test={testId}\n className=\"text-lt-muted-fg hover:text-lt-fg\"\n onClick={onClick}\n >\n {children}\n </button>\n );\n}\n\ntype RowItemProps = {\n base: string;\n index: number;\n row: RepeaterRow;\n template: Node[];\n heading: string;\n reorderable: boolean;\n isFirst: boolean;\n isLast: boolean;\n removable: boolean;\n rowActions: WireRowAction[] | null;\n onField: (index: number, field: string, value: unknown) => void;\n onRemove: (index: number) => void;\n onMove: (index: number, delta: number) => void;\n onDuplicate: (index: number) => void;\n};\n\n// Memoised so editing one row doesn't re-render its siblings. Its props are kept\n// referentially stable by the parent: `row` survives untouched via functional\n// store updates, and the handlers are `useCallback`-stable.\nexport const RowItem = memo(function RowItem({\n base,\n index,\n row,\n template,\n heading,\n reorderable,\n isFirst,\n isLast,\n removable,\n rowActions,\n onField,\n onRemove,\n onMove,\n onDuplicate,\n}: RowItemProps) {\n const { t } = useT(\"lattice\");\n\n return (\n <div\n data-test={`repeater-${base}-row-${index}`}\n className=\"rounded-lt border border-lt-border bg-lt-surface p-4\"\n >\n <div className=\"mb-2 flex items-center justify-between\">\n <span className=\"text-sm font-medium text-lt-muted-fg\">{heading}</span>\n <div className=\"flex items-center gap-1 [&_svg]:size-lt-icon-sm\">\n {reorderable && !isFirst && (\n <RowButton\n label=\"Move up\"\n testId={`repeater-${base}-up-${index}`}\n onClick={() => onMove(index, -1)}\n >\n <Icon name=\"arrow-up\" />\n </RowButton>\n )}\n {reorderable && !isLast && (\n <RowButton\n label=\"Move down\"\n testId={`repeater-${base}-down-${index}`}\n onClick={() => onMove(index, 1)}\n >\n <Icon name=\"arrow-down\" />\n </RowButton>\n )}\n <RowActions\n actions={buildRowActions(rowActions, { index, removable, onRemove, onDuplicate, t })}\n />\n </div>\n </div>\n\n <FieldScopeProvider\n base={base}\n index={index}\n row={row}\n onChange={(field, value) => onField(index, field, value)}\n >\n <div className=\"flex flex-col gap-4\">\n {template.map((child) => (\n <RenderNode key={child.key ?? child.id} node={child} />\n ))}\n </div>\n </FieldScopeProvider>\n </div>\n );\n});\n"],"mappings":";;;;;;;;;AAYA,SAAgB,UAAU,EACxB,OACA,QACA,SACA,YAMC;CACD,OACE,oBAAC,UAAD;EACE,MAAK;EACL,cAAY;EACZ,aAAW;EACX,WAAU;EACD;EAER;CACK,CAAA;AAEZ;AAsBA,IAAa,UAAU,KAAK,SAAS,QAAQ,EAC3C,MACA,OACA,KACA,UACA,SACA,aACA,SACA,QACA,WACA,YACA,SACA,UACA,QACA,eACe;CACf,MAAM,EAAE,MAAM,KAAK,SAAS;CAE5B,OACE,qBAAC,OAAD;EACE,aAAW,YAAY,KAAK,OAAO;EACnC,WAAU;YAFZ,CAIE,qBAAC,OAAD;GAAK,WAAU;aAAf,CACE,oBAAC,QAAD;IAAM,WAAU;cAAwC;GAAc,CAAA,GACtE,qBAAC,OAAD;IAAK,WAAU;cAAf;KACG,eAAe,CAAC,WACf,oBAAC,WAAD;MACE,OAAM;MACN,QAAQ,YAAY,KAAK,MAAM;MAC/B,eAAe,OAAO,OAAO,EAAE;gBAE/B,oBAAC,MAAD,EAAM,MAAK,WAAY,CAAA;KACd,CAAA;KAEZ,eAAe,CAAC,UACf,oBAAC,WAAD;MACE,OAAM;MACN,QAAQ,YAAY,KAAK,QAAQ;MACjC,eAAe,OAAO,OAAO,CAAC;gBAE9B,oBAAC,MAAD,EAAM,MAAK,aAAc,CAAA;KAChB,CAAA;KAEb,oBAAC,YAAD,EACE,SAAS,gBAAgB,YAAY;MAAE;MAAO;MAAW;MAAU;MAAa;KAAE,CAAC,EACpF,CAAA;IACE;KACF;MAEL,oBAAC,oBAAD;GACQ;GACC;GACF;GACL,WAAW,OAAO,UAAU,QAAQ,OAAO,OAAO,KAAK;aAEvD,oBAAC,OAAD;IAAK,WAAU;cACZ,SAAS,KAAK,UACb,oBAAC,YAAD,EAAwC,MAAM,MAAQ,GAArC,MAAM,OAAO,MAAM,EAAkB,CACvD;GACE,CAAA;EACa,CAAA,CACjB;;AAET,CAAC"}
@@ -6,7 +6,7 @@ export type TableColumn = {
6
6
  label: string;
7
7
  columnWidth: ColumnWidth;
8
8
  };
9
- export type TableRowModel = {
9
+ type TableRowModel = {
10
10
  key: string;
11
11
  index: number;
12
12
  row: RepeaterRow;
@@ -30,3 +30,4 @@ export declare function TableRows({ base, columns, rows, reorderable, removable,
30
30
  resizableColumns?: boolean;
31
31
  resizeIndicator?: boolean;
32
32
  }): import("react").JSX.Element;
33
+ export {};
@@ -1 +1 @@
1
- {"version":3,"file":"table-rows.js","names":[],"sources":["../../../../resources/js/form/components/fields/table-rows.tsx"],"sourcesContent":["import type { Node } from \"@lattice-php/lattice/core/types\";\nimport { RenderNode } from \"@lattice-php/lattice/core/renderer\";\nimport { DEFAULT_COLUMN_WIDTH, type SizableColumn } from \"@lattice-php/lattice/core/column-sizing\";\nimport { useColumnResizing } from \"@lattice-php/lattice/core/use-column-resizing\";\nimport { Icon } from \"@lattice-php/lattice/icons\";\nimport { useT } from \"@lattice-php/lattice/i18n\";\nimport { memo, useEffect, useMemo, useState } from \"react\";\nimport type { ColumnWidth, RowAction as WireRowAction } from \"@lattice-php/lattice/types/generated\";\nimport { FieldScopeProvider } from \"../field-scope\";\nimport { TableCellProvider } from \"../row-layout-context\";\nimport { buildRowActions } from \"./row-action-menu\";\nimport { RowActions } from \"./row-actions\";\nimport { RowButton, RowItem } from \"./row-item\";\nimport type { RepeaterRow } from \"./repeater-rows\";\n\nconst rowControlTrack = \"3rem\";\nconst rowActionTrack = \"3rem\";\nconst rowControlTracks = [rowControlTrack];\nconst rowActionTracks = [rowActionTrack];\nconst tableViewportQuery = \"(min-width: 768px)\";\n\nexport type TableColumn = { name: string; label: string; columnWidth: ColumnWidth };\n\nexport type TableRowModel = {\n key: string;\n index: number;\n row: RepeaterRow;\n template: Node[];\n span: boolean;\n heading?: string;\n};\n\nfunction tableViewportMatches(): boolean {\n if (typeof window === \"undefined\" || typeof window.matchMedia !== \"function\") {\n return true;\n }\n\n return window.matchMedia(tableViewportQuery).matches;\n}\n\nfunction useTableViewport(): boolean {\n const [matches, setMatches] = useState(tableViewportMatches);\n\n useEffect(() => {\n if (typeof window.matchMedia !== \"function\") {\n return;\n }\n\n const query = window.matchMedia(tableViewportQuery);\n const update = () => setMatches(query.matches);\n\n update();\n query.addEventListener(\"change\", update);\n\n return () => query.removeEventListener(\"change\", update);\n }, []);\n\n return matches;\n}\n\nexport function columnsFromSchema(nodes: Node[]): TableColumn[] {\n return nodes.map((node) => {\n const props = node.props as {\n name: unknown;\n label?: unknown;\n columnWidth?: ColumnWidth | null;\n };\n return {\n name: String(props.name),\n label: String(props.label ?? props.name),\n columnWidth: props.columnWidth ?? DEFAULT_COLUMN_WIDTH,\n };\n });\n}\n\ntype TableRowItemProps = {\n base: string;\n index: number;\n row: RepeaterRow;\n template: Node[];\n span: boolean;\n isFirst: boolean;\n isLast: boolean;\n columnCount: number;\n gridTemplateColumns: string;\n flipKey: string;\n reorderable: boolean;\n removable: boolean;\n rowActions: WireRowAction[] | null;\n onField: (index: number, field: string, value: unknown) => void;\n onMove: (index: number, delta: number) => void;\n onRemove: (index: number) => void;\n onDuplicate: (index: number) => void;\n registerRow?: (key: string, el: HTMLElement | null) => void;\n};\n\nconst TableRowItem = memo(function TableRowItem({\n base,\n index,\n row,\n template,\n span,\n isFirst,\n isLast,\n columnCount,\n gridTemplateColumns,\n flipKey,\n reorderable,\n removable,\n rowActions,\n onField,\n onMove,\n onRemove,\n onDuplicate,\n registerRow,\n}: TableRowItemProps) {\n const { t } = useT(\"lattice\");\n\n return (\n <div\n ref={(el) => registerRow?.(flipKey, el)}\n data-flip-key={flipKey}\n data-test={`table-row-${base}-${index}`}\n className=\"grid items-start gap-x-3\"\n style={{ gridTemplateColumns }}\n >\n <div className=\"flex items-center gap-1 [&_svg]:size-lt-icon-sm\">\n {reorderable && !isFirst && (\n <RowButton\n label=\"Move up\"\n testId={`table-${base}-up-${index}`}\n onClick={() => onMove(index, -1)}\n >\n <Icon name=\"arrow-up\" />\n </RowButton>\n )}\n {reorderable && !isLast && (\n <RowButton\n label=\"Move down\"\n testId={`table-${base}-down-${index}`}\n onClick={() => onMove(index, 1)}\n >\n <Icon name=\"arrow-down\" />\n </RowButton>\n )}\n </div>\n\n <FieldScopeProvider\n base={base}\n index={index}\n row={row}\n onChange={(field, value) => onField(index, field, value)}\n >\n <TableCellProvider>\n {span ? (\n <div\n data-test={`table-row-${base}-${index}-span`}\n className=\"flex flex-col gap-2\"\n style={{ gridColumn: `span ${columnCount}` }}\n >\n {template.map((child) => (\n <RenderNode key={child.key ?? child.id} node={child} />\n ))}\n </div>\n ) : (\n template.map((child) => (\n <div key={child.key ?? child.id}>\n <RenderNode node={child} />\n </div>\n ))\n )}\n </TableCellProvider>\n </FieldScopeProvider>\n\n <div className=\"flex items-center\">\n <RowActions\n actions={buildRowActions(rowActions, { index, removable, onRemove, onDuplicate, t })}\n />\n </div>\n </div>\n );\n});\n\nexport function TableRows({\n base,\n columns,\n rows,\n reorderable,\n removable,\n rowActions,\n onField,\n onMove,\n onRemove,\n onDuplicate,\n registerRow,\n resizableColumns = false,\n resizeIndicator = false,\n}: {\n base: string;\n columns: TableColumn[];\n rows: TableRowModel[];\n reorderable: boolean;\n removable: (index: number) => boolean;\n rowActions: WireRowAction[] | null;\n onField: (index: number, field: string, value: unknown) => void;\n onMove: (index: number, delta: number) => void;\n onRemove: (index: number) => void;\n onDuplicate: (index: number) => void;\n registerRow?: (key: string, el: HTMLElement | null) => void;\n resizableColumns?: boolean;\n resizeIndicator?: boolean;\n}) {\n const { t } = useT(\"lattice\");\n const isTableViewport = useTableViewport();\n const sizingColumns = useMemo<SizableColumn[]>(\n () =>\n columns.map((column) => ({\n key: column.name,\n label: column.label,\n width: column.columnWidth,\n })),\n [columns],\n );\n const { getResizeHandleProps, gridTemplateColumns, hasOverrides, resetColumns } =\n useColumnResizing({\n columns: sizingColumns,\n enabled: resizableColumns,\n columnGapPx: 12,\n leadingTracks: rowControlTracks,\n showIndicator: resizeIndicator,\n storageKey: resizableColumns ? `lattice:table-columns:form:${base}` : undefined,\n trailingTracks: rowActionTracks,\n });\n\n if (!isTableViewport) {\n return (\n <div className=\"flex flex-col gap-3\">\n {rows.map((row) => (\n <div key={row.key} ref={(el) => registerRow?.(row.key, el)} data-flip-key={row.key}>\n <RowItem\n base={base}\n index={row.index}\n row={row.row}\n template={row.template}\n heading={row.heading ?? `#${row.index + 1}`}\n reorderable={reorderable}\n isFirst={row.index === 0}\n isLast={row.index === rows.length - 1}\n removable={removable(row.index)}\n rowActions={rowActions}\n onField={onField}\n onRemove={onRemove}\n onMove={onMove}\n onDuplicate={onDuplicate}\n />\n </div>\n ))}\n </div>\n );\n }\n\n return (\n <div className=\"relative\">\n {hasOverrides && (\n <button\n aria-label={t(\"table.resetColumnWidths\", \"Reset column widths\")}\n className=\"absolute right-1 top-1 z-10 hidden rounded-lt-sm p-1 text-lt-muted-fg hover:text-lt-fg md:inline-flex\"\n data-test=\"table-reset-columns\"\n onClick={resetColumns}\n title={t(\"table.resetColumnWidths\", \"Reset column widths\")}\n type=\"button\"\n >\n <Icon name=\"rotate-ccw\" className=\"size-lt-icon-sm\" />\n </button>\n )}\n <div className=\"overflow-x-auto\">\n <div className=\"flex min-w-max flex-col gap-2\">\n <div className=\"grid items-center gap-x-3\" style={{ gridTemplateColumns }}>\n <div />\n {columns.map((column, index) => (\n <div\n key={column.name}\n className=\"relative min-w-0 pr-3 text-xs font-medium text-lt-muted-fg\"\n >\n {column.label}\n {resizableColumns && <div {...getResizeHandleProps(sizingColumns[index])} />}\n </div>\n ))}\n <div />\n </div>\n\n {rows.map((row) => (\n <TableRowItem\n key={row.key}\n base={base}\n index={row.index}\n row={row.row}\n template={row.template}\n span={row.span}\n isFirst={row.index === 0}\n isLast={row.index === rows.length - 1}\n columnCount={columns.length}\n gridTemplateColumns={gridTemplateColumns}\n flipKey={row.key}\n reorderable={reorderable}\n removable={removable(row.index)}\n rowActions={rowActions}\n onField={onField}\n onMove={onMove}\n onRemove={onRemove}\n onDuplicate={onDuplicate}\n registerRow={registerRow}\n />\n ))}\n </div>\n </div>\n </div>\n );\n}\n"],"mappings":";;;;;;;;;;;;;AAeA,IAAM,kBAAkB;AACxB,IAAM,iBAAiB;AACvB,IAAM,mBAAmB,CAAC,eAAe;AACzC,IAAM,kBAAkB,CAAC,cAAc;AACvC,IAAM,qBAAqB;AAa3B,SAAS,uBAAgC;CACvC,IAAI,OAAO,WAAW,eAAe,OAAO,OAAO,eAAe,YAChE,OAAO;CAGT,OAAO,OAAO,WAAW,kBAAkB,EAAE;AAC/C;AAEA,SAAS,mBAA4B;CACnC,MAAM,CAAC,SAAS,cAAc,SAAS,oBAAoB;CAE3D,gBAAgB;EACd,IAAI,OAAO,OAAO,eAAe,YAC/B;EAGF,MAAM,QAAQ,OAAO,WAAW,kBAAkB;EAClD,MAAM,eAAe,WAAW,MAAM,OAAO;EAE7C,OAAO;EACP,MAAM,iBAAiB,UAAU,MAAM;EAEvC,aAAa,MAAM,oBAAoB,UAAU,MAAM;CACzD,GAAG,CAAC,CAAC;CAEL,OAAO;AACT;AAEA,SAAgB,kBAAkB,OAA8B;CAC9D,OAAO,MAAM,KAAK,SAAS;EACzB,MAAM,QAAQ,KAAK;EAKnB,OAAO;GACL,MAAM,OAAO,MAAM,IAAI;GACvB,OAAO,OAAO,MAAM,SAAS,MAAM,IAAI;GACvC,aAAa,MAAM,eAAA;EACrB;CACF,CAAC;AACH;AAuBA,IAAM,eAAe,KAAK,SAAS,aAAa,EAC9C,MACA,OACA,KACA,UACA,MACA,SACA,QACA,aACA,qBACA,SACA,aACA,WACA,YACA,SACA,QACA,UACA,aACA,eACoB;CACpB,MAAM,EAAE,MAAM,KAAK,SAAS;CAE5B,OACE,qBAAC,OAAD;EACE,MAAM,OAAO,cAAc,SAAS,EAAE;EACtC,iBAAe;EACf,aAAW,aAAa,KAAK,GAAG;EAChC,WAAU;EACV,OAAO,EAAE,oBAAoB;YAL/B;GAOE,qBAAC,OAAD;IAAK,WAAU;cAAf,CACG,eAAe,CAAC,WACf,oBAAC,WAAD;KACE,OAAM;KACN,QAAQ,SAAS,KAAK,MAAM;KAC5B,eAAe,OAAO,OAAO,EAAE;eAE/B,oBAAC,MAAD,EAAM,MAAK,WAAY,CAAA;IACd,CAAA,GAEZ,eAAe,CAAC,UACf,oBAAC,WAAD;KACE,OAAM;KACN,QAAQ,SAAS,KAAK,QAAQ;KAC9B,eAAe,OAAO,OAAO,CAAC;eAE9B,oBAAC,MAAD,EAAM,MAAK,aAAc,CAAA;IAChB,CAAA,CAEV;;GAEL,oBAAC,oBAAD;IACQ;IACC;IACF;IACL,WAAW,OAAO,UAAU,QAAQ,OAAO,OAAO,KAAK;cAEvD,oBAAC,mBAAD,EAAA,UACG,OACC,oBAAC,OAAD;KACE,aAAW,aAAa,KAAK,GAAG,MAAM;KACtC,WAAU;KACV,OAAO,EAAE,YAAY,QAAQ,cAAc;eAE1C,SAAS,KAAK,UACb,oBAAC,YAAD,EAAwC,MAAM,MAAQ,GAArC,MAAM,OAAO,MAAM,EAAkB,CACvD;IACE,CAAA,IAEL,SAAS,KAAK,UACZ,oBAAC,OAAD,EAAA,UACE,oBAAC,YAAD,EAAY,MAAM,MAAQ,CAAA,EACvB,GAFK,MAAM,OAAO,MAAM,EAExB,CACN,EAEc,CAAA;GACD,CAAA;GAEpB,oBAAC,OAAD;IAAK,WAAU;cACb,oBAAC,YAAD,EACE,SAAS,gBAAgB,YAAY;KAAE;KAAO;KAAW;KAAU;KAAa;IAAE,CAAC,EACpF,CAAA;GACE,CAAA;EACF;;AAET,CAAC;AAED,SAAgB,UAAU,EACxB,MACA,SACA,MACA,aACA,WACA,YACA,SACA,QACA,UACA,aACA,aACA,mBAAmB,OACnB,kBAAkB,SAejB;CACD,MAAM,EAAE,MAAM,KAAK,SAAS;CAC5B,MAAM,kBAAkB,iBAAiB;CACzC,MAAM,gBAAgB,cAElB,QAAQ,KAAK,YAAY;EACvB,KAAK,OAAO;EACZ,OAAO,OAAO;EACd,OAAO,OAAO;CAChB,EAAE,GACJ,CAAC,OAAO,CACV;CACA,MAAM,EAAE,sBAAsB,qBAAqB,cAAc,iBAC/D,kBAAkB;EAChB,SAAS;EACT,SAAS;EACT,aAAa;EACb,eAAe;EACf,eAAe;EACf,YAAY,mBAAmB,8BAA8B,SAAS,KAAA;EACtE,gBAAgB;CAClB,CAAC;CAEH,IAAI,CAAC,iBACH,OACE,oBAAC,OAAD;EAAK,WAAU;YACZ,KAAK,KAAK,QACT,oBAAC,OAAD;GAAmB,MAAM,OAAO,cAAc,IAAI,KAAK,EAAE;GAAG,iBAAe,IAAI;aAC7E,oBAAC,SAAD;IACQ;IACN,OAAO,IAAI;IACX,KAAK,IAAI;IACT,UAAU,IAAI;IACd,SAAS,IAAI,WAAW,IAAI,IAAI,QAAQ;IAC3B;IACb,SAAS,IAAI,UAAU;IACvB,QAAQ,IAAI,UAAU,KAAK,SAAS;IACpC,WAAW,UAAU,IAAI,KAAK;IAClB;IACH;IACC;IACF;IACK;GACd,CAAA;EACE,GAjBK,IAAI,GAiBT,CACN;CACE,CAAA;CAIT,OACE,qBAAC,OAAD;EAAK,WAAU;YAAf,CACG,gBACC,oBAAC,UAAD;GACE,cAAY,EAAE,2BAA2B,qBAAqB;GAC9D,WAAU;GACV,aAAU;GACV,SAAS;GACT,OAAO,EAAE,2BAA2B,qBAAqB;GACzD,MAAK;aAEL,oBAAC,MAAD;IAAM,MAAK;IAAa,WAAU;GAAmB,CAAA;EAC/C,CAAA,GAEV,oBAAC,OAAD;GAAK,WAAU;aACb,qBAAC,OAAD;IAAK,WAAU;cAAf,CACE,qBAAC,OAAD;KAAK,WAAU;KAA4B,OAAO,EAAE,oBAAoB;eAAxE;MACE,oBAAC,OAAD,CAAM,CAAA;MACL,QAAQ,KAAK,QAAQ,UACpB,qBAAC,OAAD;OAEE,WAAU;iBAFZ,CAIG,OAAO,OACP,oBAAoB,oBAAC,OAAD,EAAK,GAAI,qBAAqB,cAAc,MAAM,EAAI,CAAA,CACxE;SALE,OAAO,IAKT,CACN;MACD,oBAAC,OAAD,CAAM,CAAA;KACH;QAEJ,KAAK,KAAK,QACT,oBAAC,cAAD;KAEQ;KACN,OAAO,IAAI;KACX,KAAK,IAAI;KACT,UAAU,IAAI;KACd,MAAM,IAAI;KACV,SAAS,IAAI,UAAU;KACvB,QAAQ,IAAI,UAAU,KAAK,SAAS;KACpC,aAAa,QAAQ;KACA;KACrB,SAAS,IAAI;KACA;KACb,WAAW,UAAU,IAAI,KAAK;KAClB;KACH;KACD;KACE;KACG;KACA;IACd,GAnBM,IAAI,GAmBV,CACF,CACE;;EACF,CAAA,CACF;;AAET"}
1
+ {"version":3,"file":"table-rows.js","names":[],"sources":["../../../../resources/js/form/components/fields/table-rows.tsx"],"sourcesContent":["import type { Node } from \"@lattice-php/lattice/core/types\";\nimport { RenderNode } from \"@lattice-php/lattice/core/renderer\";\nimport { DEFAULT_COLUMN_WIDTH, type SizableColumn } from \"@lattice-php/lattice/core/column-sizing\";\nimport { useColumnResizing } from \"@lattice-php/lattice/core/use-column-resizing\";\nimport { Icon } from \"@lattice-php/lattice/icons\";\nimport { useT } from \"@lattice-php/lattice/i18n\";\nimport { memo, useEffect, useMemo, useState } from \"react\";\nimport type { ColumnWidth, RowAction as WireRowAction } from \"@lattice-php/lattice/types/generated\";\nimport { FieldScopeProvider } from \"../field-scope\";\nimport { TableCellProvider } from \"../row-layout-context\";\nimport { buildRowActions } from \"./row-action-menu\";\nimport { RowActions } from \"./row-actions\";\nimport { RowButton, RowItem } from \"./row-item\";\nimport type { RepeaterRow } from \"./repeater-rows\";\n\nconst rowControlTrack = \"3rem\";\nconst rowActionTrack = \"3rem\";\nconst rowControlTracks = [rowControlTrack];\nconst rowActionTracks = [rowActionTrack];\nconst tableViewportQuery = \"(min-width: 768px)\";\n\nexport type TableColumn = { name: string; label: string; columnWidth: ColumnWidth };\n\ntype TableRowModel = {\n key: string;\n index: number;\n row: RepeaterRow;\n template: Node[];\n span: boolean;\n heading?: string;\n};\n\nfunction tableViewportMatches(): boolean {\n if (typeof window === \"undefined\" || typeof window.matchMedia !== \"function\") {\n return true;\n }\n\n return window.matchMedia(tableViewportQuery).matches;\n}\n\nfunction useTableViewport(): boolean {\n const [matches, setMatches] = useState(tableViewportMatches);\n\n useEffect(() => {\n if (typeof window.matchMedia !== \"function\") {\n return;\n }\n\n const query = window.matchMedia(tableViewportQuery);\n const update = () => setMatches(query.matches);\n\n update();\n query.addEventListener(\"change\", update);\n\n return () => query.removeEventListener(\"change\", update);\n }, []);\n\n return matches;\n}\n\nexport function columnsFromSchema(nodes: Node[]): TableColumn[] {\n return nodes.map((node) => {\n const props = node.props as {\n name: unknown;\n label?: unknown;\n columnWidth?: ColumnWidth | null;\n };\n return {\n name: String(props.name),\n label: String(props.label ?? props.name),\n columnWidth: props.columnWidth ?? DEFAULT_COLUMN_WIDTH,\n };\n });\n}\n\ntype TableRowItemProps = {\n base: string;\n index: number;\n row: RepeaterRow;\n template: Node[];\n span: boolean;\n isFirst: boolean;\n isLast: boolean;\n columnCount: number;\n gridTemplateColumns: string;\n flipKey: string;\n reorderable: boolean;\n removable: boolean;\n rowActions: WireRowAction[] | null;\n onField: (index: number, field: string, value: unknown) => void;\n onMove: (index: number, delta: number) => void;\n onRemove: (index: number) => void;\n onDuplicate: (index: number) => void;\n registerRow?: (key: string, el: HTMLElement | null) => void;\n};\n\nconst TableRowItem = memo(function TableRowItem({\n base,\n index,\n row,\n template,\n span,\n isFirst,\n isLast,\n columnCount,\n gridTemplateColumns,\n flipKey,\n reorderable,\n removable,\n rowActions,\n onField,\n onMove,\n onRemove,\n onDuplicate,\n registerRow,\n}: TableRowItemProps) {\n const { t } = useT(\"lattice\");\n\n return (\n <div\n ref={(el) => registerRow?.(flipKey, el)}\n data-flip-key={flipKey}\n data-test={`table-row-${base}-${index}`}\n className=\"grid items-start gap-x-3\"\n style={{ gridTemplateColumns }}\n >\n <div className=\"flex items-center gap-1 [&_svg]:size-lt-icon-sm\">\n {reorderable && !isFirst && (\n <RowButton\n label=\"Move up\"\n testId={`table-${base}-up-${index}`}\n onClick={() => onMove(index, -1)}\n >\n <Icon name=\"arrow-up\" />\n </RowButton>\n )}\n {reorderable && !isLast && (\n <RowButton\n label=\"Move down\"\n testId={`table-${base}-down-${index}`}\n onClick={() => onMove(index, 1)}\n >\n <Icon name=\"arrow-down\" />\n </RowButton>\n )}\n </div>\n\n <FieldScopeProvider\n base={base}\n index={index}\n row={row}\n onChange={(field, value) => onField(index, field, value)}\n >\n <TableCellProvider>\n {span ? (\n <div\n data-test={`table-row-${base}-${index}-span`}\n className=\"flex flex-col gap-2\"\n style={{ gridColumn: `span ${columnCount}` }}\n >\n {template.map((child) => (\n <RenderNode key={child.key ?? child.id} node={child} />\n ))}\n </div>\n ) : (\n template.map((child) => (\n <div key={child.key ?? child.id}>\n <RenderNode node={child} />\n </div>\n ))\n )}\n </TableCellProvider>\n </FieldScopeProvider>\n\n <div className=\"flex items-center\">\n <RowActions\n actions={buildRowActions(rowActions, { index, removable, onRemove, onDuplicate, t })}\n />\n </div>\n </div>\n );\n});\n\nexport function TableRows({\n base,\n columns,\n rows,\n reorderable,\n removable,\n rowActions,\n onField,\n onMove,\n onRemove,\n onDuplicate,\n registerRow,\n resizableColumns = false,\n resizeIndicator = false,\n}: {\n base: string;\n columns: TableColumn[];\n rows: TableRowModel[];\n reorderable: boolean;\n removable: (index: number) => boolean;\n rowActions: WireRowAction[] | null;\n onField: (index: number, field: string, value: unknown) => void;\n onMove: (index: number, delta: number) => void;\n onRemove: (index: number) => void;\n onDuplicate: (index: number) => void;\n registerRow?: (key: string, el: HTMLElement | null) => void;\n resizableColumns?: boolean;\n resizeIndicator?: boolean;\n}) {\n const { t } = useT(\"lattice\");\n const isTableViewport = useTableViewport();\n const sizingColumns = useMemo<SizableColumn[]>(\n () =>\n columns.map((column) => ({\n key: column.name,\n label: column.label,\n width: column.columnWidth,\n })),\n [columns],\n );\n const { getResizeHandleProps, gridTemplateColumns, hasOverrides, resetColumns } =\n useColumnResizing({\n columns: sizingColumns,\n enabled: resizableColumns,\n columnGapPx: 12,\n leadingTracks: rowControlTracks,\n showIndicator: resizeIndicator,\n storageKey: resizableColumns ? `lattice:table-columns:form:${base}` : undefined,\n trailingTracks: rowActionTracks,\n });\n\n if (!isTableViewport) {\n return (\n <div className=\"flex flex-col gap-3\">\n {rows.map((row) => (\n <div key={row.key} ref={(el) => registerRow?.(row.key, el)} data-flip-key={row.key}>\n <RowItem\n base={base}\n index={row.index}\n row={row.row}\n template={row.template}\n heading={row.heading ?? `#${row.index + 1}`}\n reorderable={reorderable}\n isFirst={row.index === 0}\n isLast={row.index === rows.length - 1}\n removable={removable(row.index)}\n rowActions={rowActions}\n onField={onField}\n onRemove={onRemove}\n onMove={onMove}\n onDuplicate={onDuplicate}\n />\n </div>\n ))}\n </div>\n );\n }\n\n return (\n <div className=\"relative\">\n {hasOverrides && (\n <button\n aria-label={t(\"table.resetColumnWidths\", \"Reset column widths\")}\n className=\"absolute right-1 top-1 z-10 hidden rounded-lt-sm p-1 text-lt-muted-fg hover:text-lt-fg md:inline-flex\"\n data-test=\"table-reset-columns\"\n onClick={resetColumns}\n title={t(\"table.resetColumnWidths\", \"Reset column widths\")}\n type=\"button\"\n >\n <Icon name=\"rotate-ccw\" className=\"size-lt-icon-sm\" />\n </button>\n )}\n <div className=\"overflow-x-auto\">\n <div className=\"flex min-w-max flex-col gap-2\">\n <div className=\"grid items-center gap-x-3\" style={{ gridTemplateColumns }}>\n <div />\n {columns.map((column, index) => (\n <div\n key={column.name}\n className=\"relative min-w-0 pr-3 text-xs font-medium text-lt-muted-fg\"\n >\n {column.label}\n {resizableColumns && <div {...getResizeHandleProps(sizingColumns[index])} />}\n </div>\n ))}\n <div />\n </div>\n\n {rows.map((row) => (\n <TableRowItem\n key={row.key}\n base={base}\n index={row.index}\n row={row.row}\n template={row.template}\n span={row.span}\n isFirst={row.index === 0}\n isLast={row.index === rows.length - 1}\n columnCount={columns.length}\n gridTemplateColumns={gridTemplateColumns}\n flipKey={row.key}\n reorderable={reorderable}\n removable={removable(row.index)}\n rowActions={rowActions}\n onField={onField}\n onMove={onMove}\n onRemove={onRemove}\n onDuplicate={onDuplicate}\n registerRow={registerRow}\n />\n ))}\n </div>\n </div>\n </div>\n );\n}\n"],"mappings":"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"}
@@ -8,7 +8,7 @@ export type TimeColumnOption = {
8
8
  label: string;
9
9
  disabled: boolean;
10
10
  };
11
- export type TimeColumns = {
11
+ type TimeColumns = {
12
12
  hours: TimeColumnOption[];
13
13
  minutes: TimeColumnOption[];
14
14
  seconds: TimeColumnOption[] | null;
@@ -21,3 +21,4 @@ export declare function buildTimeColumns(step: number | null | undefined, option
21
21
  max?: string | null;
22
22
  current?: TimeValue | null;
23
23
  }): TimeColumns;
24
+ export {};
@@ -1 +1 @@
1
- {"version":3,"file":"time-picker-columns.js","names":[],"sources":["../../../../resources/js/form/components/fields/time-picker-columns.ts"],"sourcesContent":["export type TimeValue = { hour: number; minute: number; second: number };\n\nexport type TimeColumnOption = { value: number; label: string; disabled: boolean };\n\nexport type TimeColumns = {\n hours: TimeColumnOption[];\n minutes: TimeColumnOption[];\n seconds: TimeColumnOption[] | null;\n};\n\ntype Bound = { hour: number; minute: number };\n\nconst timePattern = /^(\\d{1,2}):(\\d{2})(?::(\\d{2}))?$/;\n\nexport function parseTimeString(value: string | null | undefined): TimeValue | null {\n if (typeof value !== \"string\") {\n return null;\n }\n\n const match = timePattern.exec(value.trim());\n\n if (!match) {\n return null;\n }\n\n const hour = Number(match[1]);\n const minute = Number(match[2]);\n const second = match[3] ? Number(match[3]) : 0;\n\n if (hour > 23 || minute > 59 || second > 59) {\n return null;\n }\n\n return { hour, minute, second };\n}\n\nexport function formatTimeValue(value: TimeValue, withSeconds: boolean): string {\n const parts = [pad(value.hour), pad(value.minute)];\n\n if (withSeconds) {\n parts.push(pad(value.second));\n }\n\n return parts.join(\":\");\n}\n\nexport function secondsEnabled(step: number | null | undefined): boolean {\n return step != null && step < 60;\n}\n\nexport function buildTimeColumns(\n step: number | null | undefined,\n options: { min?: string | null; max?: string | null; current?: TimeValue | null } = {},\n): TimeColumns {\n const { min, max, current } = options;\n const minBound = toBound(min);\n const maxBound = toBound(max);\n const minuteStep = step == null || step < 60 ? 1 : step % 60 === 0 ? step / 60 : 1;\n\n const hours = range(0, 23, 1).map((value) => ({\n value,\n label: pad(value),\n disabled:\n (minBound != null && value < minBound.hour) || (maxBound != null && value > maxBound.hour),\n }));\n\n const minuteValues = withValue(range(0, 59, minuteStep), current?.minute);\n const minutes = minuteValues.map((value) => ({\n value,\n label: pad(value),\n disabled: minuteDisabled(value, current, minBound, maxBound),\n }));\n\n const seconds = secondsEnabled(step)\n ? range(0, 59, 1).map((value) => ({ value, label: pad(value), disabled: false }))\n : null;\n\n return { hours, minutes, seconds };\n}\n\nfunction minuteDisabled(\n minute: number,\n current: TimeValue | null | undefined,\n minBound: Bound | null,\n maxBound: Bound | null,\n): boolean {\n if (!current) {\n return false;\n }\n\n if (minBound != null && current.hour === minBound.hour && minute < minBound.minute) {\n return true;\n }\n\n if (maxBound != null && current.hour === maxBound.hour && minute > maxBound.minute) {\n return true;\n }\n\n return false;\n}\n\nfunction toBound(value: string | null | undefined): Bound | null {\n const parsed = parseTimeString(value);\n\n return parsed ? { hour: parsed.hour, minute: parsed.minute } : null;\n}\n\nfunction withValue(values: number[], extra: number | undefined): number[] {\n if (extra == null || values.includes(extra)) {\n return values;\n }\n\n return [...values, extra].sort((left, right) => left - right);\n}\n\nfunction range(start: number, end: number, step: number): number[] {\n const values: number[] = [];\n\n for (let value = start; value <= end; value += step) {\n values.push(value);\n }\n\n return values;\n}\n\nfunction pad(value: number): string {\n return String(value).padStart(2, \"0\");\n}\n"],"mappings":";AAYA,IAAM,cAAc;AAEpB,SAAgB,gBAAgB,OAAoD;CAClF,IAAI,OAAO,UAAU,UACnB,OAAO;CAGT,MAAM,QAAQ,YAAY,KAAK,MAAM,KAAK,CAAC;CAE3C,IAAI,CAAC,OACH,OAAO;CAGT,MAAM,OAAO,OAAO,MAAM,EAAE;CAC5B,MAAM,SAAS,OAAO,MAAM,EAAE;CAC9B,MAAM,SAAS,MAAM,KAAK,OAAO,MAAM,EAAE,IAAI;CAE7C,IAAI,OAAO,MAAM,SAAS,MAAM,SAAS,IACvC,OAAO;CAGT,OAAO;EAAE;EAAM;EAAQ;CAAO;AAChC;AAEA,SAAgB,gBAAgB,OAAkB,aAA8B;CAC9E,MAAM,QAAQ,CAAC,IAAI,MAAM,IAAI,GAAG,IAAI,MAAM,MAAM,CAAC;CAEjD,IAAI,aACF,MAAM,KAAK,IAAI,MAAM,MAAM,CAAC;CAG9B,OAAO,MAAM,KAAK,GAAG;AACvB;AAEA,SAAgB,eAAe,MAA0C;CACvE,OAAO,QAAQ,QAAQ,OAAO;AAChC;AAEA,SAAgB,iBACd,MACA,UAAoF,CAAC,GACxE;CACb,MAAM,EAAE,KAAK,KAAK,YAAY;CAC9B,MAAM,WAAW,QAAQ,GAAG;CAC5B,MAAM,WAAW,QAAQ,GAAG;CAC5B,MAAM,aAAa,QAAQ,QAAQ,OAAO,KAAK,IAAI,OAAO,OAAO,IAAI,OAAO,KAAK;CAoBjF,OAAO;EAAE,OAlBK,MAAM,GAAG,IAAI,CAAC,EAAE,KAAK,WAAW;GAC5C;GACA,OAAO,IAAI,KAAK;GAChB,UACG,YAAY,QAAQ,QAAQ,SAAS,QAAU,YAAY,QAAQ,QAAQ,SAAS;EACzF,EAaS;EAAO,SAXK,UAAU,MAAM,GAAG,IAAI,UAAU,GAAG,SAAS,MAClD,EAAa,KAAK,WAAW;GAC3C;GACA,OAAO,IAAI,KAAK;GAChB,UAAU,eAAe,OAAO,SAAS,UAAU,QAAQ;EAC7D,EAMgB;EAAS,SAJT,eAAe,IAAI,IAC/B,MAAM,GAAG,IAAI,CAAC,EAAE,KAAK,WAAW;GAAE;GAAO,OAAO,IAAI,KAAK;GAAG,UAAU;EAAM,EAAE,IAC9E;CAE6B;AACnC;AAEA,SAAS,eACP,QACA,SACA,UACA,UACS;CACT,IAAI,CAAC,SACH,OAAO;CAGT,IAAI,YAAY,QAAQ,QAAQ,SAAS,SAAS,QAAQ,SAAS,SAAS,QAC1E,OAAO;CAGT,IAAI,YAAY,QAAQ,QAAQ,SAAS,SAAS,QAAQ,SAAS,SAAS,QAC1E,OAAO;CAGT,OAAO;AACT;AAEA,SAAS,QAAQ,OAAgD;CAC/D,MAAM,SAAS,gBAAgB,KAAK;CAEpC,OAAO,SAAS;EAAE,MAAM,OAAO;EAAM,QAAQ,OAAO;CAAO,IAAI;AACjE;AAEA,SAAS,UAAU,QAAkB,OAAqC;CACxE,IAAI,SAAS,QAAQ,OAAO,SAAS,KAAK,GACxC,OAAO;CAGT,OAAO,CAAC,GAAG,QAAQ,KAAK,EAAE,MAAM,MAAM,UAAU,OAAO,KAAK;AAC9D;AAEA,SAAS,MAAM,OAAe,KAAa,MAAwB;CACjE,MAAM,SAAmB,CAAC;CAE1B,KAAK,IAAI,QAAQ,OAAO,SAAS,KAAK,SAAS,MAC7C,OAAO,KAAK,KAAK;CAGnB,OAAO;AACT;AAEA,SAAS,IAAI,OAAuB;CAClC,OAAO,OAAO,KAAK,EAAE,SAAS,GAAG,GAAG;AACtC"}
1
+ {"version":3,"file":"time-picker-columns.js","names":[],"sources":["../../../../resources/js/form/components/fields/time-picker-columns.ts"],"sourcesContent":["export type TimeValue = { hour: number; minute: number; second: number };\n\nexport type TimeColumnOption = { value: number; label: string; disabled: boolean };\n\ntype TimeColumns = {\n hours: TimeColumnOption[];\n minutes: TimeColumnOption[];\n seconds: TimeColumnOption[] | null;\n};\n\ntype Bound = { hour: number; minute: number };\n\nconst timePattern = /^(\\d{1,2}):(\\d{2})(?::(\\d{2}))?$/;\n\nexport function parseTimeString(value: string | null | undefined): TimeValue | null {\n if (typeof value !== \"string\") {\n return null;\n }\n\n const match = timePattern.exec(value.trim());\n\n if (!match) {\n return null;\n }\n\n const hour = Number(match[1]);\n const minute = Number(match[2]);\n const second = match[3] ? Number(match[3]) : 0;\n\n if (hour > 23 || minute > 59 || second > 59) {\n return null;\n }\n\n return { hour, minute, second };\n}\n\nexport function formatTimeValue(value: TimeValue, withSeconds: boolean): string {\n const parts = [pad(value.hour), pad(value.minute)];\n\n if (withSeconds) {\n parts.push(pad(value.second));\n }\n\n return parts.join(\":\");\n}\n\nexport function secondsEnabled(step: number | null | undefined): boolean {\n return step != null && step < 60;\n}\n\nexport function buildTimeColumns(\n step: number | null | undefined,\n options: { min?: string | null; max?: string | null; current?: TimeValue | null } = {},\n): TimeColumns {\n const { min, max, current } = options;\n const minBound = toBound(min);\n const maxBound = toBound(max);\n const minuteStep = step == null || step < 60 ? 1 : step % 60 === 0 ? step / 60 : 1;\n\n const hours = range(0, 23, 1).map((value) => ({\n value,\n label: pad(value),\n disabled:\n (minBound != null && value < minBound.hour) || (maxBound != null && value > maxBound.hour),\n }));\n\n const minuteValues = withValue(range(0, 59, minuteStep), current?.minute);\n const minutes = minuteValues.map((value) => ({\n value,\n label: pad(value),\n disabled: minuteDisabled(value, current, minBound, maxBound),\n }));\n\n const seconds = secondsEnabled(step)\n ? range(0, 59, 1).map((value) => ({ value, label: pad(value), disabled: false }))\n : null;\n\n return { hours, minutes, seconds };\n}\n\nfunction minuteDisabled(\n minute: number,\n current: TimeValue | null | undefined,\n minBound: Bound | null,\n maxBound: Bound | null,\n): boolean {\n if (!current) {\n return false;\n }\n\n if (minBound != null && current.hour === minBound.hour && minute < minBound.minute) {\n return true;\n }\n\n if (maxBound != null && current.hour === maxBound.hour && minute > maxBound.minute) {\n return true;\n }\n\n return false;\n}\n\nfunction toBound(value: string | null | undefined): Bound | null {\n const parsed = parseTimeString(value);\n\n return parsed ? { hour: parsed.hour, minute: parsed.minute } : null;\n}\n\nfunction withValue(values: number[], extra: number | undefined): number[] {\n if (extra == null || values.includes(extra)) {\n return values;\n }\n\n return [...values, extra].sort((left, right) => left - right);\n}\n\nfunction range(start: number, end: number, step: number): number[] {\n const values: number[] = [];\n\n for (let value = start; value <= end; value += step) {\n values.push(value);\n }\n\n return values;\n}\n\nfunction pad(value: number): string {\n return String(value).padStart(2, \"0\");\n}\n"],"mappings":";AAYA,IAAM,cAAc;AAEpB,SAAgB,gBAAgB,OAAoD;CAClF,IAAI,OAAO,UAAU,UACnB,OAAO;CAGT,MAAM,QAAQ,YAAY,KAAK,MAAM,KAAK,CAAC;CAE3C,IAAI,CAAC,OACH,OAAO;CAGT,MAAM,OAAO,OAAO,MAAM,EAAE;CAC5B,MAAM,SAAS,OAAO,MAAM,EAAE;CAC9B,MAAM,SAAS,MAAM,KAAK,OAAO,MAAM,EAAE,IAAI;CAE7C,IAAI,OAAO,MAAM,SAAS,MAAM,SAAS,IACvC,OAAO;CAGT,OAAO;EAAE;EAAM;EAAQ;CAAO;AAChC;AAEA,SAAgB,gBAAgB,OAAkB,aAA8B;CAC9E,MAAM,QAAQ,CAAC,IAAI,MAAM,IAAI,GAAG,IAAI,MAAM,MAAM,CAAC;CAEjD,IAAI,aACF,MAAM,KAAK,IAAI,MAAM,MAAM,CAAC;CAG9B,OAAO,MAAM,KAAK,GAAG;AACvB;AAEA,SAAgB,eAAe,MAA0C;CACvE,OAAO,QAAQ,QAAQ,OAAO;AAChC;AAEA,SAAgB,iBACd,MACA,UAAoF,CAAC,GACxE;CACb,MAAM,EAAE,KAAK,KAAK,YAAY;CAC9B,MAAM,WAAW,QAAQ,GAAG;CAC5B,MAAM,WAAW,QAAQ,GAAG;CAC5B,MAAM,aAAa,QAAQ,QAAQ,OAAO,KAAK,IAAI,OAAO,OAAO,IAAI,OAAO,KAAK;CAoBjF,OAAO;EAAE,OAlBK,MAAM,GAAG,IAAI,CAAC,EAAE,KAAK,WAAW;GAC5C;GACA,OAAO,IAAI,KAAK;GAChB,UACG,YAAY,QAAQ,QAAQ,SAAS,QAAU,YAAY,QAAQ,QAAQ,SAAS;EACzF,EAaS;EAAO,SAXK,UAAU,MAAM,GAAG,IAAI,UAAU,GAAG,SAAS,MAClD,EAAa,KAAK,WAAW;GAC3C;GACA,OAAO,IAAI,KAAK;GAChB,UAAU,eAAe,OAAO,SAAS,UAAU,QAAQ;EAC7D,EAMgB;EAAS,SAJT,eAAe,IAAI,IAC/B,MAAM,GAAG,IAAI,CAAC,EAAE,KAAK,WAAW;GAAE;GAAO,OAAO,IAAI,KAAK;GAAG,UAAU;EAAM,EAAE,IAC9E;CAE6B;AACnC;AAEA,SAAS,eACP,QACA,SACA,UACA,UACS;CACT,IAAI,CAAC,SACH,OAAO;CAGT,IAAI,YAAY,QAAQ,QAAQ,SAAS,SAAS,QAAQ,SAAS,SAAS,QAC1E,OAAO;CAGT,IAAI,YAAY,QAAQ,QAAQ,SAAS,SAAS,QAAQ,SAAS,SAAS,QAC1E,OAAO;CAGT,OAAO;AACT;AAEA,SAAS,QAAQ,OAAgD;CAC/D,MAAM,SAAS,gBAAgB,KAAK;CAEpC,OAAO,SAAS;EAAE,MAAM,OAAO;EAAM,QAAQ,OAAO;CAAO,IAAI;AACjE;AAEA,SAAS,UAAU,QAAkB,OAAqC;CACxE,IAAI,SAAS,QAAQ,OAAO,SAAS,KAAK,GACxC,OAAO;CAGT,OAAO,CAAC,GAAG,QAAQ,KAAK,EAAE,MAAM,MAAM,UAAU,OAAO,KAAK;AAC9D;AAEA,SAAS,MAAM,OAAe,KAAa,MAAwB;CACjE,MAAM,SAAmB,CAAC;CAE1B,KAAK,IAAI,QAAQ,OAAO,SAAS,KAAK,SAAS,MAC7C,OAAO,KAAK,KAAK;CAGnB,OAAO;AACT;AAEA,SAAS,IAAI,OAAuB;CAClC,OAAO,OAAO,KAAK,EAAE,SAAS,GAAG,GAAG;AACtC"}
@@ -1,5 +1,5 @@
1
1
  import { TimeValue } from './time-picker-columns';
2
- export type TimePickerProps = {
2
+ type TimePickerProps = {
3
3
  value: TimeValue | null;
4
4
  onChange: (next: TimeValue) => void;
5
5
  step?: number | null;
@@ -15,3 +15,4 @@ export type TimePickerProps = {
15
15
  testId?: string;
16
16
  };
17
17
  export declare function TimePicker({ value, onChange, step, min, max, disabled, readOnly, labels, testId, }: TimePickerProps): import("react").JSX.Element;
18
+ export {};
@@ -1 +1 @@
1
- {"version":3,"file":"time-picker.js","names":[],"sources":["../../../../resources/js/form/components/fields/time-picker.tsx"],"sourcesContent":["import { type KeyboardEvent, useEffect, useRef } from \"react\";\nimport { cn } from \"@lattice-php/lattice/lib/utils\";\nimport { buildTimeColumns, type TimeColumnOption, type TimeValue } from \"./time-picker-columns\";\n\nexport type TimePickerProps = {\n value: TimeValue | null;\n onChange: (next: TimeValue) => void;\n step?: number | null;\n min?: string | null;\n max?: string | null;\n disabled?: boolean;\n readOnly?: boolean;\n labels?: { hour?: string; minute?: string; second?: string };\n testId?: string;\n};\n\nexport function TimePicker({\n value,\n onChange,\n step,\n min,\n max,\n disabled = false,\n readOnly = false,\n labels,\n testId,\n}: TimePickerProps) {\n const containerRef = useRef<HTMLDivElement>(null);\n const columns = buildTimeColumns(step, { min, max, current: value });\n const current: TimeValue = value ?? { hour: 0, minute: 0, second: 0 };\n const interactive = !disabled && !readOnly;\n\n const columnList = [\n {\n key: \"hour\" as const,\n label: labels?.hour ?? \"Hour\",\n options: columns.hours,\n selected: current.hour,\n },\n {\n key: \"minute\" as const,\n label: labels?.minute ?? \"Minute\",\n options: columns.minutes,\n selected: current.minute,\n },\n ...(columns.seconds\n ? [\n {\n key: \"second\" as const,\n label: labels?.second ?? \"Second\",\n options: columns.seconds,\n selected: current.second,\n },\n ]\n : []),\n ];\n\n function focusColumn(index: number) {\n const listboxes = containerRef.current?.querySelectorAll<HTMLElement>('[role=\"listbox\"]');\n const target = listboxes?.[index];\n\n if (!target) {\n return;\n }\n\n const active =\n target.querySelector<HTMLElement>('[data-active=\"true\"]') ??\n target.querySelector<HTMLElement>('[role=\"option\"]');\n\n active?.focus();\n }\n\n return (\n <div ref={containerRef} className=\"flex gap-1\" data-test={testId}>\n {columnList.map((column, index) => (\n <TimeColumn\n key={column.key}\n label={column.label}\n options={column.options}\n selected={value ? column.selected : null}\n disabled={!interactive}\n onSelect={(optionValue) =>\n interactive && onChange({ ...current, [column.key]: optionValue })\n }\n onHorizontal={(direction) => focusColumn(index + direction)}\n />\n ))}\n </div>\n );\n}\n\nfunction TimeColumn({\n label,\n options,\n selected,\n disabled,\n onSelect,\n onHorizontal,\n}: {\n label: string;\n options: TimeColumnOption[];\n selected: number | null;\n disabled: boolean;\n onSelect: (value: number) => void;\n onHorizontal: (direction: 1 | -1) => void;\n}) {\n const listRef = useRef<HTMLDivElement>(null);\n const enabledValues = options.filter((option) => !option.disabled).map((option) => option.value);\n const activeValue = selected ?? enabledValues[0] ?? options[0]?.value ?? 0;\n\n useEffect(() => {\n const active = listRef.current?.querySelector<HTMLElement>('[data-active=\"true\"]');\n\n active?.scrollIntoView?.({ block: \"nearest\" });\n }, [selected]);\n\n function moveTo(nextValue: number | undefined) {\n if (nextValue == null) {\n return;\n }\n\n listRef.current?.querySelector<HTMLElement>(`[data-value=\"${nextValue}\"]`)?.focus();\n onSelect(nextValue);\n }\n\n function handleKeyDown(event: KeyboardEvent) {\n if (disabled) {\n return;\n }\n\n const index = enabledValues.indexOf(activeValue);\n\n switch (event.key) {\n case \"ArrowDown\":\n event.preventDefault();\n moveTo(enabledValues[Math.min(index + 1, enabledValues.length - 1)]);\n break;\n case \"ArrowUp\":\n event.preventDefault();\n moveTo(enabledValues[Math.max(index - 1, 0)]);\n break;\n case \"Home\":\n event.preventDefault();\n moveTo(enabledValues[0]);\n break;\n case \"End\":\n event.preventDefault();\n moveTo(enabledValues[enabledValues.length - 1]);\n break;\n case \"ArrowRight\":\n event.preventDefault();\n onHorizontal(1);\n break;\n case \"ArrowLeft\":\n event.preventDefault();\n onHorizontal(-1);\n break;\n }\n }\n\n return (\n <div\n ref={listRef}\n role=\"listbox\"\n aria-label={label}\n aria-orientation=\"vertical\"\n tabIndex={-1}\n className=\"flex max-h-40 w-14 flex-col overflow-y-auto\"\n onKeyDown={handleKeyDown}\n >\n {options.map((option) => {\n const isSelected = selected === option.value;\n\n return (\n <button\n key={option.value}\n type=\"button\"\n role=\"option\"\n aria-selected={isSelected}\n aria-label={`${label} ${option.label}`}\n data-value={option.value}\n data-active={activeValue === option.value}\n disabled={disabled || option.disabled}\n tabIndex={activeValue === option.value ? 0 : -1}\n onClick={() => onSelect(option.value)}\n className={cn(\n \"shrink-0 rounded-lt-sm px-2 py-1 text-sm text-lt-fg hover:bg-lt-muted\",\n isSelected && \"bg-lt-primary text-lt-primary-fg\",\n (disabled || option.disabled) && \"cursor-not-allowed opacity-40\",\n )}\n >\n {option.label}\n </button>\n );\n })}\n </div>\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"time-picker.js","names":[],"sources":["../../../../resources/js/form/components/fields/time-picker.tsx"],"sourcesContent":["import { type KeyboardEvent, useEffect, useRef } from \"react\";\nimport { cn } from \"@lattice-php/lattice/lib/utils\";\nimport { buildTimeColumns, type TimeColumnOption, type TimeValue } from \"./time-picker-columns\";\n\ntype TimePickerProps = {\n value: TimeValue | null;\n onChange: (next: TimeValue) => void;\n step?: number | null;\n min?: string | null;\n max?: string | null;\n disabled?: boolean;\n readOnly?: boolean;\n labels?: { hour?: string; minute?: string; second?: string };\n testId?: string;\n};\n\nexport function TimePicker({\n value,\n onChange,\n step,\n min,\n max,\n disabled = false,\n readOnly = false,\n labels,\n testId,\n}: TimePickerProps) {\n const containerRef = useRef<HTMLDivElement>(null);\n const columns = buildTimeColumns(step, { min, max, current: value });\n const current: TimeValue = value ?? { hour: 0, minute: 0, second: 0 };\n const interactive = !disabled && !readOnly;\n\n const columnList = [\n {\n key: \"hour\" as const,\n label: labels?.hour ?? \"Hour\",\n options: columns.hours,\n selected: current.hour,\n },\n {\n key: \"minute\" as const,\n label: labels?.minute ?? \"Minute\",\n options: columns.minutes,\n selected: current.minute,\n },\n ...(columns.seconds\n ? [\n {\n key: \"second\" as const,\n label: labels?.second ?? \"Second\",\n options: columns.seconds,\n selected: current.second,\n },\n ]\n : []),\n ];\n\n function focusColumn(index: number) {\n const listboxes = containerRef.current?.querySelectorAll<HTMLElement>('[role=\"listbox\"]');\n const target = listboxes?.[index];\n\n if (!target) {\n return;\n }\n\n const active =\n target.querySelector<HTMLElement>('[data-active=\"true\"]') ??\n target.querySelector<HTMLElement>('[role=\"option\"]');\n\n active?.focus();\n }\n\n return (\n <div ref={containerRef} className=\"flex gap-1\" data-test={testId}>\n {columnList.map((column, index) => (\n <TimeColumn\n key={column.key}\n label={column.label}\n options={column.options}\n selected={value ? column.selected : null}\n disabled={!interactive}\n onSelect={(optionValue) =>\n interactive && onChange({ ...current, [column.key]: optionValue })\n }\n onHorizontal={(direction) => focusColumn(index + direction)}\n />\n ))}\n </div>\n );\n}\n\nfunction TimeColumn({\n label,\n options,\n selected,\n disabled,\n onSelect,\n onHorizontal,\n}: {\n label: string;\n options: TimeColumnOption[];\n selected: number | null;\n disabled: boolean;\n onSelect: (value: number) => void;\n onHorizontal: (direction: 1 | -1) => void;\n}) {\n const listRef = useRef<HTMLDivElement>(null);\n const enabledValues = options.filter((option) => !option.disabled).map((option) => option.value);\n const activeValue = selected ?? enabledValues[0] ?? options[0]?.value ?? 0;\n\n useEffect(() => {\n const active = listRef.current?.querySelector<HTMLElement>('[data-active=\"true\"]');\n\n active?.scrollIntoView?.({ block: \"nearest\" });\n }, [selected]);\n\n function moveTo(nextValue: number | undefined) {\n if (nextValue == null) {\n return;\n }\n\n listRef.current?.querySelector<HTMLElement>(`[data-value=\"${nextValue}\"]`)?.focus();\n onSelect(nextValue);\n }\n\n function handleKeyDown(event: KeyboardEvent) {\n if (disabled) {\n return;\n }\n\n const index = enabledValues.indexOf(activeValue);\n\n switch (event.key) {\n case \"ArrowDown\":\n event.preventDefault();\n moveTo(enabledValues[Math.min(index + 1, enabledValues.length - 1)]);\n break;\n case \"ArrowUp\":\n event.preventDefault();\n moveTo(enabledValues[Math.max(index - 1, 0)]);\n break;\n case \"Home\":\n event.preventDefault();\n moveTo(enabledValues[0]);\n break;\n case \"End\":\n event.preventDefault();\n moveTo(enabledValues[enabledValues.length - 1]);\n break;\n case \"ArrowRight\":\n event.preventDefault();\n onHorizontal(1);\n break;\n case \"ArrowLeft\":\n event.preventDefault();\n onHorizontal(-1);\n break;\n }\n }\n\n return (\n <div\n ref={listRef}\n role=\"listbox\"\n aria-label={label}\n aria-orientation=\"vertical\"\n tabIndex={-1}\n className=\"flex max-h-40 w-14 flex-col overflow-y-auto\"\n onKeyDown={handleKeyDown}\n >\n {options.map((option) => {\n const isSelected = selected === option.value;\n\n return (\n <button\n key={option.value}\n type=\"button\"\n role=\"option\"\n aria-selected={isSelected}\n aria-label={`${label} ${option.label}`}\n data-value={option.value}\n data-active={activeValue === option.value}\n disabled={disabled || option.disabled}\n tabIndex={activeValue === option.value ? 0 : -1}\n onClick={() => onSelect(option.value)}\n className={cn(\n \"shrink-0 rounded-lt-sm px-2 py-1 text-sm text-lt-fg hover:bg-lt-muted\",\n isSelected && \"bg-lt-primary text-lt-primary-fg\",\n (disabled || option.disabled) && \"cursor-not-allowed opacity-40\",\n )}\n >\n {option.label}\n </button>\n );\n })}\n </div>\n );\n}\n"],"mappings":"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"}
@@ -1,5 +1,5 @@
1
1
  import { RepeaterRow } from './repeater-rows';
2
- export type RowCollection = {
2
+ type RowCollection = {
3
3
  path: string;
4
4
  rows: RepeaterRow[];
5
5
  onField: (index: number, field: string, value: unknown) => void;
@@ -9,3 +9,4 @@ export type RowCollection = {
9
9
  append: (row: RepeaterRow) => void;
10
10
  };
11
11
  export declare function useRowCollection(name: string, defaultItems: number): RowCollection;
12
+ export {};
@@ -1 +1 @@
1
- {"version":3,"file":"use-row-collection.js","names":[],"sources":["../../../../resources/js/form/components/fields/use-row-collection.ts"],"sourcesContent":["import { useCallback, useLayoutEffect } from \"react\";\nimport { useFieldScope } from \"../field-scope\";\nimport { useFormValue, useSetFormValue } from \"../values\";\nimport {\n duplicateRow,\n ensureRowIds,\n moveRow,\n removeRow,\n seedRows,\n withRowId,\n type RepeaterRow,\n} from \"./repeater-rows\";\n\nexport type RowCollection = {\n path: string;\n rows: RepeaterRow[];\n onField: (index: number, field: string, value: unknown) => void;\n onRemove: (index: number) => void;\n onMove: (index: number, delta: number) => void;\n onDuplicate: (index: number) => void;\n append: (row: RepeaterRow) => void;\n};\n\nexport function useRowCollection(name: string, defaultItems: number): RowCollection {\n const scope = useFieldScope();\n const path = scope ? scope.errorKey(name) : name;\n const setValue = useSetFormValue();\n const stored = useFormValue(path);\n const raw: RepeaterRow[] = Array.isArray(stored) ? stored : seedRows(stored, defaultItems);\n const rows = ensureRowIds(raw);\n\n useLayoutEffect(() => {\n if (rows !== raw) {\n setValue(path, rows);\n }\n }, [raw, rows, setValue, path]);\n\n // Functional store updates preserve the identity of untouched rows, which lets\n // the memoised RowItem skip re-rendering siblings on a single-row edit.\n const mutate = useCallback(\n (fn: (rows: RepeaterRow[]) => RepeaterRow[]): void => {\n setValue(path, (prev: unknown) =>\n fn(Array.isArray(prev) ? (prev as RepeaterRow[]) : seedRows(prev, defaultItems)),\n );\n },\n [setValue, path, defaultItems],\n );\n\n const onField = useCallback(\n (index: number, field: string, value: unknown): void =>\n mutate((current) => current.map((r, i) => (i === index ? { ...r, [field]: value } : r))),\n [mutate],\n );\n const onRemove = useCallback(\n (index: number): void => mutate((current) => removeRow(current, index)),\n [mutate],\n );\n const onMove = useCallback(\n (index: number, delta: number): void =>\n mutate((current) => moveRow(current, index, index + delta)),\n [mutate],\n );\n const onDuplicate = useCallback(\n (index: number): void => mutate((current) => duplicateRow(current, index)),\n [mutate],\n );\n const append = useCallback(\n (row: RepeaterRow): void => mutate((current) => [...current, withRowId(row)]),\n [mutate],\n );\n\n return { path, rows, onField, onRemove, onMove, onDuplicate, append };\n}\n"],"mappings":";;;;;AAuBA,SAAgB,iBAAiB,MAAc,cAAqC;CAClF,MAAM,QAAQ,cAAc;CAC5B,MAAM,OAAO,QAAQ,MAAM,SAAS,IAAI,IAAI;CAC5C,MAAM,WAAW,gBAAgB;CACjC,MAAM,SAAS,aAAa,IAAI;CAChC,MAAM,MAAqB,MAAM,QAAQ,MAAM,IAAI,SAAS,SAAS,QAAQ,YAAY;CACzF,MAAM,OAAO,aAAa,GAAG;CAE7B,sBAAsB;EACpB,IAAI,SAAS,KACX,SAAS,MAAM,IAAI;CAEvB,GAAG;EAAC;EAAK;EAAM;EAAU;CAAI,CAAC;CAI9B,MAAM,SAAS,aACZ,OAAqD;EACpD,SAAS,OAAO,SACd,GAAG,MAAM,QAAQ,IAAI,IAAK,OAAyB,SAAS,MAAM,YAAY,CAAC,CACjF;CACF,GACA;EAAC;EAAU;EAAM;CAAY,CAC/B;CAyBA,OAAO;EAAE;EAAM;EAAM,SAvBL,aACb,OAAe,OAAe,UAC7B,QAAQ,YAAY,QAAQ,KAAK,GAAG,MAAO,MAAM,QAAQ;GAAE,GAAG;IAAI,QAAQ;EAAM,IAAI,CAAE,CAAC,GACzF,CAAC,MAAM,CAoBY;EAAS,UAlBb,aACd,UAAwB,QAAQ,YAAY,UAAU,SAAS,KAAK,CAAC,GACtE,CAAC,MAAM,CAgBqB;EAAU,QAdzB,aACZ,OAAe,UACd,QAAQ,YAAY,QAAQ,SAAS,OAAO,QAAQ,KAAK,CAAC,GAC5D,CAAC,MAAM,CAW+B;EAAQ,aAT5B,aACjB,UAAwB,QAAQ,YAAY,aAAa,SAAS,KAAK,CAAC,GACzE,CAAC,MAAM,CAOuC;EAAa,QAL9C,aACZ,QAA2B,QAAQ,YAAY,CAAC,GAAG,SAAS,UAAU,GAAG,CAAC,CAAC,GAC5E,CAAC,MAAM,CAGoD;CAAO;AACtE"}
1
+ {"version":3,"file":"use-row-collection.js","names":[],"sources":["../../../../resources/js/form/components/fields/use-row-collection.ts"],"sourcesContent":["import { useCallback, useLayoutEffect } from \"react\";\nimport { useFieldScope } from \"../field-scope\";\nimport { useFormValue, useSetFormValue } from \"../values\";\nimport {\n duplicateRow,\n ensureRowIds,\n moveRow,\n removeRow,\n seedRows,\n withRowId,\n type RepeaterRow,\n} from \"./repeater-rows\";\n\ntype RowCollection = {\n path: string;\n rows: RepeaterRow[];\n onField: (index: number, field: string, value: unknown) => void;\n onRemove: (index: number) => void;\n onMove: (index: number, delta: number) => void;\n onDuplicate: (index: number) => void;\n append: (row: RepeaterRow) => void;\n};\n\nexport function useRowCollection(name: string, defaultItems: number): RowCollection {\n const scope = useFieldScope();\n const path = scope ? scope.errorKey(name) : name;\n const setValue = useSetFormValue();\n const stored = useFormValue(path);\n const raw: RepeaterRow[] = Array.isArray(stored) ? stored : seedRows(stored, defaultItems);\n const rows = ensureRowIds(raw);\n\n useLayoutEffect(() => {\n if (rows !== raw) {\n setValue(path, rows);\n }\n }, [raw, rows, setValue, path]);\n\n // Functional store updates preserve the identity of untouched rows, which lets\n // the memoised RowItem skip re-rendering siblings on a single-row edit.\n const mutate = useCallback(\n (fn: (rows: RepeaterRow[]) => RepeaterRow[]): void => {\n setValue(path, (prev: unknown) =>\n fn(Array.isArray(prev) ? (prev as RepeaterRow[]) : seedRows(prev, defaultItems)),\n );\n },\n [setValue, path, defaultItems],\n );\n\n const onField = useCallback(\n (index: number, field: string, value: unknown): void =>\n mutate((current) => current.map((r, i) => (i === index ? { ...r, [field]: value } : r))),\n [mutate],\n );\n const onRemove = useCallback(\n (index: number): void => mutate((current) => removeRow(current, index)),\n [mutate],\n );\n const onMove = useCallback(\n (index: number, delta: number): void =>\n mutate((current) => moveRow(current, index, index + delta)),\n [mutate],\n );\n const onDuplicate = useCallback(\n (index: number): void => mutate((current) => duplicateRow(current, index)),\n [mutate],\n );\n const append = useCallback(\n (row: RepeaterRow): void => mutate((current) => [...current, withRowId(row)]),\n [mutate],\n );\n\n return { path, rows, onField, onRemove, onMove, onDuplicate, append };\n}\n"],"mappings":";;;;;AAuBA,SAAgB,iBAAiB,MAAc,cAAqC;CAClF,MAAM,QAAQ,cAAc;CAC5B,MAAM,OAAO,QAAQ,MAAM,SAAS,IAAI,IAAI;CAC5C,MAAM,WAAW,gBAAgB;CACjC,MAAM,SAAS,aAAa,IAAI;CAChC,MAAM,MAAqB,MAAM,QAAQ,MAAM,IAAI,SAAS,SAAS,QAAQ,YAAY;CACzF,MAAM,OAAO,aAAa,GAAG;CAE7B,sBAAsB;EACpB,IAAI,SAAS,KACX,SAAS,MAAM,IAAI;CAEvB,GAAG;EAAC;EAAK;EAAM;EAAU;CAAI,CAAC;CAI9B,MAAM,SAAS,aACZ,OAAqD;EACpD,SAAS,OAAO,SACd,GAAG,MAAM,QAAQ,IAAI,IAAK,OAAyB,SAAS,MAAM,YAAY,CAAC,CACjF;CACF,GACA;EAAC;EAAU;EAAM;CAAY,CAC/B;CAyBA,OAAO;EAAE;EAAM;EAAM,SAvBL,aACb,OAAe,OAAe,UAC7B,QAAQ,YAAY,QAAQ,KAAK,GAAG,MAAO,MAAM,QAAQ;GAAE,GAAG;IAAI,QAAQ;EAAM,IAAI,CAAE,CAAC,GACzF,CAAC,MAAM,CAoBY;EAAS,UAlBb,aACd,UAAwB,QAAQ,YAAY,UAAU,SAAS,KAAK,CAAC,GACtE,CAAC,MAAM,CAgBqB;EAAU,QAdzB,aACZ,OAAe,UACd,QAAQ,YAAY,QAAQ,SAAS,OAAO,QAAQ,KAAK,CAAC,GAC5D,CAAC,MAAM,CAW+B;EAAQ,aAT5B,aACjB,UAAwB,QAAQ,YAAY,aAAa,SAAS,KAAK,CAAC,GACzE,CAAC,MAAM,CAOuC;EAAa,QAL9C,aACZ,QAA2B,QAAQ,YAAY,CAAC,GAAG,SAAS,UAAU,GAAG,CAAC,CAAC,GAC5E,CAAC,MAAM,CAGoD;CAAO;AACtE"}
@@ -1,4 +1,3 @@
1
- export declare function pathParts(path: string): string[];
2
1
  export declare function appendPath(base: string | null | undefined, ...parts: Array<string | number>): string;
3
2
  export declare function toHtmlName(path: string): string;
4
3
  export declare function getPath(values: Record<string, unknown>, path: string): unknown;
@@ -35,6 +35,6 @@ function setPath(values, path, value) {
35
35
  return write(values, 0);
36
36
  }
37
37
  //#endregion
38
- export { appendPath, getPath, pathParts, setPath, toHtmlName };
38
+ export { appendPath, getPath, setPath, toHtmlName };
39
39
 
40
40
  //# sourceMappingURL=form-path.js.map