@lmvz-ds/components 0.24.0 → 0.25.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 (111) hide show
  1. package/CHANGELOG.md +11 -0
  2. package/cjs/{index-lW-SEvL7.js → index-BCFBLj0e.js} +1 -1
  3. package/cjs/lmvz-action.cjs.entry.js +1 -1
  4. package/cjs/lmvz-button_3.cjs.entry.js +4 -4
  5. package/cjs/lmvz-card.cjs.entry.js +2 -2
  6. package/cjs/lmvz-checkbox.cjs.entry.js +5 -5
  7. package/cjs/lmvz-chip.cjs.entry.js +3 -3
  8. package/cjs/lmvz-components.cjs.js +3 -3
  9. package/cjs/lmvz-header_2.cjs.entry.js +2 -2
  10. package/cjs/lmvz-input.cjs.entry.js +3 -3
  11. package/cjs/lmvz-menuitem.cjs.entry.js +3 -3
  12. package/cjs/lmvz-modal.cjs.entry.js +5 -5
  13. package/cjs/lmvz-radio.cjs.entry.js +334 -0
  14. package/cjs/lmvz-select.cjs.entry.js +4 -4
  15. package/cjs/lmvz-toggle.cjs.entry.js +7 -5
  16. package/cjs/loader.cjs.js +2 -2
  17. package/cjs/{reactive-controller-host-BOFg4vL-.js → reactive-controller-host-DrtMkMd7.js} +1 -1
  18. package/collection/collection-manifest.json +2 -1
  19. package/collection/components/lmvz-button/lmvz-button.css +7 -7
  20. package/collection/components/lmvz-button-group/lmvz-button-group.css +1 -1
  21. package/collection/components/lmvz-card/lmvz-card.css +7 -7
  22. package/collection/components/lmvz-checkbox/lmvz-checkbox.css +8 -11
  23. package/collection/components/lmvz-checkbox/lmvz-checkbox.js +2 -2
  24. package/collection/components/lmvz-chip/lmvz-chip.css +3 -3
  25. package/collection/components/lmvz-input/lmvz-input.css +5 -9
  26. package/collection/components/lmvz-menuitem/lmvz-menuitem.css +2 -2
  27. package/collection/components/lmvz-modal/lmvz-modal.css +28 -10
  28. package/collection/components/lmvz-modal/lmvz-modal.js +2 -2
  29. package/collection/components/lmvz-radio/lmvz-radio.css +182 -0
  30. package/collection/components/lmvz-radio/lmvz-radio.js +487 -0
  31. package/collection/components/lmvz-select/lmvz-select.css +3 -3
  32. package/collection/components/lmvz-select/lmvz-select.js +1 -1
  33. package/collection/components/lmvz-toggle/lmvz-toggle.css +4 -9
  34. package/collection/components/lmvz-toggle/lmvz-toggle.js +3 -3
  35. package/collection/integration/header-integration/header-integration.js +1 -1
  36. package/collection/styles/fragments/_focus-within.css +13 -0
  37. package/collection/utils/radio/radio-group-controller.js +160 -0
  38. package/components/index.d.ts +2 -0
  39. package/components/index.d.ts.bak +2 -0
  40. package/components/index.js +1 -1
  41. package/components/lmvz-action.js +1 -1
  42. package/components/lmvz-button-group.js +1 -1
  43. package/components/lmvz-button.js +1 -1
  44. package/components/lmvz-card.js +1 -1
  45. package/components/lmvz-checkbox.js +1 -1
  46. package/components/lmvz-chip.js +1 -1
  47. package/components/lmvz-header.js +1 -1
  48. package/components/lmvz-icon.js +1 -1
  49. package/components/lmvz-input.js +1 -1
  50. package/components/lmvz-menuitem.js +1 -1
  51. package/components/lmvz-modal.js +1 -1
  52. package/components/lmvz-radio.d.ts +11 -0
  53. package/components/lmvz-radio.d.ts.bak +11 -0
  54. package/components/lmvz-radio.js +1 -0
  55. package/components/lmvz-select.js +1 -1
  56. package/components/lmvz-toggle.js +1 -1
  57. package/components/p-Bb-kEOmU.js +1 -0
  58. package/components/{p-Cg2XX_J-.js → p-CCcoDnH-.js} +1 -1
  59. package/components/{p-slgmfnHm.js → p-CNmHnJ1D.js} +1 -1
  60. package/components/p-vUYpZZoR.js +1 -0
  61. package/esm/{index-Aa_425iY.js → index-CKYszC64.js} +1 -1
  62. package/esm/lmvz-action.entry.js +1 -1
  63. package/esm/lmvz-button_3.entry.js +4 -4
  64. package/esm/lmvz-card.entry.js +2 -2
  65. package/esm/lmvz-checkbox.entry.js +5 -5
  66. package/esm/lmvz-chip.entry.js +3 -3
  67. package/esm/lmvz-components.js +4 -4
  68. package/esm/lmvz-header_2.entry.js +2 -2
  69. package/esm/lmvz-input.entry.js +3 -3
  70. package/esm/lmvz-menuitem.entry.js +3 -3
  71. package/esm/lmvz-modal.entry.js +5 -5
  72. package/esm/lmvz-radio.entry.js +332 -0
  73. package/esm/lmvz-select.entry.js +4 -4
  74. package/esm/lmvz-toggle.entry.js +7 -5
  75. package/esm/loader.js +3 -3
  76. package/esm/{reactive-controller-host-CroMsXdS.js → reactive-controller-host-ZrGf1F2-.js} +1 -1
  77. package/hydrate/index.js +371 -19
  78. package/hydrate/index.mjs +371 -19
  79. package/lmvz-components/lmvz-components.esm.js +1 -1
  80. package/lmvz-components/{p-d1dacf7e.entry.js → p-01aeca60.entry.js} +1 -1
  81. package/lmvz-components/p-0dced359.entry.js +1 -0
  82. package/lmvz-components/{p-f6d1d9df.entry.js → p-2044a9ac.entry.js} +1 -1
  83. package/lmvz-components/p-3c2adbb4.entry.js +1 -0
  84. package/lmvz-components/{p-4263c9b2.entry.js → p-3df070b0.entry.js} +1 -1
  85. package/lmvz-components/{p-6f8cbc4f.entry.js → p-758078db.entry.js} +1 -1
  86. package/lmvz-components/p-90f5a19d.entry.js +1 -0
  87. package/lmvz-components/{p-BRl6zKXT.js → p-CwX1wKkM.js} +1 -1
  88. package/lmvz-components/p-acfeae08.entry.js +1 -0
  89. package/lmvz-components/{p-88adb9fa.entry.js → p-c01a6c70.entry.js} +1 -1
  90. package/lmvz-components/{p-a7c3074a.entry.js → p-e1eaa7a2.entry.js} +1 -1
  91. package/lmvz-components/p-e23d0054.entry.js +1 -0
  92. package/lmvz-components/p-fe607f10.entry.js +1 -0
  93. package/manifest.json +410 -2
  94. package/package.json +5 -1
  95. package/types/components/lmvz-radio/lmvz-radio.d.ts +42 -0
  96. package/types/components.d.ts +176 -0
  97. package/types/stencil-public-runtime.d.ts +1 -0
  98. package/types/utils/radio/radio-group-controller.d.ts +26 -0
  99. package/assets/icons/checkmark.svg +0 -4
  100. package/assets/icons/close-sm.svg +0 -3
  101. package/collection/assets/icons/checkmark.svg +0 -4
  102. package/collection/assets/icons/close-sm.svg +0 -3
  103. package/components/p-CcnyKhAw.js +0 -1
  104. package/components/p-DSvYtVoD.js +0 -1
  105. package/lmvz-components/p-2824a56b.entry.js +0 -1
  106. package/lmvz-components/p-3846ba08.entry.js +0 -1
  107. package/lmvz-components/p-4f5c3c4a.entry.js +0 -1
  108. package/lmvz-components/p-b3b04d46.entry.js +0 -1
  109. package/lmvz-components/p-fefefc54.entry.js +0 -1
  110. /package/components/{p-CK8cAKcB.js → p-DYr7Jc0V.js} +0 -0
  111. /package/lmvz-components/{p-Aa_425iY.js → p-CKYszC64.js} +0 -0
package/manifest.json CHANGED
@@ -1,8 +1,8 @@
1
1
  {
2
- "timestamp": "2026-06-01T13:24:33",
2
+ "timestamp": "2026-06-02T16:23:34",
3
3
  "compiler": {
4
4
  "name": "@stencil/core",
5
- "version": "4.43.4",
5
+ "version": "4.43.5",
6
6
  "typescriptVersion": "5.8.3"
7
7
  },
8
8
  "components": [
@@ -5878,6 +5878,414 @@
5878
5878
  ]
5879
5879
  }
5880
5880
  },
5881
+ {
5882
+ "filePath": "src/components/lmvz-radio/lmvz-radio.tsx",
5883
+ "encapsulation": "scoped",
5884
+ "tag": "lmvz-radio",
5885
+ "readme": "# lmvz-radio\n\nAccessible, form-associated radio button built as a Stencil scoped web component. Supports form association, native radio group mutual exclusion via `name` forwarding, roving tabindex, and ARIA APG-compliant keyboard navigation.\n\n## Usage\n\n### Basic\n\n```html\n<lmvz-radio name=\"choice\" value=\"a\" label=\"Option A\"></lmvz-radio>\n<lmvz-radio name=\"choice\" value=\"b\" label=\"Option B\"></lmvz-radio>\n```\n\n## Form Integration\n\n`lmvz-radio` is a FACE (Form-Associated Custom Element). It participates in native HTML forms via `ElementInternals`: the `name` and `value` attributes are submitted to the form when the radio is `checked`.\n\nSetting `required` triggers native form validation — the form will not submit unless a radio with the given `name` is checked.\n\n### Form Reset Behavior\n\nWhen a form is reset, `lmvz-radio` restores its `checked` state to the value it held when the component first mounted (the `initialChecked` value), without emitting `lmvzChange`. This matches native `<input type=\"radio\">` behavior. Internal form state (via `ElementInternals.setFormValue`) is always updated regardless. Browser autofill and session-restore operations (via `formStateRestoreCallback`) also do not emit `lmvzChange`.\n\n> **Note:** `aria-required` is intentionally absent from `lmvz-radio`. When a radio group is required, expose `aria-required` on the `role=\"radiogroup\"` wrapper element via your application code. This is the consumer's responsibility.\n\n## Radio Group Behavior\n\nWhen multiple `lmvz-radio` elements share the same `name` attribute and are within the same form (or document scope if outside any form), they form a native radio group. The `name` is forwarded directly to the native `<input type=\"radio\">`, enabling the browser's built-in mutual-exclusion logic: selecting one radio automatically deselects all others with the same name in the same scope. Radios with the same `name` in different forms are treated as independent groups.\n\n**Roving tabindex:** The component automatically manages keyboard focus navigation via the `RadioGroupController`. When a group of radios shares the same `name`:\n- The checked radio has `tabindex=\"0\"` and is reachable via Tab.\n- All other enabled radios have `tabindex=\"-1\"` and are not directly tabbable.\n- If no radio is checked, the first enabled radio in DOM order receives `tabindex=\"0\"`, ensuring the group is always reachable.\n\n**Keyboard navigation (manual selection pattern):**\n\n| Key | Action |\n|-----|--------|\n| Arrow Down / Arrow Right | Moves focus to the next radio in the group (no selection) |\n| Arrow Up / Arrow Left | Moves focus to the previous radio in the group (no selection) |\n| Home | Moves focus to the first radio in the group (no selection) |\n| End | Moves focus to the last radio in the group (no selection) |\n| Space | Selects the focused radio; emits `lmvzActivation` and (if state changed) `lmvzChange` |\n| Tab | Moves focus out of the radio group |\n\nDisabled radios are skipped during navigation.\n\nThis component implements the WAI-ARIA [manual selection](https://www.w3.org/WAI/ARIA/apg/patterns/radio/) pattern: focus and selection are decoupled. Arrow keys move focus without selecting. The consumer is responsible for wrapping grouped radios in a `role=\"radiogroup\"` element.\n\n**Consumer responsibility — `role=\"radiogroup\"`:**\nWrap a group of related `lmvz-radio` elements in a container element with `role=\"radiogroup\"` and an accessible label via `aria-label` or `aria-labelledby`. The radio component does not add this role itself because a radio button cannot also be a radiogroup.\n\n## Accessibility\n\n- A native `<input type=\"radio\">` is rendered inside the component for full keyboard and screen reader support.\n- `role=\"radiogroup\"` must be added by the consumer on a wrapper element (see \"Radio Group Behavior\" above).\n- `aria-invalid` is set when `error=true`.\n- `aria-describedby` links the input to helper text when `helper-text` is provided.\n- Helper text uses `aria-live=\"polite\"` for dynamic updates.\n- The focus ring is visible and meets WCAG 2.1 AA contrast requirements.\n- Forced Colors (Windows High Contrast Mode) is supported.\n\n## CSS Custom Properties\n\nOverride these on the `:host` element to theme the component. All defaults reference LMVZ semantic or global design tokens.\n\n| Property | Default | Description |\n|---|---|---|\n| `--radio-circle-size` | `var(--lmvz-global-s18)` | Width and height of the radio circle |\n| `--radio-dot-size` | `0.5rem` | Size of the inner selected dot |\n| `--radio-bg` | `var(--lmvz-semantic-color-surface-input-primary)` | Circle background (unchecked) |\n| `--radio-border-color` | `var(--lmvz-semantic-color-border-default)` | Circle border (default) |\n| `--radio-border-color-hover` | `var(--lmvz-semantic-color-border-hover)` | Circle border on hover |\n| `--radio-border-color-checked` | `var(--lmvz-semantic-color-border-active)` | Circle border when checked |\n| `--radio-border-color-error` | `var(--lmvz-semantic-color-status-on-danger)` | Circle border in error state |\n| `--radio-dot-color` | `var(--lmvz-semantic-color-border-active)` | Color of the inner dot |\n| `--radio-wrapper-bg-hover` | `var(--lmvz-semantic-color-int-tertiary-hover)` | Pill background on hover |\n| `--radio-wrapper-bg-active` | `var(--lmvz-semantic-color-int-tertiary-active)` | Pill background when pressed |\n| `--radio-wrapper-bg-checked` | `var(--lmvz-semantic-color-status-active)` | Pill background when checked |\n| `--radio-label-color` | `var(--lmvz-semantic-color-on-surface-primary)` | Label text color (default) |\n| `--radio-label-color-checked` | `var(--lmvz-semantic-color-status-on-active)` | Label text color when checked |\n| `--radio-helper-color` | `var(--lmvz-semantic-color-on-surface-secondary)` | Helper text color |\n| `--radio-focus-color` | `var(--lmvz-semantic-color-status-on-active)` | Focus ring color |\n| `--radio-easing` | `var(--lmvz-global-easing-default, ease)` | Transition easing function |\n| `--radio-duration` | `0.2s` | Transition duration |\n\n## lmvzChange Emission Contract\n\nThe `lmvzChange` event emits only when the radio's checked state changes. The event detail contains the new `checked` boolean value.\n\n**Fires on:**\n- User activation: clicking the radio or pressing Space (only if state changes)\n- Programmatic checked state transitions: setting `checked = true` or `checked = false`\n\n**Does NOT fire on:**\n- Arrow key navigation (Arrow Down, Arrow Up, Home, End). These move focus only, without selection.\n- Browser form lifecycle callbacks (`formResetCallback`, `formStateRestoreCallback`). This matches native `<input type=\"radio\">` behavior, which does not fire `change` on form reset. Internal form state (`ElementInternals.setFormValue`) is always updated regardless.\n\n## Angular Integration\n\n### Automatic Form Integration\n\nUse the `LmvzCheckableValueChangeHelper` directive (included in `@lmvz-ds/angular`) to automatically wire `lmvz-radio` to Angular form controls. When this directive is present on the element, it automatically binds the `lmvzChange` event to the form control's `valueChange` output:\n\n```html\n<!-- With [(ngModel)] -->\n<lmvz-radio\n label=\"Option A\"\n name=\"choice\"\n value=\"a\"\n [(ngModel)]=\"selectedValue\">\n</lmvz-radio>\n\n<!-- With [formControl] -->\n<lmvz-radio\n label=\"Option B\"\n name=\"choice\"\n value=\"b\"\n [formControl]=\"controlRef\">\n</lmvz-radio>\n```\n\nNo additional setup is required — the directive is applied automatically via the selector `lmvz-checkbox, lmvz-radio`.\n\n### Manual Event Binding\n\nIf you need direct event handling, listen to the `lmvzChange` event:\n\n```html\n<lmvz-radio\n label=\"Option\"\n name=\"choice\"\n [checked]=\"isChecked\"\n (lmvzChange)=\"isChecked = $event.target.checked\">\n</lmvz-radio>\n```\n\n## Public Methods\n\n### focusInput()\n\nProgrammatically set focus on the native radio input. Use this method when you need to move keyboard focus to a radio after a user interaction or page state change:\n\n```typescript\nconst radioEl = document.querySelector('lmvz-radio');\nawait radioEl.focusInput();\n```\n\n## Event Reference\n\n### lmvzActivation\n\nThe `lmvzActivation` event fires on every explicit user activation: click or Space on the native input. This includes re-activation of an already-checked radio. Use this event to react directly to user intent, distinct from state transitions.\n\n### lmvzChange vs lmvzActivation\n\n- **`lmvzActivation`:** Fires on every explicit user activation (click or Space), regardless of whether the checked state actually changes.\n- **`lmvzChange`:** Fires only on state transitions (checked ↔ unchecked).\n\nWhen a user selects a different radio in a group, both events fire together. When a user re-activates an already-checked radio, only `lmvzActivation` fires.\n\n## Design Notes / Waivers\n\n### Checked + hover state (OQ-5)\n\nWhen a radio is both checked and hovered, the checked background (`--radio-wrapper-bg-checked`) is held — the hover background does not override it. No Figma spec exists for this combined state; this behavior is an intentional implementation decision.\n\n### Label wrapping (OQ-3)\n\nThe label uses `overflow-wrap: break-word` (normal wrapping). `white-space: nowrap` is intentionally not applied.\n",
5886
+ "docs": "Radio button component with form association, ARIA validation, accessible label support,\nand ARIA APG-compliant Arrow-key keyboard navigation.\n\n**Consumer responsibility — `role=\"radiogroup\"`:**\nWrap a group of `lmvz-radio` elements in a container element with `role=\"radiogroup\"` and\nan accessible label via `aria-label` or `aria-labelledby`. `lmvz-radio` must not carry\n`role=\"radiogroup\"` itself because a radio cannot also be a radiogroup.\n\n**Arrow-key navigation and roving tabindex:**\nWhen multiple `lmvz-radio` elements share the same `name` attribute, this component\nautomatically handles Arrow Down / Arrow Right (next), Arrow Up / Arrow Left (previous),\nHome (first), and End (last) navigation with wrapping. Disabled radios are skipped.\nThe checked radio has `tabindex=\"0\"`. When no radio is checked, the first enabled radio\nin DOM order receives `tabindex=\"0\"`, ensuring the group is always reachable by Tab.",
5887
+ "docsTags": [
5888
+ {
5889
+ "name": "example",
5890
+ "text": "```html\n<div role=\"radiogroup\" aria-label=\"Choose an option\">\n <lmvz-radio label=\"Option A\" name=\"choice\" checked></lmvz-radio>\n <lmvz-radio label=\"Option B\" name=\"choice\"></lmvz-radio>\n</div>\n```"
5891
+ }
5892
+ ],
5893
+ "usage": {},
5894
+ "props": [
5895
+ {
5896
+ "name": "autofocus",
5897
+ "type": "boolean",
5898
+ "complexType": {
5899
+ "original": "boolean",
5900
+ "resolved": "boolean",
5901
+ "references": {}
5902
+ },
5903
+ "mutable": false,
5904
+ "attr": "autofocus",
5905
+ "reflectToAttr": false,
5906
+ "docs": "Whether the radio should autofocus.",
5907
+ "docsTags": [
5908
+ {
5909
+ "name": "default",
5910
+ "text": "false"
5911
+ }
5912
+ ],
5913
+ "default": "false",
5914
+ "values": [
5915
+ {
5916
+ "type": "boolean"
5917
+ }
5918
+ ],
5919
+ "optional": false,
5920
+ "required": false,
5921
+ "getter": false,
5922
+ "setter": false
5923
+ },
5924
+ {
5925
+ "name": "checked",
5926
+ "type": "boolean",
5927
+ "complexType": {
5928
+ "original": "boolean",
5929
+ "resolved": "boolean",
5930
+ "references": {}
5931
+ },
5932
+ "mutable": true,
5933
+ "attr": "checked",
5934
+ "reflectToAttr": true,
5935
+ "docs": "Whether the radio is checked.\n\nSetting this prop programmatically (e.g. `element.checked = true`) fires `lmvzChange`\nwith the new value, unless the change occurs during native form lifecycle callbacks\n(`formResetCallback` or `formStateRestoreCallback`), in which case emission is suppressed\nto match native `<input type=\"radio\">` behavior. Internal form state is always updated\nregardless of emission suppression.",
5936
+ "docsTags": [
5937
+ {
5938
+ "name": "default",
5939
+ "text": "false"
5940
+ }
5941
+ ],
5942
+ "default": "false",
5943
+ "values": [
5944
+ {
5945
+ "type": "boolean"
5946
+ }
5947
+ ],
5948
+ "optional": false,
5949
+ "required": false,
5950
+ "getter": false,
5951
+ "setter": false
5952
+ },
5953
+ {
5954
+ "name": "disabled",
5955
+ "type": "boolean",
5956
+ "complexType": {
5957
+ "original": "boolean",
5958
+ "resolved": "boolean",
5959
+ "references": {}
5960
+ },
5961
+ "mutable": false,
5962
+ "attr": "disabled",
5963
+ "reflectToAttr": true,
5964
+ "docs": "Whether the radio is disabled.",
5965
+ "docsTags": [
5966
+ {
5967
+ "name": "default",
5968
+ "text": "false"
5969
+ }
5970
+ ],
5971
+ "default": "false",
5972
+ "values": [
5973
+ {
5974
+ "type": "boolean"
5975
+ }
5976
+ ],
5977
+ "optional": false,
5978
+ "required": false,
5979
+ "getter": false,
5980
+ "setter": false
5981
+ },
5982
+ {
5983
+ "name": "error",
5984
+ "type": "boolean",
5985
+ "complexType": {
5986
+ "original": "boolean",
5987
+ "resolved": "boolean",
5988
+ "references": {}
5989
+ },
5990
+ "mutable": false,
5991
+ "attr": "error",
5992
+ "reflectToAttr": true,
5993
+ "docs": "Whether the radio is in an error state.",
5994
+ "docsTags": [
5995
+ {
5996
+ "name": "default",
5997
+ "text": "false"
5998
+ }
5999
+ ],
6000
+ "default": "false",
6001
+ "values": [
6002
+ {
6003
+ "type": "boolean"
6004
+ }
6005
+ ],
6006
+ "optional": false,
6007
+ "required": false,
6008
+ "getter": false,
6009
+ "setter": false
6010
+ },
6011
+ {
6012
+ "name": "form",
6013
+ "type": "string | undefined",
6014
+ "complexType": {
6015
+ "original": "string",
6016
+ "resolved": "string | undefined",
6017
+ "references": {}
6018
+ },
6019
+ "mutable": false,
6020
+ "attr": "form",
6021
+ "reflectToAttr": true,
6022
+ "docs": "Form id to associate with (for out-of-form usage).\nReflected to the host attribute so both HTML attribute and programmatic assignment work.",
6023
+ "docsTags": [],
6024
+ "values": [
6025
+ {
6026
+ "type": "string"
6027
+ },
6028
+ {
6029
+ "type": "undefined"
6030
+ }
6031
+ ],
6032
+ "optional": true,
6033
+ "required": false,
6034
+ "getter": false,
6035
+ "setter": false
6036
+ },
6037
+ {
6038
+ "name": "helperText",
6039
+ "type": "string | undefined",
6040
+ "complexType": {
6041
+ "original": "string",
6042
+ "resolved": "string | undefined",
6043
+ "references": {}
6044
+ },
6045
+ "mutable": false,
6046
+ "attr": "helper-text",
6047
+ "reflectToAttr": false,
6048
+ "docs": "Helper / description text displayed below the label.",
6049
+ "docsTags": [],
6050
+ "values": [
6051
+ {
6052
+ "type": "string"
6053
+ },
6054
+ {
6055
+ "type": "undefined"
6056
+ }
6057
+ ],
6058
+ "optional": true,
6059
+ "required": false,
6060
+ "getter": false,
6061
+ "setter": false
6062
+ },
6063
+ {
6064
+ "name": "label",
6065
+ "type": "string",
6066
+ "complexType": {
6067
+ "original": "string",
6068
+ "resolved": "string",
6069
+ "references": {}
6070
+ },
6071
+ "mutable": false,
6072
+ "attr": "label",
6073
+ "reflectToAttr": false,
6074
+ "docs": "Label text for the radio. Required for accessibility.",
6075
+ "docsTags": [],
6076
+ "values": [
6077
+ {
6078
+ "type": "string"
6079
+ }
6080
+ ],
6081
+ "optional": false,
6082
+ "required": true,
6083
+ "getter": false,
6084
+ "setter": false
6085
+ },
6086
+ {
6087
+ "name": "name",
6088
+ "type": "string | undefined",
6089
+ "complexType": {
6090
+ "original": "string",
6091
+ "resolved": "string | undefined",
6092
+ "references": {}
6093
+ },
6094
+ "mutable": false,
6095
+ "attr": "name",
6096
+ "reflectToAttr": false,
6097
+ "docs": "Name attribute for form submission via ElementInternals.\n\nWhen multiple `lmvz-radio` elements share the same `name` and form scope,\nthe `name` is forwarded directly to the native `<input type=\"radio\">`,\nenabling browser-native mutual exclusion: selecting one radio automatically\ndeselects all others with the same name in that form. If a radio is outside\nany form, its scope defaults to the document level — same-name radios\noutside forms form a document-scoped group. Radios with the same `name` in\ndifferent forms are independent groups.\n\nThe `RadioGroupController` automatically manages roving tabindex (only the\nchecked radio has `tabindex=\"0\"`) and keyboard navigation (Arrow keys, Home, End)\nwithin the form-scoped group.",
6098
+ "docsTags": [
6099
+ {
6100
+ "name": "remarks",
6101
+ "text": "A value of `\"\"` (empty string) is forwarded to the native `<input>`, but\n`RadioGroupController` treats it as unnamed — no group coordination occurs between\nradios with `name=\"\"`."
6102
+ }
6103
+ ],
6104
+ "values": [
6105
+ {
6106
+ "type": "string"
6107
+ },
6108
+ {
6109
+ "type": "undefined"
6110
+ }
6111
+ ],
6112
+ "optional": true,
6113
+ "required": false,
6114
+ "getter": false,
6115
+ "setter": false
6116
+ },
6117
+ {
6118
+ "name": "required",
6119
+ "type": "boolean",
6120
+ "complexType": {
6121
+ "original": "boolean",
6122
+ "resolved": "boolean",
6123
+ "references": {}
6124
+ },
6125
+ "mutable": false,
6126
+ "attr": "required",
6127
+ "reflectToAttr": true,
6128
+ "docs": "Whether the radio is required.",
6129
+ "docsTags": [
6130
+ {
6131
+ "name": "default",
6132
+ "text": "false"
6133
+ }
6134
+ ],
6135
+ "default": "false",
6136
+ "values": [
6137
+ {
6138
+ "type": "boolean"
6139
+ }
6140
+ ],
6141
+ "optional": false,
6142
+ "required": false,
6143
+ "getter": false,
6144
+ "setter": false
6145
+ },
6146
+ {
6147
+ "name": "value",
6148
+ "type": "string",
6149
+ "complexType": {
6150
+ "original": "string",
6151
+ "resolved": "string",
6152
+ "references": {}
6153
+ },
6154
+ "mutable": false,
6155
+ "attr": "value",
6156
+ "reflectToAttr": false,
6157
+ "docs": "Form submission value when checked.",
6158
+ "docsTags": [
6159
+ {
6160
+ "name": "default",
6161
+ "text": "'on'"
6162
+ }
6163
+ ],
6164
+ "default": "'on'",
6165
+ "values": [
6166
+ {
6167
+ "type": "string"
6168
+ }
6169
+ ],
6170
+ "optional": false,
6171
+ "required": false,
6172
+ "getter": false,
6173
+ "setter": false
6174
+ }
6175
+ ],
6176
+ "methods": [
6177
+ {
6178
+ "name": "checkValidity",
6179
+ "returns": {
6180
+ "type": "Promise<boolean>",
6181
+ "docs": ""
6182
+ },
6183
+ "complexType": {
6184
+ "signature": "() => Promise<boolean>",
6185
+ "parameters": [],
6186
+ "references": {
6187
+ "Promise": {
6188
+ "location": "global",
6189
+ "id": "global::Promise"
6190
+ }
6191
+ },
6192
+ "return": "Promise<boolean>"
6193
+ },
6194
+ "signature": "checkValidity() => Promise<boolean>",
6195
+ "parameters": [],
6196
+ "docs": "Returns whether the radio satisfies its validation constraints.",
6197
+ "docsTags": []
6198
+ },
6199
+ {
6200
+ "name": "focusInput",
6201
+ "returns": {
6202
+ "type": "Promise<void>",
6203
+ "docs": ""
6204
+ },
6205
+ "complexType": {
6206
+ "signature": "() => Promise<void>",
6207
+ "parameters": [],
6208
+ "references": {
6209
+ "Promise": {
6210
+ "location": "global",
6211
+ "id": "global::Promise"
6212
+ }
6213
+ },
6214
+ "return": "Promise<void>"
6215
+ },
6216
+ "signature": "focusInput() => Promise<void>",
6217
+ "parameters": [],
6218
+ "docs": "Sets focus on the native radio input.",
6219
+ "docsTags": []
6220
+ },
6221
+ {
6222
+ "name": "reportValidity",
6223
+ "returns": {
6224
+ "type": "Promise<boolean>",
6225
+ "docs": ""
6226
+ },
6227
+ "complexType": {
6228
+ "signature": "() => Promise<boolean>",
6229
+ "parameters": [],
6230
+ "references": {
6231
+ "Promise": {
6232
+ "location": "global",
6233
+ "id": "global::Promise"
6234
+ }
6235
+ },
6236
+ "return": "Promise<boolean>"
6237
+ },
6238
+ "signature": "reportValidity() => Promise<boolean>",
6239
+ "parameters": [],
6240
+ "docs": "Reports validation errors to the user.",
6241
+ "docsTags": []
6242
+ }
6243
+ ],
6244
+ "events": [
6245
+ {
6246
+ "event": "lmvzActivation",
6247
+ "detail": "void",
6248
+ "bubbles": true,
6249
+ "complexType": {
6250
+ "original": "void",
6251
+ "resolved": "void",
6252
+ "references": {}
6253
+ },
6254
+ "cancelable": true,
6255
+ "composed": true,
6256
+ "docs": "Fired on every explicit user activation of this radio — via click or Space key on the\nnative input. Fires even when the radio is already checked (re-activation). Use this\nevent to react to user intent; use `lmvzChange` to react to state transitions.",
6257
+ "docsTags": []
6258
+ },
6259
+ {
6260
+ "event": "lmvzChange",
6261
+ "detail": "boolean",
6262
+ "bubbles": true,
6263
+ "complexType": {
6264
+ "original": "boolean",
6265
+ "resolved": "boolean",
6266
+ "references": {}
6267
+ },
6268
+ "cancelable": true,
6269
+ "composed": true,
6270
+ "docs": "Emitted whenever the radio checked state changes.\nEvent detail contains the new checked boolean value.\n\nEmission contract:\n- Fires `true` on user selection (native `change` event).\n- Fires on programmatic external prop transitions: `true → false` (emits `false`) and\n `false → true` (emits `true`), e.g. `element.checked = false` or `element.checked = true`.\n- Does NOT fire during browser-driven form lifecycle callbacks: `formResetCallback` and\n `formStateRestoreCallback` (autofill / session restore). This matches native `<input type=\"radio\">`\n behaviour, which does not fire `change` on form reset. Note that internal form state\n (`ElementInternals.setFormValue`) is always updated regardless of suppression — only the\n event channel is silenced.\n- Does NOT re-fire from the `@Watch('checked')` watcher during the same tick as the native\n `change` handler, preventing a double-emission when the user clicks the radio.",
6271
+ "docsTags": []
6272
+ }
6273
+ ],
6274
+ "listeners": [
6275
+ {
6276
+ "event": "keydown",
6277
+ "capture": false,
6278
+ "passive": false
6279
+ }
6280
+ ],
6281
+ "styles": [],
6282
+ "slots": [],
6283
+ "parts": [],
6284
+ "states": [],
6285
+ "dependents": [],
6286
+ "dependencies": [],
6287
+ "dependencyGraph": {}
6288
+ },
5881
6289
  {
5882
6290
  "filePath": "src/components/lmvz-select/lmvz-select.tsx",
5883
6291
  "encapsulation": "scoped",
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@lmvz-ds/components",
3
3
  "private": false,
4
- "version": "0.24.0",
4
+ "version": "0.25.0",
5
5
  "type": "module",
6
6
  "description": "The components of the design system",
7
7
  "author": "Patrick Nemenz <patrick.nemenz@adesso.at>",
@@ -83,6 +83,10 @@
83
83
  "./lmvz-button-group": {
84
84
  "import": "./components/lmvz-button-group.js",
85
85
  "types": "./components/lmvz-button-group.d.ts"
86
+ },
87
+ "./lmvz-radio": {
88
+ "import": "./components/lmvz-radio.js",
89
+ "types": "./components/lmvz-radio.d.ts"
86
90
  }
87
91
  },
88
92
  "main": "./index.cjs.js",
@@ -0,0 +1,42 @@
1
+ import { type EventEmitter } from '../../stencil-public-runtime';
2
+ import { type AriaValidationHost } from '../../utils/aria/aria-validation-controller';
3
+ import { type RadioHost } from '../../utils/radio/radio-group-controller';
4
+ import { ReactiveControllerHost } from '../../utils/reactive-controller-host';
5
+ export declare class LmvzRadio extends ReactiveControllerHost implements AriaValidationHost, RadioHost {
6
+ readonly el: HTMLElement;
7
+ get validationEl(): HTMLElement;
8
+ internals: ElementInternals;
9
+ private nativeInput;
10
+ private radioId;
11
+ private initialChecked;
12
+ private radioGroupController;
13
+ private get helperId();
14
+ label: string;
15
+ checked: boolean;
16
+ value: string;
17
+ name?: string;
18
+ disabled: boolean;
19
+ required: boolean;
20
+ error: boolean;
21
+ helperText?: string;
22
+ form?: string;
23
+ autofocus: boolean;
24
+ private _handlingNativeChange;
25
+ private _handlingFormReset;
26
+ protected handleCheckedChange(newVal: boolean, oldVal: boolean): void;
27
+ protected handleValueChange(newVal: string): void;
28
+ protected handleLabelChange(newVal: string): void;
29
+ lmvzChange: EventEmitter<boolean>;
30
+ lmvzActivation: EventEmitter<void>;
31
+ focusInput(): Promise<void>;
32
+ checkValidity(): Promise<boolean>;
33
+ reportValidity(): Promise<boolean>;
34
+ constructor();
35
+ componentWillLoad(): void;
36
+ formAssociatedCallback(): void;
37
+ formResetCallback(): void;
38
+ formStateRestoreCallback(state: string | File | FormData): void;
39
+ private handleChange;
40
+ handleKeydown(event: KeyboardEvent): void;
41
+ render(): any;
42
+ }