{"version":3,"file":"aria.mjs","sources":["../../../../src/lib/form/aria.mts"],"sourcesContent":["/**\n * Functions for setting ARIA roles and states on form elements, this provides better accessibility\n * support for screen readers and other assistive technologies within Formula forms.\n *\n * @module formula/lib/form/aria\n * @license MIT\n * @author Tane Piper <me@tane.dev>\n */\n\nimport type { FormElement } from '../shared/fields.mjs';\n\n/**\n * Recursively find the parent element that contains a radio group\n * @param el The starting element to search from\n *\n * @returns The parent element that contains the radio group, or undefined if not found\n */\nfunction getRadioGroupParent(el?: HTMLElement): HTMLElement | undefined {\n  if (!el || !el.parentElement) {\n    return undefined;\n  }\n\n  const parent = el.parentElement;\n  const isGroupContainer = parent.querySelectorAll(':scope input[type=radio]').length > 1;\n  const hasStoppingAttribute = parent.dataset?.beakerGroup || parent.dataset?.formulaForm;\n\n  if (isGroupContainer && !hasStoppingAttribute) {\n    return parent;\n  }\n\n  return getRadioGroupParent(parent);\n}\n\n/**\n * Sets the ARIA role for the given element based on its input type\n * @param el The form element to set the ARIA role for\n * @param elements The group of elements the form element belongs to\n *\n * @returns void\n */\nexport function setAriaRole(el: FormElement, elements: FormElement[]): void {\n  if (el.hasAttribute('aria-role')) {\n    return;\n  }\n\n  const setRole = (role: string) => el.setAttribute('aria-role', role);\n\n  if (el.type === 'radio') {\n    if (elements.length < 2) {\n      el?.parentElement?.setAttribute('aria-role', 'radiogroup');\n    } else {\n      const radioGroup = getRadioGroupParent(el);\n      if (radioGroup) radioGroup.setAttribute('aria-role', 'radiogroup');\n    }\n    setRole('radio');\n  } else {\n    setRole(\n      (function () {\n        switch (el.type) {\n          case 'select-one':\n          case 'select-multiple':\n          case 'checkbox':\n            return el.type;\n          case 'file':\n            return 'file-upload';\n          case 'textarea':\n            return 'textbox';\n          default:\n            return `input-${el.type}`;\n        }\n      })(),\n    );\n  }\n}\n\n/**\n * Sets ARIA states based on the attributes of the form element\n * @param el The form element to set ARIA states for\n *\n * @returns void\n */\nexport function setAriaStates(el: FormElement): void {\n  if (el.hasAttribute('required')) {\n    el.setAttribute('aria-required', 'true');\n  }\n}\n\n/**\n * Updates the ARIA checked state for the given element\n * @param element The form element to update the ARIA checked state for\n * @param elGroup The group of elements the form element belongs to\n *\n * @returns void\n */\nexport function setAriaValue(element: FormElement, elGroup: FormElement[]): void {\n  if (element.type === 'radio') {\n    elGroup.forEach((el) => el.removeAttribute('aria-checked'));\n    element.setAttribute('aria-checked', (element as HTMLInputElement).checked ? 'true' : 'false');\n  } else if (element.type === 'checkbox') {\n    element.setAttribute('aria-checked', (element as HTMLInputElement).checked ? 'true' : 'false');\n  }\n}\n\n/**\n * Sets the ARIA role for the container element\n * @param container The container element to set the ARIA role for\n * @param isGroup Whether the container is a group of elements\n *\n * @returns void\n */\nexport function setAriaContainer(container: HTMLElement, isGroup: boolean): void {\n  if (!container.hasAttribute('aria-role')) {\n    container.setAttribute('aria-role', isGroup ? 'row' : 'form');\n  }\n}\n\n/**\n * Adds the ARIA button role to all buttons in the container\n * @param container The container element containing the buttons\n *\n * @returns void\n */\nexport function setAriaButtons(container: HTMLElement): void {\n  const nonAriaButtons = Array.from(container.querySelectorAll('button:not([aria-role])'));\n  nonAriaButtons.forEach((el) => el.setAttribute('aria-role', 'button'));\n}\n"],"names":["getRadioGroupParent","el","parent","isGroupContainer","hasStoppingAttribute","setAriaRole","elements","setRole","role","radioGroup","setAriaStates","setAriaValue","element","elGroup","setAriaContainer","container","isGroup","setAriaButtons"],"mappings":"AAiBA,SAASA,EAAoBC,GAA2C;AACtE,MAAI,CAACA,KAAM,CAACA,EAAG;AACb;AAGF,QAAMC,IAASD,EAAG,eACZE,IAAmBD,EAAO,iBAAiB,0BAA0B,EAAE,SAAS,GAChFE,IAAuBF,EAAO,SAAS,eAAeA,EAAO,SAAS;AAE5E,SAAIC,KAAoB,CAACC,IAChBF,IAGFF,EAAoBE,CAAM;AACnC;AASO,SAASG,EAAYJ,GAAiBK,GAA+B;AAC1E,MAAIL,EAAG,aAAa,WAAW;AAC7B;AAGF,QAAMM,IAAU,CAACC,MAAiBP,EAAG,aAAa,aAAaO,CAAI;AAEnE,MAAIP,EAAG,SAAS,SAAS;AACvB,QAAIK,EAAS,SAAS;AACpB,MAAAL,GAAI,eAAe,aAAa,aAAa,YAAY;AAAA,SACpD;AACL,YAAMQ,IAAaT,EAAoBC,CAAE;AACzC,MAAIQ,KAAYA,EAAW,aAAa,aAAa,YAAY;AAAA,IACnE;AACA,IAAAF,EAAQ,OAAO;AAAA,EACjB;AACE,IAAAA;AAAA,OACG,WAAY;AACX,gBAAQN,EAAG,MAAA;AAAA,UACT,KAAK;AAAA,UACL,KAAK;AAAA,UACL,KAAK;AACH,mBAAOA,EAAG;AAAA,UACZ,KAAK;AACH,mBAAO;AAAA,UACT,KAAK;AACH,mBAAO;AAAA,UACT;AACE,mBAAO,SAASA,EAAG,IAAI;AAAA,QAAA;AAAA,MAE7B,GAAA;AAAA,IAAG;AAGT;AAQO,SAASS,EAAcT,GAAuB;AACnD,EAAIA,EAAG,aAAa,UAAU,KAC5BA,EAAG,aAAa,iBAAiB,MAAM;AAE3C;AASO,SAASU,EAAaC,GAAsBC,GAA8B;AAC/E,EAAID,EAAQ,SAAS,WACnBC,EAAQ,QAAQ,CAACZ,MAAOA,EAAG,gBAAgB,cAAc,CAAC,GAC1DW,EAAQ,aAAa,gBAAiBA,EAA6B,UAAU,SAAS,OAAO,KACpFA,EAAQ,SAAS,cAC1BA,EAAQ,aAAa,gBAAiBA,EAA6B,UAAU,SAAS,OAAO;AAEjG;AASO,SAASE,EAAiBC,GAAwBC,GAAwB;AAC/E,EAAKD,EAAU,aAAa,WAAW,KACrCA,EAAU,aAAa,aAAaC,IAAU,QAAQ,MAAM;AAEhE;AAQO,SAASC,EAAeF,GAA8B;AAE3D,EADuB,MAAM,KAAKA,EAAU,iBAAiB,yBAAyB,CAAC,EACxE,QAAQ,CAACd,MAAOA,EAAG,aAAa,aAAa,QAAQ,CAAC;AACvE;"}