@vielzeug/refine 1.3.1 → 1.4.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 (134) hide show
  1. package/dist/checkbox-group.cjs +7 -7
  2. package/dist/checkbox-group.cjs.map +1 -1
  3. package/dist/checkbox-group.js +35 -26
  4. package/dist/checkbox-group.js.map +1 -1
  5. package/dist/checkbox.cjs +3 -3
  6. package/dist/checkbox.cjs.map +1 -1
  7. package/dist/checkbox.js +24 -19
  8. package/dist/checkbox.js.map +1 -1
  9. package/dist/combobox.cjs +24 -24
  10. package/dist/combobox.cjs.map +1 -1
  11. package/dist/combobox.js +133 -129
  12. package/dist/combobox.js.map +1 -1
  13. package/dist/custom-elements.json +4227 -3725
  14. package/dist/headless/auto-resize.cjs +2 -0
  15. package/dist/headless/auto-resize.cjs.map +1 -0
  16. package/dist/headless/auto-resize.d.ts +29 -0
  17. package/dist/headless/auto-resize.d.ts.map +1 -0
  18. package/dist/headless/auto-resize.js +16 -0
  19. package/dist/headless/auto-resize.js.map +1 -0
  20. package/dist/headless/checkable.cjs +1 -1
  21. package/dist/headless/checkable.cjs.map +1 -1
  22. package/dist/headless/checkable.d.ts +25 -7
  23. package/dist/headless/checkable.d.ts.map +1 -1
  24. package/dist/headless/checkable.js +19 -14
  25. package/dist/headless/checkable.js.map +1 -1
  26. package/dist/headless/choice-field.cjs +1 -1
  27. package/dist/headless/choice-field.cjs.map +1 -1
  28. package/dist/headless/choice-field.d.ts +21 -0
  29. package/dist/headless/choice-field.d.ts.map +1 -1
  30. package/dist/headless/choice-field.js +27 -19
  31. package/dist/headless/choice-field.js.map +1 -1
  32. package/dist/headless/composer.cjs +2 -0
  33. package/dist/headless/composer.cjs.map +1 -0
  34. package/dist/headless/composer.d.ts +44 -0
  35. package/dist/headless/composer.d.ts.map +1 -0
  36. package/dist/headless/composer.js +21 -0
  37. package/dist/headless/composer.js.map +1 -0
  38. package/dist/headless/field-base.cjs +1 -1
  39. package/dist/headless/field-base.cjs.map +1 -1
  40. package/dist/headless/field-base.d.ts +97 -84
  41. package/dist/headless/field-base.d.ts.map +1 -1
  42. package/dist/headless/field-base.js +43 -32
  43. package/dist/headless/field-base.js.map +1 -1
  44. package/dist/headless/index.d.ts +3 -1
  45. package/dist/headless/index.d.ts.map +1 -1
  46. package/dist/headless/text-field.cjs +1 -1
  47. package/dist/headless/text-field.cjs.map +1 -1
  48. package/dist/headless/text-field.d.ts +40 -0
  49. package/dist/headless/text-field.d.ts.map +1 -1
  50. package/dist/headless/text-field.js +30 -25
  51. package/dist/headless/text-field.js.map +1 -1
  52. package/dist/headless.cjs +1 -1
  53. package/dist/headless.js +27 -25
  54. package/dist/index.cjs +1 -1
  55. package/dist/index.js +61 -60
  56. package/dist/input.cjs +9 -9
  57. package/dist/input.cjs.map +1 -1
  58. package/dist/input.js +49 -44
  59. package/dist/input.js.map +1 -1
  60. package/dist/inputs/checkbox/checkbox.d.ts +3 -0
  61. package/dist/inputs/checkbox/checkbox.d.ts.map +1 -1
  62. package/dist/inputs/combobox/combobox.d.ts +1 -0
  63. package/dist/inputs/combobox/combobox.d.ts.map +1 -1
  64. package/dist/inputs/combobox/combobox.types.d.ts +2 -0
  65. package/dist/inputs/combobox/combobox.types.d.ts.map +1 -1
  66. package/dist/inputs/index.d.ts +2 -0
  67. package/dist/inputs/index.d.ts.map +1 -1
  68. package/dist/inputs/input/input.d.ts.map +1 -1
  69. package/dist/inputs/message-composer/message-composer.css.cjs +2 -0
  70. package/dist/inputs/message-composer/message-composer.css.cjs.map +1 -0
  71. package/dist/inputs/message-composer/message-composer.css.js +6 -0
  72. package/dist/inputs/message-composer/message-composer.css.js.map +1 -0
  73. package/dist/inputs/message-composer/message-composer.d.ts +139 -0
  74. package/dist/inputs/message-composer/message-composer.d.ts.map +1 -0
  75. package/dist/inputs/shared/field-binding.cjs +1 -1
  76. package/dist/inputs/shared/field-binding.cjs.map +1 -1
  77. package/dist/inputs/shared/field-binding.d.ts +15 -0
  78. package/dist/inputs/shared/field-binding.d.ts.map +1 -1
  79. package/dist/inputs/shared/field-binding.js +4 -3
  80. package/dist/inputs/shared/field-binding.js.map +1 -1
  81. package/dist/inputs/shared/form-context.cjs.map +1 -1
  82. package/dist/inputs/shared/form-context.d.ts +6 -0
  83. package/dist/inputs/shared/form-context.d.ts.map +1 -1
  84. package/dist/inputs/shared/form-context.js.map +1 -1
  85. package/dist/inputs/textarea/textarea.d.ts.map +1 -1
  86. package/dist/message-composer.cjs +52 -0
  87. package/dist/message-composer.cjs.map +1 -0
  88. package/dist/message-composer.js +168 -0
  89. package/dist/message-composer.js.map +1 -0
  90. package/dist/ore/dist/base-element.cjs +1 -1
  91. package/dist/ore/dist/base-element.cjs.map +1 -1
  92. package/dist/ore/dist/base-element.js +13 -3
  93. package/dist/ore/dist/base-element.js.map +1 -1
  94. package/dist/ore/dist/forms/field.cjs +1 -1
  95. package/dist/ore/dist/forms/field.cjs.map +1 -1
  96. package/dist/ore/dist/forms/field.js +29 -22
  97. package/dist/ore/dist/forms/field.js.map +1 -1
  98. package/dist/ore/dist/runtime.cjs +1 -1
  99. package/dist/ore/dist/runtime.cjs.map +1 -1
  100. package/dist/ore/dist/runtime.js +3 -1
  101. package/dist/ore/dist/runtime.js.map +1 -1
  102. package/dist/radio-group.cjs +9 -9
  103. package/dist/radio-group.cjs.map +1 -1
  104. package/dist/radio-group.js +44 -38
  105. package/dist/radio-group.js.map +1 -1
  106. package/dist/radio.cjs +3 -3
  107. package/dist/radio.cjs.map +1 -1
  108. package/dist/radio.js +23 -24
  109. package/dist/radio.js.map +1 -1
  110. package/dist/refine.cjs +228 -178
  111. package/dist/refine.cjs.map +1 -1
  112. package/dist/refine.iife.js +228 -178
  113. package/dist/refine.iife.js.map +1 -1
  114. package/dist/refine.js +251 -201
  115. package/dist/refine.js.map +1 -1
  116. package/dist/select.cjs +31 -31
  117. package/dist/select.cjs.map +1 -1
  118. package/dist/select.js +125 -122
  119. package/dist/select.js.map +1 -1
  120. package/dist/shared/size-presets.cjs +1 -1
  121. package/dist/shared/size-presets.cjs.map +1 -1
  122. package/dist/shared/size-presets.d.ts +23 -0
  123. package/dist/shared/size-presets.d.ts.map +1 -1
  124. package/dist/shared/size-presets.js +17 -1
  125. package/dist/shared/size-presets.js.map +1 -1
  126. package/dist/switch.cjs +3 -3
  127. package/dist/switch.cjs.map +1 -1
  128. package/dist/switch.js +17 -18
  129. package/dist/switch.js.map +1 -1
  130. package/dist/textarea.cjs +15 -15
  131. package/dist/textarea.cjs.map +1 -1
  132. package/dist/textarea.js +64 -60
  133. package/dist/textarea.js.map +1 -1
  134. package/package.json +11 -3
@@ -1 +1 @@
1
- {"version":3,"file":"radio.cjs","names":[],"sources":["../src/inputs/radio/radio.ts"],"sourcesContent":["import { define, html, inject, prop, bind, getHost, onCleanup, useEmit } from '@vielzeug/ore';\nimport { useField } from '@vielzeug/ore/forms';\nimport { computed } from '@vielzeug/ripple';\n\nimport type { CheckableProps, ComponentSize, ThemeColor } from '../../types';\n\nimport { type CheckableChangePayload, lifecycleSignal, createCheckable, createListControl } from '../../headless';\nimport { CONTROL_SIZE_PRESET, disablableBundle, sizableBundle, themableBundle } from '../../shared';\nimport {\n coarsePointerMixin,\n colorThemeMixin,\n disabledStateMixin,\n forcedColorsFormControlMixin,\n sizeVariantMixin,\n} from '../../styles';\nimport { RADIO_GROUP_CTX } from '../radio-group/radio-group';\nimport { FORM_CTX, useFormContext } from '../shared/form-context';\nimport { renderHelperRegion } from '../shared/templates';\nimport componentStyles from './radio.css?inline';\n\n/** Radio component properties */\n\nexport type OreRadioEvents = {\n change: CheckableChangePayload;\n};\n\nexport type OreRadioProps = CheckableProps & {\n /** Theme color */\n color?: ThemeColor;\n /** Disable interaction */\n disabled?: boolean;\n /** Error message (marks field as invalid) */\n error?: string;\n /** Helper text displayed below the radio */\n helper?: string;\n /** Component size */\n size?: ComponentSize;\n};\n\n/**\n * A customizable radio button component for mutually exclusive selections.\n *\n * @element ore-radio\n *\n * @attr {boolean} checked - Checked state\n * @attr {boolean} disabled - Disable radio interaction\n * @attr {string} value - Field value (required for radio groups)\n * @attr {string} name - Form field name (required for radio groups)\n * @attr {string} color - Theme color: 'primary' | 'secondary' | 'info' | 'success' | 'warning' | 'error'\n * @attr {string} size - Radio size: 'sm' | 'md' | 'lg'\n * @attr {string} error - Error message (marks field as invalid)\n * @attr {string} helper - Helper text displayed below the radio\n *\n * @fires change - Emitted when radio is selected. detail: { checked: boolean, value: string, originalEvent?: Event }\n *\n * @slot - Radio button label text\n *\n * @cssprop --radio-size - Control size (width and height)\n * @cssprop --radio-bg - Unchecked background color\n * @cssprop --radio-border-color - Unchecked border color\n * @cssprop --radio-checked-bg - Selected indicator background color\n * @cssprop --radio-color - Selected indicator dot color\n * @cssprop --radio-font-size - Label font size\n * @part radio - The radio wrapper element\n * @part circle - The visual radio circle\n * @part label - The label element\n * @part helper-text - The helper/error text element\n *\n * @example\n * ```html\n * <ore-radio name=\"plan\" value=\"free\">Free</ore-radio>\n * <ore-radio name=\"plan\" value=\"pro\" checked color=\"primary\">Pro</ore-radio>\n * <ore-radio name=\"plan\" value=\"enterprise\" disabled>Enterprise</ore-radio>\n * ```\n */\nexport const RADIO_TAG = 'ore-radio' as const;\ndefine<OreRadioProps>(RADIO_TAG, {\n formAssociated: true,\n props: {\n ...themableBundle,\n ...sizableBundle,\n ...disablableBundle,\n checked: prop.bool(false),\n error: prop.string(),\n helper: prop.string(),\n name: prop.string(),\n value: prop.string(),\n },\n setup(props) {\n const el = getHost();\n const emit = useEmit<OreRadioEvents>();\n\n const groupCtx = inject(RADIO_GROUP_CTX);\n const formCtx = inject(FORM_CTX);\n const fCtxProps = useFormContext(props, formCtx);\n\n const effectiveName = computed(() => groupCtx?.name.value || props.name.value || '');\n const effectiveSize = computed(() => groupCtx?.size.value ?? fCtxProps.size.value);\n const effectiveColor = computed(() => groupCtx?.color.value ?? props.color.value);\n const checkedFromState = computed(() => {\n if (groupCtx) return groupCtx.value.value === props.value.value;\n\n return Boolean(props.checked.value);\n });\n\n const getRadioGroup = (): HTMLElement[] => {\n const radioName = effectiveName.value;\n\n if (!radioName) return [];\n\n return Array.from(document.querySelectorAll<HTMLElement>(`ore-radio[name=\"${radioName}\"]`)).filter(\n (r) => !r.hasAttribute('disabled'),\n );\n };\n\n const selectRadio = (radio: HTMLElement, originalEvent?: Event): void => {\n if (groupCtx) {\n groupCtx.select(radio.getAttribute('value') ?? '', originalEvent);\n\n return;\n }\n\n radio.click();\n };\n\n const listControl = createListControl({\n getItems: () => getRadioGroup(),\n keys: { next: ['ArrowDown', 'ArrowRight'], prev: ['ArrowUp', 'ArrowLeft'] },\n loop: true,\n onNavigate: (_action, index, event) => {\n const nextRadio = getRadioGroup()[index];\n\n if (!nextRadio) return;\n\n nextRadio.focus();\n selectRadio(nextRadio, event);\n },\n });\n\n const activateSelf = (originalEvent?: Event): void => {\n if (checkable.checked.value) return;\n\n if (groupCtx) {\n groupCtx.select(props.value.value ?? '', originalEvent);\n\n return;\n }\n\n checkable.toggle(originalEvent ?? new Event('change'));\n };\n\n let _formField: { reportValidity(): void } | null = null;\n const checkable = createCheckable({\n checked: checkedFromState,\n disabled: computed(() => fCtxProps.disabled.value || Boolean(groupCtx?.disabled.value)),\n error: props.error,\n getFormField: () => _formField,\n helper: props.helper,\n onToggle: (payload) => {\n emit('change', payload);\n },\n prefix: 'radio',\n signal: lifecycleSignal(onCleanup),\n validateOn: formCtx?.validateOn,\n value: props.value,\n });\n\n _formField = useField<string | null>({\n disabled: checkable.disabled,\n toFormValue: (v) => v,\n value: checkable.checkableFormValue,\n });\n\n const { assistiveId, checked, disabled, errorText, helperText, labelId, toggle } = checkable;\n\n bind({\n attr: {\n ariaChecked: () => (checked.value ? 'true' : 'false'),\n ariaDescribedby: () => (errorText.value || helperText.value ? assistiveId : null),\n ariaDisabled: () => (disabled.value ? 'true' : null),\n ariaInvalid: () => (errorText.value ? 'true' : null),\n ariaLabelledby: labelId,\n checked,\n color: effectiveColor,\n disabled: () => (disabled.value ? true : undefined),\n name: () => effectiveName.value || undefined,\n role: 'radio',\n size: effectiveSize,\n tabindex: () => {\n if (disabled.value) return undefined;\n\n return checked.value ? 0 : -1;\n },\n },\n class: () => ({\n 'is-checked': checked.value,\n 'is-disabled': disabled.value,\n }),\n on: {\n click: (e: MouseEvent) => {\n if (disabled.value) return;\n\n if (groupCtx) {\n groupCtx.select(props.value.value ?? '', e);\n } else {\n if (!effectiveName.value) return;\n\n if (!checked.value) {\n const radioName = props.name.value;\n const allRadios = document.querySelectorAll<HTMLElement>(`ore-radio[name=\"${radioName}\"]`);\n\n allRadios.forEach((radio) => {\n if (radio !== el) radio.removeAttribute('checked');\n });\n\n toggle(e);\n }\n }\n },\n keydown: (e: KeyboardEvent) => {\n if (e.key === ' ' || e.key === 'Enter') {\n e.preventDefault();\n activateSelf(e);\n\n return;\n }\n\n const radios = getRadioGroup();\n\n if (radios.length === 0) return;\n\n const selfIndex = radios.indexOf(el);\n\n if (selfIndex === -1) return;\n\n listControl.set(selfIndex);\n listControl.handleKeydown(e);\n },\n },\n });\n\n return html`\n <div class=\"radio-wrapper\" part=\"radio\">\n <div class=\"circle\" part=\"circle\">\n <div class=\"dot\" part=\"dot\"></div>\n </div>\n </div>\n <span class=\"label\" part=\"label\" id=\"${labelId}\"><slot></slot></span>\n ${renderHelperRegion(assistiveId, errorText, helperText)}\n `;\n },\n styles: [\n colorThemeMixin,\n forcedColorsFormControlMixin,\n disabledStateMixin,\n coarsePointerMixin,\n sizeVariantMixin(CONTROL_SIZE_PRESET),\n componentStyles,\n ],\n});\n"],"mappings":"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"}
1
+ {"version":3,"file":"radio.cjs","names":[],"sources":["../src/inputs/radio/radio.ts"],"sourcesContent":["import { define, html, inject, prop, bind, getHost, onCleanup, useEmit } from '@vielzeug/ore';\nimport { useField } from '@vielzeug/ore/forms';\nimport { computed } from '@vielzeug/ripple';\n\nimport type { CheckableProps, ComponentSize, ThemeColor } from '../../types';\n\nimport { type CheckableChangePayload, lifecycleSignal, createCheckable, createListControl } from '../../headless';\nimport { CONTROL_SIZE_PRESET, disablableBundle, sizableBundle, themableBundle } from '../../shared';\nimport {\n coarsePointerMixin,\n colorThemeMixin,\n disabledStateMixin,\n forcedColorsFormControlMixin,\n sizeVariantMixin,\n} from '../../styles';\nimport { RADIO_GROUP_CTX } from '../radio-group/radio-group';\nimport { FORM_CTX, useFormContext } from '../shared/form-context';\nimport { renderHelperRegion } from '../shared/templates';\nimport componentStyles from './radio.css?inline';\n\n/** Radio component properties */\n\nexport type OreRadioEvents = {\n change: CheckableChangePayload;\n};\n\nexport type OreRadioProps = CheckableProps & {\n /** Theme color */\n color?: ThemeColor;\n /** Disable interaction */\n disabled?: boolean;\n /** Error message (marks field as invalid) */\n error?: string;\n /** Helper text displayed below the radio */\n helper?: string;\n /** Component size */\n size?: ComponentSize;\n};\n\n/**\n * A customizable radio button component for mutually exclusive selections.\n *\n * @element ore-radio\n *\n * @attr {boolean} checked - Checked state\n * @attr {boolean} disabled - Disable radio interaction\n * @attr {string} value - Field value (required for radio groups)\n * @attr {string} name - Form field name (required for radio groups)\n * @attr {string} color - Theme color: 'primary' | 'secondary' | 'info' | 'success' | 'warning' | 'error'\n * @attr {string} size - Radio size: 'sm' | 'md' | 'lg'\n * @attr {string} error - Error message (marks field as invalid)\n * @attr {string} helper - Helper text displayed below the radio\n *\n * @fires change - Emitted when radio is selected. detail: { checked: boolean, value: string, originalEvent?: Event }\n *\n * @slot - Radio button label text\n *\n * @cssprop --radio-size - Control size (width and height)\n * @cssprop --radio-bg - Unchecked background color\n * @cssprop --radio-border-color - Unchecked border color\n * @cssprop --radio-checked-bg - Selected indicator background color\n * @cssprop --radio-color - Selected indicator dot color\n * @cssprop --radio-font-size - Label font size\n * @part radio - The radio wrapper element\n * @part circle - The visual radio circle\n * @part label - The label element\n * @part helper-text - The helper/error text element\n *\n * @example\n * ```html\n * <ore-radio name=\"plan\" value=\"free\">Free</ore-radio>\n * <ore-radio name=\"plan\" value=\"pro\" checked color=\"primary\">Pro</ore-radio>\n * <ore-radio name=\"plan\" value=\"enterprise\" disabled>Enterprise</ore-radio>\n * ```\n */\nexport const RADIO_TAG = 'ore-radio' as const;\ndefine<OreRadioProps>(RADIO_TAG, {\n formAssociated: true,\n props: {\n ...themableBundle,\n ...sizableBundle,\n ...disablableBundle,\n checked: prop.bool(false),\n error: prop.string(),\n helper: prop.string(),\n name: prop.string(),\n value: prop.string(),\n },\n setup(props) {\n const el = getHost();\n const emit = useEmit<OreRadioEvents>();\n\n const groupCtx = inject(RADIO_GROUP_CTX);\n const formCtx = inject(FORM_CTX);\n const fCtxProps = useFormContext(props, formCtx);\n\n const effectiveName = computed(() => groupCtx?.name.value || props.name.value || '');\n const effectiveSize = computed(() => groupCtx?.size.value ?? fCtxProps.size.value);\n const effectiveColor = computed(() => groupCtx?.color.value ?? props.color.value);\n const checkedFromState = computed(() => {\n if (groupCtx) return groupCtx.value.value === props.value.value;\n\n return Boolean(props.checked.value);\n });\n\n const getRadioGroup = (): HTMLElement[] => {\n const radioName = effectiveName.value;\n\n if (!radioName) return [];\n\n return Array.from(document.querySelectorAll<HTMLElement>(`ore-radio[name=\"${radioName}\"]`)).filter(\n (r) => !r.hasAttribute('disabled'),\n );\n };\n\n const selectRadio = (radio: HTMLElement, originalEvent?: Event): void => {\n if (groupCtx) {\n groupCtx.select(radio.getAttribute('value') ?? '', originalEvent);\n\n return;\n }\n\n radio.click();\n };\n\n const listControl = createListControl({\n getItems: () => getRadioGroup(),\n keys: { next: ['ArrowDown', 'ArrowRight'], prev: ['ArrowUp', 'ArrowLeft'] },\n loop: true,\n onNavigate: (_action, index, event) => {\n const nextRadio = getRadioGroup()[index];\n\n if (!nextRadio) return;\n\n nextRadio.focus();\n selectRadio(nextRadio, event);\n },\n });\n\n const activateSelf = (originalEvent?: Event): void => {\n if (checkable.checked.value) return;\n\n if (groupCtx) {\n groupCtx.select(props.value.value ?? '', originalEvent);\n\n return;\n }\n\n checkable.toggle(originalEvent ?? new Event('change'));\n };\n\n const checkable = createCheckable({\n checked: checkedFromState,\n disabled: computed(() => fCtxProps.disabled.value || Boolean(groupCtx?.disabled.value)),\n error: props.error,\n helper: props.helper,\n onToggle: (payload) => {\n emit('change', payload);\n },\n prefix: 'radio',\n signal: lifecycleSignal(onCleanup),\n validateOn: formCtx?.validateOn,\n value: props.value,\n });\n\n checkable.attachFormField(\n useField<string | null>({\n disabled: checkable.disabled,\n toFormValue: (v) => v,\n value: checkable.checkableFormValue,\n }),\n );\n\n const { assistiveId, checked, disabled, errorText, helperText, labelId, toggle } = checkable;\n\n bind({\n attr: {\n ariaChecked: () => (checked.value ? 'true' : 'false'),\n ariaDescribedby: () => (errorText.value || helperText.value ? assistiveId : null),\n ariaDisabled: () => (disabled.value ? 'true' : null),\n ariaInvalid: () => (errorText.value ? 'true' : null),\n ariaLabelledby: labelId,\n checked,\n color: effectiveColor,\n disabled: () => (disabled.value ? true : undefined),\n name: () => effectiveName.value || undefined,\n role: 'radio',\n size: effectiveSize,\n tabindex: () => {\n if (disabled.value) return undefined;\n\n return checked.value ? 0 : -1;\n },\n },\n class: () => ({\n 'is-checked': checked.value,\n 'is-disabled': disabled.value,\n }),\n on: {\n click: (e: MouseEvent) => {\n if (disabled.value) return;\n\n if (groupCtx) {\n groupCtx.select(props.value.value ?? '', e);\n } else {\n if (!effectiveName.value) return;\n\n if (!checked.value) {\n const radioName = props.name.value;\n const allRadios = document.querySelectorAll<HTMLElement>(`ore-radio[name=\"${radioName}\"]`);\n\n allRadios.forEach((radio) => {\n if (radio !== el) radio.removeAttribute('checked');\n });\n\n toggle(e);\n }\n }\n },\n keydown: (e: KeyboardEvent) => {\n if (e.key === ' ' || e.key === 'Enter') {\n e.preventDefault();\n activateSelf(e);\n\n return;\n }\n\n const radios = getRadioGroup();\n\n if (radios.length === 0) return;\n\n const selfIndex = radios.indexOf(el);\n\n if (selfIndex === -1) return;\n\n listControl.set(selfIndex);\n listControl.handleKeydown(e);\n },\n },\n });\n\n return html`\n <div class=\"radio-wrapper\" part=\"radio\">\n <div class=\"circle\" part=\"circle\">\n <div class=\"dot\" part=\"dot\"></div>\n </div>\n </div>\n <span class=\"label\" part=\"label\" id=\"${labelId}\"><slot></slot></span>\n ${renderHelperRegion(assistiveId, errorText, helperText)}\n `;\n },\n styles: [\n colorThemeMixin,\n forcedColorsFormControlMixin,\n disabledStateMixin,\n coarsePointerMixin,\n sizeVariantMixin(CONTROL_SIZE_PRESET),\n componentStyles,\n ],\n});\n"],"mappings":"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"}
package/dist/radio.js CHANGED
@@ -51,18 +51,17 @@ y(D, {
51
51
  r && (r.focus(), w(r, n));
52
52
  }
53
53
  }), O = (t) => {
54
- if (!A.checked.value) {
54
+ if (!k.checked.value) {
55
55
  if (r) {
56
56
  r.select(e.value.value ?? "", t);
57
57
  return;
58
58
  }
59
- A.toggle(t ?? new Event("change"));
59
+ k.toggle(t ?? new Event("change"));
60
60
  }
61
- }, k = null, A = u({
61
+ }, k = u({
62
62
  checked: _,
63
63
  disabled: E(() => a.disabled.value || !!r?.disabled.value),
64
64
  error: e.error,
65
- getFormField: () => k,
66
65
  helper: e.helper,
67
66
  onToggle: (e) => {
68
67
  n("change", e);
@@ -72,43 +71,43 @@ y(D, {
72
71
  validateOn: i?.validateOn,
73
72
  value: e.value
74
73
  });
75
- k = f({
76
- disabled: A.disabled,
74
+ k.attachFormField(f({
75
+ disabled: k.disabled,
77
76
  toFormValue: (e) => e,
78
- value: A.checkableFormValue
79
- });
80
- let { assistiveId: j, checked: M, disabled: N, errorText: P, helperText: F, labelId: I, toggle: L } = A;
77
+ value: k.checkableFormValue
78
+ }));
79
+ let { assistiveId: A, checked: j, disabled: M, errorText: N, helperText: P, labelId: F, toggle: I } = k;
81
80
  return v({
82
81
  attr: {
83
- ariaChecked: () => M.value ? "true" : "false",
84
- ariaDescribedby: () => P.value || F.value ? j : null,
85
- ariaDisabled: () => N.value ? "true" : null,
86
- ariaInvalid: () => P.value ? "true" : null,
87
- ariaLabelledby: I,
88
- checked: M,
82
+ ariaChecked: () => j.value ? "true" : "false",
83
+ ariaDescribedby: () => N.value || P.value ? A : null,
84
+ ariaDisabled: () => M.value ? "true" : null,
85
+ ariaInvalid: () => N.value ? "true" : null,
86
+ ariaLabelledby: F,
87
+ checked: j,
89
88
  color: c,
90
- disabled: () => N.value ? !0 : void 0,
89
+ disabled: () => M.value ? !0 : void 0,
91
90
  name: () => o.value || void 0,
92
91
  role: "radio",
93
92
  size: s,
94
93
  tabindex: () => {
95
- if (!N.value) return M.value ? 0 : -1;
94
+ if (!M.value) return j.value ? 0 : -1;
96
95
  }
97
96
  },
98
97
  class: () => ({
99
- "is-checked": M.value,
100
- "is-disabled": N.value
98
+ "is-checked": j.value,
99
+ "is-disabled": M.value
101
100
  }),
102
101
  on: {
103
102
  click: (n) => {
104
- if (!N.value) if (r) r.select(e.value.value ?? "", n);
103
+ if (!M.value) if (r) r.select(e.value.value ?? "", n);
105
104
  else {
106
105
  if (!o.value) return;
107
- if (!M.value) {
106
+ if (!j.value) {
108
107
  let r = e.name.value;
109
108
  document.querySelectorAll(`ore-radio[name="${r}"]`).forEach((e) => {
110
109
  e !== t && e.removeAttribute("checked");
111
- }), L(n);
110
+ }), I(n);
112
111
  }
113
112
  }
114
113
  },
@@ -129,8 +128,8 @@ y(D, {
129
128
  <div class="dot" part="dot"></div>
130
129
  </div>
131
130
  </div>
132
- <span class="label" part="label" id="${I}"><slot></slot></span>
133
- ${h(j, P, F)}
131
+ <span class="label" part="label" id="${F}"><slot></slot></span>
132
+ ${h(A, N, P)}
134
133
  `;
135
134
  },
136
135
  styles: [
package/dist/radio.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"radio.js","names":[],"sources":["../src/inputs/radio/radio.ts"],"sourcesContent":["import { define, html, inject, prop, bind, getHost, onCleanup, useEmit } from '@vielzeug/ore';\nimport { useField } from '@vielzeug/ore/forms';\nimport { computed } from '@vielzeug/ripple';\n\nimport type { CheckableProps, ComponentSize, ThemeColor } from '../../types';\n\nimport { type CheckableChangePayload, lifecycleSignal, createCheckable, createListControl } from '../../headless';\nimport { CONTROL_SIZE_PRESET, disablableBundle, sizableBundle, themableBundle } from '../../shared';\nimport {\n coarsePointerMixin,\n colorThemeMixin,\n disabledStateMixin,\n forcedColorsFormControlMixin,\n sizeVariantMixin,\n} from '../../styles';\nimport { RADIO_GROUP_CTX } from '../radio-group/radio-group';\nimport { FORM_CTX, useFormContext } from '../shared/form-context';\nimport { renderHelperRegion } from '../shared/templates';\nimport componentStyles from './radio.css?inline';\n\n/** Radio component properties */\n\nexport type OreRadioEvents = {\n change: CheckableChangePayload;\n};\n\nexport type OreRadioProps = CheckableProps & {\n /** Theme color */\n color?: ThemeColor;\n /** Disable interaction */\n disabled?: boolean;\n /** Error message (marks field as invalid) */\n error?: string;\n /** Helper text displayed below the radio */\n helper?: string;\n /** Component size */\n size?: ComponentSize;\n};\n\n/**\n * A customizable radio button component for mutually exclusive selections.\n *\n * @element ore-radio\n *\n * @attr {boolean} checked - Checked state\n * @attr {boolean} disabled - Disable radio interaction\n * @attr {string} value - Field value (required for radio groups)\n * @attr {string} name - Form field name (required for radio groups)\n * @attr {string} color - Theme color: 'primary' | 'secondary' | 'info' | 'success' | 'warning' | 'error'\n * @attr {string} size - Radio size: 'sm' | 'md' | 'lg'\n * @attr {string} error - Error message (marks field as invalid)\n * @attr {string} helper - Helper text displayed below the radio\n *\n * @fires change - Emitted when radio is selected. detail: { checked: boolean, value: string, originalEvent?: Event }\n *\n * @slot - Radio button label text\n *\n * @cssprop --radio-size - Control size (width and height)\n * @cssprop --radio-bg - Unchecked background color\n * @cssprop --radio-border-color - Unchecked border color\n * @cssprop --radio-checked-bg - Selected indicator background color\n * @cssprop --radio-color - Selected indicator dot color\n * @cssprop --radio-font-size - Label font size\n * @part radio - The radio wrapper element\n * @part circle - The visual radio circle\n * @part label - The label element\n * @part helper-text - The helper/error text element\n *\n * @example\n * ```html\n * <ore-radio name=\"plan\" value=\"free\">Free</ore-radio>\n * <ore-radio name=\"plan\" value=\"pro\" checked color=\"primary\">Pro</ore-radio>\n * <ore-radio name=\"plan\" value=\"enterprise\" disabled>Enterprise</ore-radio>\n * ```\n */\nexport const RADIO_TAG = 'ore-radio' as const;\ndefine<OreRadioProps>(RADIO_TAG, {\n formAssociated: true,\n props: {\n ...themableBundle,\n ...sizableBundle,\n ...disablableBundle,\n checked: prop.bool(false),\n error: prop.string(),\n helper: prop.string(),\n name: prop.string(),\n value: prop.string(),\n },\n setup(props) {\n const el = getHost();\n const emit = useEmit<OreRadioEvents>();\n\n const groupCtx = inject(RADIO_GROUP_CTX);\n const formCtx = inject(FORM_CTX);\n const fCtxProps = useFormContext(props, formCtx);\n\n const effectiveName = computed(() => groupCtx?.name.value || props.name.value || '');\n const effectiveSize = computed(() => groupCtx?.size.value ?? fCtxProps.size.value);\n const effectiveColor = computed(() => groupCtx?.color.value ?? props.color.value);\n const checkedFromState = computed(() => {\n if (groupCtx) return groupCtx.value.value === props.value.value;\n\n return Boolean(props.checked.value);\n });\n\n const getRadioGroup = (): HTMLElement[] => {\n const radioName = effectiveName.value;\n\n if (!radioName) return [];\n\n return Array.from(document.querySelectorAll<HTMLElement>(`ore-radio[name=\"${radioName}\"]`)).filter(\n (r) => !r.hasAttribute('disabled'),\n );\n };\n\n const selectRadio = (radio: HTMLElement, originalEvent?: Event): void => {\n if (groupCtx) {\n groupCtx.select(radio.getAttribute('value') ?? '', originalEvent);\n\n return;\n }\n\n radio.click();\n };\n\n const listControl = createListControl({\n getItems: () => getRadioGroup(),\n keys: { next: ['ArrowDown', 'ArrowRight'], prev: ['ArrowUp', 'ArrowLeft'] },\n loop: true,\n onNavigate: (_action, index, event) => {\n const nextRadio = getRadioGroup()[index];\n\n if (!nextRadio) return;\n\n nextRadio.focus();\n selectRadio(nextRadio, event);\n },\n });\n\n const activateSelf = (originalEvent?: Event): void => {\n if (checkable.checked.value) return;\n\n if (groupCtx) {\n groupCtx.select(props.value.value ?? '', originalEvent);\n\n return;\n }\n\n checkable.toggle(originalEvent ?? new Event('change'));\n };\n\n let _formField: { reportValidity(): void } | null = null;\n const checkable = createCheckable({\n checked: checkedFromState,\n disabled: computed(() => fCtxProps.disabled.value || Boolean(groupCtx?.disabled.value)),\n error: props.error,\n getFormField: () => _formField,\n helper: props.helper,\n onToggle: (payload) => {\n emit('change', payload);\n },\n prefix: 'radio',\n signal: lifecycleSignal(onCleanup),\n validateOn: formCtx?.validateOn,\n value: props.value,\n });\n\n _formField = useField<string | null>({\n disabled: checkable.disabled,\n toFormValue: (v) => v,\n value: checkable.checkableFormValue,\n });\n\n const { assistiveId, checked, disabled, errorText, helperText, labelId, toggle } = checkable;\n\n bind({\n attr: {\n ariaChecked: () => (checked.value ? 'true' : 'false'),\n ariaDescribedby: () => (errorText.value || helperText.value ? assistiveId : null),\n ariaDisabled: () => (disabled.value ? 'true' : null),\n ariaInvalid: () => (errorText.value ? 'true' : null),\n ariaLabelledby: labelId,\n checked,\n color: effectiveColor,\n disabled: () => (disabled.value ? true : undefined),\n name: () => effectiveName.value || undefined,\n role: 'radio',\n size: effectiveSize,\n tabindex: () => {\n if (disabled.value) return undefined;\n\n return checked.value ? 0 : -1;\n },\n },\n class: () => ({\n 'is-checked': checked.value,\n 'is-disabled': disabled.value,\n }),\n on: {\n click: (e: MouseEvent) => {\n if (disabled.value) return;\n\n if (groupCtx) {\n groupCtx.select(props.value.value ?? '', e);\n } else {\n if (!effectiveName.value) return;\n\n if (!checked.value) {\n const radioName = props.name.value;\n const allRadios = document.querySelectorAll<HTMLElement>(`ore-radio[name=\"${radioName}\"]`);\n\n allRadios.forEach((radio) => {\n if (radio !== el) radio.removeAttribute('checked');\n });\n\n toggle(e);\n }\n }\n },\n keydown: (e: KeyboardEvent) => {\n if (e.key === ' ' || e.key === 'Enter') {\n e.preventDefault();\n activateSelf(e);\n\n return;\n }\n\n const radios = getRadioGroup();\n\n if (radios.length === 0) return;\n\n const selfIndex = radios.indexOf(el);\n\n if (selfIndex === -1) return;\n\n listControl.set(selfIndex);\n listControl.handleKeydown(e);\n },\n },\n });\n\n return html`\n <div class=\"radio-wrapper\" part=\"radio\">\n <div class=\"circle\" part=\"circle\">\n <div class=\"dot\" part=\"dot\"></div>\n </div>\n </div>\n <span class=\"label\" part=\"label\" id=\"${labelId}\"><slot></slot></span>\n ${renderHelperRegion(assistiveId, errorText, helperText)}\n `;\n },\n styles: [\n colorThemeMixin,\n forcedColorsFormControlMixin,\n disabledStateMixin,\n coarsePointerMixin,\n sizeVariantMixin(CONTROL_SIZE_PRESET),\n componentStyles,\n ],\n});\n"],"mappings":"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"}
1
+ {"version":3,"file":"radio.js","names":[],"sources":["../src/inputs/radio/radio.ts"],"sourcesContent":["import { define, html, inject, prop, bind, getHost, onCleanup, useEmit } from '@vielzeug/ore';\nimport { useField } from '@vielzeug/ore/forms';\nimport { computed } from '@vielzeug/ripple';\n\nimport type { CheckableProps, ComponentSize, ThemeColor } from '../../types';\n\nimport { type CheckableChangePayload, lifecycleSignal, createCheckable, createListControl } from '../../headless';\nimport { CONTROL_SIZE_PRESET, disablableBundle, sizableBundle, themableBundle } from '../../shared';\nimport {\n coarsePointerMixin,\n colorThemeMixin,\n disabledStateMixin,\n forcedColorsFormControlMixin,\n sizeVariantMixin,\n} from '../../styles';\nimport { RADIO_GROUP_CTX } from '../radio-group/radio-group';\nimport { FORM_CTX, useFormContext } from '../shared/form-context';\nimport { renderHelperRegion } from '../shared/templates';\nimport componentStyles from './radio.css?inline';\n\n/** Radio component properties */\n\nexport type OreRadioEvents = {\n change: CheckableChangePayload;\n};\n\nexport type OreRadioProps = CheckableProps & {\n /** Theme color */\n color?: ThemeColor;\n /** Disable interaction */\n disabled?: boolean;\n /** Error message (marks field as invalid) */\n error?: string;\n /** Helper text displayed below the radio */\n helper?: string;\n /** Component size */\n size?: ComponentSize;\n};\n\n/**\n * A customizable radio button component for mutually exclusive selections.\n *\n * @element ore-radio\n *\n * @attr {boolean} checked - Checked state\n * @attr {boolean} disabled - Disable radio interaction\n * @attr {string} value - Field value (required for radio groups)\n * @attr {string} name - Form field name (required for radio groups)\n * @attr {string} color - Theme color: 'primary' | 'secondary' | 'info' | 'success' | 'warning' | 'error'\n * @attr {string} size - Radio size: 'sm' | 'md' | 'lg'\n * @attr {string} error - Error message (marks field as invalid)\n * @attr {string} helper - Helper text displayed below the radio\n *\n * @fires change - Emitted when radio is selected. detail: { checked: boolean, value: string, originalEvent?: Event }\n *\n * @slot - Radio button label text\n *\n * @cssprop --radio-size - Control size (width and height)\n * @cssprop --radio-bg - Unchecked background color\n * @cssprop --radio-border-color - Unchecked border color\n * @cssprop --radio-checked-bg - Selected indicator background color\n * @cssprop --radio-color - Selected indicator dot color\n * @cssprop --radio-font-size - Label font size\n * @part radio - The radio wrapper element\n * @part circle - The visual radio circle\n * @part label - The label element\n * @part helper-text - The helper/error text element\n *\n * @example\n * ```html\n * <ore-radio name=\"plan\" value=\"free\">Free</ore-radio>\n * <ore-radio name=\"plan\" value=\"pro\" checked color=\"primary\">Pro</ore-radio>\n * <ore-radio name=\"plan\" value=\"enterprise\" disabled>Enterprise</ore-radio>\n * ```\n */\nexport const RADIO_TAG = 'ore-radio' as const;\ndefine<OreRadioProps>(RADIO_TAG, {\n formAssociated: true,\n props: {\n ...themableBundle,\n ...sizableBundle,\n ...disablableBundle,\n checked: prop.bool(false),\n error: prop.string(),\n helper: prop.string(),\n name: prop.string(),\n value: prop.string(),\n },\n setup(props) {\n const el = getHost();\n const emit = useEmit<OreRadioEvents>();\n\n const groupCtx = inject(RADIO_GROUP_CTX);\n const formCtx = inject(FORM_CTX);\n const fCtxProps = useFormContext(props, formCtx);\n\n const effectiveName = computed(() => groupCtx?.name.value || props.name.value || '');\n const effectiveSize = computed(() => groupCtx?.size.value ?? fCtxProps.size.value);\n const effectiveColor = computed(() => groupCtx?.color.value ?? props.color.value);\n const checkedFromState = computed(() => {\n if (groupCtx) return groupCtx.value.value === props.value.value;\n\n return Boolean(props.checked.value);\n });\n\n const getRadioGroup = (): HTMLElement[] => {\n const radioName = effectiveName.value;\n\n if (!radioName) return [];\n\n return Array.from(document.querySelectorAll<HTMLElement>(`ore-radio[name=\"${radioName}\"]`)).filter(\n (r) => !r.hasAttribute('disabled'),\n );\n };\n\n const selectRadio = (radio: HTMLElement, originalEvent?: Event): void => {\n if (groupCtx) {\n groupCtx.select(radio.getAttribute('value') ?? '', originalEvent);\n\n return;\n }\n\n radio.click();\n };\n\n const listControl = createListControl({\n getItems: () => getRadioGroup(),\n keys: { next: ['ArrowDown', 'ArrowRight'], prev: ['ArrowUp', 'ArrowLeft'] },\n loop: true,\n onNavigate: (_action, index, event) => {\n const nextRadio = getRadioGroup()[index];\n\n if (!nextRadio) return;\n\n nextRadio.focus();\n selectRadio(nextRadio, event);\n },\n });\n\n const activateSelf = (originalEvent?: Event): void => {\n if (checkable.checked.value) return;\n\n if (groupCtx) {\n groupCtx.select(props.value.value ?? '', originalEvent);\n\n return;\n }\n\n checkable.toggle(originalEvent ?? new Event('change'));\n };\n\n const checkable = createCheckable({\n checked: checkedFromState,\n disabled: computed(() => fCtxProps.disabled.value || Boolean(groupCtx?.disabled.value)),\n error: props.error,\n helper: props.helper,\n onToggle: (payload) => {\n emit('change', payload);\n },\n prefix: 'radio',\n signal: lifecycleSignal(onCleanup),\n validateOn: formCtx?.validateOn,\n value: props.value,\n });\n\n checkable.attachFormField(\n useField<string | null>({\n disabled: checkable.disabled,\n toFormValue: (v) => v,\n value: checkable.checkableFormValue,\n }),\n );\n\n const { assistiveId, checked, disabled, errorText, helperText, labelId, toggle } = checkable;\n\n bind({\n attr: {\n ariaChecked: () => (checked.value ? 'true' : 'false'),\n ariaDescribedby: () => (errorText.value || helperText.value ? assistiveId : null),\n ariaDisabled: () => (disabled.value ? 'true' : null),\n ariaInvalid: () => (errorText.value ? 'true' : null),\n ariaLabelledby: labelId,\n checked,\n color: effectiveColor,\n disabled: () => (disabled.value ? true : undefined),\n name: () => effectiveName.value || undefined,\n role: 'radio',\n size: effectiveSize,\n tabindex: () => {\n if (disabled.value) return undefined;\n\n return checked.value ? 0 : -1;\n },\n },\n class: () => ({\n 'is-checked': checked.value,\n 'is-disabled': disabled.value,\n }),\n on: {\n click: (e: MouseEvent) => {\n if (disabled.value) return;\n\n if (groupCtx) {\n groupCtx.select(props.value.value ?? '', e);\n } else {\n if (!effectiveName.value) return;\n\n if (!checked.value) {\n const radioName = props.name.value;\n const allRadios = document.querySelectorAll<HTMLElement>(`ore-radio[name=\"${radioName}\"]`);\n\n allRadios.forEach((radio) => {\n if (radio !== el) radio.removeAttribute('checked');\n });\n\n toggle(e);\n }\n }\n },\n keydown: (e: KeyboardEvent) => {\n if (e.key === ' ' || e.key === 'Enter') {\n e.preventDefault();\n activateSelf(e);\n\n return;\n }\n\n const radios = getRadioGroup();\n\n if (radios.length === 0) return;\n\n const selfIndex = radios.indexOf(el);\n\n if (selfIndex === -1) return;\n\n listControl.set(selfIndex);\n listControl.handleKeydown(e);\n },\n },\n });\n\n return html`\n <div class=\"radio-wrapper\" part=\"radio\">\n <div class=\"circle\" part=\"circle\">\n <div class=\"dot\" part=\"dot\"></div>\n </div>\n </div>\n <span class=\"label\" part=\"label\" id=\"${labelId}\"><slot></slot></span>\n ${renderHelperRegion(assistiveId, errorText, helperText)}\n `;\n },\n styles: [\n colorThemeMixin,\n forcedColorsFormControlMixin,\n disabledStateMixin,\n coarsePointerMixin,\n sizeVariantMixin(CONTROL_SIZE_PRESET),\n componentStyles,\n ],\n});\n"],"mappings":"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"}