@lattice-php/lattice 0.25.0 → 0.27.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 (150) hide show
  1. package/dist/action/components/action-form.js +3 -3
  2. package/dist/action/components/action-form.js.map +1 -1
  3. package/dist/action/components/action-group.js +1 -1
  4. package/dist/action/components/action-group.js.map +1 -1
  5. package/dist/action/components/action.js +3 -2
  6. package/dist/action/components/action.js.map +1 -1
  7. package/dist/action/hooks/use-action.js +4 -3
  8. package/dist/action/hooks/use-action.js.map +1 -1
  9. package/dist/appearance/index.d.ts +1 -1
  10. package/dist/appearance/index.js +8 -8
  11. package/dist/appearance/index.js.map +1 -1
  12. package/dist/chat/components/chat-box.js +1 -1
  13. package/dist/chat/components/prompt-input.js +1 -2
  14. package/dist/chat/components/prompt-input.js.map +1 -1
  15. package/dist/core/api.d.ts +13 -0
  16. package/dist/core/api.js +38 -4
  17. package/dist/core/api.js.map +1 -1
  18. package/dist/core/component-ref.d.ts +3 -0
  19. package/dist/core/component-ref.js +20 -2
  20. package/dist/core/component-ref.js.map +1 -1
  21. package/dist/core/headers.js +1 -1
  22. package/dist/core/index.js +4 -4
  23. package/dist/create-app.js +8 -3
  24. package/dist/create-app.js.map +1 -1
  25. package/dist/dnd/index.d.ts +16 -0
  26. package/dist/dnd/index.js +13 -0
  27. package/dist/form/components/base/submit-button.d.ts +4 -3
  28. package/dist/form/components/base/submit-button.js +2 -1
  29. package/dist/form/components/base/submit-button.js.map +1 -1
  30. package/dist/form/components/fields/date-picker-field.js +2 -2
  31. package/dist/form/components/fields/date-picker-field.js.map +1 -1
  32. package/dist/form/components/fields/file-upload.js +3 -2
  33. package/dist/form/components/fields/file-upload.js.map +1 -1
  34. package/dist/form/components/fields/number-input.js +1 -1
  35. package/dist/form/components/fields/number-input.js.map +1 -1
  36. package/dist/form/components/fields/rich-editor-field.js +1 -1
  37. package/dist/form/components/fields/rich-editor-field.js.map +1 -1
  38. package/dist/form/components/fields/row-action-menu.js +3 -3
  39. package/dist/form/components/fields/row-action-menu.js.map +1 -1
  40. package/dist/form/components/fields/row-actions.d.ts +1 -1
  41. package/dist/form/components/fields/row-actions.js +4 -4
  42. package/dist/form/components/fields/row-actions.js.map +1 -1
  43. package/dist/form/components/fields/select.js +4 -3
  44. package/dist/form/components/fields/select.js.map +1 -1
  45. package/dist/form/components/fields/toggle.js +1 -1
  46. package/dist/form/components/fields/toggle.js.map +1 -1
  47. package/dist/form/components/form.js +69 -29
  48. package/dist/form/components/form.js.map +1 -1
  49. package/dist/form/components/wizard.js +1 -1
  50. package/dist/form/components/wizard.js.map +1 -1
  51. package/dist/form/hooks/use-form-resolver.js +1 -1
  52. package/dist/form/hooks/use-form-resolver.js.map +1 -1
  53. package/dist/form/hooks/values.d.ts +8 -0
  54. package/dist/form/hooks/values.js +18 -1
  55. package/dist/form/hooks/values.js.map +1 -1
  56. package/dist/i18n/backend.js +1 -1
  57. package/dist/i18n/instance.js +1 -1
  58. package/dist/i18n/timezone.js +1 -1
  59. package/dist/index.d.ts +2 -2
  60. package/dist/index.js +5 -5
  61. package/dist/inertia.d.ts +7 -0
  62. package/dist/inertia.js +19 -1
  63. package/dist/inertia.js.map +1 -1
  64. package/dist/lattice.css +189 -116
  65. package/dist/notifications/components/notification-item.js +3 -1
  66. package/dist/notifications/components/notification-item.js.map +1 -1
  67. package/dist/notifications/components/notifications.js +2 -4
  68. package/dist/notifications/components/notifications.js.map +1 -1
  69. package/dist/remote/components/data-list.js +2 -2
  70. package/dist/table/components/bulk-bar.js +3 -1
  71. package/dist/table/components/bulk-bar.js.map +1 -1
  72. package/dist/table/components/cells/badge-cell.js +3 -6
  73. package/dist/table/components/cells/badge-cell.js.map +1 -1
  74. package/dist/table/components/cells/text-cell.js +6 -9
  75. package/dist/table/components/cells/text-cell.js.map +1 -1
  76. package/dist/table/components/column-filter-control.js +2 -2
  77. package/dist/table/components/column-filter-control.js.map +1 -1
  78. package/dist/table/components/filter-bar.js +1 -1
  79. package/dist/table/components/filter-bar.js.map +1 -1
  80. package/dist/table/components/pagination.js +6 -6
  81. package/dist/table/components/pagination.js.map +1 -1
  82. package/dist/table/hooks/use-table.js +3 -2
  83. package/dist/table/hooks/use-table.js.map +1 -1
  84. package/dist/table/lib/bulk.d.ts +3 -2
  85. package/dist/table/lib/bulk.js +2 -1
  86. package/dist/table/lib/bulk.js.map +1 -1
  87. package/dist/toast/toast.js +3 -1
  88. package/dist/toast/toast.js.map +1 -1
  89. package/dist/toast/variant-styles.js +15 -1
  90. package/dist/toast/variant-styles.js.map +1 -1
  91. package/dist/types/generated.d.ts +14 -9
  92. package/dist/ui/action-menu-context.d.ts +1 -1
  93. package/dist/ui/action-menu-context.js +1 -1
  94. package/dist/ui/action-menu-context.js.map +1 -1
  95. package/dist/ui/affix-group.js +1 -1
  96. package/dist/ui/affix-group.js.map +1 -1
  97. package/dist/ui/badge.d.ts +4 -7
  98. package/dist/ui/badge.js +11 -17
  99. package/dist/ui/badge.js.map +1 -1
  100. package/dist/ui/button.d.ts +6 -5
  101. package/dist/ui/button.js +154 -15
  102. package/dist/ui/button.js.map +1 -1
  103. package/dist/ui/chart-view.js +9 -7
  104. package/dist/ui/chart-view.js.map +1 -1
  105. package/dist/ui/checkbox.js +1 -1
  106. package/dist/ui/checkbox.js.map +1 -1
  107. package/dist/ui/confirm-dialog.d.ts +4 -3
  108. package/dist/ui/confirm-dialog.js +3 -2
  109. package/dist/ui/confirm-dialog.js.map +1 -1
  110. package/dist/ui/control.d.ts +1 -1
  111. package/dist/ui/control.js +1 -1
  112. package/dist/ui/control.js.map +1 -1
  113. package/dist/ui/dialog.js +1 -1
  114. package/dist/ui/dialog.js.map +1 -1
  115. package/dist/ui/dropdown-menu.d.ts +2 -2
  116. package/dist/ui/dropdown-menu.js +2 -2
  117. package/dist/ui/dropdown-menu.js.map +1 -1
  118. package/dist/ui/fragment.js +1 -1
  119. package/dist/ui/icon-button.d.ts +3 -3
  120. package/dist/ui/icon-button.js +6 -6
  121. package/dist/ui/icon-button.js.map +1 -1
  122. package/dist/ui/image-preview.js +1 -1
  123. package/dist/ui/image-preview.js.map +1 -1
  124. package/dist/ui/index.d.ts +2 -2
  125. package/dist/ui/index.js +2 -2
  126. package/dist/ui/info-tooltip.js +1 -1
  127. package/dist/ui/info-tooltip.js.map +1 -1
  128. package/dist/ui/input-otp.js +1 -1
  129. package/dist/ui/input-otp.js.map +1 -1
  130. package/dist/ui/label.js +1 -1
  131. package/dist/ui/label.js.map +1 -1
  132. package/dist/ui/password-input.js +1 -1
  133. package/dist/ui/password-input.js.map +1 -1
  134. package/dist/ui/progress.js +2 -2
  135. package/dist/ui/progress.js.map +1 -1
  136. package/dist/ui/text.js +1 -1
  137. package/dist/ui/tooltip.js +1 -1
  138. package/dist/ui/tooltip.js.map +1 -1
  139. package/dist-standalone/chunks/{chart-view-DEwGTt9d.js → chart-view-CpYsLvzR.js} +4 -4
  140. package/dist-standalone/chunks/date-picker-field-lX8N40Ii.js +1 -0
  141. package/dist-standalone/chunks/{page-props-D3FnL614.js → page-props-ClpVjpOc.js} +1 -1
  142. package/dist-standalone/chunks/{rich-editor-field-B9Nv1qia.js → rich-editor-field-C71csVJv.js} +2 -2
  143. package/dist-standalone/chunks/{subscriptions-C-0lSr7X.js → subscriptions-Bt2s3IF3.js} +1 -1
  144. package/dist-standalone/chunks/use-effect-dispatcher-DGFXSzA6.js +97 -0
  145. package/dist-standalone/lattice.css +1 -1
  146. package/dist-standalone/lattice.js +15 -15
  147. package/dist-standalone/manifest.json +8 -8
  148. package/package.json +9 -1
  149. package/dist-standalone/chunks/date-picker-field-CCQ9nWx0.js +0 -1
  150. package/dist-standalone/chunks/use-effect-dispatcher-EVZxmfoo.js +0 -97
@@ -1 +1 @@
1
- {"version":3,"file":"select.js","names":[],"sources":["../../../../resources/js/form/components/fields/select.tsx"],"sourcesContent":["import { Icon } from \"@lattice-php/lattice/icons\";\nimport { useCallback, useMemo, useRef, useState } from \"react\";\nimport { Combobox } from \"@lattice-php/lattice/ui/combobox\";\nimport { controlSurface } from \"@lattice-php/lattice/ui/control\";\nimport { coerceColor, colorValue } from \"@lattice-php/lattice/lib/color\";\nimport { cn } from \"@lattice-php/lattice/lib/utils\";\nimport { useT } from \"@lattice-php/lattice/i18n\";\nimport { Renderer } from \"@lattice-php/lattice/core/renderer\";\nimport { materializeSchema } from \"@lattice-php/lattice/core/materialize\";\nimport type { Node, Option, RendererComponent } from \"@lattice-php/lattice/core/types\";\nimport { FormFieldFrame } from \"@lattice-php/lattice/form/components/base/field\";\nimport { useFormContext } from \"@lattice-php/lattice/form/hooks/context\";\nimport { fieldDomName } from \"@lattice-php/lattice/form/lib/field-dom-name\";\nimport { postFormAction } from \"@lattice-php/lattice/form/lib/form-transport\";\nimport { useResolvedNode } from \"@lattice-php/lattice/form/hooks/resolved-nodes\";\nimport { useDependentField } from \"@lattice-php/lattice/form/hooks/use-dependent-field\";\nimport { useFieldCommit } from \"@lattice-php/lattice/form/hooks/use-field-commit\";\nimport { useFieldScope } from \"@lattice-php/lattice/form/hooks/field-scope\";\nimport { useFormValue, useFormValues } from \"@lattice-php/lattice/form/hooks/values\";\n\nfunction toValues(stored: unknown, fallback: unknown): string[] {\n const source = stored ?? fallback;\n\n if (Array.isArray(source)) {\n return source.map(String);\n }\n\n if (source === undefined || source === null || source === \"\") {\n return [];\n }\n\n return [String(source)];\n}\n\nexport const SelectComponent: RendererComponent<\"field.select\"> = ({ node }) => {\n const { t } = useT(\"lattice\");\n const props = node.props;\n const { action, componentRef, errors, fieldIdPrefix, searchOptions } = useFormContext();\n const { hidden, required, readOnly, disabled } = useDependentField(node);\n const { change, blur } = useFieldCommit();\n const resolvedNode = useResolvedNode(node);\n const name = props.name;\n const scope = useFieldScope();\n const domName = fieldDomName(scope ? scope.scopedName(name) : name, fieldIdPrefix);\n const errorKey = scope ? scope.errorKey(name) : name;\n const searchKey = errorKey;\n const placeholder = props.placeholder || \"Select…\";\n const multiple = props.multiple;\n const searchable = props.searchable;\n const creatable = props.creatable;\n const staticOptions = useMemo(\n () => (resolvedNode.props as { options?: Option[] }).options ?? [],\n [resolvedNode.props],\n );\n const optionSchema = (resolvedNode.props as { optionSchema?: Node[] }).optionSchema;\n\n const globalValue = useFormValue(name);\n const values = useFormValues();\n const valuesRef = useRef(values);\n valuesRef.current = values;\n const storedValue = scope ? scope.getValue(name) : globalValue;\n const selected = useMemo(() => toValues(storedValue, props.value), [storedValue, props.value]);\n const selectedRef = useRef(selected);\n selectedRef.current = selected;\n\n const [open, setOpen] = useState(false);\n const [results, setResults] = useState<Option[] | null>(null);\n const [loading, setLoading] = useState(false);\n const searchAbort = useRef<AbortController | null>(null);\n\n const optionsByValue = useMemo(() => {\n const map = new Map<string, Option>();\n\n for (const option of [...staticOptions, ...(results ?? [])]) {\n map.set(option.value, option);\n }\n\n return map;\n }, [staticOptions, results]);\n const labelFor = (value: string) => optionsByValue.get(value)?.label ?? value;\n const colorFor = (value: string) =>\n coerceColor((optionsByValue.get(value)?.data as { color?: unknown } | undefined)?.color);\n\n const locked = readOnly || disabled;\n\n const search = useCallback(\n (query: string) => {\n searchAbort.current?.abort();\n\n if (query.trim() === \"\") {\n setResults(null);\n setLoading(false);\n\n return;\n }\n\n const controller = new AbortController();\n searchAbort.current = controller;\n setLoading(true);\n\n if (searchOptions) {\n void searchOptions(searchKey, query, valuesRef.current, controller.signal)\n .then((options) => {\n setResults(options);\n setLoading(false);\n })\n .catch(() => {});\n\n return;\n }\n\n void postFormAction<{ options?: Option[] }>(\n action,\n componentRef,\n { ...valuesRef.current, _search: searchKey, q: query },\n controller.signal,\n )\n .then((response) => {\n setResults(response?.options ?? []);\n setLoading(false);\n })\n .catch(() => {});\n },\n [action, componentRef, searchKey, searchOptions],\n );\n\n function commit(next: string[]): void {\n change(name, multiple ? next : (next[0] ?? \"\"));\n }\n\n function select(value: string): void {\n if (multiple) {\n const next = selectedRef.current.includes(value)\n ? selectedRef.current.filter((item) => item !== value)\n : [...selectedRef.current, value];\n selectedRef.current = next;\n commit(next);\n\n return;\n }\n\n selectedRef.current = [value];\n commit([value]);\n }\n\n function remove(value: string): void {\n commit(selected.filter((item) => item !== value));\n }\n\n function applyCreated(value: string): void {\n if (!multiple) {\n selectedRef.current = [value];\n commit([value]);\n\n return;\n }\n\n if (!selectedRef.current.includes(value)) {\n const next = [...selectedRef.current, value];\n selectedRef.current = next;\n commit(next);\n }\n }\n\n if (hidden) {\n return null;\n }\n\n const options = searchable ? (results ?? staticOptions) : staticOptions;\n\n const renderOption = optionSchema?.length\n ? (option: Option) => (\n <Renderer\n nodes={materializeSchema(optionSchema, {\n ...option.data,\n label: option.label,\n value: option.value,\n })}\n />\n )\n : undefined;\n\n return (\n <FormFieldFrame\n error={errors[errorKey]}\n helperText={props.helperText ?? undefined}\n tooltip={props.tooltip ?? undefined}\n label={props.label ?? \"\"}\n name={domName}\n required={required}\n >\n {multiple ? (\n selected.map((value) => (\n <input key={value} name={`${domName}[]`} type=\"hidden\" value={value} />\n ))\n ) : (\n <input name={domName} type=\"hidden\" value={selected[0] ?? \"\"} />\n )}\n\n <div>\n {multiple && selected.length > 0 && (\n <div className=\"mb-1.5 flex flex-wrap gap-1\">\n {selected.map((value) => {\n const color = colorFor(value);\n\n return (\n <span\n className=\"inline-flex items-center gap-1 rounded-lt-sm bg-lt-muted px-2 py-0.5 text-xs\"\n key={value}\n >\n {color && (\n <span\n aria-hidden=\"true\"\n className=\"size-2 shrink-0 rounded-full\"\n style={{ background: colorValue(color) }}\n />\n )}\n {labelFor(value)}\n {!locked && (\n <button\n aria-label={t(\"form.remove-option\", \"Remove {{label}}\", {\n label: labelFor(value),\n })}\n data-test={`select-${name}-remove-${value}`}\n className=\"text-lt-muted-fg hover:text-lt-fg [&_svg]:size-lt-icon-xs\"\n onClick={() => remove(value)}\n type=\"button\"\n >\n <Icon name=\"x\" />\n </button>\n )}\n </span>\n );\n })}\n </div>\n )}\n\n <Combobox\n creatable={creatable}\n emptyLabel={props.emptyLabel ?? undefined}\n loading={loading}\n multiple={multiple}\n onCommit={applyCreated}\n onCreate={applyCreated}\n onSearch={searchable ? search : undefined}\n onSelect={select}\n open={open && !locked}\n onOpenChange={(next) => {\n setOpen(next);\n\n if (!next) {\n blur(name);\n }\n }}\n options={options}\n renderOption={renderOption}\n searchPlaceholder={props.searchPlaceholder ?? undefined}\n showSearch={Boolean(searchable || creatable)}\n selected={selected}\n testId={`select-${name}`}\n trigger={\n <>\n {!multiple && selected.length > 0 ? (\n <span>{labelFor(selected[0])}</span>\n ) : (\n <span className=\"text-lt-muted-fg\">{placeholder}</span>\n )}\n <Icon name=\"chevrons-up-down\" className=\"size-lt-icon-md shrink-0 text-lt-muted-fg\" />\n </>\n }\n triggerClassName={cn(\n controlSurface(),\n \"flex items-center justify-between gap-2 text-left\",\n locked && \"cursor-not-allowed opacity-60\",\n )}\n triggerProps={{\n \"aria-haspopup\": \"listbox\",\n autoFocus: props.autoFocus ?? undefined,\n \"data-test\": `select-${name}`,\n disabled: locked,\n id: domName,\n tabIndex: props.tabIndex ?? undefined,\n }}\n />\n </div>\n </FormFieldFrame>\n );\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"select.js","names":[],"sources":["../../../../resources/js/form/components/fields/select.tsx"],"sourcesContent":["import { Icon } from \"@lattice-php/lattice/icons\";\nimport { useCallback, useMemo, useRef, useState } from \"react\";\nimport { Combobox } from \"@lattice-php/lattice/ui/combobox\";\nimport { controlSurface } from \"@lattice-php/lattice/ui/control\";\nimport { coerceColor, colorValue } from \"@lattice-php/lattice/lib/color\";\nimport { cn } from \"@lattice-php/lattice/lib/utils\";\nimport { useT } from \"@lattice-php/lattice/i18n\";\nimport { Renderer } from \"@lattice-php/lattice/core/renderer\";\nimport { materializeSchema } from \"@lattice-php/lattice/core/materialize\";\nimport type { Node, Option, RendererComponent } from \"@lattice-php/lattice/core/types\";\nimport { FormFieldFrame } from \"@lattice-php/lattice/form/components/base/field\";\nimport { useFormContext } from \"@lattice-php/lattice/form/hooks/context\";\nimport { fieldDomName } from \"@lattice-php/lattice/form/lib/field-dom-name\";\nimport { postFormAction } from \"@lattice-php/lattice/form/lib/form-transport\";\nimport { useResolvedNode } from \"@lattice-php/lattice/form/hooks/resolved-nodes\";\nimport { useDependentField } from \"@lattice-php/lattice/form/hooks/use-dependent-field\";\nimport { useFieldCommit } from \"@lattice-php/lattice/form/hooks/use-field-commit\";\nimport { useFieldScope } from \"@lattice-php/lattice/form/hooks/field-scope\";\nimport { useFormValue, useFormValues } from \"@lattice-php/lattice/form/hooks/values\";\n\nfunction toValues(stored: unknown, fallback: unknown): string[] {\n const source = stored ?? fallback;\n\n if (Array.isArray(source)) {\n return source.map(String);\n }\n\n if (source === undefined || source === null || source === \"\") {\n return [];\n }\n\n return [String(source)];\n}\n\nexport const SelectComponent: RendererComponent<\"field.select\"> = ({ node }) => {\n const { t } = useT(\"lattice\");\n const props = node.props;\n const { action, componentRef, errors, fieldIdPrefix, searchOptions } = useFormContext();\n const { hidden, required, readOnly, disabled } = useDependentField(node);\n const { change, blur } = useFieldCommit();\n const resolvedNode = useResolvedNode(node);\n const name = props.name;\n const scope = useFieldScope();\n const domName = fieldDomName(scope ? scope.scopedName(name) : name, fieldIdPrefix);\n const errorKey = scope ? scope.errorKey(name) : name;\n const searchKey = errorKey;\n const placeholder = props.placeholder || \"Select…\";\n const multiple = props.multiple;\n const searchable = props.searchable;\n const creatable = props.creatable;\n const staticOptions = useMemo(\n () => (resolvedNode.props as { options?: Option[] }).options ?? [],\n [resolvedNode.props],\n );\n const optionSchema = (resolvedNode.props as { optionSchema?: Node[] }).optionSchema;\n\n const globalValue = useFormValue(name);\n const values = useFormValues();\n const valuesRef = useRef(values);\n valuesRef.current = values;\n const storedValue = scope ? scope.getValue(name) : globalValue;\n const selected = useMemo(() => toValues(storedValue, props.value), [storedValue, props.value]);\n const selectedRef = useRef(selected);\n selectedRef.current = selected;\n\n const [open, setOpen] = useState(false);\n const [results, setResults] = useState<Option[] | null>(null);\n const [loading, setLoading] = useState(false);\n const searchAbort = useRef<AbortController | null>(null);\n\n const optionsByValue = useMemo(() => {\n const map = new Map<string, Option>();\n\n for (const option of [...staticOptions, ...(results ?? [])]) {\n map.set(option.value, option);\n }\n\n return map;\n }, [staticOptions, results]);\n const labelFor = (value: string) => optionsByValue.get(value)?.label ?? value;\n const colorFor = (value: string) =>\n coerceColor((optionsByValue.get(value)?.data as { color?: unknown } | undefined)?.color);\n\n const locked = readOnly || disabled;\n\n const search = useCallback(\n (query: string) => {\n searchAbort.current?.abort();\n\n if (query.trim() === \"\") {\n setResults(null);\n setLoading(false);\n\n return;\n }\n\n const controller = new AbortController();\n searchAbort.current = controller;\n setLoading(true);\n\n if (searchOptions) {\n void searchOptions(searchKey, query, valuesRef.current, controller.signal)\n .then((options) => {\n setResults(options);\n setLoading(false);\n })\n .catch(() => {});\n\n return;\n }\n\n void postFormAction<{ options?: Option[] }>(\n action,\n componentRef,\n { ...valuesRef.current, _sub: \"search\", _target: searchKey, _q: query },\n controller.signal,\n )\n .then((response) => {\n setResults(response?.options ?? []);\n setLoading(false);\n })\n .catch(() => {});\n },\n [action, componentRef, searchKey, searchOptions],\n );\n\n function commit(next: string[]): void {\n change(name, multiple ? next : (next[0] ?? \"\"));\n }\n\n function select(value: string): void {\n if (multiple) {\n const next = selectedRef.current.includes(value)\n ? selectedRef.current.filter((item) => item !== value)\n : [...selectedRef.current, value];\n selectedRef.current = next;\n commit(next);\n\n return;\n }\n\n selectedRef.current = [value];\n commit([value]);\n }\n\n function remove(value: string): void {\n commit(selected.filter((item) => item !== value));\n }\n\n function applyCreated(value: string): void {\n if (!multiple) {\n selectedRef.current = [value];\n commit([value]);\n\n return;\n }\n\n if (!selectedRef.current.includes(value)) {\n const next = [...selectedRef.current, value];\n selectedRef.current = next;\n commit(next);\n }\n }\n\n if (hidden) {\n return null;\n }\n\n const options = searchable ? (results ?? staticOptions) : staticOptions;\n\n const renderOption = optionSchema?.length\n ? (option: Option) => (\n <Renderer\n nodes={materializeSchema(optionSchema, {\n ...option.data,\n label: option.label,\n value: option.value,\n })}\n />\n )\n : undefined;\n\n return (\n <FormFieldFrame\n error={errors[errorKey]}\n helperText={props.helperText ?? undefined}\n tooltip={props.tooltip ?? undefined}\n label={props.label ?? \"\"}\n name={domName}\n required={required}\n >\n {multiple ? (\n selected.map((value) => (\n <input key={value} name={`${domName}[]`} type=\"hidden\" value={value} />\n ))\n ) : (\n <input name={domName} type=\"hidden\" value={selected[0] ?? \"\"} />\n )}\n\n <div>\n {multiple && selected.length > 0 && (\n <div className=\"mb-1.5 flex flex-wrap gap-1\">\n {selected.map((value) => {\n const color = colorFor(value);\n\n return (\n <span\n className=\"inline-flex items-center gap-1 rounded-lt-sm bg-lt-muted px-2 py-0.5 text-xs\"\n key={value}\n >\n {color && (\n <span\n aria-hidden=\"true\"\n className=\"size-2 shrink-0 rounded-full\"\n style={{ background: colorValue(color) }}\n />\n )}\n {labelFor(value)}\n {!locked && (\n <button\n aria-label={t(\"form.remove-option\", \"Remove {{label}}\", {\n label: labelFor(value),\n })}\n data-test={`select-${name}-remove-${value}`}\n className=\"text-lt-muted-fg hover:text-lt-fg [&_svg]:size-lt-icon-xs\"\n onClick={() => remove(value)}\n type=\"button\"\n >\n <Icon name=\"x\" />\n </button>\n )}\n </span>\n );\n })}\n </div>\n )}\n\n <Combobox\n creatable={creatable}\n emptyLabel={props.emptyLabel ?? undefined}\n loading={loading}\n multiple={multiple}\n onCommit={applyCreated}\n onCreate={applyCreated}\n onSearch={searchable ? search : undefined}\n onSelect={select}\n open={open && !locked}\n onOpenChange={(next) => {\n setOpen(next);\n\n if (!next) {\n blur(name);\n }\n }}\n options={options}\n renderOption={renderOption}\n searchPlaceholder={props.searchPlaceholder ?? undefined}\n showSearch={Boolean(searchable || creatable)}\n selected={selected}\n testId={`select-${name}`}\n trigger={\n <>\n {!multiple && selected.length > 0 ? (\n <span>{labelFor(selected[0])}</span>\n ) : (\n <span className=\"text-lt-muted-fg\">{placeholder}</span>\n )}\n <Icon name=\"chevrons-up-down\" className=\"size-lt-icon-md shrink-0 text-lt-muted-fg\" />\n </>\n }\n triggerClassName={cn(\n controlSurface(),\n \"flex items-center justify-between gap-2 text-left\",\n locked && \"cursor-not-allowed opacity-60\",\n )}\n triggerProps={{\n \"aria-haspopup\": \"listbox\",\n autoFocus: props.autoFocus ?? undefined,\n \"data-test\": `select-${name}`,\n disabled: locked,\n id: domName,\n tabIndex: props.tabIndex ?? undefined,\n }}\n />\n </div>\n </FormFieldFrame>\n );\n};\n"],"mappings":"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"}
@@ -43,7 +43,7 @@ var ToggleComponent = ({ node }) => {
43
43
  "aria-checked": checked,
44
44
  "aria-label": props.label ?? localName,
45
45
  autoFocus: props.autoFocus ?? false,
46
- className: cn("inline-flex h-6 w-11 shrink-0 cursor-pointer items-center rounded-full border border-transparent bg-lt-muted p-0.5 shadow-lt-xs transition-colors outline-none focus-visible:border-lt-ring focus-visible:ring-[3px] focus-visible:ring-lt-ring/50 disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-lt-primary"),
46
+ className: cn("inline-flex h-6 w-11 shrink-0 cursor-pointer items-center rounded-full border border-transparent bg-lt-muted p-0.5 shadow-lt-xs transition-colors outline-none focus-visible:border-lt-ring focus-visible:ring-[length:var(--lt-ring-width)] focus-visible:ring-lt-ring/50 disabled:cursor-not-allowed disabled:bg-lt-disabled data-[state=checked]:bg-lt-primary disabled:data-[state=checked]:bg-lt-disabled"),
47
47
  "data-state": checked ? "checked" : "unchecked",
48
48
  "data-test": testIdentity(localName),
49
49
  disabled: locked,
@@ -1 +1 @@
1
- {"version":3,"file":"toggle.js","names":[],"sources":["../../../../resources/js/form/components/fields/toggle.tsx"],"sourcesContent":["import type { RendererComponent } from \"@lattice-php/lattice/core/types\";\nimport { testIdentity } from \"@lattice-php/lattice/core/test-id\";\nimport { cn } from \"@lattice-php/lattice/lib/utils\";\nimport { FormFieldFrame } from \"@lattice-php/lattice/form/components/base/field\";\nimport { toBoolean } from \"@lattice-php/lattice/form/lib/conditions\";\nimport { useFormContext } from \"@lattice-php/lattice/form/hooks/context\";\nimport { fieldDomName } from \"@lattice-php/lattice/form/lib/field-dom-name\";\nimport { useFieldScope } from \"@lattice-php/lattice/form/hooks/field-scope\";\nimport { useDependentField } from \"@lattice-php/lattice/form/hooks/use-dependent-field\";\nimport { useFieldCommit } from \"@lattice-php/lattice/form/hooks/use-field-commit\";\nimport { useSeedDefault } from \"@lattice-php/lattice/form/hooks/use-seed-default\";\nimport { useFormValue } from \"@lattice-php/lattice/form/hooks/values\";\n\nexport const ToggleComponent: RendererComponent<\"field.toggle\"> = ({ node }) => {\n const { hidden, required, readOnly, disabled } = useDependentField(node);\n const props = node.props;\n const localName = props.name;\n const scope = useFieldScope();\n const { errors, fieldIdPrefix } = useFormContext();\n const name = fieldDomName(scope ? scope.scopedName(localName) : localName, fieldIdPrefix);\n const errorKey = scope ? scope.errorKey(localName) : localName;\n const globalValue = useFormValue(localName);\n const storedValue = scope ? scope.getValue(localName) : globalValue;\n const defaultChecked = toBoolean(props.value);\n const checked = storedValue !== undefined ? toBoolean(storedValue) : defaultChecked;\n const locked = readOnly || disabled;\n const { commit } = useFieldCommit();\n\n useSeedDefault(localName, defaultChecked);\n\n if (hidden) {\n return null;\n }\n\n return (\n <FormFieldFrame\n error={errors[errorKey]}\n helperText={props.helperText ?? undefined}\n tooltip={props.tooltip ?? undefined}\n label={props.label ?? \"\"}\n name={name}\n required={required}\n >\n <input disabled={locked} name={name} type=\"hidden\" value={checked ? \"1\" : \"0\"} />\n <button\n aria-checked={checked}\n aria-label={props.label ?? localName}\n autoFocus={props.autoFocus ?? false}\n className={cn(\n \"inline-flex h-6 w-11 shrink-0 cursor-pointer items-center rounded-full border border-transparent bg-lt-muted p-0.5 shadow-lt-xs transition-colors outline-none focus-visible:border-lt-ring focus-visible:ring-[3px] focus-visible:ring-lt-ring/50 disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-lt-primary\",\n )}\n data-state={checked ? \"checked\" : \"unchecked\"}\n data-test={testIdentity(localName)}\n disabled={locked}\n id={name}\n name={name}\n onClick={() => commit(localName, !checked)}\n role=\"switch\"\n tabIndex={props.tabIndex ?? undefined}\n type=\"button\"\n >\n <span\n className=\"size-5 rounded-full bg-lt-bg shadow-lt-sm transition-transform data-[state=checked]:translate-x-5 data-[state=unchecked]:translate-x-0\"\n data-state={checked ? \"checked\" : \"unchecked\"}\n />\n </button>\n </FormFieldFrame>\n );\n};\n"],"mappings":";;;;;;;;;;;;;AAaA,IAAa,mBAAsD,EAAE,WAAW;CAC9E,MAAM,EAAE,QAAQ,UAAU,UAAU,aAAa,kBAAkB,IAAI;CACvE,MAAM,QAAQ,KAAK;CACnB,MAAM,YAAY,MAAM;CACxB,MAAM,QAAQ,cAAc;CAC5B,MAAM,EAAE,QAAQ,kBAAkB,eAAe;CACjD,MAAM,OAAO,aAAa,QAAQ,MAAM,WAAW,SAAS,IAAI,WAAW,aAAa;CACxF,MAAM,WAAW,QAAQ,MAAM,SAAS,SAAS,IAAI;CACrD,MAAM,cAAc,aAAa,SAAS;CAC1C,MAAM,cAAc,QAAQ,MAAM,SAAS,SAAS,IAAI;CACxD,MAAM,iBAAiB,UAAU,MAAM,KAAK;CAC5C,MAAM,UAAU,gBAAgB,KAAA,IAAY,UAAU,WAAW,IAAI;CACrE,MAAM,SAAS,YAAY;CAC3B,MAAM,EAAE,WAAW,eAAe;CAElC,eAAe,WAAW,cAAc;CAExC,IAAI,QACF,OAAO;CAGT,OACE,qBAAC,gBAAD;EACE,OAAO,OAAO;EACd,YAAY,MAAM,cAAc,KAAA;EAChC,SAAS,MAAM,WAAW,KAAA;EAC1B,OAAO,MAAM,SAAS;EAChB;EACI;YANZ,CAQE,oBAAC,SAAD;GAAO,UAAU;GAAc;GAAM,MAAK;GAAS,OAAO,UAAU,MAAM;EAAM,CAAA,GAChF,oBAAC,UAAD;GACE,gBAAc;GACd,cAAY,MAAM,SAAS;GAC3B,WAAW,MAAM,aAAa;GAC9B,WAAW,GACT,uUACF;GACA,cAAY,UAAU,YAAY;GAClC,aAAW,aAAa,SAAS;GACjC,UAAU;GACV,IAAI;GACE;GACN,eAAe,OAAO,WAAW,CAAC,OAAO;GACzC,MAAK;GACL,UAAU,MAAM,YAAY,KAAA;GAC5B,MAAK;aAEL,oBAAC,QAAD;IACE,WAAU;IACV,cAAY,UAAU,YAAY;GACnC,CAAA;EACK,CAAA,CACM;;AAEpB"}
1
+ {"version":3,"file":"toggle.js","names":[],"sources":["../../../../resources/js/form/components/fields/toggle.tsx"],"sourcesContent":["import type { RendererComponent } from \"@lattice-php/lattice/core/types\";\nimport { testIdentity } from \"@lattice-php/lattice/core/test-id\";\nimport { cn } from \"@lattice-php/lattice/lib/utils\";\nimport { FormFieldFrame } from \"@lattice-php/lattice/form/components/base/field\";\nimport { toBoolean } from \"@lattice-php/lattice/form/lib/conditions\";\nimport { useFormContext } from \"@lattice-php/lattice/form/hooks/context\";\nimport { fieldDomName } from \"@lattice-php/lattice/form/lib/field-dom-name\";\nimport { useFieldScope } from \"@lattice-php/lattice/form/hooks/field-scope\";\nimport { useDependentField } from \"@lattice-php/lattice/form/hooks/use-dependent-field\";\nimport { useFieldCommit } from \"@lattice-php/lattice/form/hooks/use-field-commit\";\nimport { useSeedDefault } from \"@lattice-php/lattice/form/hooks/use-seed-default\";\nimport { useFormValue } from \"@lattice-php/lattice/form/hooks/values\";\n\nexport const ToggleComponent: RendererComponent<\"field.toggle\"> = ({ node }) => {\n const { hidden, required, readOnly, disabled } = useDependentField(node);\n const props = node.props;\n const localName = props.name;\n const scope = useFieldScope();\n const { errors, fieldIdPrefix } = useFormContext();\n const name = fieldDomName(scope ? scope.scopedName(localName) : localName, fieldIdPrefix);\n const errorKey = scope ? scope.errorKey(localName) : localName;\n const globalValue = useFormValue(localName);\n const storedValue = scope ? scope.getValue(localName) : globalValue;\n const defaultChecked = toBoolean(props.value);\n const checked = storedValue !== undefined ? toBoolean(storedValue) : defaultChecked;\n const locked = readOnly || disabled;\n const { commit } = useFieldCommit();\n\n useSeedDefault(localName, defaultChecked);\n\n if (hidden) {\n return null;\n }\n\n return (\n <FormFieldFrame\n error={errors[errorKey]}\n helperText={props.helperText ?? undefined}\n tooltip={props.tooltip ?? undefined}\n label={props.label ?? \"\"}\n name={name}\n required={required}\n >\n <input disabled={locked} name={name} type=\"hidden\" value={checked ? \"1\" : \"0\"} />\n <button\n aria-checked={checked}\n aria-label={props.label ?? localName}\n autoFocus={props.autoFocus ?? false}\n className={cn(\n \"inline-flex h-6 w-11 shrink-0 cursor-pointer items-center rounded-full border border-transparent bg-lt-muted p-0.5 shadow-lt-xs transition-colors outline-none focus-visible:border-lt-ring focus-visible:ring-[length:var(--lt-ring-width)] focus-visible:ring-lt-ring/50 disabled:cursor-not-allowed disabled:bg-lt-disabled data-[state=checked]:bg-lt-primary disabled:data-[state=checked]:bg-lt-disabled\",\n )}\n data-state={checked ? \"checked\" : \"unchecked\"}\n data-test={testIdentity(localName)}\n disabled={locked}\n id={name}\n name={name}\n onClick={() => commit(localName, !checked)}\n role=\"switch\"\n tabIndex={props.tabIndex ?? undefined}\n type=\"button\"\n >\n <span\n className=\"size-5 rounded-full bg-lt-bg shadow-lt-sm transition-transform data-[state=checked]:translate-x-5 data-[state=unchecked]:translate-x-0\"\n data-state={checked ? \"checked\" : \"unchecked\"}\n />\n </button>\n </FormFieldFrame>\n );\n};\n"],"mappings":";;;;;;;;;;;;;AAaA,IAAa,mBAAsD,EAAE,WAAW;CAC9E,MAAM,EAAE,QAAQ,UAAU,UAAU,aAAa,kBAAkB,IAAI;CACvE,MAAM,QAAQ,KAAK;CACnB,MAAM,YAAY,MAAM;CACxB,MAAM,QAAQ,cAAc;CAC5B,MAAM,EAAE,QAAQ,kBAAkB,eAAe;CACjD,MAAM,OAAO,aAAa,QAAQ,MAAM,WAAW,SAAS,IAAI,WAAW,aAAa;CACxF,MAAM,WAAW,QAAQ,MAAM,SAAS,SAAS,IAAI;CACrD,MAAM,cAAc,aAAa,SAAS;CAC1C,MAAM,cAAc,QAAQ,MAAM,SAAS,SAAS,IAAI;CACxD,MAAM,iBAAiB,UAAU,MAAM,KAAK;CAC5C,MAAM,UAAU,gBAAgB,KAAA,IAAY,UAAU,WAAW,IAAI;CACrE,MAAM,SAAS,YAAY;CAC3B,MAAM,EAAE,WAAW,eAAe;CAElC,eAAe,WAAW,cAAc;CAExC,IAAI,QACF,OAAO;CAGT,OACE,qBAAC,gBAAD;EACE,OAAO,OAAO;EACd,YAAY,MAAM,cAAc,KAAA;EAChC,SAAS,MAAM,WAAW,KAAA;EAC1B,OAAO,MAAM,SAAS;EAChB;EACI;YANZ,CAQE,oBAAC,SAAD;GAAO,UAAU;GAAc;GAAM,MAAK;GAAS,OAAO,UAAU,MAAM;EAAM,CAAA,GAChF,oBAAC,UAAD;GACE,gBAAc;GACd,cAAY,MAAM,SAAS;GAC3B,WAAW,MAAM,aAAa;GAC9B,WAAW,GACT,gZACF;GACA,cAAY,UAAU,YAAY;GAClC,aAAW,aAAa,SAAS;GACjC,UAAU;GACV,IAAI;GACE;GACN,eAAe,OAAO,WAAW,CAAC,OAAO;GACzC,MAAK;GACL,UAAU,MAAM,YAAY,KAAA;GAC5B,MAAK;aAEL,oBAAC,QAAD;IACE,WAAU;IACV,cAAY,UAAU,YAAY;GACnC,CAAA;EACK,CAAA,CACM;;AAEpB"}
@@ -1,18 +1,19 @@
1
1
  import { LATTICE_EVENT } from "../../core/event-names.js";
2
+ import { withHeaders } from "../../core/headers.js";
3
+ import { refreshRef } from "../../core/api.js";
2
4
  import { useT } from "../../i18n/instance.js";
3
5
  import { useWindowEvent } from "../../core/hooks/use-window-event.js";
4
- import { withHeaders } from "../../core/headers.js";
5
6
  import { nodeKey } from "../../core/nodes.js";
6
7
  import { RenderNode } from "../../core/renderer.js";
7
8
  import { FormProvider } from "../hooks/context.js";
8
9
  import { PrefillProvider } from "../hooks/prefill-context.js";
9
10
  import { ResolvedNodesProvider } from "../hooks/resolved-nodes.js";
10
- import { FormValuesProvider } from "../hooks/values.js";
11
+ import { FormValuesProvider, useResetFormValues } from "../hooks/values.js";
11
12
  import { useFormResolver } from "../hooks/use-form-resolver.js";
12
13
  import { collectFields } from "../lib/collect-fields.js";
13
14
  import { FormSubmitButton } from "./base/submit-button.js";
14
15
  import { Form } from "@inertiajs/react";
15
- import { useMemo } from "react";
16
+ import { useEffect, useMemo, useRef, useState } from "react";
16
17
  import { jsx, jsxs } from "react/jsx-runtime";
17
18
  //#region resources/js/form/components/form.tsx
18
19
  var JUSTIFY_CLASS = {
@@ -24,16 +25,20 @@ var JUSTIFY_CLASS = {
24
25
  evenly: "justify-evenly"
25
26
  };
26
27
  function FormResetListener({ componentId, reset }) {
28
+ const resetValues = useResetFormValues();
27
29
  useWindowEvent(LATTICE_EVENT.resetForm, (event) => {
28
30
  const detail = event.detail;
29
- if (!detail?.form || detail.form === componentId) reset();
31
+ if (!detail?.form || detail.form === componentId) {
32
+ reset();
33
+ resetValues();
34
+ }
30
35
  });
31
36
  return null;
32
37
  }
33
- function FormBody({ action, children, componentRef, nodes, shouldRenderSubmitButton, submitButtons, submitJustify, submitLabel, submitVariant, summaryLabel }) {
38
+ function FormBody({ action, children, componentRef, nodes, shouldRenderSubmitButton, submitButtons, submitEmphasis, submitJustify, submitLabel, submitVariant, summaryLabel }) {
34
39
  const { nodes: resolvedNodes, markUserEdit } = useFormResolver(action, componentRef, nodes);
35
40
  return /* @__PURE__ */ jsx(PrefillProvider, {
36
- value: { markUserEdit },
41
+ value: useMemo(() => ({ markUserEdit }), [markUserEdit]),
37
42
  children: /* @__PURE__ */ jsx(ResolvedNodesProvider, {
38
43
  nodes: resolvedNodes,
39
44
  children: /* @__PURE__ */ jsxs("div", {
@@ -41,20 +46,38 @@ function FormBody({ action, children, componentRef, nodes, shouldRenderSubmitBut
41
46
  children: [children, shouldRenderSubmitButton && /* @__PURE__ */ jsx("div", {
42
47
  className: `flex gap-3 ${JUSTIFY_CLASS[submitJustify ?? "end"]}`,
43
48
  children: submitButtons?.length ? submitButtons.map((button, index) => button.props.buttonType === "submit" ? /* @__PURE__ */ jsx(FormSubmitButton, {
49
+ emphasis: button.props.emphasis ?? submitEmphasis,
44
50
  label: button.props.label ?? submitLabel,
45
51
  summaryLabel,
46
- variant: button.props.variant ?? submitVariant ?? "default"
52
+ variant: button.props.variant ?? submitVariant
47
53
  }, nodeKey(button, index)) : /* @__PURE__ */ jsx(RenderNode, { node: button }, nodeKey(button, index))) : /* @__PURE__ */ jsx(FormSubmitButton, {
54
+ emphasis: submitEmphasis,
48
55
  label: submitLabel,
49
56
  summaryLabel,
50
- variant: submitVariant ?? "default"
57
+ variant: submitVariant
51
58
  })
52
59
  })]
53
60
  })
54
61
  })
55
62
  });
56
63
  }
64
+ function configuredResetFields(configured) {
65
+ if (!configured || Array.isArray(configured) && configured.length === 0) return false;
66
+ return Array.isArray(configured) ? configured : void 0;
67
+ }
57
68
  var FormComponent = ({ children, node }) => {
69
+ return /* @__PURE__ */ jsx(FormValuesProvider, {
70
+ initial: useMemo(() => ({
71
+ ...collectFields(node.schema).values,
72
+ ...node.props.state
73
+ }), [node.schema, node.props.state]),
74
+ children: /* @__PURE__ */ jsx(FormShell, {
75
+ node,
76
+ children
77
+ })
78
+ });
79
+ };
80
+ function FormShell({ children, node }) {
58
81
  const { t } = useT("lattice");
59
82
  const props = node.props;
60
83
  const action = props.action ?? "#";
@@ -64,20 +87,28 @@ var FormComponent = ({ children, node }) => {
64
87
  const precognitive = props.precognitive;
65
88
  const resetOnError = props.resetOnError ?? false;
66
89
  const resetOnSuccess = props.resetOnSuccess ?? [];
67
- const state = props.state;
68
- const { labels: fieldLabels, values: fieldValues } = useMemo(() => collectFields(node.schema), [node.schema]);
69
- const initialValues = useMemo(() => ({
70
- ...fieldValues,
71
- ...state
72
- }), [fieldValues, state]);
90
+ const fieldLabels = useMemo(() => collectFields(node.schema).labels, [node.schema]);
73
91
  const shouldRenderSubmitButton = props.submitButton;
74
92
  const submitButtons = props.submitButtons ?? void 0;
75
93
  const submitJustify = props.submitJustify ?? void 0;
76
94
  const submitLabel = props.submitLabel ?? t("form.submit", "Submit");
77
95
  const submitVariant = props.submitVariant ?? void 0;
96
+ const submitEmphasis = props.submitEmphasis ?? void 0;
78
97
  const summaryLabel = props.validationSummaryLabel;
79
98
  const validationTimeout = props.validationTimeout ?? void 0;
99
+ const resetValues = useResetFormValues();
100
+ const resetConfigured = (configured) => {
101
+ const fields = configuredResetFields(configured);
102
+ if (fields !== false) resetValues(fields);
103
+ };
104
+ const formRef = useRef(null);
105
+ const retryPhase = useRef("idle");
106
+ const [renewedSubmitTick, setRenewedSubmitTick] = useState(0);
107
+ useEffect(() => {
108
+ if (renewedSubmitTick > 0 && retryPhase.current === "renewing") formRef.current?.submit();
109
+ }, [renewedSubmitTick]);
80
110
  return /* @__PURE__ */ jsx(Form, {
111
+ ref: formRef,
81
112
  action,
82
113
  "data-slot": "form",
83
114
  "data-lattice-component": node.id,
@@ -88,6 +119,17 @@ var FormComponent = ({ children, node }) => {
88
119
  validationTimeout: precognitive ? validationTimeout : void 0,
89
120
  headers: withHeaders(componentRef),
90
121
  className: "mx-auto flex w-full max-w-2xl flex-col gap-6",
122
+ onStart: () => {
123
+ retryPhase.current = retryPhase.current === "renewing" ? "retried" : "idle";
124
+ },
125
+ onSuccess: () => resetConfigured(resetOnSuccess),
126
+ onError: () => resetConfigured(resetOnError),
127
+ onHttpException: (response) => {
128
+ if (response.status !== 403 || componentRef === "" || retryPhase.current === "retried") return;
129
+ retryPhase.current = "renewing";
130
+ refreshRef(componentRef).finally(() => setRenewedSubmitTick((tick) => tick + 1));
131
+ return false;
132
+ },
91
133
  children: ({ clearErrors, errors, processing, reset, touch, validate, validating }) => /* @__PURE__ */ jsxs(FormProvider, {
92
134
  value: {
93
135
  action,
@@ -115,25 +157,23 @@ var FormComponent = ({ children, node }) => {
115
157
  className: "text-center text-sm font-medium text-lt-success",
116
158
  children: props.status
117
159
  }),
118
- /* @__PURE__ */ jsx(FormValuesProvider, {
119
- initial: initialValues,
120
- children: /* @__PURE__ */ jsx(FormBody, {
121
- action,
122
- componentRef,
123
- nodes: node.schema,
124
- shouldRenderSubmitButton,
125
- submitButtons,
126
- submitJustify,
127
- submitLabel,
128
- submitVariant,
129
- summaryLabel,
130
- children
131
- })
160
+ /* @__PURE__ */ jsx(FormBody, {
161
+ action,
162
+ componentRef,
163
+ nodes: node.schema,
164
+ shouldRenderSubmitButton,
165
+ submitButtons,
166
+ submitEmphasis,
167
+ submitJustify,
168
+ submitLabel,
169
+ submitVariant,
170
+ summaryLabel,
171
+ children
132
172
  })
133
173
  ]
134
174
  })
135
175
  });
136
- };
176
+ }
137
177
  //#endregion
138
178
  export { FormComponent };
139
179
 
@@ -1 +1 @@
1
- {"version":3,"file":"form.js","names":[],"sources":["../../../resources/js/form/components/form.tsx"],"sourcesContent":["import { Form as InertiaForm } from \"@inertiajs/react\";\nimport { withHeaders } from \"@lattice-php/lattice/core/headers\";\nimport { LATTICE_EVENT } from \"@lattice-php/lattice/core/event-names\";\nimport { useWindowEvent } from \"@lattice-php/lattice/core/hooks/use-window-event\";\nimport { nodeKey } from \"@lattice-php/lattice/core/nodes\";\nimport { RenderNode } from \"@lattice-php/lattice/core/renderer\";\nimport type { Node, RendererComponent } from \"@lattice-php/lattice/core/types\";\nimport { useT } from \"@lattice-php/lattice/i18n\";\nimport type { ButtonVariant, Justify } from \"@lattice-php/lattice/types/generated\";\nimport { useMemo } from \"react\";\nimport { FormSubmitButton } from \"./base/submit-button\";\nimport { FormProvider } from \"@lattice-php/lattice/form/hooks/context\";\nimport { collectFields } from \"@lattice-php/lattice/form/lib/collect-fields\";\nimport { PrefillProvider } from \"@lattice-php/lattice/form/hooks/prefill-context\";\nimport { ResolvedNodesProvider } from \"@lattice-php/lattice/form/hooks/resolved-nodes\";\nimport { useFormResolver } from \"@lattice-php/lattice/form/hooks/use-form-resolver\";\nimport { FormValuesProvider } from \"@lattice-php/lattice/form/hooks/values\";\n\nconst JUSTIFY_CLASS: Record<Justify, string> = {\n start: \"justify-start\",\n center: \"justify-center\",\n end: \"justify-end\",\n between: \"justify-between\",\n around: \"justify-around\",\n evenly: \"justify-evenly\",\n};\n\nfunction FormResetListener({\n componentId,\n reset,\n}: {\n componentId?: string;\n reset: (...fields: string[]) => void;\n}) {\n useWindowEvent(LATTICE_EVENT.resetForm, (event) => {\n const detail = (event as CustomEvent<{ form: string | null }>).detail;\n\n if (!detail?.form || detail.form === componentId) {\n reset();\n }\n });\n\n return null;\n}\n\nfunction FormBody({\n action,\n children,\n componentRef,\n nodes,\n shouldRenderSubmitButton,\n submitButtons,\n submitJustify,\n submitLabel,\n submitVariant,\n summaryLabel,\n}: {\n action: string;\n children: React.ReactNode;\n componentRef: string;\n nodes: Node[] | undefined;\n shouldRenderSubmitButton: boolean;\n submitButtons: Node<\"button\">[] | undefined;\n submitJustify: Justify | undefined;\n submitLabel: string;\n submitVariant: ButtonVariant | undefined;\n summaryLabel: string;\n}) {\n const { nodes: resolvedNodes, markUserEdit } = useFormResolver(action, componentRef, nodes);\n\n return (\n <PrefillProvider value={{ markUserEdit }}>\n <ResolvedNodesProvider nodes={resolvedNodes}>\n <div className=\"flex flex-col gap-6\">\n {children}\n\n {shouldRenderSubmitButton && (\n <div className={`flex gap-3 ${JUSTIFY_CLASS[submitJustify ?? \"end\"]}`}>\n {submitButtons?.length ? (\n submitButtons.map((button, index) =>\n button.props.buttonType === \"submit\" ? (\n <FormSubmitButton\n key={nodeKey(button, index)}\n label={button.props.label ?? submitLabel}\n summaryLabel={summaryLabel}\n variant={button.props.variant ?? submitVariant ?? \"default\"}\n />\n ) : (\n <RenderNode key={nodeKey(button, index)} node={button} />\n ),\n )\n ) : (\n <FormSubmitButton\n label={submitLabel}\n summaryLabel={summaryLabel}\n variant={submitVariant ?? \"default\"}\n />\n )}\n </div>\n )}\n </div>\n </ResolvedNodesProvider>\n </PrefillProvider>\n );\n}\n\nexport const FormComponent: RendererComponent<\"form\"> = ({ children, node }) => {\n const { t } = useT(\"lattice\");\n const props = node.props;\n const action = props.action ?? \"#\";\n const errorBag = props.errorBag;\n const componentRef = props.ref ?? \"\";\n const method = props.method ?? \"post\";\n const precognitive = props.precognitive;\n const resetOnError = props.resetOnError ?? false;\n const resetOnSuccess = props.resetOnSuccess ?? [];\n const state = props.state;\n const { labels: fieldLabels, values: fieldValues } = useMemo(\n () => collectFields(node.schema),\n [node.schema],\n );\n const initialValues = useMemo(() => ({ ...fieldValues, ...state }), [fieldValues, state]);\n const shouldRenderSubmitButton = props.submitButton;\n const submitButtons = props.submitButtons ?? undefined;\n const submitJustify = props.submitJustify ?? undefined;\n const submitLabel = props.submitLabel ?? t(\"form.submit\", \"Submit\");\n const submitVariant = props.submitVariant ?? undefined;\n const summaryLabel = props.validationSummaryLabel;\n const validationTimeout = props.validationTimeout ?? undefined;\n\n return (\n <InertiaForm\n action={action}\n data-slot=\"form\"\n data-lattice-component={node.id}\n errorBag={errorBag}\n method={method}\n resetOnError={resetOnError}\n resetOnSuccess={resetOnSuccess}\n validationTimeout={precognitive ? validationTimeout : undefined}\n headers={withHeaders(componentRef)}\n className=\"mx-auto flex w-full max-w-2xl flex-col gap-6\"\n >\n {({ clearErrors, errors, processing, reset, touch, validate, validating }) => (\n <FormProvider\n value={{\n action,\n clearErrors: (field) => clearErrors(field),\n componentId: node.id,\n componentRef,\n errors: errors as Record<string, string | undefined>,\n fieldLabels,\n precognitive,\n processing,\n touch: (fields) => touch(...fields),\n validate: (field) => validate(field),\n validateFields: (fields, options) => validate({ only: fields, ...options }),\n validating,\n }}\n >\n <FormResetListener componentId={node.id} reset={reset} />\n\n {props.status && (\n <div className=\"text-center text-sm font-medium text-lt-success\">{props.status}</div>\n )}\n\n <FormValuesProvider initial={initialValues}>\n <FormBody\n action={action}\n componentRef={componentRef}\n nodes={node.schema}\n shouldRenderSubmitButton={shouldRenderSubmitButton}\n submitButtons={submitButtons}\n submitJustify={submitJustify}\n submitLabel={submitLabel}\n submitVariant={submitVariant}\n summaryLabel={summaryLabel}\n >\n {children}\n </FormBody>\n </FormValuesProvider>\n </FormProvider>\n )}\n </InertiaForm>\n );\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"form.js","names":[],"sources":["../../../resources/js/form/components/form.tsx"],"sourcesContent":["import type { FormComponentRef, HttpExceptionResponse } from \"@inertiajs/core\";\nimport { Form as InertiaForm } from \"@inertiajs/react\";\nimport { refreshRef } from \"@lattice-php/lattice/core/api\";\nimport { withHeaders } from \"@lattice-php/lattice/core/headers\";\nimport { LATTICE_EVENT } from \"@lattice-php/lattice/core/event-names\";\nimport { useWindowEvent } from \"@lattice-php/lattice/core/hooks/use-window-event\";\nimport { nodeKey } from \"@lattice-php/lattice/core/nodes\";\nimport { RenderNode } from \"@lattice-php/lattice/core/renderer\";\nimport type { Node, RendererComponent } from \"@lattice-php/lattice/core/types\";\nimport { useT } from \"@lattice-php/lattice/i18n\";\nimport type { Emphasis, Justify, Variant } from \"@lattice-php/lattice/types/generated\";\nimport { useEffect, useMemo, useRef, useState } from \"react\";\nimport { FormSubmitButton } from \"./base/submit-button\";\nimport { FormProvider } from \"@lattice-php/lattice/form/hooks/context\";\nimport { collectFields } from \"@lattice-php/lattice/form/lib/collect-fields\";\nimport { PrefillProvider } from \"@lattice-php/lattice/form/hooks/prefill-context\";\nimport { ResolvedNodesProvider } from \"@lattice-php/lattice/form/hooks/resolved-nodes\";\nimport { useFormResolver } from \"@lattice-php/lattice/form/hooks/use-form-resolver\";\nimport { FormValuesProvider, useResetFormValues } from \"@lattice-php/lattice/form/hooks/values\";\n\nconst JUSTIFY_CLASS: Record<Justify, string> = {\n start: \"justify-start\",\n center: \"justify-center\",\n end: \"justify-end\",\n between: \"justify-between\",\n around: \"justify-around\",\n evenly: \"justify-evenly\",\n};\n\nfunction FormResetListener({\n componentId,\n reset,\n}: {\n componentId?: string;\n reset: (...fields: string[]) => void;\n}) {\n const resetValues = useResetFormValues();\n\n useWindowEvent(LATTICE_EVENT.resetForm, (event) => {\n const detail = (event as CustomEvent<{ form: string | null }>).detail;\n\n if (!detail?.form || detail.form === componentId) {\n reset();\n resetValues();\n }\n });\n\n return null;\n}\n\nfunction FormBody({\n action,\n children,\n componentRef,\n nodes,\n shouldRenderSubmitButton,\n submitButtons,\n submitEmphasis,\n submitJustify,\n submitLabel,\n submitVariant,\n summaryLabel,\n}: {\n action: string;\n children: React.ReactNode;\n componentRef: string;\n nodes: Node[] | undefined;\n shouldRenderSubmitButton: boolean;\n submitButtons: Node<\"button\">[] | undefined;\n submitEmphasis: Emphasis | undefined;\n submitJustify: Justify | undefined;\n submitLabel: string;\n submitVariant: Variant | undefined;\n summaryLabel: string;\n}) {\n const { nodes: resolvedNodes, markUserEdit } = useFormResolver(action, componentRef, nodes);\n const prefill = useMemo(() => ({ markUserEdit }), [markUserEdit]);\n\n return (\n <PrefillProvider value={prefill}>\n <ResolvedNodesProvider nodes={resolvedNodes}>\n <div className=\"flex flex-col gap-6\">\n {children}\n\n {shouldRenderSubmitButton && (\n <div className={`flex gap-3 ${JUSTIFY_CLASS[submitJustify ?? \"end\"]}`}>\n {submitButtons?.length ? (\n submitButtons.map((button, index) =>\n button.props.buttonType === \"submit\" ? (\n <FormSubmitButton\n key={nodeKey(button, index)}\n emphasis={button.props.emphasis ?? submitEmphasis}\n label={button.props.label ?? submitLabel}\n summaryLabel={summaryLabel}\n variant={button.props.variant ?? submitVariant}\n />\n ) : (\n <RenderNode key={nodeKey(button, index)} node={button} />\n ),\n )\n ) : (\n <FormSubmitButton\n emphasis={submitEmphasis}\n label={submitLabel}\n summaryLabel={summaryLabel}\n variant={submitVariant}\n />\n )}\n </div>\n )}\n </div>\n </ResolvedNodesProvider>\n </PrefillProvider>\n );\n}\n\nfunction configuredResetFields(\n configured: string[] | boolean | null | undefined,\n): string[] | undefined | false {\n if (!configured || (Array.isArray(configured) && configured.length === 0)) {\n return false;\n }\n\n return Array.isArray(configured) ? configured : undefined;\n}\n\nexport const FormComponent: RendererComponent<\"form\"> = ({ children, node }) => {\n const initialValues = useMemo(\n () => ({ ...collectFields(node.schema).values, ...node.props.state }),\n [node.schema, node.props.state],\n );\n\n return (\n <FormValuesProvider initial={initialValues}>\n <FormShell node={node}>{children}</FormShell>\n </FormValuesProvider>\n );\n};\n\nfunction FormShell({ children, node }: { children: React.ReactNode; node: Node<\"form\"> }) {\n const { t } = useT(\"lattice\");\n const props = node.props;\n const action = props.action ?? \"#\";\n const errorBag = props.errorBag;\n const componentRef = props.ref ?? \"\";\n const method = props.method ?? \"post\";\n const precognitive = props.precognitive;\n const resetOnError = props.resetOnError ?? false;\n const resetOnSuccess = props.resetOnSuccess ?? [];\n const fieldLabels = useMemo(() => collectFields(node.schema).labels, [node.schema]);\n const shouldRenderSubmitButton = props.submitButton;\n const submitButtons = props.submitButtons ?? undefined;\n const submitJustify = props.submitJustify ?? undefined;\n const submitLabel = props.submitLabel ?? t(\"form.submit\", \"Submit\");\n const submitVariant = props.submitVariant ?? undefined;\n const submitEmphasis = props.submitEmphasis ?? undefined;\n const summaryLabel = props.validationSummaryLabel;\n const validationTimeout = props.validationTimeout ?? undefined;\n\n const resetValues = useResetFormValues();\n const resetConfigured = (configured: string[] | boolean | null | undefined): void => {\n const fields = configuredResetFields(configured);\n\n if (fields !== false) {\n resetValues(fields);\n }\n };\n\n const formRef = useRef<FormComponentRef | null>(null);\n // One renewal attempt per user-initiated submit: 'renewing' marks the window\n // between the 403 and our programmatic retry, 'retried' lets the second\n // failure surface normally.\n const retryPhase = useRef<\"idle\" | \"renewing\" | \"retried\">(\"idle\");\n const [renewedSubmitTick, setRenewedSubmitTick] = useState(0);\n\n useEffect(() => {\n // The state bump forces this render first, so the headers prop below has\n // re-resolved the renewed token before the retry goes out.\n if (renewedSubmitTick > 0 && retryPhase.current === \"renewing\") {\n formRef.current?.submit();\n }\n }, [renewedSubmitTick]);\n\n return (\n <InertiaForm\n ref={formRef}\n action={action}\n data-slot=\"form\"\n data-lattice-component={node.id}\n errorBag={errorBag}\n method={method}\n resetOnError={resetOnError}\n resetOnSuccess={resetOnSuccess}\n validationTimeout={precognitive ? validationTimeout : undefined}\n headers={withHeaders(componentRef)}\n className=\"mx-auto flex w-full max-w-2xl flex-col gap-6\"\n onStart={() => {\n retryPhase.current = retryPhase.current === \"renewing\" ? \"retried\" : \"idle\";\n }}\n onSuccess={() => resetConfigured(resetOnSuccess)}\n onError={() => resetConfigured(resetOnError)}\n onHttpException={(response: HttpExceptionResponse) => {\n if (response.status !== 403 || componentRef === \"\" || retryPhase.current === \"retried\") {\n return undefined;\n }\n\n retryPhase.current = \"renewing\";\n // Retry even when the renewal failed: a genuine 403 then surfaces\n // through the second attempt instead of being swallowed here.\n void refreshRef(componentRef).finally(() => setRenewedSubmitTick((tick) => tick + 1));\n\n return false;\n }}\n >\n {({ clearErrors, errors, processing, reset, touch, validate, validating }) => (\n <FormProvider\n value={{\n action,\n clearErrors: (field) => clearErrors(field),\n componentId: node.id,\n componentRef,\n errors: errors as Record<string, string | undefined>,\n fieldLabels,\n precognitive,\n processing,\n touch: (fields) => touch(...fields),\n validate: (field) => validate(field),\n validateFields: (fields, options) => validate({ only: fields, ...options }),\n validating,\n }}\n >\n <FormResetListener componentId={node.id} reset={reset} />\n\n {props.status && (\n <div className=\"text-center text-sm font-medium text-lt-success\">{props.status}</div>\n )}\n\n <FormBody\n action={action}\n componentRef={componentRef}\n nodes={node.schema}\n shouldRenderSubmitButton={shouldRenderSubmitButton}\n submitButtons={submitButtons}\n submitEmphasis={submitEmphasis}\n submitJustify={submitJustify}\n submitLabel={submitLabel}\n submitVariant={submitVariant}\n summaryLabel={summaryLabel}\n >\n {children}\n </FormBody>\n </FormProvider>\n )}\n </InertiaForm>\n );\n}\n"],"mappings":"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"}
@@ -107,7 +107,7 @@ var WizardComponent = ({ children, node }) => {
107
107
  disabled: activeIndex === 0 || processing,
108
108
  onClick: () => goTo(activeIndex - 1),
109
109
  type: "button",
110
- variant: "outline",
110
+ emphasis: "outline",
111
111
  children: t("form.wizard.back", "Back")
112
112
  }), isLast ? /* @__PURE__ */ jsxs(Button, {
113
113
  "data-test": "wizard-finish",
@@ -1 +1 @@
1
- {"version":3,"file":"wizard.js","names":[],"sources":["../../../resources/js/form/components/wizard.tsx"],"sourcesContent":["import { createContext, useContext, useEffect, useMemo, useRef, useState } from \"react\";\nimport type { ReactNode } from \"react\";\nimport type { Node, RendererComponent } from \"@lattice-php/lattice/core/types\";\nimport type { WizardStep } from \"@lattice-php/lattice/types/generated\";\nimport { cn } from \"@lattice-php/lattice/lib/utils\";\nimport { useT } from \"@lattice-php/lattice/i18n\";\nimport { Icon } from \"@lattice-php/lattice/icons\";\nimport { Button } from \"@lattice-php/lattice/ui/button\";\nimport { Spinner } from \"@lattice-php/lattice/ui/spinner\";\nimport { useFormContext } from \"@lattice-php/lattice/form/hooks/context\";\nimport {\n firstErroredStep,\n stepFieldNames,\n stepsWithErrors,\n stepValidationPaths,\n} from \"@lattice-php/lattice/form/lib/wizard-steps\";\n\ntype WizardContextValue = { activeName: string };\n\nconst WizardContext = createContext<WizardContextValue>({ activeName: \"\" });\n\nfunction getSteps(node: Node<\"wizard\">): { items: WizardStep[]; nodes: Node[] } {\n const nodes = (node.schema ?? []).filter((child) => child.type === \"wizard-step\");\n const items = nodes.map((child) => child.props as unknown as WizardStep);\n\n return { items, nodes };\n}\n\nexport const WizardComponent: RendererComponent<\"wizard\"> = ({ children, node }) => {\n const { t } = useT(\"lattice\");\n const { errors, processing, touch, validateFields, validating } = useFormContext();\n const { items, nodes } = useMemo(() => getSteps(node), [node]);\n const stepNames = useMemo(() => nodes.map((step) => stepFieldNames(step)), [nodes]);\n const isVertical = node.props.orientation === \"vertical\";\n\n const [activeIndex, setActiveIndex] = useState(0);\n const [visited, setVisited] = useState<Set<number>>(() => new Set([0]));\n const [completed, setCompleted] = useState<Set<number>>(() => new Set());\n const erroredSteps = useMemo(() => stepsWithErrors(stepNames, errors), [stepNames, errors]);\n const isLast = activeIndex === items.length - 1;\n\n const goTo = (index: number): void => {\n setActiveIndex(index);\n setVisited((previous) => new Set(previous).add(index));\n };\n\n const advance = (): void => {\n setCompleted((previous) => new Set(previous).add(activeIndex));\n\n if (!isLast) {\n goTo(activeIndex + 1);\n }\n };\n\n const onNext = (): void => {\n const step = nodes[activeIndex];\n const paths = step ? stepValidationPaths(step) : [];\n\n if (paths.length === 0) {\n advance();\n\n return;\n }\n\n touch(paths);\n validateFields(paths, { onSuccess: advance });\n };\n\n const wasProcessing = useRef(false);\n useEffect(() => {\n if (wasProcessing.current && !processing) {\n const target = firstErroredStep(stepNames, errors);\n\n if (target !== null && target !== activeIndex) {\n goTo(target);\n }\n }\n\n wasProcessing.current = processing;\n }, [processing, errors, stepNames, activeIndex]);\n\n const contextValue = useMemo(\n () => ({ activeName: items[activeIndex]?.name ?? \"\" }),\n [items, activeIndex],\n );\n\n return (\n <WizardContext.Provider value={contextValue}>\n <div className={cn(\"gap-6\", isVertical ? \"flex\" : \"grid\")} data-slot=\"wizard\">\n <ol\n aria-label={t(\"form.wizard.steps\", \"Steps\")}\n className={cn(\"gap-1\", isVertical ? \"flex w-56 shrink-0 flex-col\" : \"flex flex-wrap\")}\n >\n {items.map((step, index) => {\n const isActive = index === activeIndex;\n const isDone = completed.has(index);\n const hasError = erroredSteps.has(index);\n\n return (\n <li key={step.name}>\n <button\n aria-current={isActive ? \"step\" : undefined}\n className={cn(\n \"flex w-full items-center gap-2 rounded-lt px-3 py-2 text-left text-sm\",\n isActive ? \"bg-lt-muted font-medium text-lt-fg\" : \"text-lt-muted-fg\",\n !visited.has(index) && \"cursor-not-allowed opacity-60\",\n )}\n data-error={hasError || undefined}\n data-test={`wizard-rail-${step.name}`}\n disabled={!visited.has(index)}\n id={`wizard-step-${step.name}-trigger`}\n onClick={() => goTo(index)}\n type=\"button\"\n >\n <span\n className={cn(\n \"flex size-5 shrink-0 items-center justify-center rounded-full border text-xs\",\n hasError\n ? \"border-lt-danger text-lt-danger\"\n : isDone\n ? \"border-lt-primary bg-lt-primary text-lt-primary-fg\"\n : \"border-lt-border\",\n )}\n >\n {isDone && !hasError ? (\n <Icon className=\"size-lt-icon-sm\" name=\"check\" />\n ) : (\n index + 1\n )}\n </span>\n <span className=\"min-w-0\">\n <span className=\"block truncate\">{step.label}</span>\n {isVertical && step.description && (\n <span className=\"block truncate text-xs text-lt-muted-fg\">\n {step.description}\n </span>\n )}\n </span>\n </button>\n </li>\n );\n })}\n </ol>\n\n <div className=\"min-w-0 flex-1 space-y-6\">\n {children}\n\n <div className=\"flex items-center justify-between gap-3\">\n <Button\n data-test=\"wizard-back\"\n disabled={activeIndex === 0 || processing}\n onClick={() => goTo(activeIndex - 1)}\n type=\"button\"\n variant=\"outline\"\n >\n {t(\"form.wizard.back\", \"Back\")}\n </Button>\n\n {isLast ? (\n <Button data-test=\"wizard-finish\" disabled={processing} type=\"submit\">\n {processing && <Spinner />}\n {t(\"form.wizard.finish\", \"Finish\")}\n </Button>\n ) : (\n <Button\n data-test=\"wizard-next\"\n disabled={processing || validating}\n onClick={onNext}\n type=\"button\"\n >\n {validating && <Spinner />}\n {t(\"form.wizard.next\", \"Next\")}\n </Button>\n )}\n </div>\n </div>\n </div>\n </WizardContext.Provider>\n );\n};\n\nexport const WizardStepComponent: RendererComponent<\"wizard-step\"> = ({ children, node }) => {\n const { activeName } = useContext(WizardContext);\n const name = node.props.name;\n const isActive = activeName === name;\n const [hasOpened, setHasOpened] = useState(isActive);\n\n useEffect(() => {\n if (isActive) {\n setHasOpened(true);\n }\n }, [isActive]);\n\n return (\n <section\n aria-labelledby={`wizard-step-${name}-trigger`}\n className={cn(\"space-y-8\", !isActive && \"hidden\")}\n hidden={!isActive}\n id={`wizard-step-${name}-panel`}\n >\n {hasOpened ? (children as ReactNode) : null}\n </section>\n );\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"wizard.js","names":[],"sources":["../../../resources/js/form/components/wizard.tsx"],"sourcesContent":["import { createContext, useContext, useEffect, useMemo, useRef, useState } from \"react\";\nimport type { ReactNode } from \"react\";\nimport type { Node, RendererComponent } from \"@lattice-php/lattice/core/types\";\nimport type { WizardStep } from \"@lattice-php/lattice/types/generated\";\nimport { cn } from \"@lattice-php/lattice/lib/utils\";\nimport { useT } from \"@lattice-php/lattice/i18n\";\nimport { Icon } from \"@lattice-php/lattice/icons\";\nimport { Button } from \"@lattice-php/lattice/ui/button\";\nimport { Spinner } from \"@lattice-php/lattice/ui/spinner\";\nimport { useFormContext } from \"@lattice-php/lattice/form/hooks/context\";\nimport {\n firstErroredStep,\n stepFieldNames,\n stepsWithErrors,\n stepValidationPaths,\n} from \"@lattice-php/lattice/form/lib/wizard-steps\";\n\ntype WizardContextValue = { activeName: string };\n\nconst WizardContext = createContext<WizardContextValue>({ activeName: \"\" });\n\nfunction getSteps(node: Node<\"wizard\">): { items: WizardStep[]; nodes: Node[] } {\n const nodes = (node.schema ?? []).filter((child) => child.type === \"wizard-step\");\n const items = nodes.map((child) => child.props as unknown as WizardStep);\n\n return { items, nodes };\n}\n\nexport const WizardComponent: RendererComponent<\"wizard\"> = ({ children, node }) => {\n const { t } = useT(\"lattice\");\n const { errors, processing, touch, validateFields, validating } = useFormContext();\n const { items, nodes } = useMemo(() => getSteps(node), [node]);\n const stepNames = useMemo(() => nodes.map((step) => stepFieldNames(step)), [nodes]);\n const isVertical = node.props.orientation === \"vertical\";\n\n const [activeIndex, setActiveIndex] = useState(0);\n const [visited, setVisited] = useState<Set<number>>(() => new Set([0]));\n const [completed, setCompleted] = useState<Set<number>>(() => new Set());\n const erroredSteps = useMemo(() => stepsWithErrors(stepNames, errors), [stepNames, errors]);\n const isLast = activeIndex === items.length - 1;\n\n const goTo = (index: number): void => {\n setActiveIndex(index);\n setVisited((previous) => new Set(previous).add(index));\n };\n\n const advance = (): void => {\n setCompleted((previous) => new Set(previous).add(activeIndex));\n\n if (!isLast) {\n goTo(activeIndex + 1);\n }\n };\n\n const onNext = (): void => {\n const step = nodes[activeIndex];\n const paths = step ? stepValidationPaths(step) : [];\n\n if (paths.length === 0) {\n advance();\n\n return;\n }\n\n touch(paths);\n validateFields(paths, { onSuccess: advance });\n };\n\n const wasProcessing = useRef(false);\n useEffect(() => {\n if (wasProcessing.current && !processing) {\n const target = firstErroredStep(stepNames, errors);\n\n if (target !== null && target !== activeIndex) {\n goTo(target);\n }\n }\n\n wasProcessing.current = processing;\n }, [processing, errors, stepNames, activeIndex]);\n\n const contextValue = useMemo(\n () => ({ activeName: items[activeIndex]?.name ?? \"\" }),\n [items, activeIndex],\n );\n\n return (\n <WizardContext.Provider value={contextValue}>\n <div className={cn(\"gap-6\", isVertical ? \"flex\" : \"grid\")} data-slot=\"wizard\">\n <ol\n aria-label={t(\"form.wizard.steps\", \"Steps\")}\n className={cn(\"gap-1\", isVertical ? \"flex w-56 shrink-0 flex-col\" : \"flex flex-wrap\")}\n >\n {items.map((step, index) => {\n const isActive = index === activeIndex;\n const isDone = completed.has(index);\n const hasError = erroredSteps.has(index);\n\n return (\n <li key={step.name}>\n <button\n aria-current={isActive ? \"step\" : undefined}\n className={cn(\n \"flex w-full items-center gap-2 rounded-lt px-3 py-2 text-left text-sm\",\n isActive ? \"bg-lt-muted font-medium text-lt-fg\" : \"text-lt-muted-fg\",\n !visited.has(index) && \"cursor-not-allowed opacity-60\",\n )}\n data-error={hasError || undefined}\n data-test={`wizard-rail-${step.name}`}\n disabled={!visited.has(index)}\n id={`wizard-step-${step.name}-trigger`}\n onClick={() => goTo(index)}\n type=\"button\"\n >\n <span\n className={cn(\n \"flex size-5 shrink-0 items-center justify-center rounded-full border text-xs\",\n hasError\n ? \"border-lt-danger text-lt-danger\"\n : isDone\n ? \"border-lt-primary bg-lt-primary text-lt-primary-fg\"\n : \"border-lt-border\",\n )}\n >\n {isDone && !hasError ? (\n <Icon className=\"size-lt-icon-sm\" name=\"check\" />\n ) : (\n index + 1\n )}\n </span>\n <span className=\"min-w-0\">\n <span className=\"block truncate\">{step.label}</span>\n {isVertical && step.description && (\n <span className=\"block truncate text-xs text-lt-muted-fg\">\n {step.description}\n </span>\n )}\n </span>\n </button>\n </li>\n );\n })}\n </ol>\n\n <div className=\"min-w-0 flex-1 space-y-6\">\n {children}\n\n <div className=\"flex items-center justify-between gap-3\">\n <Button\n data-test=\"wizard-back\"\n disabled={activeIndex === 0 || processing}\n onClick={() => goTo(activeIndex - 1)}\n type=\"button\"\n emphasis=\"outline\"\n >\n {t(\"form.wizard.back\", \"Back\")}\n </Button>\n\n {isLast ? (\n <Button data-test=\"wizard-finish\" disabled={processing} type=\"submit\">\n {processing && <Spinner />}\n {t(\"form.wizard.finish\", \"Finish\")}\n </Button>\n ) : (\n <Button\n data-test=\"wizard-next\"\n disabled={processing || validating}\n onClick={onNext}\n type=\"button\"\n >\n {validating && <Spinner />}\n {t(\"form.wizard.next\", \"Next\")}\n </Button>\n )}\n </div>\n </div>\n </div>\n </WizardContext.Provider>\n );\n};\n\nexport const WizardStepComponent: RendererComponent<\"wizard-step\"> = ({ children, node }) => {\n const { activeName } = useContext(WizardContext);\n const name = node.props.name;\n const isActive = activeName === name;\n const [hasOpened, setHasOpened] = useState(isActive);\n\n useEffect(() => {\n if (isActive) {\n setHasOpened(true);\n }\n }, [isActive]);\n\n return (\n <section\n aria-labelledby={`wizard-step-${name}-trigger`}\n className={cn(\"space-y-8\", !isActive && \"hidden\")}\n hidden={!isActive}\n id={`wizard-step-${name}-panel`}\n >\n {hasOpened ? (children as ReactNode) : null}\n </section>\n );\n};\n"],"mappings":";;;;;;;;;;AAmBA,IAAM,gBAAgB,cAAkC,EAAE,YAAY,GAAG,CAAC;AAE1E,SAAS,SAAS,MAA8D;CAC9E,MAAM,SAAS,KAAK,UAAU,CAAC,GAAG,QAAQ,UAAU,MAAM,SAAS,aAAa;CAGhF,OAAO;EAAE,OAFK,MAAM,KAAK,UAAU,MAAM,KAEhC;EAAO;CAAM;AACxB;AAEA,IAAa,mBAAgD,EAAE,UAAU,WAAW;CAClF,MAAM,EAAE,MAAM,KAAK,SAAS;CAC5B,MAAM,EAAE,QAAQ,YAAY,OAAO,gBAAgB,eAAe,eAAe;CACjF,MAAM,EAAE,OAAO,UAAU,cAAc,SAAS,IAAI,GAAG,CAAC,IAAI,CAAC;CAC7D,MAAM,YAAY,cAAc,MAAM,KAAK,SAAS,eAAe,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC;CAClF,MAAM,aAAa,KAAK,MAAM,gBAAgB;CAE9C,MAAM,CAAC,aAAa,kBAAkB,SAAS,CAAC;CAChD,MAAM,CAAC,SAAS,cAAc,eAA4B,IAAI,IAAI,CAAC,CAAC,CAAC,CAAC;CACtE,MAAM,CAAC,WAAW,gBAAgB,+BAA4B,IAAI,IAAI,CAAC;CACvE,MAAM,eAAe,cAAc,gBAAgB,WAAW,MAAM,GAAG,CAAC,WAAW,MAAM,CAAC;CAC1F,MAAM,SAAS,gBAAgB,MAAM,SAAS;CAE9C,MAAM,QAAQ,UAAwB;EACpC,eAAe,KAAK;EACpB,YAAY,aAAa,IAAI,IAAI,QAAQ,EAAE,IAAI,KAAK,CAAC;CACvD;CAEA,MAAM,gBAAsB;EAC1B,cAAc,aAAa,IAAI,IAAI,QAAQ,EAAE,IAAI,WAAW,CAAC;EAE7D,IAAI,CAAC,QACH,KAAK,cAAc,CAAC;CAExB;CAEA,MAAM,eAAqB;EACzB,MAAM,OAAO,MAAM;EACnB,MAAM,QAAQ,OAAO,oBAAoB,IAAI,IAAI,CAAC;EAElD,IAAI,MAAM,WAAW,GAAG;GACtB,QAAQ;GAER;EACF;EAEA,MAAM,KAAK;EACX,eAAe,OAAO,EAAE,WAAW,QAAQ,CAAC;CAC9C;CAEA,MAAM,gBAAgB,OAAO,KAAK;CAClC,gBAAgB;EACd,IAAI,cAAc,WAAW,CAAC,YAAY;GACxC,MAAM,SAAS,iBAAiB,WAAW,MAAM;GAEjD,IAAI,WAAW,QAAQ,WAAW,aAChC,KAAK,MAAM;EAEf;EAEA,cAAc,UAAU;CAC1B,GAAG;EAAC;EAAY;EAAQ;EAAW;CAAW,CAAC;CAE/C,MAAM,eAAe,eACZ,EAAE,YAAY,MAAM,cAAc,QAAQ,GAAG,IACpD,CAAC,OAAO,WAAW,CACrB;CAEA,OACE,oBAAC,cAAc,UAAf;EAAwB,OAAO;YAC7B,qBAAC,OAAD;GAAK,WAAW,GAAG,SAAS,aAAa,SAAS,MAAM;GAAG,aAAU;aAArE,CACE,oBAAC,MAAD;IACE,cAAY,EAAE,qBAAqB,OAAO;IAC1C,WAAW,GAAG,SAAS,aAAa,gCAAgC,gBAAgB;cAEnF,MAAM,KAAK,MAAM,UAAU;KAC1B,MAAM,WAAW,UAAU;KAC3B,MAAM,SAAS,UAAU,IAAI,KAAK;KAClC,MAAM,WAAW,aAAa,IAAI,KAAK;KAEvC,OACE,oBAAC,MAAD,EAAA,UACE,qBAAC,UAAD;MACE,gBAAc,WAAW,SAAS,KAAA;MAClC,WAAW,GACT,yEACA,WAAW,uCAAuC,oBAClD,CAAC,QAAQ,IAAI,KAAK,KAAK,+BACzB;MACA,cAAY,YAAY,KAAA;MACxB,aAAW,eAAe,KAAK;MAC/B,UAAU,CAAC,QAAQ,IAAI,KAAK;MAC5B,IAAI,eAAe,KAAK,KAAK;MAC7B,eAAe,KAAK,KAAK;MACzB,MAAK;gBAZP,CAcE,oBAAC,QAAD;OACE,WAAW,GACT,gFACA,WACI,oCACA,SACE,uDACA,kBACR;iBAEC,UAAU,CAAC,WACV,oBAAC,MAAD;QAAM,WAAU;QAAkB,MAAK;OAAS,CAAA,IAEhD,QAAQ;MAEN,CAAA,GACN,qBAAC,QAAD;OAAM,WAAU;iBAAhB,CACE,oBAAC,QAAD;QAAM,WAAU;kBAAkB,KAAK;OAAY,CAAA,GAClD,cAAc,KAAK,eAClB,oBAAC,QAAD;QAAM,WAAU;kBACb,KAAK;OACF,CAAA,CAEJ;QACA;QACN,GAxCK,KAAK,IAwCV;IAER,CAAC;GACC,CAAA,GAEJ,qBAAC,OAAD;IAAK,WAAU;cAAf,CACG,UAED,qBAAC,OAAD;KAAK,WAAU;eAAf,CACE,oBAAC,QAAD;MACE,aAAU;MACV,UAAU,gBAAgB,KAAK;MAC/B,eAAe,KAAK,cAAc,CAAC;MACnC,MAAK;MACL,UAAS;gBAER,EAAE,oBAAoB,MAAM;KACvB,CAAA,GAEP,SACC,qBAAC,QAAD;MAAQ,aAAU;MAAgB,UAAU;MAAY,MAAK;gBAA7D,CACG,cAAc,oBAAC,SAAD,CAAU,CAAA,GACxB,EAAE,sBAAsB,QAAQ,CAC3B;UAER,qBAAC,QAAD;MACE,aAAU;MACV,UAAU,cAAc;MACxB,SAAS;MACT,MAAK;gBAJP,CAMG,cAAc,oBAAC,SAAD,CAAU,CAAA,GACxB,EAAE,oBAAoB,MAAM,CACvB;OAEP;MACF;KACF;;CACiB,CAAA;AAE5B;AAEA,IAAa,uBAAyD,EAAE,UAAU,WAAW;CAC3F,MAAM,EAAE,eAAe,WAAW,aAAa;CAC/C,MAAM,OAAO,KAAK,MAAM;CACxB,MAAM,WAAW,eAAe;CAChC,MAAM,CAAC,WAAW,gBAAgB,SAAS,QAAQ;CAEnD,gBAAgB;EACd,IAAI,UACF,aAAa,IAAI;CAErB,GAAG,CAAC,QAAQ,CAAC;CAEb,OACE,oBAAC,WAAD;EACE,mBAAiB,eAAe,KAAK;EACrC,WAAW,GAAG,aAAa,CAAC,YAAY,QAAQ;EAChD,QAAQ,CAAC;EACT,IAAI,eAAe,KAAK;YAEvB,YAAa,WAAyB;CAChC,CAAA;AAEb"}
@@ -62,7 +62,7 @@ function useFormResolver(action, componentRef, nodes) {
62
62
  const controller = new AbortController();
63
63
  const timer = window.setTimeout(() => {
64
64
  postFormAction(action, componentRef, {
65
- _resolve: true,
65
+ _sub: "resolve",
66
66
  ...values
67
67
  }, controller.signal).then((response) => {
68
68
  if (!response) return;
@@ -1 +1 @@
1
- {"version":3,"file":"use-form-resolver.js","names":[],"sources":["../../../resources/js/form/hooks/use-form-resolver.ts"],"sourcesContent":["import { useCallback, useEffect, useLayoutEffect, useMemo, useRef, useState } from \"react\";\nimport type { Node } from \"@lattice-php/lattice/core/types\";\nimport type { ResolveResponse } from \"@lattice-php/lattice/types/generated\";\nimport { walkFields } from \"@lattice-php/lattice/form/lib/field-props\";\nimport { FORM_DEBOUNCE_MS, postFormAction } from \"@lattice-php/lattice/form/lib/form-transport\";\nimport {\n collectPrefillTargets,\n getPath,\n pathsToClear,\n pruneOverrides,\n seededOverrides,\n} from \"@lattice-php/lattice/form/lib/prefill-targets\";\nimport type { PrefillController } from \"./prefill-context\";\nimport { useFormValues, useSetFormValue } from \"./values\";\n\ntype FormResolver = {\n nodes: Record<string, Node>;\n markUserEdit: PrefillController[\"markUserEdit\"];\n};\n\nexport function useFormResolver(\n action: string,\n componentRef: string,\n nodes: Node[] | undefined,\n): FormResolver {\n const values = useFormValues();\n const setValue = useSetFormValue();\n const [resolved, setResolved] = useState<Record<string, Node>>({});\n\n const targets = useMemo(() => collectPrefillTargets(nodes, values), [nodes, values]);\n\n const overrides = useRef<Set<string>>(new Set());\n const seededOverrideKeys = useRef<Set<string>>(new Set());\n const previousValues = useRef<Record<string, unknown>>(values);\n const previousTargets = useRef(targets);\n\n // Read targets via a ref inside the effect: `targets` changes identity on every\n // value change, but the effect must fire only when `watchSignature` changes\n // (which already reflects added/removed target paths). Keeping `targets` out of\n // the dep array preserves the targeted watch in non-\"any\" mode.\n const targetsRef = useRef(targets);\n targetsRef.current = targets;\n\n useLayoutEffect(() => {\n const liveOverrideKeys = new Set(targets.map((target) => target.overrideKey));\n seededOverrideKeys.current = new Set(\n [...seededOverrideKeys.current].filter((overrideKey) => liveOverrideKeys.has(overrideKey)),\n );\n const freshTargets = targets.filter(\n (target) => !seededOverrideKeys.current.has(target.overrideKey),\n );\n\n // Layout ordering seeds loaded values before the first resolve effect can apply prefill.\n for (const overrideKey of seededOverrides(freshTargets, values)) {\n overrides.current.add(overrideKey);\n }\n\n for (const target of freshTargets) {\n seededOverrideKeys.current.add(target.overrideKey);\n }\n }, [targets, values]);\n\n const markUserEdit = useCallback((overrideKey: string) => {\n overrides.current.add(overrideKey);\n }, []);\n\n const watch = useMemo(() => {\n const keys = new Set<string>();\n let any = false;\n walkFields(nodes, (props) => {\n if (Array.isArray(props.dependsOnKeys)) {\n for (const key of props.dependsOnKeys) {\n keys.add(String(key));\n }\n }\n if (props.dependsOnAny) {\n any = true;\n }\n });\n return { keys: [...keys], any };\n }, [nodes]);\n\n const watchPaths = useMemo(() => {\n const set = new Set<string>(watch.keys);\n for (const target of targets) {\n for (const dep of target.resetOn) {\n set.add(dep);\n }\n for (const dep of target.refreshOn) {\n set.add(dep);\n }\n }\n return [...set];\n }, [watch.keys, targets]);\n\n // In \"any\" mode the values store keeps a stable reference until something\n // actually changes, so its identity is the change signal. Otherwise hash the\n // watched paths (form-level and per-row).\n const watchSignature = watch.any\n ? values\n : JSON.stringify(watchPaths.map((path) => getPath(values, path)));\n\n useEffect(() => {\n if (watchPaths.length === 0 && !watch.any) {\n return;\n }\n\n const previous = previousValues.current;\n previousValues.current = values;\n\n // `resetOn` deps unlock a path (a fresh product gives a fresh price); `refreshOn`\n // deps only re-ask the server and never clear an override (a customer change\n // re-prices untouched rows but leaves user-edited ones alone).\n for (const overrideKey of pathsToClear(\n { targets: previousTargets.current, values: previous },\n { targets: targetsRef.current, values },\n )) {\n overrides.current.delete(overrideKey);\n }\n previousTargets.current = targetsRef.current;\n\n // Override ownership is row-id keyed, so pruning removes departed rows without reindex drift.\n overrides.current = pruneOverrides(overrides.current, targetsRef.current);\n\n const controller = new AbortController();\n\n const timer = window.setTimeout(() => {\n void postFormAction<ResolveResponse>(\n action,\n componentRef,\n { _resolve: true, ...values },\n controller.signal,\n )\n .then((response) => {\n if (!response) {\n return;\n }\n for (const [name, value] of Object.entries(response.values ?? {})) {\n setValue(name, value);\n }\n const targetsByPath = new Map(\n targetsRef.current.map((target) => [target.path, target] as const),\n );\n for (const [path, value] of Object.entries(response.prefill ?? {})) {\n const target = targetsByPath.get(path);\n\n if (target && !overrides.current.has(target.overrideKey)) {\n setValue(path, value);\n }\n }\n if (response.fields) {\n setResolved(response.fields);\n }\n })\n .catch(() => {});\n }, FORM_DEBOUNCE_MS);\n\n return () => {\n window.clearTimeout(timer);\n controller.abort();\n };\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [watchSignature, action, componentRef, watch.any, setValue]);\n\n return { nodes: resolved, markUserEdit };\n}\n"],"mappings":";;;;;;;AAoBA,SAAgB,gBACd,QACA,cACA,OACc;CACd,MAAM,SAAS,cAAc;CAC7B,MAAM,WAAW,gBAAgB;CACjC,MAAM,CAAC,UAAU,eAAe,SAA+B,CAAC,CAAC;CAEjE,MAAM,UAAU,cAAc,sBAAsB,OAAO,MAAM,GAAG,CAAC,OAAO,MAAM,CAAC;CAEnF,MAAM,YAAY,uBAAoB,IAAI,IAAI,CAAC;CAC/C,MAAM,qBAAqB,uBAAoB,IAAI,IAAI,CAAC;CACxD,MAAM,iBAAiB,OAAgC,MAAM;CAC7D,MAAM,kBAAkB,OAAO,OAAO;CAMtC,MAAM,aAAa,OAAO,OAAO;CACjC,WAAW,UAAU;CAErB,sBAAsB;EACpB,MAAM,mBAAmB,IAAI,IAAI,QAAQ,KAAK,WAAW,OAAO,WAAW,CAAC;EAC5E,mBAAmB,UAAU,IAAI,IAC/B,CAAC,GAAG,mBAAmB,OAAO,EAAE,QAAQ,gBAAgB,iBAAiB,IAAI,WAAW,CAAC,CAC3F;EACA,MAAM,eAAe,QAAQ,QAC1B,WAAW,CAAC,mBAAmB,QAAQ,IAAI,OAAO,WAAW,CAChE;EAGA,KAAK,MAAM,eAAe,gBAAgB,cAAc,MAAM,GAC5D,UAAU,QAAQ,IAAI,WAAW;EAGnC,KAAK,MAAM,UAAU,cACnB,mBAAmB,QAAQ,IAAI,OAAO,WAAW;CAErD,GAAG,CAAC,SAAS,MAAM,CAAC;CAEpB,MAAM,eAAe,aAAa,gBAAwB;EACxD,UAAU,QAAQ,IAAI,WAAW;CACnC,GAAG,CAAC,CAAC;CAEL,MAAM,QAAQ,cAAc;EAC1B,MAAM,uBAAO,IAAI,IAAY;EAC7B,IAAI,MAAM;EACV,WAAW,QAAQ,UAAU;GAC3B,IAAI,MAAM,QAAQ,MAAM,aAAa,GACnC,KAAK,MAAM,OAAO,MAAM,eACtB,KAAK,IAAI,OAAO,GAAG,CAAC;GAGxB,IAAI,MAAM,cACR,MAAM;EAEV,CAAC;EACD,OAAO;GAAE,MAAM,CAAC,GAAG,IAAI;GAAG;EAAI;CAChC,GAAG,CAAC,KAAK,CAAC;CAEV,MAAM,aAAa,cAAc;EAC/B,MAAM,MAAM,IAAI,IAAY,MAAM,IAAI;EACtC,KAAK,MAAM,UAAU,SAAS;GAC5B,KAAK,MAAM,OAAO,OAAO,SACvB,IAAI,IAAI,GAAG;GAEb,KAAK,MAAM,OAAO,OAAO,WACvB,IAAI,IAAI,GAAG;EAEf;EACA,OAAO,CAAC,GAAG,GAAG;CAChB,GAAG,CAAC,MAAM,MAAM,OAAO,CAAC;CASxB,gBAAgB;EACd,IAAI,WAAW,WAAW,KAAK,CAAC,MAAM,KACpC;EAGF,MAAM,WAAW,eAAe;EAChC,eAAe,UAAU;EAKzB,KAAK,MAAM,eAAe,aACxB;GAAE,SAAS,gBAAgB;GAAS,QAAQ;EAAS,GACrD;GAAE,SAAS,WAAW;GAAS;EAAO,CACxC,GACE,UAAU,QAAQ,OAAO,WAAW;EAEtC,gBAAgB,UAAU,WAAW;EAGrC,UAAU,UAAU,eAAe,UAAU,SAAS,WAAW,OAAO;EAExE,MAAM,aAAa,IAAI,gBAAgB;EAEvC,MAAM,QAAQ,OAAO,iBAAiB;GACpC,eACE,QACA,cACA;IAAE,UAAU;IAAM,GAAG;GAAO,GAC5B,WAAW,MACb,EACG,MAAM,aAAa;IAClB,IAAI,CAAC,UACH;IAEF,KAAK,MAAM,CAAC,MAAM,UAAU,OAAO,QAAQ,SAAS,UAAU,CAAC,CAAC,GAC9D,SAAS,MAAM,KAAK;IAEtB,MAAM,gBAAgB,IAAI,IACxB,WAAW,QAAQ,KAAK,WAAW,CAAC,OAAO,MAAM,MAAM,CAAU,CACnE;IACA,KAAK,MAAM,CAAC,MAAM,UAAU,OAAO,QAAQ,SAAS,WAAW,CAAC,CAAC,GAAG;KAClE,MAAM,SAAS,cAAc,IAAI,IAAI;KAErC,IAAI,UAAU,CAAC,UAAU,QAAQ,IAAI,OAAO,WAAW,GACrD,SAAS,MAAM,KAAK;IAExB;IACA,IAAI,SAAS,QACX,YAAY,SAAS,MAAM;GAE/B,CAAC,EACA,YAAY,CAAC,CAAC;EACnB,GAAA,GAAmB;EAEnB,aAAa;GACX,OAAO,aAAa,KAAK;GACzB,WAAW,MAAM;EACnB;CAEF,GAAG;EAhEoB,MAAM,MACzB,SACA,KAAK,UAAU,WAAW,KAAK,SAAS,QAAQ,QAAQ,IAAI,CAAC,CAAC;EA8D9C;EAAQ;EAAc,MAAM;EAAK;CAAQ,CAAC;CAE9D,OAAO;EAAE,OAAO;EAAU;CAAa;AACzC"}
1
+ {"version":3,"file":"use-form-resolver.js","names":[],"sources":["../../../resources/js/form/hooks/use-form-resolver.ts"],"sourcesContent":["import { useCallback, useEffect, useLayoutEffect, useMemo, useRef, useState } from \"react\";\nimport type { Node } from \"@lattice-php/lattice/core/types\";\nimport type { ResolveResponse } from \"@lattice-php/lattice/types/generated\";\nimport { walkFields } from \"@lattice-php/lattice/form/lib/field-props\";\nimport { FORM_DEBOUNCE_MS, postFormAction } from \"@lattice-php/lattice/form/lib/form-transport\";\nimport {\n collectPrefillTargets,\n getPath,\n pathsToClear,\n pruneOverrides,\n seededOverrides,\n} from \"@lattice-php/lattice/form/lib/prefill-targets\";\nimport type { PrefillController } from \"./prefill-context\";\nimport { useFormValues, useSetFormValue } from \"./values\";\n\ntype FormResolver = {\n nodes: Record<string, Node>;\n markUserEdit: PrefillController[\"markUserEdit\"];\n};\n\nexport function useFormResolver(\n action: string,\n componentRef: string,\n nodes: Node[] | undefined,\n): FormResolver {\n const values = useFormValues();\n const setValue = useSetFormValue();\n const [resolved, setResolved] = useState<Record<string, Node>>({});\n\n const targets = useMemo(() => collectPrefillTargets(nodes, values), [nodes, values]);\n\n const overrides = useRef<Set<string>>(new Set());\n const seededOverrideKeys = useRef<Set<string>>(new Set());\n const previousValues = useRef<Record<string, unknown>>(values);\n const previousTargets = useRef(targets);\n\n // Read targets via a ref inside the effect: `targets` changes identity on every\n // value change, but the effect must fire only when `watchSignature` changes\n // (which already reflects added/removed target paths). Keeping `targets` out of\n // the dep array preserves the targeted watch in non-\"any\" mode.\n const targetsRef = useRef(targets);\n targetsRef.current = targets;\n\n useLayoutEffect(() => {\n const liveOverrideKeys = new Set(targets.map((target) => target.overrideKey));\n seededOverrideKeys.current = new Set(\n [...seededOverrideKeys.current].filter((overrideKey) => liveOverrideKeys.has(overrideKey)),\n );\n const freshTargets = targets.filter(\n (target) => !seededOverrideKeys.current.has(target.overrideKey),\n );\n\n // Layout ordering seeds loaded values before the first resolve effect can apply prefill.\n for (const overrideKey of seededOverrides(freshTargets, values)) {\n overrides.current.add(overrideKey);\n }\n\n for (const target of freshTargets) {\n seededOverrideKeys.current.add(target.overrideKey);\n }\n }, [targets, values]);\n\n const markUserEdit = useCallback((overrideKey: string) => {\n overrides.current.add(overrideKey);\n }, []);\n\n const watch = useMemo(() => {\n const keys = new Set<string>();\n let any = false;\n walkFields(nodes, (props) => {\n if (Array.isArray(props.dependsOnKeys)) {\n for (const key of props.dependsOnKeys) {\n keys.add(String(key));\n }\n }\n if (props.dependsOnAny) {\n any = true;\n }\n });\n return { keys: [...keys], any };\n }, [nodes]);\n\n const watchPaths = useMemo(() => {\n const set = new Set<string>(watch.keys);\n for (const target of targets) {\n for (const dep of target.resetOn) {\n set.add(dep);\n }\n for (const dep of target.refreshOn) {\n set.add(dep);\n }\n }\n return [...set];\n }, [watch.keys, targets]);\n\n // In \"any\" mode the values store keeps a stable reference until something\n // actually changes, so its identity is the change signal. Otherwise hash the\n // watched paths (form-level and per-row).\n const watchSignature = watch.any\n ? values\n : JSON.stringify(watchPaths.map((path) => getPath(values, path)));\n\n useEffect(() => {\n if (watchPaths.length === 0 && !watch.any) {\n return;\n }\n\n const previous = previousValues.current;\n previousValues.current = values;\n\n // `resetOn` deps unlock a path (a fresh product gives a fresh price); `refreshOn`\n // deps only re-ask the server and never clear an override (a customer change\n // re-prices untouched rows but leaves user-edited ones alone).\n for (const overrideKey of pathsToClear(\n { targets: previousTargets.current, values: previous },\n { targets: targetsRef.current, values },\n )) {\n overrides.current.delete(overrideKey);\n }\n previousTargets.current = targetsRef.current;\n\n // Override ownership is row-id keyed, so pruning removes departed rows without reindex drift.\n overrides.current = pruneOverrides(overrides.current, targetsRef.current);\n\n const controller = new AbortController();\n\n const timer = window.setTimeout(() => {\n void postFormAction<ResolveResponse>(\n action,\n componentRef,\n { _sub: \"resolve\", ...values },\n controller.signal,\n )\n .then((response) => {\n if (!response) {\n return;\n }\n for (const [name, value] of Object.entries(response.values ?? {})) {\n setValue(name, value);\n }\n const targetsByPath = new Map(\n targetsRef.current.map((target) => [target.path, target] as const),\n );\n for (const [path, value] of Object.entries(response.prefill ?? {})) {\n const target = targetsByPath.get(path);\n\n if (target && !overrides.current.has(target.overrideKey)) {\n setValue(path, value);\n }\n }\n if (response.fields) {\n setResolved(response.fields);\n }\n })\n .catch(() => {});\n }, FORM_DEBOUNCE_MS);\n\n return () => {\n window.clearTimeout(timer);\n controller.abort();\n };\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [watchSignature, action, componentRef, watch.any, setValue]);\n\n return { nodes: resolved, markUserEdit };\n}\n"],"mappings":"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"}
@@ -1,4 +1,5 @@
1
1
  export type SetFormValue = (name: string, value: unknown | ((previous: unknown) => unknown)) => void;
2
+ export type ResetFormValues = (fields?: string[]) => void;
2
3
  export declare function FormValuesProvider({ initial, children, }: {
3
4
  initial: Record<string, unknown>;
4
5
  children: React.ReactNode;
@@ -7,3 +8,10 @@ export declare function useFormValues(): Record<string, unknown>;
7
8
  export declare function useFormValue(name: string): unknown;
8
9
  export declare function useFormValuesFor(paths: string[]): Record<string, unknown>;
9
10
  export declare function useSetFormValue(): SetFormValue;
11
+ /**
12
+ * Reset values to the store's initial snapshot — all of them, or just the
13
+ * given field paths. This is the reset that actually clears controlled
14
+ * fields; Inertia's own form reset only touches its internal data and the
15
+ * DOM, which store-driven inputs ignore.
16
+ */
17
+ export declare function useResetFormValues(): ResetFormValues;
@@ -72,6 +72,13 @@ function createFormValuesStore(initial) {
72
72
  initialValues = nextInitial;
73
73
  updateValues(nextInitial, "");
74
74
  },
75
+ reset: (fields) => {
76
+ if (fields === void 0) {
77
+ updateValues(initialValues, "");
78
+ return;
79
+ }
80
+ updateValues(fields.reduce((accumulated, field) => setPath(accumulated, field, getPath(initialValues, field)), values), "");
81
+ },
75
82
  setValue: (name, value) => {
76
83
  const previous = getPath(values, name);
77
84
  const next = typeof value === "function" ? value(previous) : value;
@@ -130,7 +137,17 @@ function useFormValuesFor(paths) {
130
137
  function useSetFormValue() {
131
138
  return useContext(SetFormValueContext);
132
139
  }
140
+ /**
141
+ * Reset values to the store's initial snapshot — all of them, or just the
142
+ * given field paths. This is the reset that actually clears controlled
143
+ * fields; Inertia's own form reset only touches its internal data and the
144
+ * DOM, which store-driven inputs ignore.
145
+ */
146
+ function useResetFormValues() {
147
+ const store = useFormValuesStore();
148
+ return useCallback((fields) => store.reset(fields), [store]);
149
+ }
133
150
  //#endregion
134
- export { FormValuesProvider, useFormValue, useFormValues, useFormValuesFor, useSetFormValue };
151
+ export { FormValuesProvider, useFormValue, useFormValues, useFormValuesFor, useResetFormValues, useSetFormValue };
135
152
 
136
153
  //# sourceMappingURL=values.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"values.js","names":[],"sources":["../../../resources/js/form/hooks/values.tsx"],"sourcesContent":["import {\n createContext,\n useCallback,\n useContext,\n useEffect,\n useMemo,\n useRef,\n useSyncExternalStore,\n} from \"react\";\nimport { getPath, setPath } from \"@lattice-php/lattice/form/lib/form-path\";\n\nexport type SetFormValue = (\n name: string,\n value: unknown | ((previous: unknown) => unknown),\n) => void;\n\ntype FormValuesStore = {\n getPathSnapshot: (path: string) => unknown;\n getPathsSnapshot: (paths: string[]) => Record<string, unknown>;\n getSnapshot: () => Record<string, unknown>;\n replaceInitial: (initial: Record<string, unknown>) => void;\n setValue: SetFormValue;\n subscribe: (listener: () => void) => () => void;\n subscribePath: (path: string, listener: () => void) => () => void;\n subscribePaths: (paths: string[], listener: () => void) => () => void;\n};\n\nconst emptyValues: Record<string, unknown> = {};\nconst emptySelectedValues: Record<string, unknown> = {};\n\nconst FormValuesStoreContext = createContext<FormValuesStore | null>(null);\nconst SetFormValueContext = createContext<SetFormValue>(() => {});\n\nfunction valuesEqual(a: unknown, b: unknown): boolean {\n if (Object.is(a, b)) {\n return true;\n }\n\n if (!a || !b || typeof a !== \"object\" || typeof b !== \"object\") {\n return false;\n }\n\n if (Array.isArray(a) || Array.isArray(b)) {\n return (\n Array.isArray(a) &&\n Array.isArray(b) &&\n a.length === b.length &&\n a.every((value, index) => valuesEqual(value, b[index]))\n );\n }\n\n const aEntries = Object.entries(a);\n const bObject = b as Record<string, unknown>;\n\n return (\n aEntries.length === Object.keys(bObject).length &&\n aEntries.every(([key, value]) => valuesEqual(value, bObject[key]))\n );\n}\n\nfunction normalizePath(path: string): string {\n return path\n .split(\".\")\n .filter((part) => part !== \"\")\n .join(\".\");\n}\n\nfunction pathsOverlap(left: string, right: string): boolean {\n return (\n left === \"\" ||\n right === \"\" ||\n left === right ||\n left.startsWith(`${right}.`) ||\n right.startsWith(`${left}.`)\n );\n}\n\nfunction createFormValuesStore(initial: Record<string, unknown>): FormValuesStore {\n let initialValues = initial;\n let values = initial;\n const listeners = new Set<() => void>();\n const pathListeners = new Map<string, Set<() => void>>();\n const selectedCache = new Map<string, { snapshot: Record<string, unknown>; values: unknown[] }>();\n\n const notify = (path: string): void => {\n for (const listener of listeners) {\n listener();\n }\n\n const normalizedPath = normalizePath(path);\n\n for (const [subscribedPath, subscribedListeners] of pathListeners) {\n if (!pathsOverlap(subscribedPath, normalizedPath)) {\n continue;\n }\n\n for (const listener of subscribedListeners) {\n listener();\n }\n }\n };\n\n const updateValues = (next: Record<string, unknown>, path: string): void => {\n if (Object.is(values, next)) {\n return;\n }\n\n values = next;\n selectedCache.clear();\n notify(path);\n };\n\n const subscribePath = (path: string, listener: () => void): (() => void) => {\n const normalizedPath = normalizePath(path);\n const listenersForPath = pathListeners.get(normalizedPath) ?? new Set<() => void>();\n\n listenersForPath.add(listener);\n pathListeners.set(normalizedPath, listenersForPath);\n\n return () => {\n listenersForPath.delete(listener);\n\n if (listenersForPath.size === 0) {\n pathListeners.delete(normalizedPath);\n }\n };\n };\n\n return {\n getPathSnapshot: (path: string): unknown => getPath(values, path),\n getPathsSnapshot: (paths: string[]): Record<string, unknown> => {\n if (paths.length === 0) {\n return emptySelectedValues;\n }\n\n const normalizedPaths = paths.map(normalizePath);\n const key = JSON.stringify(paths);\n const selectedValues = normalizedPaths.map((path) => getPath(values, path));\n const cached = selectedCache.get(key);\n\n if (\n cached &&\n cached.values.length === selectedValues.length &&\n selectedValues.every((value, index) => Object.is(value, cached.values[index]))\n ) {\n return cached.snapshot;\n }\n\n const snapshot = Object.fromEntries(\n paths.map((path, index) => [path, selectedValues[index]]),\n );\n\n selectedCache.set(key, { snapshot, values: selectedValues });\n\n return snapshot;\n },\n getSnapshot: () => values,\n replaceInitial: (nextInitial: Record<string, unknown>): void => {\n if (valuesEqual(initialValues, nextInitial)) {\n return;\n }\n\n initialValues = nextInitial;\n updateValues(nextInitial, \"\");\n },\n setValue: (name: string, value: unknown | ((previous: unknown) => unknown)): void => {\n const previous = getPath(values, name);\n const next = typeof value === \"function\" ? value(previous) : value;\n\n if (Object.is(previous, next)) {\n return;\n }\n\n updateValues(setPath(values, name, next), name);\n },\n subscribe: (listener: () => void): (() => void) => {\n listeners.add(listener);\n\n return () => listeners.delete(listener);\n },\n subscribePath,\n subscribePaths: (paths: string[], listener: () => void): (() => void) => {\n const unsubscribers = Array.from(new Set(paths.map(normalizePath))).map((path) =>\n subscribePath(path, listener),\n );\n\n return () => {\n for (const unsubscribe of unsubscribers) {\n unsubscribe();\n }\n };\n },\n };\n}\n\nconst fallbackFormValuesStore = createFormValuesStore(emptyValues);\n\nexport function FormValuesProvider({\n initial,\n children,\n}: {\n initial: Record<string, unknown>;\n children: React.ReactNode;\n}) {\n const storeRef = useRef<FormValuesStore>(null);\n\n if (storeRef.current === null) {\n storeRef.current = createFormValuesStore(initial);\n }\n\n useEffect(() => {\n storeRef.current?.replaceInitial(initial);\n }, [initial]);\n\n return (\n <FormValuesStoreContext.Provider value={storeRef.current}>\n <SetFormValueContext.Provider value={storeRef.current.setValue}>\n {children}\n </SetFormValueContext.Provider>\n </FormValuesStoreContext.Provider>\n );\n}\n\nfunction useFormValuesStore(): FormValuesStore {\n return useContext(FormValuesStoreContext) ?? fallbackFormValuesStore;\n}\n\nexport function useFormValues(): Record<string, unknown> {\n const store = useFormValuesStore();\n\n return useSyncExternalStore(store.subscribe, store.getSnapshot, store.getSnapshot);\n}\n\nexport function useFormValue(name: string): unknown {\n const store = useFormValuesStore();\n const subscribe = useCallback(\n (listener: () => void) => store.subscribePath(name, listener),\n [name, store],\n );\n const getSnapshot = useCallback(() => store.getPathSnapshot(name), [name, store]);\n\n return useSyncExternalStore(subscribe, getSnapshot, getSnapshot);\n}\n\nexport function useFormValuesFor(paths: string[]): Record<string, unknown> {\n const store = useFormValuesStore();\n const pathsKey = JSON.stringify(paths);\n const selectedPaths = useMemo(() => JSON.parse(pathsKey) as string[], [pathsKey]);\n const subscribe = useCallback(\n (listener: () => void) => store.subscribePaths(selectedPaths, listener),\n [selectedPaths, store],\n );\n const getSnapshot = useCallback(\n () => store.getPathsSnapshot(selectedPaths),\n [selectedPaths, store],\n );\n\n return useSyncExternalStore(subscribe, getSnapshot, getSnapshot);\n}\n\nexport function useSetFormValue(): SetFormValue {\n return useContext(SetFormValueContext);\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"values.js","names":[],"sources":["../../../resources/js/form/hooks/values.tsx"],"sourcesContent":["import {\n createContext,\n useCallback,\n useContext,\n useEffect,\n useMemo,\n useRef,\n useSyncExternalStore,\n} from \"react\";\nimport { getPath, setPath } from \"@lattice-php/lattice/form/lib/form-path\";\n\nexport type SetFormValue = (\n name: string,\n value: unknown | ((previous: unknown) => unknown),\n) => void;\n\nexport type ResetFormValues = (fields?: string[]) => void;\n\ntype FormValuesStore = {\n getPathSnapshot: (path: string) => unknown;\n getPathsSnapshot: (paths: string[]) => Record<string, unknown>;\n getSnapshot: () => Record<string, unknown>;\n replaceInitial: (initial: Record<string, unknown>) => void;\n reset: ResetFormValues;\n setValue: SetFormValue;\n subscribe: (listener: () => void) => () => void;\n subscribePath: (path: string, listener: () => void) => () => void;\n subscribePaths: (paths: string[], listener: () => void) => () => void;\n};\n\nconst emptyValues: Record<string, unknown> = {};\nconst emptySelectedValues: Record<string, unknown> = {};\n\nconst FormValuesStoreContext = createContext<FormValuesStore | null>(null);\nconst SetFormValueContext = createContext<SetFormValue>(() => {});\n\nfunction valuesEqual(a: unknown, b: unknown): boolean {\n if (Object.is(a, b)) {\n return true;\n }\n\n if (!a || !b || typeof a !== \"object\" || typeof b !== \"object\") {\n return false;\n }\n\n if (Array.isArray(a) || Array.isArray(b)) {\n return (\n Array.isArray(a) &&\n Array.isArray(b) &&\n a.length === b.length &&\n a.every((value, index) => valuesEqual(value, b[index]))\n );\n }\n\n const aEntries = Object.entries(a);\n const bObject = b as Record<string, unknown>;\n\n return (\n aEntries.length === Object.keys(bObject).length &&\n aEntries.every(([key, value]) => valuesEqual(value, bObject[key]))\n );\n}\n\nfunction normalizePath(path: string): string {\n return path\n .split(\".\")\n .filter((part) => part !== \"\")\n .join(\".\");\n}\n\nfunction pathsOverlap(left: string, right: string): boolean {\n return (\n left === \"\" ||\n right === \"\" ||\n left === right ||\n left.startsWith(`${right}.`) ||\n right.startsWith(`${left}.`)\n );\n}\n\nfunction createFormValuesStore(initial: Record<string, unknown>): FormValuesStore {\n let initialValues = initial;\n let values = initial;\n const listeners = new Set<() => void>();\n const pathListeners = new Map<string, Set<() => void>>();\n const selectedCache = new Map<string, { snapshot: Record<string, unknown>; values: unknown[] }>();\n\n const notify = (path: string): void => {\n for (const listener of listeners) {\n listener();\n }\n\n const normalizedPath = normalizePath(path);\n\n for (const [subscribedPath, subscribedListeners] of pathListeners) {\n if (!pathsOverlap(subscribedPath, normalizedPath)) {\n continue;\n }\n\n for (const listener of subscribedListeners) {\n listener();\n }\n }\n };\n\n const updateValues = (next: Record<string, unknown>, path: string): void => {\n if (Object.is(values, next)) {\n return;\n }\n\n values = next;\n selectedCache.clear();\n notify(path);\n };\n\n const subscribePath = (path: string, listener: () => void): (() => void) => {\n const normalizedPath = normalizePath(path);\n const listenersForPath = pathListeners.get(normalizedPath) ?? new Set<() => void>();\n\n listenersForPath.add(listener);\n pathListeners.set(normalizedPath, listenersForPath);\n\n return () => {\n listenersForPath.delete(listener);\n\n if (listenersForPath.size === 0) {\n pathListeners.delete(normalizedPath);\n }\n };\n };\n\n return {\n getPathSnapshot: (path: string): unknown => getPath(values, path),\n getPathsSnapshot: (paths: string[]): Record<string, unknown> => {\n if (paths.length === 0) {\n return emptySelectedValues;\n }\n\n const normalizedPaths = paths.map(normalizePath);\n const key = JSON.stringify(paths);\n const selectedValues = normalizedPaths.map((path) => getPath(values, path));\n const cached = selectedCache.get(key);\n\n if (\n cached &&\n cached.values.length === selectedValues.length &&\n selectedValues.every((value, index) => Object.is(value, cached.values[index]))\n ) {\n return cached.snapshot;\n }\n\n const snapshot = Object.fromEntries(\n paths.map((path, index) => [path, selectedValues[index]]),\n );\n\n selectedCache.set(key, { snapshot, values: selectedValues });\n\n return snapshot;\n },\n getSnapshot: () => values,\n replaceInitial: (nextInitial: Record<string, unknown>): void => {\n if (valuesEqual(initialValues, nextInitial)) {\n return;\n }\n\n initialValues = nextInitial;\n updateValues(nextInitial, \"\");\n },\n reset: (fields?: string[]): void => {\n if (fields === undefined) {\n updateValues(initialValues, \"\");\n\n return;\n }\n\n const next = fields.reduce(\n (accumulated, field) => setPath(accumulated, field, getPath(initialValues, field)),\n values,\n );\n\n updateValues(next, \"\");\n },\n setValue: (name: string, value: unknown | ((previous: unknown) => unknown)): void => {\n const previous = getPath(values, name);\n const next = typeof value === \"function\" ? value(previous) : value;\n\n if (Object.is(previous, next)) {\n return;\n }\n\n updateValues(setPath(values, name, next), name);\n },\n subscribe: (listener: () => void): (() => void) => {\n listeners.add(listener);\n\n return () => listeners.delete(listener);\n },\n subscribePath,\n subscribePaths: (paths: string[], listener: () => void): (() => void) => {\n const unsubscribers = Array.from(new Set(paths.map(normalizePath))).map((path) =>\n subscribePath(path, listener),\n );\n\n return () => {\n for (const unsubscribe of unsubscribers) {\n unsubscribe();\n }\n };\n },\n };\n}\n\nconst fallbackFormValuesStore = createFormValuesStore(emptyValues);\n\nexport function FormValuesProvider({\n initial,\n children,\n}: {\n initial: Record<string, unknown>;\n children: React.ReactNode;\n}) {\n const storeRef = useRef<FormValuesStore>(null);\n\n if (storeRef.current === null) {\n storeRef.current = createFormValuesStore(initial);\n }\n\n useEffect(() => {\n storeRef.current?.replaceInitial(initial);\n }, [initial]);\n\n return (\n <FormValuesStoreContext.Provider value={storeRef.current}>\n <SetFormValueContext.Provider value={storeRef.current.setValue}>\n {children}\n </SetFormValueContext.Provider>\n </FormValuesStoreContext.Provider>\n );\n}\n\nfunction useFormValuesStore(): FormValuesStore {\n return useContext(FormValuesStoreContext) ?? fallbackFormValuesStore;\n}\n\nexport function useFormValues(): Record<string, unknown> {\n const store = useFormValuesStore();\n\n return useSyncExternalStore(store.subscribe, store.getSnapshot, store.getSnapshot);\n}\n\nexport function useFormValue(name: string): unknown {\n const store = useFormValuesStore();\n const subscribe = useCallback(\n (listener: () => void) => store.subscribePath(name, listener),\n [name, store],\n );\n const getSnapshot = useCallback(() => store.getPathSnapshot(name), [name, store]);\n\n return useSyncExternalStore(subscribe, getSnapshot, getSnapshot);\n}\n\nexport function useFormValuesFor(paths: string[]): Record<string, unknown> {\n const store = useFormValuesStore();\n const pathsKey = JSON.stringify(paths);\n const selectedPaths = useMemo(() => JSON.parse(pathsKey) as string[], [pathsKey]);\n const subscribe = useCallback(\n (listener: () => void) => store.subscribePaths(selectedPaths, listener),\n [selectedPaths, store],\n );\n const getSnapshot = useCallback(\n () => store.getPathsSnapshot(selectedPaths),\n [selectedPaths, store],\n );\n\n return useSyncExternalStore(subscribe, getSnapshot, getSnapshot);\n}\n\nexport function useSetFormValue(): SetFormValue {\n return useContext(SetFormValueContext);\n}\n\n/**\n * Reset values to the store's initial snapshot — all of them, or just the\n * given field paths. This is the reset that actually clears controlled\n * fields; Inertia's own form reset only touches its internal data and the\n * DOM, which store-driven inputs ignore.\n */\nexport function useResetFormValues(): ResetFormValues {\n const store = useFormValuesStore();\n\n return useCallback((fields?: string[]) => store.reset(fields), [store]);\n}\n"],"mappings":"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"}
@@ -1,5 +1,5 @@
1
- import { setConfig } from "./config.js";
2
1
  import { localeHeader } from "./locale.js";
2
+ import { setConfig } from "./config.js";
3
3
  import { ensureI18n, i18n, preloadLanguages } from "./instance.js";
4
4
  import HttpBackend from "i18next-http-backend";
5
5
  //#region resources/js/i18n/backend.ts
@@ -1,5 +1,5 @@
1
- import { useConfig } from "./config.js";
2
1
  import { currentLocale, subscribeLocale, useLocale } from "./locale.js";
2
+ import { useConfig } from "./config.js";
3
3
  import { useCallback, useSyncExternalStore } from "react";
4
4
  import i18next from "i18next";
5
5
  //#region resources/js/i18n/instance.ts
@@ -1,5 +1,5 @@
1
- import { configTimezone, subscribeConfig } from "./config.js";
2
1
  import { LATTICE_EVENT } from "../core/event-names.js";
2
+ import { configTimezone, subscribeConfig } from "./config.js";
3
3
  import { useSyncExternalStore } from "react";
4
4
  //#region resources/js/i18n/timezone.ts
5
5
  var fallback = "UTC";