{"version":3,"file":"form.mjs","sources":["../../../../src/lib/form/form.mts"],"sourcesContent":["import { getFormFields, getGroupFields, type FormElement } from '../shared/fields.mjs';\nimport { createHandler, createSubmitHandler } from './event.mjs';\nimport { createReset } from './init.mjs';\nimport { createTouchHandlers } from './touch.mjs';\nimport { createDirtyHandler } from './dirty.mjs';\n\nimport { createFormStores } from '../shared/stores.mjs';\nimport { setAriaButtons, setAriaContainer, setAriaRole, setAriaStates } from './aria.mjs';\n\nimport type { FormulaStores, FormulaOptions } from '../shared/types.mjs';\n\nexport interface Formula {\n  init: (node: HTMLElement) => FormulaForm;\n  updateForm: (updatedOpts?: FormulaOptions) => void;\n  destroyForm: () => void;\n  resetForm: () => void;\n  stores: FormulaStores;\n}\n\nexport interface FormulaForm {\n  root: HTMLElement;\n  elements: Array<[string, FormElement[]]>;\n  destroy: () => void;\n}\n\nexport function createForm(\n  options: FormulaOptions,\n  globalStore: Map<string, FormulaStores> | undefined,\n  groupName: string | undefined,\n  initialData: Record<string, unknown>,\n): Formula {\n  // WeakMap allows garbage collection of handlers when elements are removed from DOM\n  const eventHandlers = new WeakMap<FormElement, Array<() => void>>();\n  const trackedElements = new Set<FormElement>(); // Track elements for cleanup iteration\n  const hiddenGroups = new Map<string, FormElement[]>();\n  const touchHandlers = new Set<() => void>();\n  const dirtyHandlers = new Set<() => void>();\n\n  const stores = createFormStores(options, initialData);\n  const isGroup = typeof groupName !== 'undefined';\n  const initialOptions = options;\n  let submitHandler: ((e: Event) => void) | undefined = undefined;\n  let unsub = () => { };\n  let innerReset = () => { };\n\n  let groupedMap: Array<[string, FormElement[]]> = [];\n\n  function bindElements(node: HTMLElement, innerOpt: FormulaOptions = {}) {\n    if (!innerOpt?.preChanges) {\n      innerOpt.preChanges = () => {\n        node?.parentElement?.dispatchEvent(new CustomEvent('form:preChanges', { detail: undefined }));\n      };\n    }\n    if (!innerOpt?.postChanges) {\n      innerOpt.postChanges = (values: Record<string, unknown>) => {\n        node?.parentElement?.dispatchEvent(new CustomEvent('form:postChanges', { detail: values }));\n      };\n    }\n\n    const formElements = isGroup ? getGroupFields(node) : getFormFields(node);\n\n    node.setAttribute(`data-formula-${isGroup ? 'row' : 'form'}`, 'true');\n    setAriaContainer(node, isGroup);\n    setAriaButtons(node);\n\n    groupedMap = [\n      ...formElements.reduce((entryMap, e) => {\n        const formulaName = e.dataset.formulaName;\n        const name = formulaName || e.getAttribute('name') || '';\n        return entryMap.set(name, [...(entryMap.get(name) || []), e]);\n      }, new Map<string, FormElement[]>()),\n    ];\n\n    innerReset = createReset(node, groupedMap, stores, innerOpt);\n\n    groupedMap.forEach(([name, elements]) => {\n      const firstEl = elements[0];\n      if (firstEl instanceof HTMLInputElement && firstEl.type === 'hidden') {\n        hiddenGroups.set(name, elements);\n        return;\n      }\n\n      touchHandlers.add(createTouchHandlers(name, elements, stores));\n      dirtyHandlers.add(createDirtyHandler(name, elements, stores));\n\n      elements.forEach((el) => {\n        if (isGroup && groupName) {\n          el.setAttribute('data-in-group', groupName);\n        }\n        setAriaRole(el, elements);\n        setAriaStates(el);\n\n        const customBindings = el.dataset.formulaBind;\n        if (customBindings) {\n          const cleanups: Array<() => void> = [];\n          customBindings.split('|').forEach((event) => {\n            cleanups.push(createHandler(name, event, el, elements, stores, innerOpt, hiddenGroups));\n          });\n          eventHandlers.set(el, cleanups);\n          trackedElements.add(el);\n        } else if (el instanceof HTMLSelectElement) {\n          eventHandlers.set(el, [createHandler(name, 'change', el, elements, stores, innerOpt, hiddenGroups)]);\n          trackedElements.add(el);\n        } else {\n          const changeEventTypes = ['radio', 'checkbox', 'file', 'range', 'color', 'date', 'time', 'week', 'number'];\n          const cleanups: Array<() => void> = [];\n\n          if (changeEventTypes.includes((el as HTMLInputElement).type)) {\n            cleanups.push(createHandler(name, 'change', el, elements, stores, innerOpt, hiddenGroups));\n          }\n\n          if ((el as HTMLInputElement).type !== 'hidden') {\n            cleanups.push(createHandler(name, 'keyup', el, elements, stores, innerOpt, hiddenGroups));\n          }\n\n          if (cleanups.length > 0) {\n            eventHandlers.set(el, cleanups);\n            trackedElements.add(el);\n          }\n        }\n      });\n    });\n\n    if (node.id && globalStore) globalStore.set(node.id, stores);\n\n    if (node instanceof HTMLFormElement) {\n      submitHandler = createSubmitHandler(stores, node);\n      node.addEventListener('submit', submitHandler);\n    }\n    stores.formReady.set(true);\n  }\n\n  let currentNode: HTMLElement;\n\n  function cleanupSubscriptions() {\n    unsub && unsub();\n    trackedElements.forEach((el) => {\n      const fns = eventHandlers.get(el);\n      if (fns) {\n        el.setCustomValidity?.('');\n        fns.forEach((fn) => fn());\n        eventHandlers.delete(el);\n      }\n    });\n    trackedElements.clear();\n    [...touchHandlers, ...dirtyHandlers].forEach((fn) => fn());\n    [touchHandlers, dirtyHandlers].forEach((h) => h.clear());\n    if (submitHandler && currentNode instanceof HTMLFormElement) {\n      currentNode.removeEventListener('submit', submitHandler);\n    }\n  }\n\n  return {\n    init: (node: HTMLElement): FormulaForm => {\n      currentNode = node;\n      bindElements(node, options);\n      return {\n        root: node,\n        elements: groupedMap,\n        destroy: () => {\n          stores.formReady.set(false);\n          cleanupSubscriptions();\n          currentNode.id && globalStore && globalStore.delete(currentNode.id);\n        },\n      };\n    },\n    updateForm: (updatedOpts?: FormulaOptions) => {\n      stores.formReady.set(false);\n      cleanupSubscriptions();\n      bindElements(currentNode, updatedOpts || initialOptions);\n    },\n    destroyForm: () => {\n      stores.formReady.set(false);\n      cleanupSubscriptions();\n      currentNode.id && globalStore && globalStore.delete(currentNode.id);\n    },\n    resetForm: () => {\n      innerReset();\n      [...touchHandlers, ...dirtyHandlers].forEach((fn) => fn());\n      groupedMap.forEach(([name, elements]) => {\n        touchHandlers.add(createTouchHandlers(name, elements, stores));\n        dirtyHandlers.add(createDirtyHandler(name, elements, stores));\n      });\n    },\n    stores,\n    ...stores,\n  };\n}\n"],"names":["createForm","options","globalStore","groupName","initialData","eventHandlers","trackedElements","hiddenGroups","touchHandlers","dirtyHandlers","stores","createFormStores","isGroup","initialOptions","submitHandler","innerReset","groupedMap","bindElements","node","innerOpt","values","formElements","getGroupFields","getFormFields","setAriaContainer","setAriaButtons","entryMap","e","name","createReset","elements","firstEl","createTouchHandlers","createDirtyHandler","el","setAriaRole","setAriaStates","customBindings","cleanups","event","createHandler","changeEventTypes","createSubmitHandler","currentNode","cleanupSubscriptions","fns","fn","h","updatedOpts"],"mappings":"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"}