@lattice-php/lattice 0.15.0 → 0.17.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (143) 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/chart.js +49 -2
  7. package/dist/core/components/chart.js.map +1 -1
  8. package/dist/core/components/control.d.ts +1 -3
  9. package/dist/core/components/control.js.map +1 -1
  10. package/dist/core/components/link.js +25 -29
  11. package/dist/core/components/link.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/date-picker-control.js +11 -13
  34. package/dist/form/components/fields/date-picker-control.js.map +1 -1
  35. package/dist/form/components/fields/row-action-menu.d.ts +2 -1
  36. package/dist/form/components/fields/row-action-menu.js.map +1 -1
  37. package/dist/form/components/fields/row-item.d.ts +2 -1
  38. package/dist/form/components/fields/row-item.js.map +1 -1
  39. package/dist/form/components/fields/table-rows.d.ts +2 -1
  40. package/dist/form/components/fields/table-rows.js.map +1 -1
  41. package/dist/form/components/fields/time-input.js +54 -15
  42. package/dist/form/components/fields/time-input.js.map +1 -1
  43. package/dist/form/components/fields/time-picker-columns.d.ts +24 -0
  44. package/dist/form/components/fields/time-picker-columns.js +76 -0
  45. package/dist/form/components/fields/time-picker-columns.js.map +1 -0
  46. package/dist/form/components/fields/time-picker.d.ts +18 -0
  47. package/dist/form/components/fields/time-picker.js +132 -0
  48. package/dist/form/components/fields/time-picker.js.map +1 -0
  49. package/dist/form/components/fields/use-row-collection.d.ts +2 -1
  50. package/dist/form/components/fields/use-row-collection.js.map +1 -1
  51. package/dist/form/components/form-path.d.ts +0 -1
  52. package/dist/form/components/form-path.js +1 -1
  53. package/dist/form/components/form-path.js.map +1 -1
  54. package/dist/form/components/prefill-targets.d.ts +1 -1
  55. package/dist/form/components/prefill-targets.js.map +1 -1
  56. package/dist/form/components/types.d.ts +5 -1
  57. package/dist/form/components/use-field-commit.d.ts +2 -1
  58. package/dist/form/components/use-field-commit.js.map +1 -1
  59. package/dist/form/components/use-form-resolver.d.ts +2 -1
  60. package/dist/form/components/use-form-resolver.js.map +1 -1
  61. package/dist/format/date-time.d.ts +12 -0
  62. package/dist/format/date-time.js +30 -0
  63. package/dist/format/date-time.js.map +1 -0
  64. package/dist/format/number.d.ts +2 -0
  65. package/dist/format/number.js +23 -0
  66. package/dist/format/number.js.map +1 -0
  67. package/dist/{table/components/cells → format}/numeric.js +1 -1
  68. package/dist/format/numeric.js.map +1 -0
  69. package/dist/format/value.d.ts +6 -0
  70. package/dist/format/value.js +17 -0
  71. package/dist/format/value.js.map +1 -0
  72. package/dist/i18n/config.d.ts +2 -1
  73. package/dist/i18n/config.js.map +1 -1
  74. package/dist/i18n/date-time.js +1 -1
  75. package/dist/i18n/date-time.js.map +1 -1
  76. package/dist/i18n/instance.d.ts +1 -1
  77. package/dist/i18n/instance.js.map +1 -1
  78. package/dist/i18n/locale-reload.d.ts +2 -1
  79. package/dist/i18n/locale-reload.js.map +1 -1
  80. package/dist/index.d.ts +1 -1
  81. package/dist/index.js +1 -1
  82. package/dist/layout/components.js +1 -1
  83. package/dist/layout/menu-item.js +43 -49
  84. package/dist/layout/menu-item.js.map +1 -1
  85. package/dist/notifications/api.d.ts +6 -0
  86. package/dist/notifications/api.js +21 -0
  87. package/dist/notifications/api.js.map +1 -0
  88. package/dist/notifications/components/empty-state.d.ts +1 -0
  89. package/dist/notifications/components/empty-state.js +21 -0
  90. package/dist/notifications/components/empty-state.js.map +1 -0
  91. package/dist/notifications/components/notification-item.d.ts +6 -0
  92. package/dist/notifications/components/notification-item.js +65 -0
  93. package/dist/notifications/components/notification-item.js.map +1 -0
  94. package/dist/notifications/components/notification-list.d.ts +10 -0
  95. package/dist/notifications/components/notification-list.js +38 -0
  96. package/dist/notifications/components/notification-list.js.map +1 -0
  97. package/dist/notifications/components/notifications-echo.d.ts +5 -0
  98. package/dist/notifications/components/notifications-echo.js +22 -0
  99. package/dist/notifications/components/notifications-echo.js.map +1 -0
  100. package/dist/notifications/components/notifications.d.ts +3 -0
  101. package/dist/notifications/components/notifications.js +109 -0
  102. package/dist/notifications/components/notifications.js.map +1 -0
  103. package/dist/notifications/index.d.ts +1 -0
  104. package/dist/notifications/index.js +11 -0
  105. package/dist/notifications/index.js.map +1 -0
  106. package/dist/notifications/store.d.ts +25 -0
  107. package/dist/notifications/store.js +100 -0
  108. package/dist/notifications/store.js.map +1 -0
  109. package/dist/notifications/types.d.ts +10 -0
  110. package/dist/notifications/types.js +0 -0
  111. package/dist/realtime/build-effects.d.ts +2 -1
  112. package/dist/realtime/build-effects.js.map +1 -1
  113. package/dist/realtime/subscriptions.js.map +1 -1
  114. package/dist/registry/eager.js +2 -1
  115. package/dist/registry/eager.js.map +1 -1
  116. package/dist/registry/lazy.js +2 -1
  117. package/dist/registry/lazy.js.map +1 -1
  118. package/dist/table/bulk.d.ts +2 -1
  119. package/dist/table/bulk.js.map +1 -1
  120. package/dist/table/components/bulk-bar.js +2 -2
  121. package/dist/table/components/cells/money-cell.js +11 -12
  122. package/dist/table/components/cells/money-cell.js.map +1 -1
  123. package/dist/table/components/cells/number-cell.js +11 -11
  124. package/dist/table/components/cells/number-cell.js.map +1 -1
  125. package/dist/table/components/cells/text-cell.js +1 -1
  126. package/dist/table/components/filter-controls.d.ts +0 -4
  127. package/dist/table/components/filter-controls.js.map +1 -1
  128. package/dist/table/components/table-cell.js.map +1 -1
  129. package/dist/table/format.d.ts +1 -10
  130. package/dist/table/format.js +2 -24
  131. package/dist/table/format.js.map +1 -1
  132. package/dist/table/types.d.ts +7 -17
  133. package/dist/types/generated.d.ts +137 -290
  134. package/dist/types/index.d.ts +1 -1
  135. package/dist/vite-client.d.ts +8 -0
  136. package/dist/vite.d.ts +35 -1
  137. package/dist/vite.js +60 -2
  138. package/dist/vite.js.map +1 -1
  139. package/package.json +13 -2
  140. package/resources/icons/bell.svg +16 -0
  141. package/resources/icons/clock.svg +16 -0
  142. package/dist/table/components/cells/numeric.js.map +0 -1
  143. /package/dist/{table/components/cells → format}/numeric.d.ts +0 -0
@@ -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":"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"}
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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"}
@@ -1,26 +1,65 @@
1
+ import { Icon } from "../../../icons/sprite.js";
2
+ import { Popover, PopoverContent, PopoverTrigger } from "../../../core/components/popover.js";
3
+ import { Button } from "../../../core/components/button.js";
1
4
  import { SimpleField } from "./simple-field.js";
2
5
  import { Input } from "../base/input.js";
3
- import { jsx } from "react/jsx-runtime";
6
+ import { formatTimeValue, parseTimeString, secondsEnabled } from "./time-picker-columns.js";
7
+ import { TimePicker } from "./time-picker.js";
8
+ import { jsx, jsxs } from "react/jsx-runtime";
4
9
  //#region resources/js/form/components/fields/time-input.tsx
5
10
  var TimeInputComponent = ({ node }) => {
6
11
  const props = node.props;
12
+ const withSeconds = secondsEnabled(props.step);
13
+ const triggerLabel = props.label ?? props.name;
7
14
  return /* @__PURE__ */ jsx(SimpleField, {
8
15
  node,
9
16
  label: props.label ?? "",
10
- children: ({ name, testId, value, readOnly, disabled, commit }) => /* @__PURE__ */ jsx(Input, {
11
- autoFocus: props.autoFocus ?? false,
12
- "data-test": testId,
13
- disabled,
14
- id: name,
15
- max: props.max || void 0,
16
- min: props.min || void 0,
17
- name,
18
- onChange: (event) => commit(event.target.value),
19
- readOnly,
20
- step: props.step ?? void 0,
21
- tabIndex: props.tabIndex ?? void 0,
22
- type: "time",
23
- value
17
+ children: ({ name, testId, value, readOnly, disabled, commit, blur }) => /* @__PURE__ */ jsxs("div", {
18
+ className: "flex gap-2",
19
+ children: [/* @__PURE__ */ jsx(Input, {
20
+ "aria-label": triggerLabel,
21
+ autoFocus: props.autoFocus ?? false,
22
+ "data-test": testId,
23
+ disabled,
24
+ id: name,
25
+ name,
26
+ onBlur: () => {
27
+ const parsed = parseTimeString(value);
28
+ if (parsed) commit(formatTimeValue(parsed, withSeconds));
29
+ blur();
30
+ },
31
+ onChange: (event) => commit(event.target.value),
32
+ readOnly,
33
+ tabIndex: props.tabIndex ?? void 0,
34
+ type: "text",
35
+ value
36
+ }), /* @__PURE__ */ jsxs(Popover, { children: [/* @__PURE__ */ jsx(PopoverTrigger, {
37
+ asChild: true,
38
+ children: /* @__PURE__ */ jsx(Button, {
39
+ "aria-label": `Open ${triggerLabel} time picker`,
40
+ disabled: disabled || readOnly,
41
+ size: "icon",
42
+ type: "button",
43
+ variant: "secondary",
44
+ children: /* @__PURE__ */ jsx(Icon, {
45
+ name: "clock",
46
+ className: "size-lt-icon-md",
47
+ "aria-hidden": "true"
48
+ })
49
+ })
50
+ }), /* @__PURE__ */ jsx(PopoverContent, {
51
+ className: "p-2",
52
+ children: /* @__PURE__ */ jsx(TimePicker, {
53
+ value: parseTimeString(value),
54
+ onChange: (next) => commit(formatTimeValue(next, withSeconds)),
55
+ step: props.step,
56
+ min: props.min,
57
+ max: props.max,
58
+ disabled,
59
+ readOnly,
60
+ testId: `${testId}-picker`
61
+ })
62
+ })] })]
24
63
  })
25
64
  });
26
65
  };
@@ -1 +1 @@
1
- {"version":3,"file":"time-input.js","names":[],"sources":["../../../../resources/js/form/components/fields/time-input.tsx"],"sourcesContent":["import type { RendererComponent } from \"@lattice-php/lattice/core/types\";\nimport { Input } from \"../base/input\";\nimport { SimpleField } from \"./simple-field\";\n\nexport const TimeInputComponent: RendererComponent<\"field.time-input\"> = ({ node }) => {\n const props = node.props;\n\n return (\n <SimpleField node={node} label={props.label ?? \"\"}>\n {({ name, testId, value, readOnly, disabled, commit }) => (\n <Input\n autoFocus={props.autoFocus ?? false}\n data-test={testId}\n disabled={disabled}\n id={name}\n max={props.max || undefined}\n min={props.min || undefined}\n name={name}\n onChange={(event) => commit(event.target.value)}\n readOnly={readOnly}\n step={props.step ?? undefined}\n tabIndex={props.tabIndex ?? undefined}\n type=\"time\"\n value={value}\n />\n )}\n </SimpleField>\n );\n};\n"],"mappings":";;;;AAIA,IAAa,sBAA6D,EAAE,WAAW;CACrF,MAAM,QAAQ,KAAK;CAEnB,OACE,oBAAC,aAAD;EAAmB;EAAM,OAAO,MAAM,SAAS;aAC3C,EAAE,MAAM,QAAQ,OAAO,UAAU,UAAU,aAC3C,oBAAC,OAAD;GACE,WAAW,MAAM,aAAa;GAC9B,aAAW;GACD;GACV,IAAI;GACJ,KAAK,MAAM,OAAO,KAAA;GAClB,KAAK,MAAM,OAAO,KAAA;GACZ;GACN,WAAW,UAAU,OAAO,MAAM,OAAO,KAAK;GACpC;GACV,MAAM,MAAM,QAAQ,KAAA;GACpB,UAAU,MAAM,YAAY,KAAA;GAC5B,MAAK;GACE;EACR,CAAA;CAEQ,CAAA;AAEjB"}
1
+ {"version":3,"file":"time-input.js","names":[],"sources":["../../../../resources/js/form/components/fields/time-input.tsx"],"sourcesContent":["import type { RendererComponent } from \"@lattice-php/lattice/core/types\";\nimport { Button } from \"@lattice-php/lattice/core/components/button\";\nimport {\n Popover,\n PopoverContent,\n PopoverTrigger,\n} from \"@lattice-php/lattice/core/components/popover\";\nimport { Icon } from \"@lattice-php/lattice/icons\";\nimport { Input } from \"../base/input\";\nimport { SimpleField } from \"./simple-field\";\nimport { TimePicker } from \"./time-picker\";\nimport { formatTimeValue, parseTimeString, secondsEnabled } from \"./time-picker-columns\";\n\nexport const TimeInputComponent: RendererComponent<\"field.time-input\"> = ({ node }) => {\n const props = node.props;\n const withSeconds = secondsEnabled(props.step);\n const triggerLabel = props.label ?? props.name;\n\n return (\n <SimpleField node={node} label={props.label ?? \"\"}>\n {({ name, testId, value, readOnly, disabled, commit, blur }) => (\n <div className=\"flex gap-2\">\n <Input\n aria-label={triggerLabel}\n autoFocus={props.autoFocus ?? false}\n data-test={testId}\n disabled={disabled}\n id={name}\n name={name}\n onBlur={() => {\n const parsed = parseTimeString(value);\n\n if (parsed) {\n commit(formatTimeValue(parsed, withSeconds));\n }\n\n blur();\n }}\n onChange={(event) => commit(event.target.value)}\n readOnly={readOnly}\n tabIndex={props.tabIndex ?? undefined}\n type=\"text\"\n value={value}\n />\n <Popover>\n <PopoverTrigger asChild>\n <Button\n aria-label={`Open ${triggerLabel} time picker`}\n disabled={disabled || readOnly}\n size=\"icon\"\n type=\"button\"\n variant=\"secondary\"\n >\n <Icon name=\"clock\" className=\"size-lt-icon-md\" aria-hidden=\"true\" />\n </Button>\n </PopoverTrigger>\n <PopoverContent className=\"p-2\">\n <TimePicker\n value={parseTimeString(value)}\n onChange={(next) => commit(formatTimeValue(next, withSeconds))}\n step={props.step}\n min={props.min}\n max={props.max}\n disabled={disabled}\n readOnly={readOnly}\n testId={`${testId}-picker`}\n />\n </PopoverContent>\n </Popover>\n </div>\n )}\n </SimpleField>\n );\n};\n"],"mappings":";;;;;;;;;AAaA,IAAa,sBAA6D,EAAE,WAAW;CACrF,MAAM,QAAQ,KAAK;CACnB,MAAM,cAAc,eAAe,MAAM,IAAI;CAC7C,MAAM,eAAe,MAAM,SAAS,MAAM;CAE1C,OACE,oBAAC,aAAD;EAAmB;EAAM,OAAO,MAAM,SAAS;aAC3C,EAAE,MAAM,QAAQ,OAAO,UAAU,UAAU,QAAQ,WACnD,qBAAC,OAAD;GAAK,WAAU;aAAf,CACE,oBAAC,OAAD;IACE,cAAY;IACZ,WAAW,MAAM,aAAa;IAC9B,aAAW;IACD;IACV,IAAI;IACE;IACN,cAAc;KACZ,MAAM,SAAS,gBAAgB,KAAK;KAEpC,IAAI,QACF,OAAO,gBAAgB,QAAQ,WAAW,CAAC;KAG7C,KAAK;IACP;IACA,WAAW,UAAU,OAAO,MAAM,OAAO,KAAK;IACpC;IACV,UAAU,MAAM,YAAY,KAAA;IAC5B,MAAK;IACE;GACR,CAAA,GACD,qBAAC,SAAD,EAAA,UAAA,CACE,oBAAC,gBAAD;IAAgB,SAAA;cACd,oBAAC,QAAD;KACE,cAAY,QAAQ,aAAa;KACjC,UAAU,YAAY;KACtB,MAAK;KACL,MAAK;KACL,SAAQ;eAER,oBAAC,MAAD;MAAM,MAAK;MAAQ,WAAU;MAAkB,eAAY;KAAQ,CAAA;IAC7D,CAAA;GACM,CAAA,GAChB,oBAAC,gBAAD;IAAgB,WAAU;cACxB,oBAAC,YAAD;KACE,OAAO,gBAAgB,KAAK;KAC5B,WAAW,SAAS,OAAO,gBAAgB,MAAM,WAAW,CAAC;KAC7D,MAAM,MAAM;KACZ,KAAK,MAAM;KACX,KAAK,MAAM;KACD;KACA;KACV,QAAQ,GAAG,OAAO;IACnB,CAAA;GACa,CAAA,CACT,EAAA,CAAA,CACN;;CAEI,CAAA;AAEjB"}
@@ -0,0 +1,24 @@
1
+ export type TimeValue = {
2
+ hour: number;
3
+ minute: number;
4
+ second: number;
5
+ };
6
+ export type TimeColumnOption = {
7
+ value: number;
8
+ label: string;
9
+ disabled: boolean;
10
+ };
11
+ type TimeColumns = {
12
+ hours: TimeColumnOption[];
13
+ minutes: TimeColumnOption[];
14
+ seconds: TimeColumnOption[] | null;
15
+ };
16
+ export declare function parseTimeString(value: string | null | undefined): TimeValue | null;
17
+ export declare function formatTimeValue(value: TimeValue, withSeconds: boolean): string;
18
+ export declare function secondsEnabled(step: number | null | undefined): boolean;
19
+ export declare function buildTimeColumns(step: number | null | undefined, options?: {
20
+ min?: string | null;
21
+ max?: string | null;
22
+ current?: TimeValue | null;
23
+ }): TimeColumns;
24
+ export {};
@@ -0,0 +1,76 @@
1
+ //#region resources/js/form/components/fields/time-picker-columns.ts
2
+ var timePattern = /^(\d{1,2}):(\d{2})(?::(\d{2}))?$/;
3
+ function parseTimeString(value) {
4
+ if (typeof value !== "string") return null;
5
+ const match = timePattern.exec(value.trim());
6
+ if (!match) return null;
7
+ const hour = Number(match[1]);
8
+ const minute = Number(match[2]);
9
+ const second = match[3] ? Number(match[3]) : 0;
10
+ if (hour > 23 || minute > 59 || second > 59) return null;
11
+ return {
12
+ hour,
13
+ minute,
14
+ second
15
+ };
16
+ }
17
+ function formatTimeValue(value, withSeconds) {
18
+ const parts = [pad(value.hour), pad(value.minute)];
19
+ if (withSeconds) parts.push(pad(value.second));
20
+ return parts.join(":");
21
+ }
22
+ function secondsEnabled(step) {
23
+ return step != null && step < 60;
24
+ }
25
+ function buildTimeColumns(step, options = {}) {
26
+ const { min, max, current } = options;
27
+ const minBound = toBound(min);
28
+ const maxBound = toBound(max);
29
+ const minuteStep = step == null || step < 60 ? 1 : step % 60 === 0 ? step / 60 : 1;
30
+ return {
31
+ hours: range(0, 23, 1).map((value) => ({
32
+ value,
33
+ label: pad(value),
34
+ disabled: minBound != null && value < minBound.hour || maxBound != null && value > maxBound.hour
35
+ })),
36
+ minutes: withValue(range(0, 59, minuteStep), current?.minute).map((value) => ({
37
+ value,
38
+ label: pad(value),
39
+ disabled: minuteDisabled(value, current, minBound, maxBound)
40
+ })),
41
+ seconds: secondsEnabled(step) ? range(0, 59, 1).map((value) => ({
42
+ value,
43
+ label: pad(value),
44
+ disabled: false
45
+ })) : null
46
+ };
47
+ }
48
+ function minuteDisabled(minute, current, minBound, maxBound) {
49
+ if (!current) return false;
50
+ if (minBound != null && current.hour === minBound.hour && minute < minBound.minute) return true;
51
+ if (maxBound != null && current.hour === maxBound.hour && minute > maxBound.minute) return true;
52
+ return false;
53
+ }
54
+ function toBound(value) {
55
+ const parsed = parseTimeString(value);
56
+ return parsed ? {
57
+ hour: parsed.hour,
58
+ minute: parsed.minute
59
+ } : null;
60
+ }
61
+ function withValue(values, extra) {
62
+ if (extra == null || values.includes(extra)) return values;
63
+ return [...values, extra].sort((left, right) => left - right);
64
+ }
65
+ function range(start, end, step) {
66
+ const values = [];
67
+ for (let value = start; value <= end; value += step) values.push(value);
68
+ return values;
69
+ }
70
+ function pad(value) {
71
+ return String(value).padStart(2, "0");
72
+ }
73
+ //#endregion
74
+ export { buildTimeColumns, formatTimeValue, parseTimeString, secondsEnabled };
75
+
76
+ //# sourceMappingURL=time-picker-columns.js.map
@@ -0,0 +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\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"}
@@ -0,0 +1,18 @@
1
+ import { TimeValue } from './time-picker-columns';
2
+ type TimePickerProps = {
3
+ value: TimeValue | null;
4
+ onChange: (next: TimeValue) => void;
5
+ step?: number | null;
6
+ min?: string | null;
7
+ max?: string | null;
8
+ disabled?: boolean;
9
+ readOnly?: boolean;
10
+ labels?: {
11
+ hour?: string;
12
+ minute?: string;
13
+ second?: string;
14
+ };
15
+ testId?: string;
16
+ };
17
+ export declare function TimePicker({ value, onChange, step, min, max, disabled, readOnly, labels, testId, }: TimePickerProps): import("react").JSX.Element;
18
+ export {};
@@ -0,0 +1,132 @@
1
+ import { cn } from "../../../lib/utils.js";
2
+ import { buildTimeColumns } from "./time-picker-columns.js";
3
+ import { useEffect, useRef } from "react";
4
+ import { jsx } from "react/jsx-runtime";
5
+ //#region resources/js/form/components/fields/time-picker.tsx
6
+ function TimePicker({ value, onChange, step, min, max, disabled = false, readOnly = false, labels, testId }) {
7
+ const containerRef = useRef(null);
8
+ const columns = buildTimeColumns(step, {
9
+ min,
10
+ max,
11
+ current: value
12
+ });
13
+ const current = value ?? {
14
+ hour: 0,
15
+ minute: 0,
16
+ second: 0
17
+ };
18
+ const interactive = !disabled && !readOnly;
19
+ const columnList = [
20
+ {
21
+ key: "hour",
22
+ label: labels?.hour ?? "Hour",
23
+ options: columns.hours,
24
+ selected: current.hour
25
+ },
26
+ {
27
+ key: "minute",
28
+ label: labels?.minute ?? "Minute",
29
+ options: columns.minutes,
30
+ selected: current.minute
31
+ },
32
+ ...columns.seconds ? [{
33
+ key: "second",
34
+ label: labels?.second ?? "Second",
35
+ options: columns.seconds,
36
+ selected: current.second
37
+ }] : []
38
+ ];
39
+ function focusColumn(index) {
40
+ const target = (containerRef.current?.querySelectorAll("[role=\"listbox\"]"))?.[index];
41
+ if (!target) return;
42
+ (target.querySelector("[data-active=\"true\"]") ?? target.querySelector("[role=\"option\"]"))?.focus();
43
+ }
44
+ return /* @__PURE__ */ jsx("div", {
45
+ ref: containerRef,
46
+ className: "flex gap-1",
47
+ "data-test": testId,
48
+ children: columnList.map((column, index) => /* @__PURE__ */ jsx(TimeColumn, {
49
+ label: column.label,
50
+ options: column.options,
51
+ selected: value ? column.selected : null,
52
+ disabled: !interactive,
53
+ onSelect: (optionValue) => interactive && onChange({
54
+ ...current,
55
+ [column.key]: optionValue
56
+ }),
57
+ onHorizontal: (direction) => focusColumn(index + direction)
58
+ }, column.key))
59
+ });
60
+ }
61
+ function TimeColumn({ label, options, selected, disabled, onSelect, onHorizontal }) {
62
+ const listRef = useRef(null);
63
+ const enabledValues = options.filter((option) => !option.disabled).map((option) => option.value);
64
+ const activeValue = selected ?? enabledValues[0] ?? options[0]?.value ?? 0;
65
+ useEffect(() => {
66
+ (listRef.current?.querySelector("[data-active=\"true\"]"))?.scrollIntoView?.({ block: "nearest" });
67
+ }, [selected]);
68
+ function moveTo(nextValue) {
69
+ if (nextValue == null) return;
70
+ listRef.current?.querySelector(`[data-value="${nextValue}"]`)?.focus();
71
+ onSelect(nextValue);
72
+ }
73
+ function handleKeyDown(event) {
74
+ if (disabled) return;
75
+ const index = enabledValues.indexOf(activeValue);
76
+ switch (event.key) {
77
+ case "ArrowDown":
78
+ event.preventDefault();
79
+ moveTo(enabledValues[Math.min(index + 1, enabledValues.length - 1)]);
80
+ break;
81
+ case "ArrowUp":
82
+ event.preventDefault();
83
+ moveTo(enabledValues[Math.max(index - 1, 0)]);
84
+ break;
85
+ case "Home":
86
+ event.preventDefault();
87
+ moveTo(enabledValues[0]);
88
+ break;
89
+ case "End":
90
+ event.preventDefault();
91
+ moveTo(enabledValues[enabledValues.length - 1]);
92
+ break;
93
+ case "ArrowRight":
94
+ event.preventDefault();
95
+ onHorizontal(1);
96
+ break;
97
+ case "ArrowLeft":
98
+ event.preventDefault();
99
+ onHorizontal(-1);
100
+ break;
101
+ }
102
+ }
103
+ return /* @__PURE__ */ jsx("div", {
104
+ ref: listRef,
105
+ role: "listbox",
106
+ "aria-label": label,
107
+ "aria-orientation": "vertical",
108
+ tabIndex: -1,
109
+ className: "flex max-h-40 w-14 flex-col overflow-y-auto",
110
+ onKeyDown: handleKeyDown,
111
+ children: options.map((option) => {
112
+ const isSelected = selected === option.value;
113
+ return /* @__PURE__ */ jsx("button", {
114
+ type: "button",
115
+ role: "option",
116
+ "aria-selected": isSelected,
117
+ "aria-label": `${label} ${option.label}`,
118
+ "data-value": option.value,
119
+ "data-active": activeValue === option.value,
120
+ disabled: disabled || option.disabled,
121
+ tabIndex: activeValue === option.value ? 0 : -1,
122
+ onClick: () => onSelect(option.value),
123
+ className: cn("shrink-0 rounded-lt-sm px-2 py-1 text-sm text-lt-fg hover:bg-lt-muted", isSelected && "bg-lt-primary text-lt-primary-fg", (disabled || option.disabled) && "cursor-not-allowed opacity-40"),
124
+ children: option.label
125
+ }, option.value);
126
+ })
127
+ });
128
+ }
129
+ //#endregion
130
+ export { TimePicker };
131
+
132
+ //# sourceMappingURL=time-picker.js.map
@@ -0,0 +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\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":";;;;;AAgBA,SAAgB,WAAW,EACzB,OACA,UACA,MACA,KACA,KACA,WAAW,OACX,WAAW,OACX,QACA,UACkB;CAClB,MAAM,eAAe,OAAuB,IAAI;CAChD,MAAM,UAAU,iBAAiB,MAAM;EAAE;EAAK;EAAK,SAAS;CAAM,CAAC;CACnE,MAAM,UAAqB,SAAS;EAAE,MAAM;EAAG,QAAQ;EAAG,QAAQ;CAAE;CACpE,MAAM,cAAc,CAAC,YAAY,CAAC;CAElC,MAAM,aAAa;EACjB;GACE,KAAK;GACL,OAAO,QAAQ,QAAQ;GACvB,SAAS,QAAQ;GACjB,UAAU,QAAQ;EACpB;EACA;GACE,KAAK;GACL,OAAO,QAAQ,UAAU;GACzB,SAAS,QAAQ;GACjB,UAAU,QAAQ;EACpB;EACA,GAAI,QAAQ,UACR,CACE;GACE,KAAK;GACL,OAAO,QAAQ,UAAU;GACzB,SAAS,QAAQ;GACjB,UAAU,QAAQ;EACpB,CACF,IACA,CAAC;CACP;CAEA,SAAS,YAAY,OAAe;EAElC,MAAM,UADY,aAAa,SAAS,iBAA8B,oBAAkB,KAC7D;EAE3B,IAAI,CAAC,QACH;EAOF,CAHE,OAAO,cAA2B,wBAAsB,KACxD,OAAO,cAA2B,mBAAiB,IAE7C,MAAM;CAChB;CAEA,OACE,oBAAC,OAAD;EAAK,KAAK;EAAc,WAAU;EAAa,aAAW;YACvD,WAAW,KAAK,QAAQ,UACvB,oBAAC,YAAD;GAEE,OAAO,OAAO;GACd,SAAS,OAAO;GAChB,UAAU,QAAQ,OAAO,WAAW;GACpC,UAAU,CAAC;GACX,WAAW,gBACT,eAAe,SAAS;IAAE,GAAG;KAAU,OAAO,MAAM;GAAY,CAAC;GAEnE,eAAe,cAAc,YAAY,QAAQ,SAAS;EAC3D,GATM,OAAO,GASb,CACF;CACE,CAAA;AAET;AAEA,SAAS,WAAW,EAClB,OACA,SACA,UACA,UACA,UACA,gBAQC;CACD,MAAM,UAAU,OAAuB,IAAI;CAC3C,MAAM,gBAAgB,QAAQ,QAAQ,WAAW,CAAC,OAAO,QAAQ,EAAE,KAAK,WAAW,OAAO,KAAK;CAC/F,MAAM,cAAc,YAAY,cAAc,MAAM,QAAQ,IAAI,SAAS;CAEzE,gBAAgB;EAGd,CAFe,QAAQ,SAAS,cAA2B,wBAAsB,IAEzE,iBAAiB,EAAE,OAAO,UAAU,CAAC;CAC/C,GAAG,CAAC,QAAQ,CAAC;CAEb,SAAS,OAAO,WAA+B;EAC7C,IAAI,aAAa,MACf;EAGF,QAAQ,SAAS,cAA2B,gBAAgB,UAAU,GAAG,GAAG,MAAM;EAClF,SAAS,SAAS;CACpB;CAEA,SAAS,cAAc,OAAsB;EAC3C,IAAI,UACF;EAGF,MAAM,QAAQ,cAAc,QAAQ,WAAW;EAE/C,QAAQ,MAAM,KAAd;GACE,KAAK;IACH,MAAM,eAAe;IACrB,OAAO,cAAc,KAAK,IAAI,QAAQ,GAAG,cAAc,SAAS,CAAC,EAAE;IACnE;GACF,KAAK;IACH,MAAM,eAAe;IACrB,OAAO,cAAc,KAAK,IAAI,QAAQ,GAAG,CAAC,EAAE;IAC5C;GACF,KAAK;IACH,MAAM,eAAe;IACrB,OAAO,cAAc,EAAE;IACvB;GACF,KAAK;IACH,MAAM,eAAe;IACrB,OAAO,cAAc,cAAc,SAAS,EAAE;IAC9C;GACF,KAAK;IACH,MAAM,eAAe;IACrB,aAAa,CAAC;IACd;GACF,KAAK;IACH,MAAM,eAAe;IACrB,aAAa,EAAE;IACf;EACJ;CACF;CAEA,OACE,oBAAC,OAAD;EACE,KAAK;EACL,MAAK;EACL,cAAY;EACZ,oBAAiB;EACjB,UAAU;EACV,WAAU;EACV,WAAW;YAEV,QAAQ,KAAK,WAAW;GACvB,MAAM,aAAa,aAAa,OAAO;GAEvC,OACE,oBAAC,UAAD;IAEE,MAAK;IACL,MAAK;IACL,iBAAe;IACf,cAAY,GAAG,MAAM,GAAG,OAAO;IAC/B,cAAY,OAAO;IACnB,eAAa,gBAAgB,OAAO;IACpC,UAAU,YAAY,OAAO;IAC7B,UAAU,gBAAgB,OAAO,QAAQ,IAAI;IAC7C,eAAe,SAAS,OAAO,KAAK;IACpC,WAAW,GACT,yEACA,cAAc,qCACb,YAAY,OAAO,aAAa,+BACnC;cAEC,OAAO;GACF,GAjBD,OAAO,KAiBN;EAEZ,CAAC;CACE,CAAA;AAET"}
@@ -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
@@ -1 +1 @@
1
- {"version":3,"file":"form-path.js","names":[],"sources":["../../../resources/js/form/components/form-path.ts"],"sourcesContent":["export function pathParts(path: string): string[] {\n return path.split(\".\").filter((part) => part !== \"\");\n}\n\nexport function appendPath(\n base: string | null | undefined,\n ...parts: Array<string | number>\n): string {\n const suffix = parts.map(String).filter((part) => part !== \"\");\n\n return [base ?? \"\", ...suffix].filter((part) => part !== \"\").join(\".\");\n}\n\nexport function toHtmlName(path: string): string {\n const [head, ...tail] = pathParts(path);\n\n return tail.reduce((name, part) => `${name}[${part}]`, head ?? \"\");\n}\n\nexport function getPath(values: Record<string, unknown>, path: string): unknown {\n let current: unknown = values;\n\n for (const part of pathParts(path)) {\n if (current == null) {\n return undefined;\n }\n\n current = (current as Record<string, unknown>)[part];\n }\n\n return current;\n}\n\nfunction emptyContainer(nextPart: string | undefined): Record<string, unknown> | unknown[] {\n return nextPart !== undefined && /^\\d+$/.test(nextPart) ? [] : {};\n}\n\nexport function setPath(\n values: Record<string, unknown>,\n path: string,\n value: unknown,\n): Record<string, unknown> {\n const parts = pathParts(path);\n\n if (parts.length === 0) {\n return values;\n }\n\n const write = (current: unknown, index: number): unknown => {\n const part = parts[index];\n const last = index === parts.length - 1;\n const source =\n current && typeof current === \"object\" ? current : emptyContainer(parts[index + 1]);\n const next = Array.isArray(source) ? [...source] : { ...(source as Record<string, unknown>) };\n\n (next as Record<string, unknown>)[part] = last\n ? value\n : write((source as Record<string, unknown>)[part], index + 1);\n\n return next;\n };\n\n return write(values, 0) as Record<string, unknown>;\n}\n"],"mappings":";AAAA,SAAgB,UAAU,MAAwB;CAChD,OAAO,KAAK,MAAM,GAAG,EAAE,QAAQ,SAAS,SAAS,EAAE;AACrD;AAEA,SAAgB,WACd,MACA,GAAG,OACK;CACR,MAAM,SAAS,MAAM,IAAI,MAAM,EAAE,QAAQ,SAAS,SAAS,EAAE;CAE7D,OAAO,CAAC,QAAQ,IAAI,GAAG,MAAM,EAAE,QAAQ,SAAS,SAAS,EAAE,EAAE,KAAK,GAAG;AACvE;AAEA,SAAgB,WAAW,MAAsB;CAC/C,MAAM,CAAC,MAAM,GAAG,QAAQ,UAAU,IAAI;CAEtC,OAAO,KAAK,QAAQ,MAAM,SAAS,GAAG,KAAK,GAAG,KAAK,IAAI,QAAQ,EAAE;AACnE;AAEA,SAAgB,QAAQ,QAAiC,MAAuB;CAC9E,IAAI,UAAmB;CAEvB,KAAK,MAAM,QAAQ,UAAU,IAAI,GAAG;EAClC,IAAI,WAAW,MACb;EAGF,UAAW,QAAoC;CACjD;CAEA,OAAO;AACT;AAEA,SAAS,eAAe,UAAmE;CACzF,OAAO,aAAa,KAAA,KAAa,QAAQ,KAAK,QAAQ,IAAI,CAAC,IAAI,CAAC;AAClE;AAEA,SAAgB,QACd,QACA,MACA,OACyB;CACzB,MAAM,QAAQ,UAAU,IAAI;CAE5B,IAAI,MAAM,WAAW,GACnB,OAAO;CAGT,MAAM,SAAS,SAAkB,UAA2B;EAC1D,MAAM,OAAO,MAAM;EACnB,MAAM,OAAO,UAAU,MAAM,SAAS;EACtC,MAAM,SACJ,WAAW,OAAO,YAAY,WAAW,UAAU,eAAe,MAAM,QAAQ,EAAE;EACpF,MAAM,OAAO,MAAM,QAAQ,MAAM,IAAI,CAAC,GAAG,MAAM,IAAI,EAAE,GAAI,OAAmC;EAE5F,KAAkC,QAAQ,OACtC,QACA,MAAO,OAAmC,OAAO,QAAQ,CAAC;EAE9D,OAAO;CACT;CAEA,OAAO,MAAM,QAAQ,CAAC;AACxB"}
1
+ {"version":3,"file":"form-path.js","names":[],"sources":["../../../resources/js/form/components/form-path.ts"],"sourcesContent":["function pathParts(path: string): string[] {\n return path.split(\".\").filter((part) => part !== \"\");\n}\n\nexport function appendPath(\n base: string | null | undefined,\n ...parts: Array<string | number>\n): string {\n const suffix = parts.map(String).filter((part) => part !== \"\");\n\n return [base ?? \"\", ...suffix].filter((part) => part !== \"\").join(\".\");\n}\n\nexport function toHtmlName(path: string): string {\n const [head, ...tail] = pathParts(path);\n\n return tail.reduce((name, part) => `${name}[${part}]`, head ?? \"\");\n}\n\nexport function getPath(values: Record<string, unknown>, path: string): unknown {\n let current: unknown = values;\n\n for (const part of pathParts(path)) {\n if (current == null) {\n return undefined;\n }\n\n current = (current as Record<string, unknown>)[part];\n }\n\n return current;\n}\n\nfunction emptyContainer(nextPart: string | undefined): Record<string, unknown> | unknown[] {\n return nextPart !== undefined && /^\\d+$/.test(nextPart) ? [] : {};\n}\n\nexport function setPath(\n values: Record<string, unknown>,\n path: string,\n value: unknown,\n): Record<string, unknown> {\n const parts = pathParts(path);\n\n if (parts.length === 0) {\n return values;\n }\n\n const write = (current: unknown, index: number): unknown => {\n const part = parts[index];\n const last = index === parts.length - 1;\n const source =\n current && typeof current === \"object\" ? current : emptyContainer(parts[index + 1]);\n const next = Array.isArray(source) ? [...source] : { ...(source as Record<string, unknown>) };\n\n (next as Record<string, unknown>)[part] = last\n ? value\n : write((source as Record<string, unknown>)[part], index + 1);\n\n return next;\n };\n\n return write(values, 0) as Record<string, unknown>;\n}\n"],"mappings":";AAAA,SAAS,UAAU,MAAwB;CACzC,OAAO,KAAK,MAAM,GAAG,EAAE,QAAQ,SAAS,SAAS,EAAE;AACrD;AAEA,SAAgB,WACd,MACA,GAAG,OACK;CACR,MAAM,SAAS,MAAM,IAAI,MAAM,EAAE,QAAQ,SAAS,SAAS,EAAE;CAE7D,OAAO,CAAC,QAAQ,IAAI,GAAG,MAAM,EAAE,QAAQ,SAAS,SAAS,EAAE,EAAE,KAAK,GAAG;AACvE;AAEA,SAAgB,WAAW,MAAsB;CAC/C,MAAM,CAAC,MAAM,GAAG,QAAQ,UAAU,IAAI;CAEtC,OAAO,KAAK,QAAQ,MAAM,SAAS,GAAG,KAAK,GAAG,KAAK,IAAI,QAAQ,EAAE;AACnE;AAEA,SAAgB,QAAQ,QAAiC,MAAuB;CAC9E,IAAI,UAAmB;CAEvB,KAAK,MAAM,QAAQ,UAAU,IAAI,GAAG;EAClC,IAAI,WAAW,MACb;EAGF,UAAW,QAAoC;CACjD;CAEA,OAAO;AACT;AAEA,SAAS,eAAe,UAAmE;CACzF,OAAO,aAAa,KAAA,KAAa,QAAQ,KAAK,QAAQ,IAAI,CAAC,IAAI,CAAC;AAClE;AAEA,SAAgB,QACd,QACA,MACA,OACyB;CACzB,MAAM,QAAQ,UAAU,IAAI;CAE5B,IAAI,MAAM,WAAW,GACnB,OAAO;CAGT,MAAM,SAAS,SAAkB,UAA2B;EAC1D,MAAM,OAAO,MAAM;EACnB,MAAM,OAAO,UAAU,MAAM,SAAS;EACtC,MAAM,SACJ,WAAW,OAAO,YAAY,WAAW,UAAU,eAAe,MAAM,QAAQ,EAAE;EACpF,MAAM,OAAO,MAAM,QAAQ,MAAM,IAAI,CAAC,GAAG,MAAM,IAAI,EAAE,GAAI,OAAmC;EAE5F,KAAkC,QAAQ,OACtC,QACA,MAAO,OAAmC,OAAO,QAAQ,CAAC;EAE9D,OAAO;CACT;CAEA,OAAO,MAAM,QAAQ,CAAC;AACxB"}
@@ -1,5 +1,5 @@
1
1
  import { Node } from '../../core/types';
2
- export type PrefillTarget = {
2
+ type PrefillTarget = {
3
3
  path: string;
4
4
  overrideKey: string;
5
5
  resetOn: string[];
@@ -1 +1 @@
1
- {"version":3,"file":"prefill-targets.js","names":[],"sources":["../../../resources/js/form/components/prefill-targets.ts"],"sourcesContent":["import type { Node } from \"@lattice-php/lattice/core/types\";\nimport { fieldProps } from \"./field-props\";\nimport { appendPath, getPath } from \"./form-path\";\nimport { buildOverrideKey, rowIdFrom } from \"./override-keys\";\n\nexport type PrefillTarget = {\n path: string;\n overrideKey: string;\n resetOn: string[];\n refreshOn: string[];\n};\n\ntype PrefillSnapshot = {\n targets: PrefillTarget[];\n values: Record<string, unknown>;\n};\n\ntype Block = { type: string; label: string; schema: Node[] };\n\nconst ROW_COLLECTION_TYPES = new Set([\"field.builder\", \"field.repeater\"]);\n\nexport { getPath } from \"./form-path\";\n\nfunction mapDep(dep: string, rowPath: string | null): string {\n if (dep.startsWith(\"@\")) {\n return dep.slice(1);\n }\n\n return rowPath === null ? dep : appendPath(rowPath, dep);\n}\n\nfunction targetFor(\n node: Node,\n rowPath: string | null,\n identityCollectionPath: string | null,\n index = 0,\n row: Record<string, unknown> = {},\n): PrefillTarget | null {\n const props = fieldProps(node);\n\n if (!props.editablePrefill || !props.name) {\n return null;\n }\n\n const rowId = rowIdFrom(row);\n\n return {\n path: rowPath === null ? props.name : appendPath(rowPath, props.name),\n overrideKey:\n identityCollectionPath === null\n ? props.name\n : buildOverrideKey(identityCollectionPath, rowId, index, props.name),\n resetOn: (props.prefillResetOn ?? []).map((dep) => mapDep(dep, rowPath)),\n refreshOn: (props.prefillRefreshOn ?? []).map((dep) => mapDep(dep, rowPath)),\n };\n}\n\nexport function collectPrefillTargets(\n nodes: Node[] | undefined,\n values: Record<string, unknown>,\n): PrefillTarget[] {\n const targets: PrefillTarget[] = [];\n\n const walk = (\n list: Node[] | undefined,\n rowPath: string | null = null,\n identityRowPath: string | null = null,\n identityCollectionPath: string | null = null,\n index = 0,\n row: Record<string, unknown> = {},\n ): void => {\n for (const node of list ?? []) {\n if (ROW_COLLECTION_TYPES.has(node.type)) {\n const name = fieldProps(node).name;\n if (name) {\n const childCollectionPath = appendPath(rowPath, name);\n const childIdentityCollectionPath = appendPath(identityRowPath, name);\n const storedRows = getPath(values, childCollectionPath);\n const rows = Array.isArray(storedRows)\n ? (storedRows as Array<Record<string, unknown>>)\n : [];\n const blocks = (node as unknown as { blocks?: Block[] }).blocks;\n\n rows.forEach((childRow, childIndex) => {\n const template = blocks\n ? (blocks.find((block) => block.type === childRow.type)?.schema ?? [])\n : (node.schema ?? []);\n\n walk(\n template,\n appendPath(childCollectionPath, childIndex),\n appendPath(childIdentityCollectionPath, rowIdFrom(childRow) ?? childIndex),\n childIdentityCollectionPath,\n childIndex,\n childRow,\n );\n });\n }\n\n continue;\n }\n\n const target = targetFor(node, rowPath, identityCollectionPath, index, row);\n if (target) {\n targets.push(target);\n }\n\n walk(node.schema, rowPath, identityRowPath, identityCollectionPath, index, row);\n }\n };\n\n walk(nodes);\n\n return targets;\n}\n\nexport function pathsToClear(previous: PrefillSnapshot, next: PrefillSnapshot): string[] {\n const previousByKey = new Map(\n previous.targets.map((target) => [target.overrideKey, target] as const),\n );\n\n return next.targets\n .filter((target) => {\n const previousTarget = previousByKey.get(target.overrideKey);\n\n return target.resetOn.some((dep, index) => {\n const previousDep = previousTarget?.resetOn[index] ?? dep;\n\n return !Object.is(getPath(previous.values, previousDep), getPath(next.values, dep));\n });\n })\n .map((target) => target.overrideKey);\n}\n\nexport function seededOverrides(\n targets: PrefillTarget[],\n values: Record<string, unknown>,\n): string[] {\n return targets\n .filter((target) => {\n const value = getPath(values, target.path);\n\n return value !== undefined && value !== null && value !== \"\";\n })\n .map((target) => target.overrideKey);\n}\n\nexport function pruneOverrides(overrides: Set<string>, targets: PrefillTarget[]): Set<string> {\n const liveKeys = new Set(targets.map((target) => target.overrideKey));\n\n return new Set([...overrides].filter((key) => liveKeys.has(key)));\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"prefill-targets.js","names":[],"sources":["../../../resources/js/form/components/prefill-targets.ts"],"sourcesContent":["import type { Node } from \"@lattice-php/lattice/core/types\";\nimport { fieldProps } from \"./field-props\";\nimport { appendPath, getPath } from \"./form-path\";\nimport { buildOverrideKey, rowIdFrom } from \"./override-keys\";\n\ntype PrefillTarget = {\n path: string;\n overrideKey: string;\n resetOn: string[];\n refreshOn: string[];\n};\n\ntype PrefillSnapshot = {\n targets: PrefillTarget[];\n values: Record<string, unknown>;\n};\n\ntype Block = { type: string; label: string; schema: Node[] };\n\nconst ROW_COLLECTION_TYPES = new Set([\"field.builder\", \"field.repeater\"]);\n\nexport { getPath } from \"./form-path\";\n\nfunction mapDep(dep: string, rowPath: string | null): string {\n if (dep.startsWith(\"@\")) {\n return dep.slice(1);\n }\n\n return rowPath === null ? dep : appendPath(rowPath, dep);\n}\n\nfunction targetFor(\n node: Node,\n rowPath: string | null,\n identityCollectionPath: string | null,\n index = 0,\n row: Record<string, unknown> = {},\n): PrefillTarget | null {\n const props = fieldProps(node);\n\n if (!props.editablePrefill || !props.name) {\n return null;\n }\n\n const rowId = rowIdFrom(row);\n\n return {\n path: rowPath === null ? props.name : appendPath(rowPath, props.name),\n overrideKey:\n identityCollectionPath === null\n ? props.name\n : buildOverrideKey(identityCollectionPath, rowId, index, props.name),\n resetOn: (props.prefillResetOn ?? []).map((dep) => mapDep(dep, rowPath)),\n refreshOn: (props.prefillRefreshOn ?? []).map((dep) => mapDep(dep, rowPath)),\n };\n}\n\nexport function collectPrefillTargets(\n nodes: Node[] | undefined,\n values: Record<string, unknown>,\n): PrefillTarget[] {\n const targets: PrefillTarget[] = [];\n\n const walk = (\n list: Node[] | undefined,\n rowPath: string | null = null,\n identityRowPath: string | null = null,\n identityCollectionPath: string | null = null,\n index = 0,\n row: Record<string, unknown> = {},\n ): void => {\n for (const node of list ?? []) {\n if (ROW_COLLECTION_TYPES.has(node.type)) {\n const name = fieldProps(node).name;\n if (name) {\n const childCollectionPath = appendPath(rowPath, name);\n const childIdentityCollectionPath = appendPath(identityRowPath, name);\n const storedRows = getPath(values, childCollectionPath);\n const rows = Array.isArray(storedRows)\n ? (storedRows as Array<Record<string, unknown>>)\n : [];\n const blocks = (node as unknown as { blocks?: Block[] }).blocks;\n\n rows.forEach((childRow, childIndex) => {\n const template = blocks\n ? (blocks.find((block) => block.type === childRow.type)?.schema ?? [])\n : (node.schema ?? []);\n\n walk(\n template,\n appendPath(childCollectionPath, childIndex),\n appendPath(childIdentityCollectionPath, rowIdFrom(childRow) ?? childIndex),\n childIdentityCollectionPath,\n childIndex,\n childRow,\n );\n });\n }\n\n continue;\n }\n\n const target = targetFor(node, rowPath, identityCollectionPath, index, row);\n if (target) {\n targets.push(target);\n }\n\n walk(node.schema, rowPath, identityRowPath, identityCollectionPath, index, row);\n }\n };\n\n walk(nodes);\n\n return targets;\n}\n\nexport function pathsToClear(previous: PrefillSnapshot, next: PrefillSnapshot): string[] {\n const previousByKey = new Map(\n previous.targets.map((target) => [target.overrideKey, target] as const),\n );\n\n return next.targets\n .filter((target) => {\n const previousTarget = previousByKey.get(target.overrideKey);\n\n return target.resetOn.some((dep, index) => {\n const previousDep = previousTarget?.resetOn[index] ?? dep;\n\n return !Object.is(getPath(previous.values, previousDep), getPath(next.values, dep));\n });\n })\n .map((target) => target.overrideKey);\n}\n\nexport function seededOverrides(\n targets: PrefillTarget[],\n values: Record<string, unknown>,\n): string[] {\n return targets\n .filter((target) => {\n const value = getPath(values, target.path);\n\n return value !== undefined && value !== null && value !== \"\";\n })\n .map((target) => target.overrideKey);\n}\n\nexport function pruneOverrides(overrides: Set<string>, targets: PrefillTarget[]): Set<string> {\n const liveKeys = new Set(targets.map((target) => target.overrideKey));\n\n return new Set([...overrides].filter((key) => liveKeys.has(key)));\n}\n"],"mappings":"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"}
@@ -1,5 +1,9 @@
1
1
  import { Method } from '@inertiajs/core';
2
- export type { Checkbox, Choice, DateInput, DateTimeInput, Form, FormFieldNode, FormNode, FormNodeType, HiddenInput, NumberInput, PasswordInput, RichEditor, Select, Textarea, TextInput, TimeInput, } from '../../types/generated';
2
+ import { NodeUnionOf } from '../../core/types';
3
+ import { FormFieldNodeType, FormNodeType } from '../../types/generated';
4
+ export type { Checkbox, Choice, DateInput, DateTimeInput, Form, FormNodeType, HiddenInput, NumberInput, PasswordInput, RichEditor, Select, Textarea, TextInput, TimeInput, } from '../../types/generated';
5
+ export type FormFieldNode = NodeUnionOf<FormFieldNodeType>;
6
+ export type FormNode = NodeUnionOf<FormNodeType>;
3
7
  export type FormMethod = Method;
4
8
  export type FormLabelAction = {
5
9
  href: string;
@@ -1,4 +1,4 @@
1
- export type FieldCommit = {
1
+ type FieldCommit = {
2
2
  /** Write the value and validate immediately (precognitive) or clear errors. */
3
3
  commit: (name: string, value: unknown) => void;
4
4
  /** Write the value and clear errors, deferring validation to a later `blur`. */
@@ -16,3 +16,4 @@ export type FieldCommit = {
16
16
  * behavior is identical to before.
17
17
  */
18
18
  export declare function useFieldCommit(): FieldCommit;
19
+ export {};
@@ -1 +1 @@
1
- {"version":3,"file":"use-field-commit.js","names":[],"sources":["../../../resources/js/form/components/use-field-commit.ts"],"sourcesContent":["import { useFieldScope } from \"./field-scope\";\nimport { useFormContext } from \"./context\";\nimport { usePrefillController } from \"./prefill-context\";\nimport { useSetFormValue } from \"./values\";\n\nexport type FieldCommit = {\n /** Write the value and validate immediately (precognitive) or clear errors. */\n commit: (name: string, value: unknown) => void;\n /** Write the value and clear errors, deferring validation to a later `blur`. */\n change: (name: string, value: unknown) => void;\n /** Validate the field now if precognitive (e.g. on blur or popover close). */\n blur: (name: string) => void;\n};\n\n/**\n * The shared field-mutation contract every form field uses to write its value\n * and drive precognition. Fields that validate on change call `commit`; fields\n * that validate on blur/close (rich editor, select) call `change` then `blur`.\n *\n * When called inside a `FieldScopeProvider`, writes go through the scope's\n * `setValue` and error paths use the scoped dot-key; outside a scope the\n * behavior is identical to before.\n */\nexport function useFieldCommit(): FieldCommit {\n const { clearErrors, precognitive, validate } = useFormContext();\n const setGlobal = useSetFormValue();\n const scope = useFieldScope();\n const prefill = usePrefillController();\n\n const write = (name: string, value: unknown): void => {\n if (scope) {\n scope.setValue(name, value);\n } else {\n setGlobal(name, value);\n }\n prefill?.markUserEdit(scope ? scope.overrideKey(name) : name);\n };\n const errorPath = (name: string): string => (scope ? scope.errorKey(name) : name);\n\n return {\n commit(name, value) {\n write(name, value);\n if (precognitive) {\n validate(errorPath(name));\n } else {\n clearErrors(errorPath(name));\n }\n },\n change(name, value) {\n write(name, value);\n clearErrors(errorPath(name));\n },\n blur(name) {\n if (precognitive) {\n validate(errorPath(name));\n }\n },\n };\n}\n"],"mappings":";;;;;;;;;;;;;;AAuBA,SAAgB,iBAA8B;CAC5C,MAAM,EAAE,aAAa,cAAc,aAAa,eAAe;CAC/D,MAAM,YAAY,gBAAgB;CAClC,MAAM,QAAQ,cAAc;CAC5B,MAAM,UAAU,qBAAqB;CAErC,MAAM,SAAS,MAAc,UAAyB;EACpD,IAAI,OACF,MAAM,SAAS,MAAM,KAAK;OAE1B,UAAU,MAAM,KAAK;EAEvB,SAAS,aAAa,QAAQ,MAAM,YAAY,IAAI,IAAI,IAAI;CAC9D;CACA,MAAM,aAAa,SAA0B,QAAQ,MAAM,SAAS,IAAI,IAAI;CAE5E,OAAO;EACL,OAAO,MAAM,OAAO;GAClB,MAAM,MAAM,KAAK;GACjB,IAAI,cACF,SAAS,UAAU,IAAI,CAAC;QAExB,YAAY,UAAU,IAAI,CAAC;EAE/B;EACA,OAAO,MAAM,OAAO;GAClB,MAAM,MAAM,KAAK;GACjB,YAAY,UAAU,IAAI,CAAC;EAC7B;EACA,KAAK,MAAM;GACT,IAAI,cACF,SAAS,UAAU,IAAI,CAAC;EAE5B;CACF;AACF"}
1
+ {"version":3,"file":"use-field-commit.js","names":[],"sources":["../../../resources/js/form/components/use-field-commit.ts"],"sourcesContent":["import { useFieldScope } from \"./field-scope\";\nimport { useFormContext } from \"./context\";\nimport { usePrefillController } from \"./prefill-context\";\nimport { useSetFormValue } from \"./values\";\n\ntype FieldCommit = {\n /** Write the value and validate immediately (precognitive) or clear errors. */\n commit: (name: string, value: unknown) => void;\n /** Write the value and clear errors, deferring validation to a later `blur`. */\n change: (name: string, value: unknown) => void;\n /** Validate the field now if precognitive (e.g. on blur or popover close). */\n blur: (name: string) => void;\n};\n\n/**\n * The shared field-mutation contract every form field uses to write its value\n * and drive precognition. Fields that validate on change call `commit`; fields\n * that validate on blur/close (rich editor, select) call `change` then `blur`.\n *\n * When called inside a `FieldScopeProvider`, writes go through the scope's\n * `setValue` and error paths use the scoped dot-key; outside a scope the\n * behavior is identical to before.\n */\nexport function useFieldCommit(): FieldCommit {\n const { clearErrors, precognitive, validate } = useFormContext();\n const setGlobal = useSetFormValue();\n const scope = useFieldScope();\n const prefill = usePrefillController();\n\n const write = (name: string, value: unknown): void => {\n if (scope) {\n scope.setValue(name, value);\n } else {\n setGlobal(name, value);\n }\n prefill?.markUserEdit(scope ? scope.overrideKey(name) : name);\n };\n const errorPath = (name: string): string => (scope ? scope.errorKey(name) : name);\n\n return {\n commit(name, value) {\n write(name, value);\n if (precognitive) {\n validate(errorPath(name));\n } else {\n clearErrors(errorPath(name));\n }\n },\n change(name, value) {\n write(name, value);\n clearErrors(errorPath(name));\n },\n blur(name) {\n if (precognitive) {\n validate(errorPath(name));\n }\n },\n };\n}\n"],"mappings":";;;;;;;;;;;;;;AAuBA,SAAgB,iBAA8B;CAC5C,MAAM,EAAE,aAAa,cAAc,aAAa,eAAe;CAC/D,MAAM,YAAY,gBAAgB;CAClC,MAAM,QAAQ,cAAc;CAC5B,MAAM,UAAU,qBAAqB;CAErC,MAAM,SAAS,MAAc,UAAyB;EACpD,IAAI,OACF,MAAM,SAAS,MAAM,KAAK;OAE1B,UAAU,MAAM,KAAK;EAEvB,SAAS,aAAa,QAAQ,MAAM,YAAY,IAAI,IAAI,IAAI;CAC9D;CACA,MAAM,aAAa,SAA0B,QAAQ,MAAM,SAAS,IAAI,IAAI;CAE5E,OAAO;EACL,OAAO,MAAM,OAAO;GAClB,MAAM,MAAM,KAAK;GACjB,IAAI,cACF,SAAS,UAAU,IAAI,CAAC;QAExB,YAAY,UAAU,IAAI,CAAC;EAE/B;EACA,OAAO,MAAM,OAAO;GAClB,MAAM,MAAM,KAAK;GACjB,YAAY,UAAU,IAAI,CAAC;EAC7B;EACA,KAAK,MAAM;GACT,IAAI,cACF,SAAS,UAAU,IAAI,CAAC;EAE5B;CACF;AACF"}
@@ -1,7 +1,8 @@
1
1
  import { Node } from '../../core/types';
2
2
  import { PrefillController } from './prefill-context';
3
- export type FormResolver = {
3
+ type FormResolver = {
4
4
  nodes: Record<string, Node>;
5
5
  markUserEdit: PrefillController["markUserEdit"];
6
6
  };
7
7
  export declare function useFormResolver(action: string, componentRef: string, nodes: Node[] | undefined): FormResolver;
8
+ export {};