@atelier-ui/react 0.1.3 → 0.1.7

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.
package/CHANGELOG.md CHANGED
@@ -1,3 +1,47 @@
1
+ ## 0.1.7 (2026-05-30)
2
+
3
+ ### 🚀 Features
4
+
5
+ - **tooling:** replace @behavior comment marker with typed covers() gate ([ff36fe9](https://github.com/DominikPieper/atelier-ui/commit/ff36fe9))
6
+ - **spec:** AI-readiness metadata + token manifest layer ([d7f6235](https://github.com/DominikPieper/atelier-ui/commit/d7f6235))
7
+
8
+ ### ❤️ Thank You
9
+
10
+ - Claude Opus 4.7 (1M context)
11
+ - Claude Opus 4.8 (1M context)
12
+ - Dominik Pieper @DominikPieper
13
+
14
+ ## 0.1.6 (2026-05-27)
15
+
16
+ ### 🚀 Features
17
+
18
+ - **a11y:** add roving arrow-key navigation to React/Vue radio-group ([0c2ae81](https://github.com/DominikPieper/atelier-ui/commit/0c2ae81))
19
+ - **tooling:** enforce behavioral-parity coverage across framework adapters ([06c1829](https://github.com/DominikPieper/atelier-ui/commit/06c1829))
20
+
21
+ ### 🩹 Fixes
22
+
23
+ - **angular:** suppress click events on disabled button ([1639ced](https://github.com/DominikPieper/atelier-ui/commit/1639ced))
24
+
25
+ ### ❤️ Thank You
26
+
27
+ - Claude Opus 4.7 (1M context)
28
+ - Dominik Pieper @DominikPieper
29
+
30
+ ## 0.1.5 (2026-05-20)
31
+
32
+ This was a version bump only for react to align it with other projects, there were no code changes.
33
+
34
+ ## 0.1.4 (2026-05-20)
35
+
36
+ ### 🩹 Fixes
37
+
38
+ - **storybook-mcp:** align hosted MCPs with Storybook 10.4 reality ([a043e56](https://github.com/DominikPieper/atelier-ui/commit/a043e56))
39
+
40
+ ### ❤️ Thank You
41
+
42
+ - Claude Opus 4.7 (1M context)
43
+ - Dominik Pieper @DominikPieper
44
+
1
45
  ## 0.1.3 (2026-05-19)
2
46
 
3
47
  ### 🩹 Fixes
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@atelier-ui/react",
3
- "version": "0.1.3",
3
+ "version": "0.1.7",
4
4
  "description": "Atelier component library for React — LLM-optimised, accessible, design-token-driven",
5
5
  "keywords": [
6
6
  "react",
@@ -1 +1 @@
1
- {"version":3,"file":"llm-radio-group.d.ts","sourceRoot":"","sources":["../../../../../../libs/react/src/lib/radio-group/llm-radio-group.tsx"],"names":[],"mappings":"AAAA,OAAO,EAA6B,mBAAmB,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAClF,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,SAAS,CAAC;AACjD,OAAO,uBAAuB,CAAC;AAE/B;;GAEG;AACH,MAAM,WAAW,sBAAsB;IACrC;;OAEG;IACH,KAAK,EAAE,MAAM,CAAC;IACd;;OAEG;IACH,IAAI,EAAE,MAAM,CAAC;IACb;;OAEG;IACH,QAAQ,EAAE,OAAO,CAAC;IAClB;;OAEG;IACH,QAAQ,EAAE,OAAO,CAAC;IAClB;;OAEG;IACH,OAAO,EAAE,OAAO,CAAC;IACjB;;OAEG;IACH,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAClC;;OAEG;IACH,MAAM,EAAE,MAAM,IAAI,CAAC;CACpB;AAED,eAAO,MAAM,iBAAiB,iDAQ5B,CAAC;AAEH;;GAEG;AACH,MAAM,WAAW,kBACf,SAAQ,IAAI,CAAC,mBAAmB,CAAC,cAAc,CAAC,EAAE,UAAU,CAAC,EAC3D,iBAAiB;IACnB;;OAEG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IACf;;OAEG;IACH,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACxC;;OAEG;IACH,WAAW,CAAC,EAAE,YAAY,GAAG,UAAU,CAAC;IACxC;;OAEG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC;IACd;;OAEG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB;;OAEG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB;;OAEG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB;;OAEG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB;;OAEG;IACH,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;IAClB;;OAEG;IACH,QAAQ,CAAC,EAAE,SAAS,CAAC;CACtB;AAED;;GAEG;AACH,wBAAgB,aAAa,CAAC,EAC5B,KAAU,EACV,aAAa,EACb,WAAwB,EACxB,IAAS,EACT,QAAgB,EAChB,QAAQ,EAAE,aAAa,EACvB,QAAQ,EAAE,YAAY,EACtB,OAAe,EACf,QAAgB,EAChB,MAAW,EACX,QAAQ,EACR,SAAS,EACT,GAAG,IAAI,EACR,EAAE,kBAAkB,2CA6CpB;AAED,wBAAgB,aAAa,IAAI,sBAAsB,CAEtD"}
1
+ {"version":3,"file":"llm-radio-group.d.ts","sourceRoot":"","sources":["../../../../../../libs/react/src/lib/radio-group/llm-radio-group.tsx"],"names":[],"mappings":"AAAA,OAAO,EAKL,mBAAmB,EACnB,SAAS,EACV,MAAM,OAAO,CAAC;AACf,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,SAAS,CAAC;AACjD,OAAO,uBAAuB,CAAC;AAE/B;;GAEG;AACH,MAAM,WAAW,sBAAsB;IACrC;;OAEG;IACH,KAAK,EAAE,MAAM,CAAC;IACd;;OAEG;IACH,IAAI,EAAE,MAAM,CAAC;IACb;;OAEG;IACH,QAAQ,EAAE,OAAO,CAAC;IAClB;;OAEG;IACH,QAAQ,EAAE,OAAO,CAAC;IAClB;;OAEG;IACH,OAAO,EAAE,OAAO,CAAC;IACjB;;OAEG;IACH,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAClC;;OAEG;IACH,MAAM,EAAE,MAAM,IAAI,CAAC;CACpB;AAED,eAAO,MAAM,iBAAiB,iDAQ5B,CAAC;AAEH;;GAEG;AACH,MAAM,WAAW,kBACf,SAAQ,IAAI,CAAC,mBAAmB,CAAC,cAAc,CAAC,EAAE,UAAU,CAAC,EAC3D,iBAAiB;IACnB;;OAEG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IACf;;OAEG;IACH,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACxC;;OAEG;IACH,WAAW,CAAC,EAAE,YAAY,GAAG,UAAU,CAAC;IACxC;;OAEG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC;IACd;;OAEG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB;;OAEG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB;;OAEG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB;;OAEG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB;;OAEG;IACH,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;IAClB;;OAEG;IACH,QAAQ,CAAC,EAAE,SAAS,CAAC;CACtB;AAED;;GAEG;AACH,wBAAgB,aAAa,CAAC,EAC5B,KAAU,EACV,aAAa,EACb,WAAwB,EACxB,IAAS,EACT,QAAgB,EAChB,QAAQ,EAAE,aAAa,EACvB,QAAQ,EAAE,YAAY,EACtB,OAAe,EACf,QAAgB,EAChB,MAAW,EACX,QAAQ,EACR,SAAS,EACT,GAAG,IAAI,EACR,EAAE,kBAAkB,2CAsEpB;AAED,wBAAgB,aAAa,IAAI,sBAAsB,CAEtD"}
@@ -1,5 +1,5 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { createContext, useContext } from 'react';
2
+ import { createContext, useContext, useRef, } from 'react';
3
3
  import './llm-radio-group.css';
4
4
  export const RadioGroupContext = createContext({
5
5
  value: '',
@@ -15,6 +15,28 @@ export const RadioGroupContext = createContext({
15
15
  */
16
16
  export function LlmRadioGroup({ value = '', onValueChange, orientation = 'vertical', name = '', disabled = false, readOnly: reactReadOnly, readonly: specReadOnly, invalid = false, required = false, errors = [], children, className, ...rest }) {
17
17
  const readOnly = reactReadOnly ?? specReadOnly ?? false;
18
+ const groupRef = useRef(null);
19
+ // Roving arrow-key navigation per the WAI-ARIA radiogroup pattern: Arrow
20
+ // Down/Right move to the next enabled radio, Up/Left to the previous, both
21
+ // wrapping, and the navigated radio is selected and focused.
22
+ const handleKeyDown = (event) => {
23
+ if (disabled || readOnly)
24
+ return;
25
+ const forward = event.key === 'ArrowDown' || event.key === 'ArrowRight';
26
+ const backward = event.key === 'ArrowUp' || event.key === 'ArrowLeft';
27
+ if (!forward && !backward)
28
+ return;
29
+ const radios = Array.from(groupRef.current?.querySelectorAll('input[type="radio"]') ?? []).filter((radio) => !radio.disabled);
30
+ if (radios.length === 0)
31
+ return;
32
+ event.preventDefault();
33
+ const currentIdx = radios.findIndex((radio) => radio.value === value);
34
+ const start = currentIdx === -1 ? (forward ? -1 : 0) : currentIdx;
35
+ const nextIdx = (start + (forward ? 1 : -1) + radios.length) % radios.length;
36
+ const target = radios[nextIdx];
37
+ target.focus();
38
+ onValueChange?.(target.value);
39
+ };
18
40
  const classes = [
19
41
  'llm-radio-group',
20
42
  `orientation-${orientation}`,
@@ -33,7 +55,7 @@ export function LlmRadioGroup({ value = '', onValueChange, orientation = 'vertic
33
55
  invalid,
34
56
  onSelect: (v) => !disabled && !readOnly && onValueChange?.(v),
35
57
  onBlur: () => undefined,
36
- }, children: _jsxs("div", { className: classes, role: "radiogroup", "aria-invalid": invalid || undefined, "aria-required": required || undefined, ...rest, children: [children, errors.length > 0 && (_jsx("div", { className: "errors", role: "alert", "aria-live": "polite", children: errors.map((err, i) => (_jsx("p", { className: "error-message", children: err }, i))) }))] }) }));
58
+ }, children: _jsxs("div", { ref: groupRef, className: classes, role: "radiogroup", "aria-invalid": invalid || undefined, "aria-required": required || undefined, onKeyDown: handleKeyDown, ...rest, children: [children, errors.length > 0 && (_jsx("div", { className: "errors", role: "alert", "aria-live": "polite", children: errors.map((err, i) => (_jsx("p", { className: "error-message", children: err }, i))) }))] }) }));
37
59
  }
38
60
  export function useRadioGroup() {
39
61
  return useContext(RadioGroupContext);
@@ -1 +1 @@
1
- {"version":3,"file":"llm-radio-group.js","sourceRoot":"","sources":["../../../../../../libs/react/src/lib/radio-group/llm-radio-group.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,aAAa,EAAE,UAAU,EAAkC,MAAM,OAAO,CAAC;AAElF,OAAO,uBAAuB,CAAC;AAoC/B,MAAM,CAAC,MAAM,iBAAiB,GAAG,aAAa,CAAyB;IACrE,KAAK,EAAE,EAAE;IACT,IAAI,EAAE,EAAE;IACR,QAAQ,EAAE,KAAK;IACf,QAAQ,EAAE,KAAK;IACf,OAAO,EAAE,KAAK;IACd,QAAQ,EAAE,GAAG,EAAE,CAAC,SAAS;IACzB,MAAM,EAAE,GAAG,EAAE,CAAC,SAAS;CACxB,CAAC,CAAC;AAkDH;;GAEG;AACH,MAAM,UAAU,aAAa,CAAC,EAC5B,KAAK,GAAG,EAAE,EACV,aAAa,EACb,WAAW,GAAG,UAAU,EACxB,IAAI,GAAG,EAAE,EACT,QAAQ,GAAG,KAAK,EAChB,QAAQ,EAAE,aAAa,EACvB,QAAQ,EAAE,YAAY,EACtB,OAAO,GAAG,KAAK,EACf,QAAQ,GAAG,KAAK,EAChB,MAAM,GAAG,EAAE,EACX,QAAQ,EACR,SAAS,EACT,GAAG,IAAI,EACY;IACnB,MAAM,QAAQ,GAAG,aAAa,IAAI,YAAY,IAAI,KAAK,CAAC;IACxD,MAAM,OAAO,GAAG;QACd,iBAAiB;QACjB,eAAe,WAAW,EAAE;QAC5B,OAAO,IAAI,YAAY;QACvB,QAAQ,IAAI,aAAa;QACzB,QAAQ,IAAI,aAAa;QACzB,SAAS;KACV;SACE,MAAM,CAAC,OAAO,CAAC;SACf,IAAI,CAAC,GAAG,CAAC,CAAC;IAEb,OAAO,CACL,KAAC,iBAAiB,CAAC,QAAQ,IACzB,KAAK,EAAE;YACL,KAAK;YACL,IAAI;YACJ,QAAQ;YACR,QAAQ;YACR,OAAO;YACP,QAAQ,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,QAAQ,IAAI,CAAC,QAAQ,IAAI,aAAa,EAAE,CAAC,CAAC,CAAC;YAC7D,MAAM,EAAE,GAAG,EAAE,CAAC,SAAS;SACxB,YAED,eACE,SAAS,EAAE,OAAO,EAClB,IAAI,EAAC,YAAY,kBACH,OAAO,IAAI,SAAS,mBACnB,QAAQ,IAAI,SAAS,KAChC,IAAI,aAEP,QAAQ,EACR,MAAM,CAAC,MAAM,GAAG,CAAC,IAAI,CACpB,cAAK,SAAS,EAAC,QAAQ,EAAC,IAAI,EAAC,OAAO,eAAW,QAAQ,YACpD,MAAM,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC,CACtB,YAAW,SAAS,EAAC,eAAe,YACjC,GAAG,IADE,CAAC,CAEL,CACL,CAAC,GACE,CACP,IACG,GACqB,CAC9B,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,aAAa;IAC3B,OAAO,UAAU,CAAC,iBAAiB,CAAC,CAAC;AACvC,CAAC","sourcesContent":["import { createContext, useContext, InputHTMLAttributes, ReactNode } from 'react';\nimport type { LlmRadioGroupSpec } from '../spec';\nimport './llm-radio-group.css';\n\n/**\n * Interface for the RadioGroup context.\n */\nexport interface RadioGroupContextValue {\n /**\n * The currently selected value.\n */\n value: string;\n /**\n * The name of the radio group.\n */\n name: string;\n /**\n * Whether the entire radio group is disabled.\n */\n disabled: boolean;\n /**\n * Whether the entire radio group is read-only.\n */\n readOnly: boolean;\n /**\n * Whether the radio group is in an invalid state.\n */\n invalid: boolean;\n /**\n * Callback to select a value.\n */\n onSelect: (value: string) => void;\n /**\n * Callback triggered on blur.\n */\n onBlur: () => void;\n}\n\nexport const RadioGroupContext = createContext<RadioGroupContextValue>({\n value: '',\n name: '',\n disabled: false,\n readOnly: false,\n invalid: false,\n onSelect: () => undefined,\n onBlur: () => undefined,\n});\n\n/**\n * Properties for the LlmRadioGroup component.\n */\nexport interface LlmRadioGroupProps\n extends Omit<InputHTMLAttributes<HTMLDivElement>, 'onChange'>,\n LlmRadioGroupSpec {\n /**\n * The current value of the radio group.\n */\n value?: string;\n /**\n * Callback triggered when the value changes.\n */\n onValueChange?: (value: string) => void;\n /**\n * The layout orientation of the radio group.\n */\n orientation?: 'horizontal' | 'vertical';\n /**\n * The name of the radio group, applied to all child radio buttons.\n */\n name?: string;\n /**\n * Whether the radio group is disabled.\n */\n disabled?: boolean;\n /**\n * Whether the radio group is read-only.\n */\n readOnly?: boolean;\n /**\n * Whether the radio group is in an invalid state.\n */\n invalid?: boolean;\n /**\n * Whether a value is required.\n */\n required?: boolean;\n /**\n * Array of error messages to display.\n */\n errors?: string[];\n /**\n * The radio buttons to be rendered.\n */\n children?: ReactNode;\n}\n\n/**\n * A group of radio buttons.\n */\nexport function LlmRadioGroup({\n value = '',\n onValueChange,\n orientation = 'vertical',\n name = '',\n disabled = false,\n readOnly: reactReadOnly,\n readonly: specReadOnly,\n invalid = false,\n required = false,\n errors = [],\n children,\n className,\n ...rest\n}: LlmRadioGroupProps) {\n const readOnly = reactReadOnly ?? specReadOnly ?? false;\n const classes = [\n 'llm-radio-group',\n `orientation-${orientation}`,\n invalid && 'is-invalid',\n disabled && 'is-disabled',\n readOnly && 'is-readonly',\n className,\n ]\n .filter(Boolean)\n .join(' ');\n\n return (\n <RadioGroupContext.Provider\n value={{\n value,\n name,\n disabled,\n readOnly,\n invalid,\n onSelect: (v) => !disabled && !readOnly && onValueChange?.(v),\n onBlur: () => undefined,\n }}\n >\n <div\n className={classes}\n role=\"radiogroup\"\n aria-invalid={invalid || undefined}\n aria-required={required || undefined}\n {...rest}\n >\n {children}\n {errors.length > 0 && (\n <div className=\"errors\" role=\"alert\" aria-live=\"polite\">\n {errors.map((err, i) => (\n <p key={i} className=\"error-message\">\n {err}\n </p>\n ))}\n </div>\n )}\n </div>\n </RadioGroupContext.Provider>\n );\n}\n\nexport function useRadioGroup(): RadioGroupContextValue {\n return useContext(RadioGroupContext);\n}\n"]}
1
+ {"version":3,"file":"llm-radio-group.js","sourceRoot":"","sources":["../../../../../../libs/react/src/lib/radio-group/llm-radio-group.tsx"],"names":[],"mappings":"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","sourcesContent":["import {\n createContext,\n useContext,\n useRef,\n type KeyboardEvent,\n InputHTMLAttributes,\n ReactNode,\n} from 'react';\nimport type { LlmRadioGroupSpec } from '../spec';\nimport './llm-radio-group.css';\n\n/**\n * Interface for the RadioGroup context.\n */\nexport interface RadioGroupContextValue {\n /**\n * The currently selected value.\n */\n value: string;\n /**\n * The name of the radio group.\n */\n name: string;\n /**\n * Whether the entire radio group is disabled.\n */\n disabled: boolean;\n /**\n * Whether the entire radio group is read-only.\n */\n readOnly: boolean;\n /**\n * Whether the radio group is in an invalid state.\n */\n invalid: boolean;\n /**\n * Callback to select a value.\n */\n onSelect: (value: string) => void;\n /**\n * Callback triggered on blur.\n */\n onBlur: () => void;\n}\n\nexport const RadioGroupContext = createContext<RadioGroupContextValue>({\n value: '',\n name: '',\n disabled: false,\n readOnly: false,\n invalid: false,\n onSelect: () => undefined,\n onBlur: () => undefined,\n});\n\n/**\n * Properties for the LlmRadioGroup component.\n */\nexport interface LlmRadioGroupProps\n extends Omit<InputHTMLAttributes<HTMLDivElement>, 'onChange'>,\n LlmRadioGroupSpec {\n /**\n * The current value of the radio group.\n */\n value?: string;\n /**\n * Callback triggered when the value changes.\n */\n onValueChange?: (value: string) => void;\n /**\n * The layout orientation of the radio group.\n */\n orientation?: 'horizontal' | 'vertical';\n /**\n * The name of the radio group, applied to all child radio buttons.\n */\n name?: string;\n /**\n * Whether the radio group is disabled.\n */\n disabled?: boolean;\n /**\n * Whether the radio group is read-only.\n */\n readOnly?: boolean;\n /**\n * Whether the radio group is in an invalid state.\n */\n invalid?: boolean;\n /**\n * Whether a value is required.\n */\n required?: boolean;\n /**\n * Array of error messages to display.\n */\n errors?: string[];\n /**\n * The radio buttons to be rendered.\n */\n children?: ReactNode;\n}\n\n/**\n * A group of radio buttons.\n */\nexport function LlmRadioGroup({\n value = '',\n onValueChange,\n orientation = 'vertical',\n name = '',\n disabled = false,\n readOnly: reactReadOnly,\n readonly: specReadOnly,\n invalid = false,\n required = false,\n errors = [],\n children,\n className,\n ...rest\n}: LlmRadioGroupProps) {\n const readOnly = reactReadOnly ?? specReadOnly ?? false;\n const groupRef = useRef<HTMLDivElement>(null);\n\n // Roving arrow-key navigation per the WAI-ARIA radiogroup pattern: Arrow\n // Down/Right move to the next enabled radio, Up/Left to the previous, both\n // wrapping, and the navigated radio is selected and focused.\n const handleKeyDown = (event: KeyboardEvent<HTMLDivElement>) => {\n if (disabled || readOnly) return;\n const forward = event.key === 'ArrowDown' || event.key === 'ArrowRight';\n const backward = event.key === 'ArrowUp' || event.key === 'ArrowLeft';\n if (!forward && !backward) return;\n const radios = Array.from(\n groupRef.current?.querySelectorAll<HTMLInputElement>('input[type=\"radio\"]') ?? []\n ).filter((radio) => !radio.disabled);\n if (radios.length === 0) return;\n event.preventDefault();\n const currentIdx = radios.findIndex((radio) => radio.value === value);\n const start = currentIdx === -1 ? (forward ? -1 : 0) : currentIdx;\n const nextIdx = (start + (forward ? 1 : -1) + radios.length) % radios.length;\n const target = radios[nextIdx];\n target.focus();\n onValueChange?.(target.value);\n };\n\n const classes = [\n 'llm-radio-group',\n `orientation-${orientation}`,\n invalid && 'is-invalid',\n disabled && 'is-disabled',\n readOnly && 'is-readonly',\n className,\n ]\n .filter(Boolean)\n .join(' ');\n\n return (\n <RadioGroupContext.Provider\n value={{\n value,\n name,\n disabled,\n readOnly,\n invalid,\n onSelect: (v) => !disabled && !readOnly && onValueChange?.(v),\n onBlur: () => undefined,\n }}\n >\n <div\n ref={groupRef}\n className={classes}\n role=\"radiogroup\"\n aria-invalid={invalid || undefined}\n aria-required={required || undefined}\n onKeyDown={handleKeyDown}\n {...rest}\n >\n {children}\n {errors.length > 0 && (\n <div className=\"errors\" role=\"alert\" aria-live=\"polite\">\n {errors.map((err, i) => (\n <p key={i} className=\"error-message\">\n {err}\n </p>\n ))}\n </div>\n )}\n </div>\n </RadioGroupContext.Provider>\n );\n}\n\nexport function useRadioGroup(): RadioGroupContextValue {\n return useContext(RadioGroupContext);\n}\n"]}