no-frills-ui 0.0.14-rc.1 → 0.0.14-rc.2

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 (51) hide show
  1. package/dist/index.js +365 -169
  2. package/dist/index.js.map +1 -1
  3. package/lib-esm/components/Chip/Chip.js +2 -2
  4. package/lib-esm/components/ChipInput/ChipInput.js +12 -5
  5. package/lib-esm/components/ChipInput/ChipInput.js.map +1 -1
  6. package/lib-esm/components/DragAndDrop/DragAndDrop.js +2 -2
  7. package/lib-esm/components/DragAndDrop/DragItem.js +2 -2
  8. package/lib-esm/components/Drawer/Drawer.d.ts +1 -1
  9. package/lib-esm/components/Drawer/Drawer.js +2 -3
  10. package/lib-esm/components/Drawer/Drawer.js.map +1 -1
  11. package/lib-esm/components/Groups/Group.js +3 -3
  12. package/lib-esm/components/Groups/Group.js.map +1 -1
  13. package/lib-esm/components/Input/Checkbox.d.ts +2 -0
  14. package/lib-esm/components/Input/Checkbox.js +54 -23
  15. package/lib-esm/components/Input/Checkbox.js.map +1 -1
  16. package/lib-esm/components/Input/Dropdown.d.ts +2 -0
  17. package/lib-esm/components/Input/Dropdown.js +123 -59
  18. package/lib-esm/components/Input/Dropdown.js.map +1 -1
  19. package/lib-esm/components/Input/Input.js +17 -8
  20. package/lib-esm/components/Input/Input.js.map +1 -1
  21. package/lib-esm/components/Input/Radio.d.ts +2 -0
  22. package/lib-esm/components/Input/Radio.js +22 -10
  23. package/lib-esm/components/Input/Radio.js.map +1 -1
  24. package/lib-esm/components/Input/RadioButton.d.ts +2 -0
  25. package/lib-esm/components/Input/RadioButton.js +21 -9
  26. package/lib-esm/components/Input/RadioButton.js.map +1 -1
  27. package/lib-esm/components/Input/Select.js +21 -11
  28. package/lib-esm/components/Input/Select.js.map +1 -1
  29. package/lib-esm/components/Input/TextArea.js +17 -8
  30. package/lib-esm/components/Input/TextArea.js.map +1 -1
  31. package/lib-esm/components/Input/Toggle.d.ts +2 -0
  32. package/lib-esm/components/Input/Toggle.js +45 -15
  33. package/lib-esm/components/Input/Toggle.js.map +1 -1
  34. package/lib-esm/components/Input/index.d.ts +1 -0
  35. package/lib-esm/components/Menu/MenuItem.d.ts +1 -1
  36. package/lib-esm/components/Menu/MenuItem.js +1 -1
  37. package/lib-esm/components/Menu/MenuItem.js.map +1 -1
  38. package/lib-esm/components/Modal/Modal.d.ts +1 -1
  39. package/lib-esm/components/Modal/Modal.js +1 -2
  40. package/lib-esm/components/Modal/Modal.js.map +1 -1
  41. package/lib-esm/components/Popover/Popover.d.ts +1 -1
  42. package/lib-esm/components/Popover/Popover.js +3 -3
  43. package/lib-esm/components/Popover/Popover.js.map +1 -1
  44. package/lib-esm/components/Stepper/Stepper.js +14 -5
  45. package/lib-esm/components/Stepper/Stepper.js.map +1 -1
  46. package/lib-esm/index.js +1 -1
  47. package/lib-esm/shared/LayerManager.js +2 -2
  48. package/lib-esm/shared/styles.d.ts +4 -0
  49. package/lib-esm/shared/styles.js +10 -6
  50. package/lib-esm/shared/styles.js.map +1 -1
  51. package/package.json +2 -2
@@ -1,5 +1,5 @@
1
1
  import { jsx, jsxs, Fragment } from '@emotion/react/jsx-runtime';
2
- import React, { useState, useEffect } from 'react';
2
+ import React, { useState, useRef, useEffect } from 'react';
3
3
  import styled from '@emotion/styled';
4
4
  import Input from './Input.js';
5
5
  import Popover, { POPOVER_POSITION } from '../Popover/Popover.js';
@@ -7,9 +7,63 @@ import Menu from '../Menu/Menu.js';
7
7
  import ExpandMore from '../../icons/ExpandMore.js';
8
8
 
9
9
  const ArrowContainer = /*#__PURE__*/ styled("span", {
10
- target: "e1d5dyoc0",
10
+ target: "eph6dat0",
11
11
  label: "ArrowContainer"
12
12
  })("position:absolute;right:12px;top:16px;pointer-events:none;");
13
+ /**
14
+ * DropdownTrigger Component
15
+ */ const DropdownTrigger = /*#__PURE__*/ React.forwardRef((props, ref)=>{
16
+ const { displayValue, label, errorText, open, menuId, toggleOpen, onKeyDown, forwardedRef, ...rest } = props;
17
+ const triggerRef = React.useRef(null);
18
+ // Helper to assign both internal triggerRef and external forwarded ref
19
+ const assignRefs = React.useCallback((node)=>{
20
+ triggerRef.current = node;
21
+ if (!forwardedRef) return;
22
+ if (typeof forwardedRef === 'function') {
23
+ forwardedRef(node);
24
+ } else {
25
+ forwardedRef.current = node;
26
+ }
27
+ }, [
28
+ forwardedRef
29
+ ]);
30
+ // Combine the ref passed by parent with our assignRefs so both are updated
31
+ const combinedRef = React.useCallback((node)=>{
32
+ assignRefs(node);
33
+ if (typeof ref === 'function') {
34
+ ref(node);
35
+ } else if (ref) {
36
+ ref.current = node;
37
+ }
38
+ }, [
39
+ assignRefs,
40
+ ref
41
+ ]);
42
+ return /*#__PURE__*/ jsxs(Fragment, {
43
+ children: [
44
+ /*#__PURE__*/ jsx(Input, {
45
+ ...rest,
46
+ ref: combinedRef,
47
+ type: "text",
48
+ value: displayValue,
49
+ label: label,
50
+ errorText: errorText,
51
+ onClick: toggleOpen,
52
+ onKeyDown: onKeyDown,
53
+ inputMode: "none",
54
+ role: "combobox",
55
+ "aria-haspopup": "listbox",
56
+ "aria-expanded": open,
57
+ "aria-controls": menuId
58
+ }),
59
+ /*#__PURE__*/ jsx(ArrowContainer, {
60
+ "aria-hidden": "true",
61
+ children: /*#__PURE__*/ jsx(ExpandMore, {})
62
+ })
63
+ ]
64
+ });
65
+ });
66
+ DropdownTrigger.displayName = 'DropdownTrigger';
13
67
  /**
14
68
  * Dropdown component that allows selection from a list of options.
15
69
  * Supports single and multi-select modes.
@@ -17,11 +71,6 @@ const ArrowContainer = /*#__PURE__*/ styled("span", {
17
71
  * @template T - The type of the value(s) in the dropdown.
18
72
  * @param props - The properties for the Dropdown component.
19
73
  * @returns The rendered Dropdown component.
20
- */ /**
21
- * Dropdown Component
22
- * @template T - The type of value(s) in the dropdown.
23
- * @param props - Component props
24
- * @param outerRef - Ref forwarded to the underlying HTMLInputElement
25
74
  */ function DropdownComponent(props, outerRef) {
26
75
  const { multiSelect = false, onChange, children, value: propValue, label, errorText, required, disabled, ...rest } = props;
27
76
  const [open, setOpen] = useState(false);
@@ -30,6 +79,42 @@ const ArrowContainer = /*#__PURE__*/ styled("span", {
30
79
  const menuId = `${id}-menu`;
31
80
  const menuRef = React.useRef(null);
32
81
  const triggerRef = React.useRef(null);
82
+ /**
83
+ * Gets the display value for the dropdown based on the current value and children.
84
+ *
85
+ * @param currentValue - The current value of the dropdown.
86
+ * @param currentChildren - The children of the dropdown.
87
+ * @returns The display value.
88
+ */ const getDisplayValue = (currentValue, currentChildren)=>{
89
+ if (currentValue === undefined || currentValue === null) return '';
90
+ const findLabel = (val)=>{
91
+ let label = '';
92
+ React.Children.forEach(currentChildren, (child)=>{
93
+ if (/*#__PURE__*/ React.isValidElement(child)) {
94
+ const props = child.props;
95
+ if ('value' in props && props.value === val) {
96
+ label = String(props.children);
97
+ }
98
+ }
99
+ });
100
+ return label;
101
+ };
102
+ if (Array.isArray(currentValue)) {
103
+ return currentValue.map(findLabel).filter(Boolean).join(', ');
104
+ }
105
+ return findLabel(currentValue);
106
+ };
107
+ const displayValue = getDisplayValue(value, children) || (value ? String(value) : '');
108
+ // Sync prop value with state
109
+ const prevValueRef = useRef(undefined);
110
+ useEffect(()=>{
111
+ if (propValue !== prevValueRef.current) {
112
+ setValue(propValue);
113
+ prevValueRef.current = propValue;
114
+ }
115
+ }, [
116
+ propValue
117
+ ]);
33
118
  // Focus menu when opened
34
119
  useEffect(()=>{
35
120
  if (open) {
@@ -51,7 +136,7 @@ const ArrowContainer = /*#__PURE__*/ styled("span", {
51
136
  * Opens the menu on 'Enter', 'Space', 'ArrowDown', or 'ArrowUp'.
52
137
  *
53
138
  * @param {React.KeyboardEvent<HTMLInputElement>} e - The keyboard event.
54
- */ const onKeyDown = (e)=>{
139
+ */ const onKeyDown = React.useCallback((e)=>{
55
140
  if ([
56
141
  'ArrowDown',
57
142
  'ArrowUp',
@@ -60,8 +145,11 @@ const ArrowContainer = /*#__PURE__*/ styled("span", {
60
145
  ].includes(e.key)) {
61
146
  e.preventDefault();
62
147
  setOpen(true);
148
+ } else if (e.key !== 'Tab') {
149
+ // Prevent typing to mimic readOnly behavior while allowing native validation
150
+ e.preventDefault();
63
151
  }
64
- };
152
+ }, []);
65
153
  /**
66
154
  * Handles changes to the dropdown value.
67
155
  * Updates local state and calls the external onChange handler.
@@ -79,59 +167,35 @@ const ArrowContainer = /*#__PURE__*/ styled("span", {
79
167
  };
80
168
  /**
81
169
  * Toggles the dropdown open state on click.
82
- */ const clickHandler = ()=>setOpen(true);
83
- const TriggerElement = /*#__PURE__*/ React.forwardRef((passedProps, ref)=>{
84
- // Helper to assign both internal triggerRef and external forwarded ref
85
- const assignRefs = (node)=>{
86
- triggerRef.current = node;
87
- if (!outerRef) return;
88
- if (typeof outerRef === 'function') {
89
- outerRef(node);
90
- } else {
91
- outerRef.current = node;
92
- }
93
- };
94
- // Combine the ref passed by parent with our assignRefs so both are updated
95
- const combinedRef = (node)=>{
96
- assignRefs(node);
97
- if (typeof ref === 'function') {
98
- ref(node);
99
- } else if (ref) {
100
- ref.current = node;
101
- }
102
- };
103
- return /*#__PURE__*/ jsxs(Fragment, {
104
- children: [
105
- /*#__PURE__*/ jsx(Input, {
106
- ...rest,
107
- ...passedProps,
108
- ref: combinedRef,
109
- type: "text",
110
- value: value && String(value),
111
- label: label,
112
- errorText: errorText,
113
- onClick: clickHandler,
114
- onKeyDown: onKeyDown,
115
- required: required,
116
- disabled: disabled,
117
- readOnly: true,
118
- role: "combobox",
119
- "aria-haspopup": "listbox",
120
- "aria-expanded": open,
121
- "aria-controls": menuId
122
- }),
123
- /*#__PURE__*/ jsx(ArrowContainer, {
124
- "aria-hidden": "true",
125
- children: /*#__PURE__*/ jsx(ExpandMore, {})
126
- })
127
- ]
128
- });
129
- });
130
- TriggerElement.displayName = 'DropdownTrigger';
170
+ */ const clickHandler = React.useCallback(()=>setOpen(true), []);
171
+ /**
172
+ * Forwarded ref handler for the trigger input.
173
+ */ const handleForwardedRef = React.useCallback((node)=>{
174
+ triggerRef.current = node;
175
+ if (typeof outerRef === 'function') {
176
+ outerRef(node);
177
+ } else if (outerRef) {
178
+ outerRef.current = node;
179
+ }
180
+ }, [
181
+ outerRef
182
+ ]);
131
183
  return /*#__PURE__*/ jsx(Popover, {
132
184
  position: POPOVER_POSITION.BOTTOM_LEFT,
133
185
  open: open,
134
- element: TriggerElement,
186
+ element: /*#__PURE__*/ jsx(DropdownTrigger, {
187
+ ...rest,
188
+ displayValue: displayValue,
189
+ label: label,
190
+ errorText: errorText,
191
+ open: open,
192
+ menuId: menuId,
193
+ toggleOpen: clickHandler,
194
+ onKeyDown: onKeyDown,
195
+ required: required,
196
+ disabled: disabled,
197
+ forwardedRef: handleForwardedRef
198
+ }),
135
199
  onClose: ()=>{
136
200
  setOpen(false);
137
201
  triggerRef.current?.focus();
@@ -1 +1 @@
1
- {"version":3,"file":"Dropdown.js","sources":["../../../src/components/Input/Dropdown.tsx"],"sourcesContent":["import React, { useEffect, useState } from 'react';\nimport styled from '@emotion/styled';\nimport { ExpandMore } from '../../icons';\nimport { Menu } from '../Menu';\nimport { Popover, POPOVER_POSITION } from '../Popover';\nimport Input from './Input';\n\ntype DropdownProps<T> = React.PropsWithChildren<{\n /** Value of the control */\n value?: T | T[];\n /**\n * If multiple elements can be selected\n * @default false\n */\n multiSelect?: boolean;\n /** Change handler */\n onChange?: (v: T | T[]) => void;\n /** Label of the control */\n label?: string;\n /** Error message */\n errorText?: string;\n /** Makes field required */\n required?: boolean;\n /** Disables the field */\n disabled?: boolean;\n}> &\n Omit<React.InputHTMLAttributes<HTMLInputElement>, 'value'>;\n\nconst ArrowContainer = styled.span`\n position: absolute;\n right: 12px;\n top: 16px;\n pointer-events: none;\n`;\n\n/**\n * Dropdown component that allows selection from a list of options.\n * Supports single and multi-select modes.\n *\n * @template T - The type of the value(s) in the dropdown.\n * @param props - The properties for the Dropdown component.\n * @returns The rendered Dropdown component.\n */\n/**\n * Dropdown Component\n * @template T - The type of value(s) in the dropdown.\n * @param props - Component props\n * @param outerRef - Ref forwarded to the underlying HTMLInputElement\n */\nfunction DropdownComponent<T extends object>(\n props: DropdownProps<T>,\n outerRef: React.Ref<HTMLInputElement>,\n) {\n const {\n multiSelect = false,\n onChange,\n children,\n value: propValue,\n label,\n errorText,\n required,\n disabled,\n ...rest\n } = props;\n const [open, setOpen] = useState(false);\n const [value, setValue] = useState<T | T[] | undefined>(propValue);\n const id = React.useId();\n const menuId = `${id}-menu`;\n const menuRef = React.useRef<HTMLDivElement | null>(null);\n const triggerRef = React.useRef<HTMLInputElement | null>(null);\n\n // Focus menu when opened\n useEffect(() => {\n if (open) {\n // Wait for Popover to fully open and focus itself first\n // Then move focus to the first menu item\n const timer = setTimeout(() => {\n const firstItem = menuRef.current?.querySelector('[role=\"option\"]') as HTMLElement;\n if (firstItem) {\n firstItem.focus();\n }\n }, 100); // Wait after Popover has set initial focus\n return () => clearTimeout(timer);\n }\n }, [open]);\n\n /**\n * Handles keydown events on the input trigger.\n * Opens the menu on 'Enter', 'Space', 'ArrowDown', or 'ArrowUp'.\n *\n * @param {React.KeyboardEvent<HTMLInputElement>} e - The keyboard event.\n */\n const onKeyDown = (e: React.KeyboardEvent<HTMLInputElement>) => {\n if (['ArrowDown', 'ArrowUp', 'Enter', ' '].includes(e.key)) {\n e.preventDefault();\n setOpen(true);\n }\n };\n\n /**\n * Handles changes to the dropdown value.\n * Updates local state and calls the external onChange handler.\n * Closes the dropdown if not in multi-select mode.\n *\n * @param {T | T[]} val - The new value(s).\n */\n const changeHandler = (val: T | T[]) => {\n setValue(val);\n onChange?.(val);\n\n // Close dropdown after selection if not multiSelect\n if (!multiSelect) {\n setOpen(false);\n triggerRef.current?.focus();\n }\n };\n\n /**\n * Toggles the dropdown open state on click.\n */\n const clickHandler = () => setOpen(true);\n\n const TriggerElement = React.forwardRef<HTMLInputElement>((passedProps, ref) => {\n // Helper to assign both internal triggerRef and external forwarded ref\n const assignRefs = (node: HTMLInputElement | null) => {\n triggerRef.current = node;\n\n if (!outerRef) return;\n if (typeof outerRef === 'function') {\n outerRef(node);\n } else {\n (outerRef as React.MutableRefObject<HTMLInputElement | null>).current = node;\n }\n };\n\n // Combine the ref passed by parent with our assignRefs so both are updated\n const combinedRef: React.Ref<HTMLInputElement> = (node) => {\n assignRefs(node);\n if (typeof ref === 'function') {\n ref(node);\n } else if (ref) {\n (ref as React.MutableRefObject<HTMLInputElement | null>).current = node;\n }\n };\n\n return (\n <>\n <Input\n {...rest}\n {...passedProps}\n ref={combinedRef}\n type=\"text\"\n value={value && String(value)}\n label={label}\n errorText={errorText}\n onClick={clickHandler}\n onKeyDown={onKeyDown}\n required={required}\n disabled={disabled}\n readOnly\n role=\"combobox\"\n aria-haspopup=\"listbox\"\n aria-expanded={open}\n aria-controls={menuId}\n />\n <ArrowContainer aria-hidden=\"true\">\n <ExpandMore />\n </ArrowContainer>\n </>\n );\n });\n TriggerElement.displayName = 'DropdownTrigger';\n\n return (\n <Popover\n position={POPOVER_POSITION.BOTTOM_LEFT}\n open={open}\n element={TriggerElement}\n onClose={() => {\n setOpen(false);\n triggerRef.current?.focus();\n }}\n >\n <Menu\n ref={menuRef}\n id={menuId}\n value={value}\n multiSelect={multiSelect}\n onChange={changeHandler}\n >\n {children}\n </Menu>\n </Popover>\n );\n}\n\nconst Dropdown = React.forwardRef(DropdownComponent) as <T>(\n props: DropdownProps<T> & React.RefAttributes<HTMLInputElement>,\n) => React.ReactElement | null;\nexport default Dropdown;\n"],"names":["ArrowContainer","styled","DropdownComponent","props","outerRef","multiSelect","onChange","children","value","propValue","label","errorText","required","disabled","rest","open","setOpen","useState","setValue","id","React","useId","menuId","menuRef","useRef","triggerRef","useEffect","timer","setTimeout","firstItem","current","querySelector","focus","clearTimeout","onKeyDown","e","includes","key","preventDefault","changeHandler","val","clickHandler","TriggerElement","forwardRef","passedProps","ref","assignRefs","node","combinedRef","_jsxs","_Fragment","_jsx","Input","type","String","onClick","readOnly","role","aria-haspopup","aria-expanded","aria-controls","aria-hidden","ExpandMore","displayName","Popover","position","POPOVER_POSITION","BOTTOM_LEFT","element","onClose","Menu","Dropdown"],"mappings":"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"}
1
+ {"version":3,"file":"Dropdown.js","sources":["../../../src/components/Input/Dropdown.tsx"],"sourcesContent":["import React, { useEffect, useRef, useState } from 'react';\nimport styled from '@emotion/styled';\nimport { ExpandMore } from '../../icons';\nimport { Menu } from '../Menu';\nimport { MenuItemProps } from '../Menu/MenuItem';\nimport { Popover, POPOVER_POSITION } from '../Popover';\nimport Input from './Input';\n\ntype DropdownProps<T> = React.PropsWithChildren<{\n /** Value of the control */\n value?: T | T[];\n /**\n * If multiple elements can be selected\n * @default false\n */\n multiSelect?: boolean;\n /** Change handler */\n onChange?: (v: T | T[]) => void;\n /** Label of the control */\n label?: string;\n /** Error message */\n errorText?: string;\n /** Makes field required */\n required?: boolean;\n /** Disables the field */\n disabled?: boolean;\n children?: React.ReactElement<MenuItemProps<T>> | React.ReactElement<MenuItemProps<T>>[];\n}> &\n Omit<React.InputHTMLAttributes<HTMLInputElement>, 'value'>;\n\nconst ArrowContainer = styled.span`\n position: absolute;\n right: 12px;\n top: 16px;\n pointer-events: none;\n`;\n\n/**\n * DropdownTrigger Component\n */\nconst DropdownTrigger = React.forwardRef<\n HTMLInputElement,\n Omit<React.InputHTMLAttributes<HTMLInputElement>, 'value'> & {\n displayValue: string;\n label?: string;\n errorText?: string;\n open: boolean;\n menuId: string;\n toggleOpen: () => void;\n onKeyDown: (e: React.KeyboardEvent<HTMLInputElement>) => void;\n forwardedRef?: React.Ref<HTMLInputElement>;\n }\n>((props, ref) => {\n const {\n displayValue,\n label,\n errorText,\n open,\n menuId,\n toggleOpen,\n onKeyDown,\n forwardedRef,\n ...rest\n } = props;\n const triggerRef = React.useRef<HTMLInputElement | null>(null);\n\n // Helper to assign both internal triggerRef and external forwarded ref\n const assignRefs = React.useCallback(\n (node: HTMLInputElement | null) => {\n triggerRef.current = node;\n\n if (!forwardedRef) return;\n if (typeof forwardedRef === 'function') {\n forwardedRef(node);\n } else {\n (forwardedRef as React.MutableRefObject<HTMLInputElement | null>).current = node;\n }\n },\n [forwardedRef],\n );\n\n // Combine the ref passed by parent with our assignRefs so both are updated\n const combinedRef = React.useCallback(\n (node: HTMLInputElement | null) => {\n assignRefs(node);\n if (typeof ref === 'function') {\n ref(node);\n } else if (ref) {\n (ref as React.MutableRefObject<HTMLInputElement | null>).current = node;\n }\n },\n [assignRefs, ref],\n );\n\n return (\n <>\n <Input\n {...rest}\n ref={combinedRef}\n type=\"text\"\n value={displayValue}\n label={label}\n errorText={errorText}\n onClick={toggleOpen}\n onKeyDown={onKeyDown}\n inputMode=\"none\"\n role=\"combobox\"\n aria-haspopup=\"listbox\"\n aria-expanded={open}\n aria-controls={menuId}\n />\n <ArrowContainer aria-hidden=\"true\">\n <ExpandMore />\n </ArrowContainer>\n </>\n );\n});\nDropdownTrigger.displayName = 'DropdownTrigger';\n\n/**\n * Dropdown component that allows selection from a list of options.\n * Supports single and multi-select modes.\n *\n * @template T - The type of the value(s) in the dropdown.\n * @param props - The properties for the Dropdown component.\n * @returns The rendered Dropdown component.\n */\nfunction DropdownComponent<T extends object>(\n props: DropdownProps<T>,\n outerRef: React.Ref<HTMLInputElement>,\n) {\n const {\n multiSelect = false,\n onChange,\n children,\n value: propValue,\n label,\n errorText,\n required,\n disabled,\n ...rest\n } = props;\n const [open, setOpen] = useState(false);\n const [value, setValue] = useState<T | T[] | undefined>(propValue);\n const id = React.useId();\n const menuId = `${id}-menu`;\n const menuRef = React.useRef<HTMLDivElement | null>(null);\n const triggerRef = React.useRef<HTMLInputElement | null>(null);\n\n /**\n * Gets the display value for the dropdown based on the current value and children.\n *\n * @param currentValue - The current value of the dropdown.\n * @param currentChildren - The children of the dropdown.\n * @returns The display value.\n */\n const getDisplayValue = (\n currentValue: T | T[] | undefined,\n currentChildren: React.ReactNode,\n ): string => {\n if (currentValue === undefined || currentValue === null) return '';\n\n const findLabel = (val: T): string => {\n let label = '';\n React.Children.forEach(currentChildren, (child) => {\n if (React.isValidElement(child)) {\n const props = child.props as MenuItemProps<T> & React.PropsWithChildren;\n if ('value' in props && props.value === val) {\n label = String(props.children);\n }\n }\n });\n return label;\n };\n\n if (Array.isArray(currentValue)) {\n return currentValue.map(findLabel).filter(Boolean).join(', ');\n }\n\n return findLabel(currentValue as T);\n };\n\n const displayValue = getDisplayValue(value, children) || (value ? String(value) : '');\n\n // Sync prop value with state\n const prevValueRef = useRef<T | T[] | undefined>(undefined);\n useEffect(() => {\n if (propValue !== prevValueRef.current) {\n setValue(propValue);\n prevValueRef.current = propValue;\n }\n }, [propValue]);\n\n // Focus menu when opened\n useEffect(() => {\n if (open) {\n // Wait for Popover to fully open and focus itself first\n // Then move focus to the first menu item\n const timer = setTimeout(() => {\n const firstItem = menuRef.current?.querySelector('[role=\"option\"]') as HTMLElement;\n if (firstItem) {\n firstItem.focus();\n }\n }, 100); // Wait after Popover has set initial focus\n return () => clearTimeout(timer);\n }\n }, [open]);\n\n /**\n * Handles keydown events on the input trigger.\n * Opens the menu on 'Enter', 'Space', 'ArrowDown', or 'ArrowUp'.\n *\n * @param {React.KeyboardEvent<HTMLInputElement>} e - The keyboard event.\n */\n const onKeyDown = React.useCallback((e: React.KeyboardEvent<HTMLInputElement>) => {\n if (['ArrowDown', 'ArrowUp', 'Enter', ' '].includes(e.key)) {\n e.preventDefault();\n setOpen(true);\n } else if (e.key !== 'Tab') {\n // Prevent typing to mimic readOnly behavior while allowing native validation\n e.preventDefault();\n }\n }, []);\n\n /**\n * Handles changes to the dropdown value.\n * Updates local state and calls the external onChange handler.\n * Closes the dropdown if not in multi-select mode.\n *\n * @param {T | T[]} val - The new value(s).\n */\n const changeHandler = (val: T | T[]) => {\n setValue(val);\n onChange?.(val);\n\n // Close dropdown after selection if not multiSelect\n if (!multiSelect) {\n setOpen(false);\n triggerRef.current?.focus();\n }\n };\n\n /**\n * Toggles the dropdown open state on click.\n */\n const clickHandler = React.useCallback(() => setOpen(true), []);\n\n /**\n * Forwarded ref handler for the trigger input.\n */\n const handleForwardedRef = React.useCallback(\n (node: HTMLInputElement | null) => {\n triggerRef.current = node;\n if (typeof outerRef === 'function') {\n outerRef(node);\n } else if (outerRef) {\n (outerRef as React.MutableRefObject<HTMLInputElement | null>).current = node;\n }\n },\n [outerRef],\n );\n\n return (\n <Popover\n position={POPOVER_POSITION.BOTTOM_LEFT}\n open={open}\n element={\n <DropdownTrigger\n {...rest}\n displayValue={displayValue}\n label={label}\n errorText={errorText}\n open={open}\n menuId={menuId}\n toggleOpen={clickHandler}\n onKeyDown={onKeyDown}\n required={required}\n disabled={disabled}\n forwardedRef={handleForwardedRef}\n />\n }\n onClose={() => {\n setOpen(false);\n triggerRef.current?.focus();\n }}\n >\n <Menu\n ref={menuRef}\n id={menuId}\n value={value}\n multiSelect={multiSelect}\n onChange={changeHandler}\n >\n {children}\n </Menu>\n </Popover>\n );\n}\n\nconst Dropdown = React.forwardRef(DropdownComponent) as <T>(\n props: DropdownProps<T> & React.RefAttributes<HTMLInputElement>,\n) => React.ReactElement | null;\nexport default Dropdown;\n"],"names":["ArrowContainer","styled","DropdownTrigger","React","forwardRef","props","ref","displayValue","label","errorText","open","menuId","toggleOpen","onKeyDown","forwardedRef","rest","triggerRef","useRef","assignRefs","useCallback","node","current","combinedRef","_jsxs","_Fragment","_jsx","Input","type","value","onClick","inputMode","role","aria-haspopup","aria-expanded","aria-controls","aria-hidden","ExpandMore","displayName","DropdownComponent","outerRef","multiSelect","onChange","children","propValue","required","disabled","setOpen","useState","setValue","id","useId","menuRef","getDisplayValue","currentValue","currentChildren","undefined","findLabel","val","Children","forEach","child","isValidElement","String","Array","isArray","map","filter","Boolean","join","prevValueRef","useEffect","timer","setTimeout","firstItem","querySelector","focus","clearTimeout","e","includes","key","preventDefault","changeHandler","clickHandler","handleForwardedRef","Popover","position","POPOVER_POSITION","BOTTOM_LEFT","element","onClose","Menu","Dropdown"],"mappings":"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"}
@@ -1,14 +1,14 @@
1
1
  import { jsxs, jsx } from '@emotion/react/jsx-runtime';
2
- import React, { useState, useId, useRef, useEffect } from 'react';
2
+ import React, { useState, useId, useRef, useImperativeHandle, useEffect } from 'react';
3
3
  import styled from '@emotion/styled';
4
4
  import { getThemeValue, THEME_NAME } from '../../shared/constants.js';
5
5
 
6
6
  const Label$5 = /*#__PURE__*/ styled("label", {
7
- target: "el9i5v60",
7
+ target: "e1g8e2pu0",
8
8
  label: "Label"
9
9
  })("display:inline-flex;flex-direction:column;position:relative;margin:10px 5px;");
10
10
  const TextField$1 = /*#__PURE__*/ styled("input", {
11
- target: "el9i5v61",
11
+ target: "e1g8e2pu1",
12
12
  label: "TextField"
13
13
  })("outline:none;color:inherit;padding:0 8px;line-height:30px;min-height:30px;width:250px;border-radius:3px;border:1px solid ", getThemeValue(THEME_NAME.BORDER_COLOR), ";display:inline-block;background-color:", getThemeValue(THEME_NAME.BACKGROUND), ";&:focus,&:active{border-color:", getThemeValue(THEME_NAME.PRIMARY), ";box-shadow:0 0 0 4px ", getThemeValue(THEME_NAME.PRIMARY_LIGHT), ";}&:focus + span,&:active + span{color:", getThemeValue(THEME_NAME.PRIMARY), ";}&:disabled{border-color:", getThemeValue(THEME_NAME.DISABLED_BORDER), ";background-color:", getThemeValue(THEME_NAME.DISABLED_BACKGROUND), ";padding:0 8px;}&:disabled + span{color:", getThemeValue(THEME_NAME.DISABLED), ";}&:focus:invalid{border-color:", getThemeValue(THEME_NAME.ERROR), ";box-shadow:0 0 0 4px ", getThemeValue(THEME_NAME.ERROR_LIGHT), ";}", (props)=>props.touched ? `
14
14
  &:invalid {
@@ -32,19 +32,21 @@ const TextField$1 = /*#__PURE__*/ styled("input", {
32
32
  line-height: 14px;
33
33
  }
34
34
  ` : '', " &:focus + span,&:placeholder-shown + span{top:-8px;background:", getThemeValue(THEME_NAME.BACKGROUND), ";font-size:12px;line-height:14px;}");
35
- const ErrorContainer$3 = /*#__PURE__*/ styled("div", {
36
- target: "el9i5v62",
35
+ const ErrorContainer$5 = /*#__PURE__*/ styled("div", {
36
+ target: "e1g8e2pu2",
37
37
  label: "ErrorContainer"
38
38
  })("color:", getThemeValue(THEME_NAME.ERROR), ";padding-top:3px;font-size:12px;line-height:14px;margin-left:3px;");
39
39
  /**
40
40
  * Input Component
41
41
  * @param props - Component props
42
42
  * @param ref - Ref forwarded to the underlying HTMLInputElement
43
- */ const Input$2 = /*#__PURE__*/ React.forwardRef((props, ref)=>{
43
+ */ const Input$2 = /*#__PURE__*/ React.forwardRef((props, forwardedRef)=>{
44
44
  const [touched, setTouched] = useState(false);
45
45
  const [value, setValue] = useState(props.value || '');
46
46
  const errorId = useId();
47
47
  const prevValueRef = useRef(undefined);
48
+ const internalRef = useRef(null);
49
+ useImperativeHandle(forwardedRef, ()=>internalRef.current);
48
50
  useEffect(()=>{
49
51
  if (props.value !== undefined && props.value !== prevValueRef.current) {
50
52
  setValue(props.value);
@@ -53,6 +55,13 @@ const ErrorContainer$3 = /*#__PURE__*/ styled("div", {
53
55
  }, [
54
56
  props.value
55
57
  ]);
58
+ useEffect(()=>{
59
+ if (internalRef.current) {
60
+ internalRef.current.setCustomValidity(props.errorText || '');
61
+ }
62
+ }, [
63
+ props.errorText
64
+ ]);
56
65
  const handleFocus = (e)=>{
57
66
  setTouched(true);
58
67
  if (props.onFocus) {
@@ -71,7 +80,7 @@ const ErrorContainer$3 = /*#__PURE__*/ styled("div", {
71
80
  children: [
72
81
  /*#__PURE__*/ jsx(TextField$1, {
73
82
  ...props,
74
- ref: ref,
83
+ ref: internalRef,
75
84
  value: value,
76
85
  onChange: onChangeHandler,
77
86
  onFocus: handleFocus,
@@ -83,7 +92,7 @@ const ErrorContainer$3 = /*#__PURE__*/ styled("div", {
83
92
  /*#__PURE__*/ jsx("span", {
84
93
  children: props.label
85
94
  }),
86
- props.errorText && /*#__PURE__*/ jsx(ErrorContainer$3, {
95
+ props.errorText && /*#__PURE__*/ jsx(ErrorContainer$5, {
87
96
  id: errorId,
88
97
  children: props.errorText
89
98
  })
@@ -1 +1 @@
1
- {"version":3,"file":"Input.js","sources":["../../../src/components/Input/Input.tsx"],"sourcesContent":["import React, { useState, useEffect, useId, useRef } from 'react';\nimport styled from '@emotion/styled';\nimport { getThemeValue, THEME_NAME } from '../../shared/constants';\n\ntype InputProps = {\n /** Label for the field */\n label?: string;\n /** Error text to be shown below the field */\n errorText?: string;\n} & React.AllHTMLAttributes<HTMLInputElement>;\n\ntype InputInternalProps = InputProps & {\n touched: boolean;\n};\n\nconst Label = styled.label`\n display: inline-flex;\n flex-direction: column;\n position: relative;\n margin: 10px 5px;\n`;\n\nconst TextField = styled.input<InputInternalProps>`\n outline: none;\n color: inherit;\n padding: 0 8px;\n line-height: 30px;\n min-height: 30px;\n width: 250px;\n border-radius: 3px;\n border: 1px solid ${getThemeValue(THEME_NAME.BORDER_COLOR)};\n display: inline-block;\n background-color: ${getThemeValue(THEME_NAME.BACKGROUND)};\n\n /** Focused */\n &:focus,\n &:active {\n border-color: ${getThemeValue(THEME_NAME.PRIMARY)};\n box-shadow: 0 0 0 4px ${getThemeValue(THEME_NAME.PRIMARY_LIGHT)};\n }\n\n &:focus + span,\n &:active + span {\n color: ${getThemeValue(THEME_NAME.PRIMARY)};\n }\n\n /** Disabled */\n &:disabled {\n border-color: ${getThemeValue(THEME_NAME.DISABLED_BORDER)};\n background-color: ${getThemeValue(THEME_NAME.DISABLED_BACKGROUND)};\n padding: 0 8px;\n }\n\n &:disabled + span {\n color: ${getThemeValue(THEME_NAME.DISABLED)};\n }\n\n /** Invalid */\n &:focus:invalid {\n border-color: ${getThemeValue(THEME_NAME.ERROR)};\n box-shadow: 0 0 0 4px ${getThemeValue(THEME_NAME.ERROR_LIGHT)};\n }\n\n ${(props) =>\n props.touched\n ? `\n &:invalid {\n border-color: ${getThemeValue(THEME_NAME.ERROR)};\n }\n\n &:invalid + span {\n color: ${getThemeValue(THEME_NAME.ERROR)};\n }\n `\n : ''}\n\n /** Error */\n ${(props) =>\n props.errorText\n ? `\n border-color: ${getThemeValue(THEME_NAME.ERROR)};\n\n & + span {\n color: ${getThemeValue(THEME_NAME.ERROR)};\n }\n `\n : ''}\n\n /** Required */\n &:required + span:after {\n content: '*';\n margin-left: 2px;\n color: ${getThemeValue(THEME_NAME.ERROR)};\n }\n\n /** Label Animation */\n & + span {\n position: absolute;\n padding: 0 5px;\n top: 0px;\n left: 4px;\n font-size: 14px;\n line-height: 32px;\n transition: all 300ms ease;\n }\n\n ${(props) =>\n props.value !== ''\n ? `\n & + span {\n top: -8px;\n background: ${getThemeValue(THEME_NAME.BACKGROUND)};\n font-size: 12px;\n line-height: 14px;\n }\n `\n : ''}\n\n &:focus + span, &:placeholder-shown + span {\n top: -8px;\n background: ${getThemeValue(THEME_NAME.BACKGROUND)};\n font-size: 12px;\n line-height: 14px;\n }\n`;\n\nconst ErrorContainer = styled.div`\n color: ${getThemeValue(THEME_NAME.ERROR)};\n padding-top: 3px;\n font-size: 12px;\n line-height: 14px;\n margin-left: 3px;\n`;\n\n/**\n * Input Component\n * @param props - Component props\n * @param ref - Ref forwarded to the underlying HTMLInputElement\n */\nconst Input = React.forwardRef<HTMLInputElement, Omit<InputProps, 'as'>>((props, ref) => {\n const [touched, setTouched] = useState(false);\n const [value, setValue] = useState(props.value || '');\n const errorId = useId();\n const prevValueRef = useRef<string>(undefined);\n\n useEffect(() => {\n if (props.value !== undefined && props.value !== prevValueRef.current) {\n setValue(props.value);\n prevValueRef.current = props.value as string;\n }\n }, [props.value]);\n\n const handleFocus = (e: React.FocusEvent<HTMLInputElement>) => {\n setTouched(true);\n if (props.onFocus) {\n props.onFocus(e);\n }\n };\n\n const onChangeHandler = (e: React.ChangeEvent<HTMLInputElement>) => {\n if (props.onChange) {\n setValue(e.target.value);\n props.onChange(e);\n } else {\n setValue(e.target.value);\n }\n };\n\n return (\n <Label>\n <TextField\n {...props}\n ref={ref}\n value={value}\n onChange={onChangeHandler}\n onFocus={handleFocus}\n touched={touched}\n aria-invalid={!!props.errorText}\n aria-required={props.required}\n aria-describedby={props.errorText ? errorId : undefined}\n />\n <span>{props.label}</span>\n {props.errorText && <ErrorContainer id={errorId}>{props.errorText}</ErrorContainer>}\n </Label>\n );\n});\n\nInput.displayName = 'Input';\nexport default Input;\n"],"names":["Label","styled","TextField","getThemeValue","THEME_NAME","BORDER_COLOR","BACKGROUND","PRIMARY","PRIMARY_LIGHT","DISABLED_BORDER","DISABLED_BACKGROUND","DISABLED","ERROR","ERROR_LIGHT","props","touched","errorText","value","ErrorContainer","Input","React","forwardRef","ref","setTouched","useState","setValue","errorId","useId","prevValueRef","useRef","undefined","useEffect","current","handleFocus","e","onFocus","onChangeHandler","onChange","target","_jsxs","_jsx","aria-invalid","aria-required","required","aria-describedby","span","label","id","displayName"],"mappings":"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"}
1
+ {"version":3,"file":"Input.js","sources":["../../../src/components/Input/Input.tsx"],"sourcesContent":["import React, { useState, useEffect, useId, useRef, useImperativeHandle } from 'react';\nimport styled from '@emotion/styled';\nimport { getThemeValue, THEME_NAME } from '../../shared/constants';\n\ntype InputProps = {\n /** Label for the field */\n label?: string;\n /** Error text to be shown below the field */\n errorText?: string;\n} & React.AllHTMLAttributes<HTMLInputElement>;\n\ntype InputInternalProps = InputProps & {\n touched: boolean;\n};\n\nconst Label = styled.label`\n display: inline-flex;\n flex-direction: column;\n position: relative;\n margin: 10px 5px;\n`;\n\nconst TextField = styled.input<InputInternalProps>`\n outline: none;\n color: inherit;\n padding: 0 8px;\n line-height: 30px;\n min-height: 30px;\n width: 250px;\n border-radius: 3px;\n border: 1px solid ${getThemeValue(THEME_NAME.BORDER_COLOR)};\n display: inline-block;\n background-color: ${getThemeValue(THEME_NAME.BACKGROUND)};\n\n /** Focused */\n &:focus,\n &:active {\n border-color: ${getThemeValue(THEME_NAME.PRIMARY)};\n box-shadow: 0 0 0 4px ${getThemeValue(THEME_NAME.PRIMARY_LIGHT)};\n }\n\n &:focus + span,\n &:active + span {\n color: ${getThemeValue(THEME_NAME.PRIMARY)};\n }\n\n /** Disabled */\n &:disabled {\n border-color: ${getThemeValue(THEME_NAME.DISABLED_BORDER)};\n background-color: ${getThemeValue(THEME_NAME.DISABLED_BACKGROUND)};\n padding: 0 8px;\n }\n\n &:disabled + span {\n color: ${getThemeValue(THEME_NAME.DISABLED)};\n }\n\n /** Invalid */\n &:focus:invalid {\n border-color: ${getThemeValue(THEME_NAME.ERROR)};\n box-shadow: 0 0 0 4px ${getThemeValue(THEME_NAME.ERROR_LIGHT)};\n }\n\n ${(props) =>\n props.touched\n ? `\n &:invalid {\n border-color: ${getThemeValue(THEME_NAME.ERROR)};\n }\n\n &:invalid + span {\n color: ${getThemeValue(THEME_NAME.ERROR)};\n }\n `\n : ''}\n\n /** Error */\n ${(props) =>\n props.errorText\n ? `\n border-color: ${getThemeValue(THEME_NAME.ERROR)};\n\n & + span {\n color: ${getThemeValue(THEME_NAME.ERROR)};\n }\n `\n : ''}\n\n /** Required */\n &:required + span:after {\n content: '*';\n margin-left: 2px;\n color: ${getThemeValue(THEME_NAME.ERROR)};\n }\n\n /** Label Animation */\n & + span {\n position: absolute;\n padding: 0 5px;\n top: 0px;\n left: 4px;\n font-size: 14px;\n line-height: 32px;\n transition: all 300ms ease;\n }\n\n ${(props) =>\n props.value !== ''\n ? `\n & + span {\n top: -8px;\n background: ${getThemeValue(THEME_NAME.BACKGROUND)};\n font-size: 12px;\n line-height: 14px;\n }\n `\n : ''}\n\n &:focus + span, &:placeholder-shown + span {\n top: -8px;\n background: ${getThemeValue(THEME_NAME.BACKGROUND)};\n font-size: 12px;\n line-height: 14px;\n }\n`;\n\nconst ErrorContainer = styled.div`\n color: ${getThemeValue(THEME_NAME.ERROR)};\n padding-top: 3px;\n font-size: 12px;\n line-height: 14px;\n margin-left: 3px;\n`;\n\n/**\n * Input Component\n * @param props - Component props\n * @param ref - Ref forwarded to the underlying HTMLInputElement\n */\nconst Input = React.forwardRef<HTMLInputElement, Omit<InputProps, 'as'>>((props, forwardedRef) => {\n const [touched, setTouched] = useState(false);\n const [value, setValue] = useState(props.value || '');\n const errorId = useId();\n const prevValueRef = useRef<string>(undefined);\n const internalRef = useRef<HTMLInputElement>(null);\n\n useImperativeHandle(forwardedRef, () => internalRef.current as HTMLInputElement);\n\n useEffect(() => {\n if (props.value !== undefined && props.value !== prevValueRef.current) {\n setValue(props.value);\n prevValueRef.current = props.value as string;\n }\n }, [props.value]);\n\n useEffect(() => {\n if (internalRef.current) {\n internalRef.current.setCustomValidity(props.errorText || '');\n }\n }, [props.errorText]);\n\n const handleFocus = (e: React.FocusEvent<HTMLInputElement>) => {\n setTouched(true);\n if (props.onFocus) {\n props.onFocus(e);\n }\n };\n\n const onChangeHandler = (e: React.ChangeEvent<HTMLInputElement>) => {\n if (props.onChange) {\n setValue(e.target.value);\n props.onChange(e);\n } else {\n setValue(e.target.value);\n }\n };\n\n return (\n <Label>\n <TextField\n {...props}\n ref={internalRef}\n value={value}\n onChange={onChangeHandler}\n onFocus={handleFocus}\n touched={touched}\n aria-invalid={!!props.errorText}\n aria-required={props.required}\n aria-describedby={props.errorText ? errorId : undefined}\n />\n <span>{props.label}</span>\n {props.errorText && <ErrorContainer id={errorId}>{props.errorText}</ErrorContainer>}\n </Label>\n );\n});\n\nInput.displayName = 'Input';\nexport default Input;\n"],"names":["Label","styled","TextField","getThemeValue","THEME_NAME","BORDER_COLOR","BACKGROUND","PRIMARY","PRIMARY_LIGHT","DISABLED_BORDER","DISABLED_BACKGROUND","DISABLED","ERROR","ERROR_LIGHT","props","touched","errorText","value","ErrorContainer","Input","React","forwardRef","forwardedRef","setTouched","useState","setValue","errorId","useId","prevValueRef","useRef","undefined","internalRef","useImperativeHandle","current","useEffect","setCustomValidity","handleFocus","e","onFocus","onChangeHandler","onChange","target","_jsxs","_jsx","ref","aria-invalid","aria-required","required","aria-describedby","span","label","id","displayName"],"mappings":"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"}
@@ -2,5 +2,7 @@ import React from 'react';
2
2
  declare const Radio: React.ForwardRefExoticComponent<{
3
3
  /** Label for the field */
4
4
  label?: string;
5
+ /** Error text to be shown below the field */
6
+ errorText?: string;
5
7
  } & React.InputHTMLAttributes<HTMLInputElement> & React.RefAttributes<HTMLInputElement>>;
6
8
  export default Radio;
@@ -1,32 +1,44 @@
1
1
  import { jsxs, jsx } from '@emotion/react/jsx-runtime';
2
- import React from 'react';
2
+ import React, { useRef, useId, useImperativeHandle, useEffect } from 'react';
3
3
  import styled from '@emotion/styled';
4
4
  import { getThemeValue, THEME_NAME } from '../../shared/constants.js';
5
5
 
6
6
  const Label$1 = /*#__PURE__*/ styled("label", {
7
- target: "e12cx2u30",
7
+ target: "edovkv60",
8
8
  label: "Label"
9
- })("display:inline-flex;align-items:center;margin:5px 0;cursor:pointer;position:relative;");
9
+ })("display:inline-flex;align-items:center;margin:5px 10px 5px 0;cursor:pointer;position:relative;");
10
10
  const StyledRadio = /*#__PURE__*/ styled("span", {
11
- target: "e12cx2u31",
11
+ target: "edovkv61",
12
12
  label: "StyledRadio"
13
13
  })("width:16px;height:16px;margin-right:5px;border:1px solid ", getThemeValue(THEME_NAME.BORDER_COLOR), ";border-radius:50%;display:block;transition:background-color 0.3s ease;position:relative;flex-shrink:0;&::after{content:'';width:100%;height:100%;border-radius:50%;position:absolute;top:0;left:0;box-shadow:inset 0 0 0 3px ", getThemeValue(THEME_NAME.BACKGROUND), ";opacity:0;transition:opacity 0.2s ease;}");
14
14
  const HiddenInput = /*#__PURE__*/ styled("input", {
15
- target: "e12cx2u32",
15
+ target: "edovkv62",
16
16
  label: "HiddenInput"
17
17
  })("opacity:0;width:0;height:0;position:absolute;margin:0;&:checked + ", StyledRadio, "{border-color:", getThemeValue(THEME_NAME.PRIMARY), ";background-color:", getThemeValue(THEME_NAME.PRIMARY), ";}&:checked + ", StyledRadio, "::after{opacity:1;}&:enabled:focus + ", StyledRadio, "{border-color:", getThemeValue(THEME_NAME.PRIMARY), ";box-shadow:0 0 0 3px ", getThemeValue(THEME_NAME.PRIMARY_LIGHT), ";}&:enabled:checked:focus + ", StyledRadio, "{border-color:", getThemeValue(THEME_NAME.PRIMARY), ";box-shadow:0 0 0 3px ", getThemeValue(THEME_NAME.PRIMARY_LIGHT), ";}&:enabled:hover + ", StyledRadio, "{border-color:", getThemeValue(THEME_NAME.PRIMARY), ";}&:enabled:hover ~ span{color:", getThemeValue(THEME_NAME.PRIMARY), ";}&:disabled + ", StyledRadio, "{border-color:", getThemeValue(THEME_NAME.DISABLED_BORDER), ";background-color:", getThemeValue(THEME_NAME.LIGHT_GREY), ";cursor:not-allowed;}&:disabled:checked + ", StyledRadio, "{border-color:", getThemeValue(THEME_NAME.DISABLED_BORDER), ";background-color:", getThemeValue(THEME_NAME.DISABLED_BORDER), ";}&:disabled ~ span{color:", getThemeValue(THEME_NAME.DISABLED_BORDER), ";cursor:not-allowed;}");
18
18
  /**
19
19
  * Radio Component
20
20
  * @param props - Component props
21
- * @param ref - Ref forwarded to the underlying HTMLInputElement
22
- */ function RadioComponent(props, ref) {
23
- const { label, ...rest } = props;
21
+ * @param forwardedRef - Ref forwarded to the underlying HTMLInputElement
22
+ */ function RadioComponent(props, forwardedRef) {
23
+ const { label, errorText, ...rest } = props;
24
+ const internalRef = useRef(null);
25
+ const errorId = useId();
26
+ useImperativeHandle(forwardedRef, ()=>internalRef.current);
27
+ useEffect(()=>{
28
+ if (internalRef.current) {
29
+ internalRef.current.setCustomValidity(errorText || '');
30
+ }
31
+ }, [
32
+ errorText
33
+ ]);
24
34
  return /*#__PURE__*/ jsxs(Label$1, {
25
35
  children: [
26
36
  /*#__PURE__*/ jsx(HiddenInput, {
27
37
  ...rest,
28
- ref: ref,
29
- type: "radio"
38
+ ref: internalRef,
39
+ type: "radio",
40
+ "aria-invalid": !!errorText,
41
+ "aria-describedby": errorText ? errorId : undefined
30
42
  }),
31
43
  /*#__PURE__*/ jsx(StyledRadio, {}),
32
44
  /*#__PURE__*/ jsx("span", {
@@ -1 +1 @@
1
- {"version":3,"file":"Radio.js","sources":["../../../src/components/Input/Radio.tsx"],"sourcesContent":["import React from 'react';\nimport styled from '@emotion/styled';\nimport { getThemeValue, THEME_NAME } from '../../shared/constants';\n\nconst Label = styled.label`\n display: inline-flex;\n align-items: center;\n margin: 5px 0;\n cursor: pointer;\n position: relative;\n`;\n\nconst StyledRadio = styled.span`\n width: 16px;\n height: 16px;\n margin-right: 5px;\n border: 1px solid ${getThemeValue(THEME_NAME.BORDER_COLOR)};\n border-radius: 50%;\n display: block;\n transition: background-color 0.3s ease;\n position: relative;\n flex-shrink: 0;\n\n &::after {\n content: '';\n width: 100%;\n height: 100%;\n border-radius: 50%;\n position: absolute;\n top: 0;\n left: 0;\n box-shadow: inset 0 0 0 3px ${getThemeValue(THEME_NAME.BACKGROUND)};\n opacity: 0;\n transition: opacity 0.2s ease;\n }\n`;\n\nconst HiddenInput = styled.input`\n opacity: 0;\n width: 0;\n height: 0;\n position: absolute;\n margin: 0;\n\n /* checked */\n &:checked + ${StyledRadio} {\n border-color: ${getThemeValue(THEME_NAME.PRIMARY)};\n background-color: ${getThemeValue(THEME_NAME.PRIMARY)};\n }\n\n &:checked + ${StyledRadio}::after {\n opacity: 1;\n }\n\n /* focus */\n &:enabled:focus + ${StyledRadio} {\n border-color: ${getThemeValue(THEME_NAME.PRIMARY)};\n box-shadow: 0 0 0 3px ${getThemeValue(THEME_NAME.PRIMARY_LIGHT)};\n }\n\n &:enabled:checked:focus + ${StyledRadio} {\n border-color: ${getThemeValue(THEME_NAME.PRIMARY)};\n box-shadow: 0 0 0 3px ${getThemeValue(THEME_NAME.PRIMARY_LIGHT)};\n }\n\n /* hover */\n &:enabled:hover + ${StyledRadio} {\n border-color: ${getThemeValue(THEME_NAME.PRIMARY)};\n }\n\n &:enabled:hover ~ span {\n color: ${getThemeValue(THEME_NAME.PRIMARY)};\n }\n\n /* disabled */\n &:disabled + ${StyledRadio} {\n border-color: ${getThemeValue(THEME_NAME.DISABLED_BORDER)};\n background-color: ${getThemeValue(THEME_NAME.LIGHT_GREY)};\n cursor: not-allowed;\n }\n\n &:disabled:checked + ${StyledRadio} {\n border-color: ${getThemeValue(THEME_NAME.DISABLED_BORDER)};\n background-color: ${getThemeValue(THEME_NAME.DISABLED_BORDER)};\n }\n\n &:disabled ~ span {\n color: ${getThemeValue(THEME_NAME.DISABLED_BORDER)};\n cursor: not-allowed;\n }\n`;\n\ntype RadioProps = {\n /** Label for the field */\n label?: string;\n} & React.InputHTMLAttributes<HTMLInputElement>;\n\n/**\n * Radio Component\n * @param props - Component props\n * @param ref - Ref forwarded to the underlying HTMLInputElement\n */\nfunction RadioComponent(props: RadioProps, ref: React.Ref<HTMLInputElement>) {\n const { label, ...rest } = props;\n\n return (\n <Label>\n <HiddenInput {...rest} ref={ref} type=\"radio\" />\n <StyledRadio />\n <span>{label}</span>\n </Label>\n );\n}\n\nconst Radio = React.forwardRef<HTMLInputElement, RadioProps>(RadioComponent);\nexport default Radio;\n"],"names":["Label","styled","StyledRadio","getThemeValue","THEME_NAME","BORDER_COLOR","BACKGROUND","HiddenInput","PRIMARY","PRIMARY_LIGHT","DISABLED_BORDER","LIGHT_GREY","RadioComponent","props","ref","label","rest","_jsxs","_jsx","type","span","Radio","React","forwardRef"],"mappings":";;;;;AAIA,MAAMA,OAAAA,iBAAQC,MAAAA,CAAAA,OAAAA,EAAAA;;;;AAQd,MAAMC,WAAAA,iBAAcD,MAAAA,CAAAA,MAAAA,EAAAA;;;AAIIE,CAAAA,CAAAA,CAAAA,2DAAAA,EAAAA,aAAAA,CAAcC,UAAAA,CAAWC,YAAY,CAAA,EAAA,gOAAA,EAevBF,aAAAA,CAAcC,WAAWE,UAAU,CAAA,EAAA,2CAAA,CAAA;AAMzE,MAAMC,WAAAA,iBAAcN,MAAAA,CAAAA,OAAAA,EAAAA;;;yEAQFC,WAAAA,EAAAA,gBAAAA,EACMC,aAAAA,CAAcC,UAAAA,CAAWI,OAAO,CAAA,EAAA,oBAAA,EAC5BL,aAAAA,CAAcC,UAAAA,CAAWI,OAAO,CAAA,EAAA,gBAAA,EAG1CN,WAAAA,EAAAA,uCAAAA,EAKMA,WAAAA,EAAAA,gBAAAA,EACAC,aAAAA,CAAcC,UAAAA,CAAWI,OAAO,6BACxBL,aAAAA,CAAcC,UAAAA,CAAWK,aAAa,CAAA,EAAA,8BAAA,EAGtCP,WAAAA,EAAAA,gBAAAA,EACRC,aAAAA,CAAcC,UAAAA,CAAWI,OAAO,CAAA,EAAA,wBAAA,EACxBL,aAAAA,CAAcC,UAAAA,CAAWK,aAAa,CAAA,EAAA,sBAAA,EAI9CP,WAAAA,EAAAA,gBAAAA,EACAC,cAAcC,UAAAA,CAAWI,OAAO,CAAA,EAAA,iCAAA,EAIvCL,aAAAA,CAAcC,UAAAA,CAAWI,OAAO,CAAA,EAAA,iBAAA,EAI9BN,WAAAA,EAAAA,gBAAAA,EACKC,aAAAA,CAAcC,UAAAA,CAAWM,eAAe,CAAA,EAAA,oBAAA,EACpCP,aAAAA,CAAcC,UAAAA,CAAWO,UAAU,CAAA,EAAA,4CAAA,EAIpCT,WAAAA,EAAAA,gBAAAA,EACHC,aAAAA,CAAcC,UAAAA,CAAWM,eAAe,CAAA,EAAA,oBAAA,EACpCP,aAAAA,CAAcC,UAAAA,CAAWM,eAAe,CAAA,EAAA,4BAAA,EAInDP,aAAAA,CAAcC,UAAAA,CAAWM,eAAe,CAAA,EAAA,uBAAA,CAAA;AAUzD;;;;AAIC,IACD,SAASE,cAAAA,CAAeC,KAAiB,EAAEC,GAAgC,EAAA;AACvE,IAAA,MAAM,EAAEC,KAAK,EAAE,GAAGC,MAAM,GAAGH,KAAAA;AAE3B,IAAA,qBACII,IAAA,CAACjB,OAAAA,EAAAA;;0BACGkB,GAAA,CAACX,WAAAA,EAAAA;AAAa,gBAAA,GAAGS,IAAI;gBAAEF,GAAAA,EAAKA,GAAAA;gBAAKK,IAAAA,EAAK;;0BACtCD,GAAA,CAAChB,WAAAA,EAAAA,EAAAA,CAAAA;0BACDgB,GAAA,CAACE,MAAAA,EAAAA;AAAML,gBAAAA,QAAAA,EAAAA;;;;AAGnB;AAEA,MAAMM,KAAAA,iBAAQC,KAAAA,CAAMC,UAAU,CAA+BX,cAAAA;;;;"}
1
+ {"version":3,"file":"Radio.js","sources":["../../../src/components/Input/Radio.tsx"],"sourcesContent":["import React, { useEffect, useId, useRef, useImperativeHandle } from 'react';\nimport styled from '@emotion/styled';\nimport { getThemeValue, THEME_NAME } from '../../shared/constants';\n\nconst Label = styled.label`\n display: inline-flex;\n align-items: center;\n margin: 5px 10px 5px 0;\n cursor: pointer;\n position: relative;\n`;\n\nconst StyledRadio = styled.span`\n width: 16px;\n height: 16px;\n margin-right: 5px;\n border: 1px solid ${getThemeValue(THEME_NAME.BORDER_COLOR)};\n border-radius: 50%;\n display: block;\n transition: background-color 0.3s ease;\n position: relative;\n flex-shrink: 0;\n\n &::after {\n content: '';\n width: 100%;\n height: 100%;\n border-radius: 50%;\n position: absolute;\n top: 0;\n left: 0;\n box-shadow: inset 0 0 0 3px ${getThemeValue(THEME_NAME.BACKGROUND)};\n opacity: 0;\n transition: opacity 0.2s ease;\n }\n`;\n\nconst HiddenInput = styled.input`\n opacity: 0;\n width: 0;\n height: 0;\n position: absolute;\n margin: 0;\n\n /* checked */\n &:checked + ${StyledRadio} {\n border-color: ${getThemeValue(THEME_NAME.PRIMARY)};\n background-color: ${getThemeValue(THEME_NAME.PRIMARY)};\n }\n\n &:checked + ${StyledRadio}::after {\n opacity: 1;\n }\n\n /* focus */\n &:enabled:focus + ${StyledRadio} {\n border-color: ${getThemeValue(THEME_NAME.PRIMARY)};\n box-shadow: 0 0 0 3px ${getThemeValue(THEME_NAME.PRIMARY_LIGHT)};\n }\n\n &:enabled:checked:focus + ${StyledRadio} {\n border-color: ${getThemeValue(THEME_NAME.PRIMARY)};\n box-shadow: 0 0 0 3px ${getThemeValue(THEME_NAME.PRIMARY_LIGHT)};\n }\n\n /* hover */\n &:enabled:hover + ${StyledRadio} {\n border-color: ${getThemeValue(THEME_NAME.PRIMARY)};\n }\n\n &:enabled:hover ~ span {\n color: ${getThemeValue(THEME_NAME.PRIMARY)};\n }\n\n /* disabled */\n &:disabled + ${StyledRadio} {\n border-color: ${getThemeValue(THEME_NAME.DISABLED_BORDER)};\n background-color: ${getThemeValue(THEME_NAME.LIGHT_GREY)};\n cursor: not-allowed;\n }\n\n &:disabled:checked + ${StyledRadio} {\n border-color: ${getThemeValue(THEME_NAME.DISABLED_BORDER)};\n background-color: ${getThemeValue(THEME_NAME.DISABLED_BORDER)};\n }\n\n &:disabled ~ span {\n color: ${getThemeValue(THEME_NAME.DISABLED_BORDER)};\n cursor: not-allowed;\n }\n`;\n\ntype RadioProps = {\n /** Label for the field */\n label?: string;\n /** Error text to be shown below the field */\n errorText?: string;\n} & React.InputHTMLAttributes<HTMLInputElement>;\n\n/**\n * Radio Component\n * @param props - Component props\n * @param forwardedRef - Ref forwarded to the underlying HTMLInputElement\n */\nfunction RadioComponent(props: RadioProps, forwardedRef: React.Ref<HTMLInputElement>) {\n const { label, errorText, ...rest } = props;\n const internalRef = useRef<HTMLInputElement>(null);\n const errorId = useId();\n\n useImperativeHandle(forwardedRef, () => internalRef.current as HTMLInputElement);\n\n useEffect(() => {\n if (internalRef.current) {\n internalRef.current.setCustomValidity(errorText || '');\n }\n }, [errorText]);\n\n return (\n <Label>\n <HiddenInput\n {...rest}\n ref={internalRef}\n type=\"radio\"\n aria-invalid={!!errorText}\n aria-describedby={errorText ? errorId : undefined}\n />\n <StyledRadio />\n <span>{label}</span>\n </Label>\n );\n}\n\nconst Radio = React.forwardRef<HTMLInputElement, RadioProps>(RadioComponent);\nexport default Radio;\n"],"names":["Label","styled","StyledRadio","getThemeValue","THEME_NAME","BORDER_COLOR","BACKGROUND","HiddenInput","PRIMARY","PRIMARY_LIGHT","DISABLED_BORDER","LIGHT_GREY","RadioComponent","props","forwardedRef","label","errorText","rest","internalRef","useRef","errorId","useId","useImperativeHandle","current","useEffect","setCustomValidity","_jsxs","_jsx","ref","type","aria-invalid","aria-describedby","undefined","span","Radio","React","forwardRef"],"mappings":";;;;;AAIA,MAAMA,OAAAA,iBAAQC,MAAAA,CAAAA,OAAAA,EAAAA;;;;AAQd,MAAMC,WAAAA,iBAAcD,MAAAA,CAAAA,MAAAA,EAAAA;;;AAIIE,CAAAA,CAAAA,CAAAA,2DAAAA,EAAAA,aAAAA,CAAcC,UAAAA,CAAWC,YAAY,CAAA,EAAA,gOAAA,EAevBF,aAAAA,CAAcC,WAAWE,UAAU,CAAA,EAAA,2CAAA,CAAA;AAMzE,MAAMC,WAAAA,iBAAcN,MAAAA,CAAAA,OAAAA,EAAAA;;;yEAQFC,WAAAA,EAAAA,gBAAAA,EACMC,aAAAA,CAAcC,UAAAA,CAAWI,OAAO,CAAA,EAAA,oBAAA,EAC5BL,aAAAA,CAAcC,UAAAA,CAAWI,OAAO,CAAA,EAAA,gBAAA,EAG1CN,WAAAA,EAAAA,uCAAAA,EAKMA,WAAAA,EAAAA,gBAAAA,EACAC,aAAAA,CAAcC,UAAAA,CAAWI,OAAO,6BACxBL,aAAAA,CAAcC,UAAAA,CAAWK,aAAa,CAAA,EAAA,8BAAA,EAGtCP,WAAAA,EAAAA,gBAAAA,EACRC,aAAAA,CAAcC,UAAAA,CAAWI,OAAO,CAAA,EAAA,wBAAA,EACxBL,aAAAA,CAAcC,UAAAA,CAAWK,aAAa,CAAA,EAAA,sBAAA,EAI9CP,WAAAA,EAAAA,gBAAAA,EACAC,cAAcC,UAAAA,CAAWI,OAAO,CAAA,EAAA,iCAAA,EAIvCL,aAAAA,CAAcC,UAAAA,CAAWI,OAAO,CAAA,EAAA,iBAAA,EAI9BN,WAAAA,EAAAA,gBAAAA,EACKC,aAAAA,CAAcC,UAAAA,CAAWM,eAAe,CAAA,EAAA,oBAAA,EACpCP,aAAAA,CAAcC,UAAAA,CAAWO,UAAU,CAAA,EAAA,4CAAA,EAIpCT,WAAAA,EAAAA,gBAAAA,EACHC,aAAAA,CAAcC,UAAAA,CAAWM,eAAe,CAAA,EAAA,oBAAA,EACpCP,aAAAA,CAAcC,UAAAA,CAAWM,eAAe,CAAA,EAAA,4BAAA,EAInDP,aAAAA,CAAcC,UAAAA,CAAWM,eAAe,CAAA,EAAA,uBAAA,CAAA;AAYzD;;;;AAIC,IACD,SAASE,cAAAA,CAAeC,KAAiB,EAAEC,YAAyC,EAAA;AAChF,IAAA,MAAM,EAAEC,KAAK,EAAEC,SAAS,EAAE,GAAGC,MAAM,GAAGJ,KAAAA;AACtC,IAAA,MAAMK,cAAcC,MAAAA,CAAyB,IAAA,CAAA;AAC7C,IAAA,MAAMC,OAAAA,GAAUC,KAAAA,EAAAA;IAEhBC,mBAAAA,CAAoBR,YAAAA,EAAc,IAAMI,WAAAA,CAAYK,OAAO,CAAA;IAE3DC,SAAAA,CAAU,IAAA;QACN,IAAIN,WAAAA,CAAYK,OAAO,EAAE;AACrBL,YAAAA,WAAAA,CAAYK,OAAO,CAACE,iBAAiB,CAACT,SAAAA,IAAa,EAAA,CAAA;AACvD,QAAA;IACJ,CAAA,EAAG;AAACA,QAAAA;AAAU,KAAA,CAAA;AAEd,IAAA,qBACIU,IAAA,CAAC1B,OAAAA,EAAAA;;0BACG2B,GAAA,CAACpB,WAAAA,EAAAA;AACI,gBAAA,GAAGU,IAAI;gBACRW,GAAAA,EAAKV,WAAAA;gBACLW,IAAAA,EAAK,OAAA;AACLC,gBAAAA,cAAAA,EAAc,CAAC,CAACd,SAAAA;AAChBe,gBAAAA,kBAAAA,EAAkBf,YAAYI,OAAAA,GAAUY;;0BAE5CL,GAAA,CAACzB,WAAAA,EAAAA,EAAAA,CAAAA;0BACDyB,GAAA,CAACM,MAAAA,EAAAA;AAAMlB,gBAAAA,QAAAA,EAAAA;;;;AAGnB;AAEA,MAAMmB,KAAAA,iBAAQC,KAAAA,CAAMC,UAAU,CAA+BxB,cAAAA;;;;"}
@@ -6,5 +6,7 @@ export declare const RadioGroup: import("@emotion/styled").StyledComponent<{
6
6
  declare const RadioButton: React.ForwardRefExoticComponent<{
7
7
  /** Label for the field */
8
8
  label?: string;
9
+ /** Error text to be shown below the field */
10
+ errorText?: string;
9
11
  } & React.InputHTMLAttributes<HTMLInputElement> & React.RefAttributes<HTMLInputElement>>;
10
12
  export default RadioButton;
@@ -1,32 +1,44 @@
1
1
  import { jsxs, jsx } from '@emotion/react/jsx-runtime';
2
- import React from 'react';
2
+ import React, { useRef, useId, useImperativeHandle, useEffect } from 'react';
3
3
  import styled from '@emotion/styled';
4
4
  import { getThemeValue, THEME_NAME } from '../../shared/constants.js';
5
5
 
6
6
  const Input = /*#__PURE__*/ styled("input", {
7
- target: "e1yp0s5y0",
7
+ target: "e76n0060",
8
8
  label: "Input"
9
9
  })("appearance:none;margin:0;width:0;& + span{color:", getThemeValue(THEME_NAME.PRIMARY), ";padding:6px 12px;border:none;border:1px solid ", getThemeValue(THEME_NAME.PRIMARY), ";cursor:pointer;margin-right:-1px;line-height:18px;}&:enabled:focus + span{box-shadow:0 0 0 4px ", getThemeValue(THEME_NAME.PRIMARY_LIGHT), ";}&:enabled:hover + span{background-color:", getThemeValue(THEME_NAME.PRIMARY_LIGHT), ";color:", getThemeValue(THEME_NAME.TEXT_COLOR_LIGHT), ";}&:enabled:checked + span{background-color:", getThemeValue(THEME_NAME.PRIMARY), ";color:", getThemeValue(THEME_NAME.TEXT_COLOR_LIGHT), ";}&:disabled + span{background-color:", getThemeValue(THEME_NAME.BORDER_LIGHT_COLOR), ";color:", getThemeValue(THEME_NAME.DISABLED_BORDER), ";}&:disabled:checked + span{background-color:", getThemeValue(THEME_NAME.DISABLED_BORDER), ";color:", getThemeValue(THEME_NAME.TEXT_COLOR_LIGHT), ";}");
10
10
  const Label = /*#__PURE__*/ styled("label", {
11
- target: "e1yp0s5y1",
11
+ target: "e76n0061",
12
12
  label: "Label"
13
13
  })("display:inline-flex;&:focus-within{z-index:1;}");
14
14
  const RadioGroup = /*#__PURE__*/ styled("div", {
15
- target: "e1yp0s5y2",
15
+ target: "e76n0062",
16
16
  label: "RadioGroup"
17
- })("display:inline-flex;align-items:center;border-radius:3px;margin:5px 0;& ", Label, ":first-child > span{border-radius:3px 0 0 3px;}& ", Label, ":last-child > span{border-radius:0 3px 3px 0;}");
17
+ })("display:inline-flex;align-items:center;border-radius:3px;margin:5px 0;& > ", Label, ":first-of-type > span{border-radius:3px 0 0 3px;}& > ", Label, ":last-of-type > span{border-radius:0 3px 3px 0;}");
18
18
  /**
19
19
  * RadioButton Component
20
20
  * @param props - Component props
21
- * @param ref - Ref forwarded to the underlying HTMLInputElement
22
- */ function RadioButtonComponent(props, ref) {
23
- const { label, ...rest } = props;
21
+ * @param forwardedRef - Ref forwarded to the underlying HTMLInputElement
22
+ */ function RadioButtonComponent(props, forwardedRef) {
23
+ const { label, errorText, ...rest } = props;
24
+ const internalRef = useRef(null);
25
+ const errorId = useId();
26
+ useImperativeHandle(forwardedRef, ()=>internalRef.current);
27
+ useEffect(()=>{
28
+ if (internalRef.current) {
29
+ internalRef.current.setCustomValidity(errorText || '');
30
+ }
31
+ }, [
32
+ errorText
33
+ ]);
24
34
  return /*#__PURE__*/ jsxs(Label, {
25
35
  children: [
26
36
  /*#__PURE__*/ jsx(Input, {
27
37
  ...rest,
28
38
  type: "radio",
29
- ref: ref
39
+ ref: internalRef,
40
+ "aria-invalid": !!errorText,
41
+ "aria-describedby": errorText ? errorId : undefined
30
42
  }),
31
43
  /*#__PURE__*/ jsx("span", {
32
44
  children: label
@@ -1 +1 @@
1
- {"version":3,"file":"RadioButton.js","sources":["../../../src/components/Input/RadioButton.tsx"],"sourcesContent":["import React from 'react';\nimport styled from '@emotion/styled';\nimport { getThemeValue, THEME_NAME } from '../../shared/constants';\n\nconst Input = styled.input`\n appearance: none;\n margin: 0;\n width: 0;\n\n & + span {\n color: ${getThemeValue(THEME_NAME.PRIMARY)};\n padding: 6px 12px;\n border: none;\n border: 1px solid ${getThemeValue(THEME_NAME.PRIMARY)};\n cursor: pointer;\n margin-right: -1px;\n line-height: 18px;\n }\n\n &:enabled:focus + span {\n box-shadow: 0 0 0 4px ${getThemeValue(THEME_NAME.PRIMARY_LIGHT)};\n }\n\n &:enabled:hover + span {\n background-color: ${getThemeValue(THEME_NAME.PRIMARY_LIGHT)};\n color: ${getThemeValue(THEME_NAME.TEXT_COLOR_LIGHT)};\n }\n\n &:enabled:checked + span {\n background-color: ${getThemeValue(THEME_NAME.PRIMARY)};\n color: ${getThemeValue(THEME_NAME.TEXT_COLOR_LIGHT)};\n }\n\n &:disabled + span {\n background-color: ${getThemeValue(THEME_NAME.BORDER_LIGHT_COLOR)};\n color: ${getThemeValue(THEME_NAME.DISABLED_BORDER)};\n }\n\n &:disabled:checked + span {\n background-color: ${getThemeValue(THEME_NAME.DISABLED_BORDER)};\n color: ${getThemeValue(THEME_NAME.TEXT_COLOR_LIGHT)};\n }\n`;\n\nconst Label = styled.label`\n display: inline-flex;\n\n &:focus-within {\n z-index: 1;\n }\n`;\n\nexport const RadioGroup = styled.div`\n display: inline-flex;\n align-items: center;\n border-radius: 3px;\n margin: 5px 0;\n\n & ${Label}:first-child > span {\n border-radius: 3px 0 0 3px;\n }\n\n & ${Label}:last-child > span {\n border-radius: 0 3px 3px 0;\n }\n`;\n\ntype RadioButtonProps = {\n /** Label for the field */\n label?: string;\n} & React.InputHTMLAttributes<HTMLInputElement>;\n\n/**\n * RadioButton Component\n * @param props - Component props\n * @param ref - Ref forwarded to the underlying HTMLInputElement\n */\nfunction RadioButtonComponent(props: RadioButtonProps, ref: React.Ref<HTMLInputElement>) {\n const { label, ...rest } = props;\n return (\n <Label>\n <Input {...rest} type=\"radio\" ref={ref} />\n <span>{label}</span>\n </Label>\n );\n}\n\nconst RadioButton = React.forwardRef(RadioButtonComponent);\nexport default RadioButton;\n"],"names":["Input","styled","getThemeValue","THEME_NAME","PRIMARY","PRIMARY_LIGHT","TEXT_COLOR_LIGHT","BORDER_LIGHT_COLOR","DISABLED_BORDER","Label","RadioGroup","RadioButtonComponent","props","ref","label","rest","_jsxs","_jsx","type","span","RadioButton","React","forwardRef"],"mappings":";;;;;AAIA,MAAMA,KAAAA,iBAAQC,MAAAA,CAAAA,OAAAA,EAAAA;;;AAMGC,CAAAA,CAAAA,CAAAA,kDAAAA,EAAAA,aAAAA,CAAcC,WAAWC,OAAO,CAAA,EAAA,iDAAA,EAGrBF,cAAcC,UAAAA,CAAWC,OAAO,uGAO5BF,aAAAA,CAAcC,UAAAA,CAAWE,aAAa,CAAA,EAAA,4CAAA,EAI1CH,cAAcC,UAAAA,CAAWE,aAAa,cACjDH,aAAAA,CAAcC,UAAAA,CAAWG,gBAAgB,CAAA,EAAA,8CAAA,EAI9BJ,aAAAA,CAAcC,UAAAA,CAAWC,OAAO,cAC3CF,aAAAA,CAAcC,UAAAA,CAAWG,gBAAgB,CAAA,EAAA,uCAAA,EAI9BJ,aAAAA,CAAcC,WAAWI,kBAAkB,CAAA,EAAA,SAAA,EACtDL,cAAcC,UAAAA,CAAWK,eAAe,oDAI7BN,aAAAA,CAAcC,UAAAA,CAAWK,eAAe,CAAA,EAAA,SAAA,EACnDN,aAAAA,CAAcC,WAAWG,gBAAgB,CAAA,EAAA,IAAA,CAAA;AAI1D,MAAMG,KAAAA,iBAAQR,MAAAA,CAAAA,OAAAA,EAAAA;;;;MAQDS,UAAAA,iBAAaT,MAAAA,CAAAA,KAAAA,EAAAA;;;AAMlBQ,CAAAA,CAAAA,CAAAA,0EAAAA,EAAAA,KAAAA,EAAAA,mDAAAA,EAIAA,KAAAA,EAAAA,gDAAAA;AAUR;;;;AAIC,IACD,SAASE,oBAAAA,CAAqBC,KAAuB,EAAEC,GAAgC,EAAA;AACnF,IAAA,MAAM,EAAEC,KAAK,EAAE,GAAGC,MAAM,GAAGH,KAAAA;AAC3B,IAAA,qBACII,IAAA,CAACP,KAAAA,EAAAA;;0BACGQ,GAAA,CAACjB,KAAAA,EAAAA;AAAO,gBAAA,GAAGe,IAAI;gBAAEG,IAAAA,EAAK,OAAA;gBAAQL,GAAAA,EAAKA;;0BACnCI,GAAA,CAACE,MAAAA,EAAAA;AAAML,gBAAAA,QAAAA,EAAAA;;;;AAGnB;AAEA,MAAMM,WAAAA,iBAAcC,KAAAA,CAAMC,UAAU,CAACX,oBAAAA;;;;"}
1
+ {"version":3,"file":"RadioButton.js","sources":["../../../src/components/Input/RadioButton.tsx"],"sourcesContent":["import React, { useEffect, useId, useRef, useImperativeHandle } from 'react';\nimport styled from '@emotion/styled';\nimport { getThemeValue, THEME_NAME } from '../../shared/constants';\n\nconst Input = styled.input`\n appearance: none;\n margin: 0;\n width: 0;\n\n & + span {\n color: ${getThemeValue(THEME_NAME.PRIMARY)};\n padding: 6px 12px;\n border: none;\n border: 1px solid ${getThemeValue(THEME_NAME.PRIMARY)};\n cursor: pointer;\n margin-right: -1px;\n line-height: 18px;\n }\n\n &:enabled:focus + span {\n box-shadow: 0 0 0 4px ${getThemeValue(THEME_NAME.PRIMARY_LIGHT)};\n }\n\n &:enabled:hover + span {\n background-color: ${getThemeValue(THEME_NAME.PRIMARY_LIGHT)};\n color: ${getThemeValue(THEME_NAME.TEXT_COLOR_LIGHT)};\n }\n\n &:enabled:checked + span {\n background-color: ${getThemeValue(THEME_NAME.PRIMARY)};\n color: ${getThemeValue(THEME_NAME.TEXT_COLOR_LIGHT)};\n }\n\n &:disabled + span {\n background-color: ${getThemeValue(THEME_NAME.BORDER_LIGHT_COLOR)};\n color: ${getThemeValue(THEME_NAME.DISABLED_BORDER)};\n }\n\n &:disabled:checked + span {\n background-color: ${getThemeValue(THEME_NAME.DISABLED_BORDER)};\n color: ${getThemeValue(THEME_NAME.TEXT_COLOR_LIGHT)};\n }\n`;\n\nconst Label = styled.label`\n display: inline-flex;\n\n &:focus-within {\n z-index: 1;\n }\n`;\n\nexport const RadioGroup = styled.div`\n display: inline-flex;\n align-items: center;\n border-radius: 3px;\n margin: 5px 0;\n\n & > ${Label}:first-of-type > span {\n border-radius: 3px 0 0 3px;\n }\n\n & > ${Label}:last-of-type > span {\n border-radius: 0 3px 3px 0;\n }\n`;\n\ntype RadioButtonProps = {\n /** Label for the field */\n label?: string;\n /** Error text to be shown below the field */\n errorText?: string;\n} & React.InputHTMLAttributes<HTMLInputElement>;\n\n/**\n * RadioButton Component\n * @param props - Component props\n * @param forwardedRef - Ref forwarded to the underlying HTMLInputElement\n */\nfunction RadioButtonComponent(props: RadioButtonProps, forwardedRef: React.Ref<HTMLInputElement>) {\n const { label, errorText, ...rest } = props;\n const internalRef = useRef<HTMLInputElement>(null);\n const errorId = useId();\n\n useImperativeHandle(forwardedRef, () => internalRef.current as HTMLInputElement);\n\n useEffect(() => {\n if (internalRef.current) {\n internalRef.current.setCustomValidity(errorText || '');\n }\n }, [errorText]);\n\n return (\n <Label>\n <Input\n {...rest}\n type=\"radio\"\n ref={internalRef}\n aria-invalid={!!errorText}\n aria-describedby={errorText ? errorId : undefined}\n />\n <span>{label}</span>\n </Label>\n );\n}\n\nconst RadioButton = React.forwardRef(RadioButtonComponent);\nexport default RadioButton;\n"],"names":["Input","styled","getThemeValue","THEME_NAME","PRIMARY","PRIMARY_LIGHT","TEXT_COLOR_LIGHT","BORDER_LIGHT_COLOR","DISABLED_BORDER","Label","RadioGroup","RadioButtonComponent","props","forwardedRef","label","errorText","rest","internalRef","useRef","errorId","useId","useImperativeHandle","current","useEffect","setCustomValidity","_jsxs","_jsx","type","ref","aria-invalid","aria-describedby","undefined","span","RadioButton","React","forwardRef"],"mappings":";;;;;AAIA,MAAMA,KAAAA,iBAAQC,MAAAA,CAAAA,OAAAA,EAAAA;;;AAMGC,CAAAA,CAAAA,CAAAA,kDAAAA,EAAAA,aAAAA,CAAcC,WAAWC,OAAO,CAAA,EAAA,iDAAA,EAGrBF,cAAcC,UAAAA,CAAWC,OAAO,uGAO5BF,aAAAA,CAAcC,UAAAA,CAAWE,aAAa,CAAA,EAAA,4CAAA,EAI1CH,cAAcC,UAAAA,CAAWE,aAAa,cACjDH,aAAAA,CAAcC,UAAAA,CAAWG,gBAAgB,CAAA,EAAA,8CAAA,EAI9BJ,aAAAA,CAAcC,UAAAA,CAAWC,OAAO,cAC3CF,aAAAA,CAAcC,UAAAA,CAAWG,gBAAgB,CAAA,EAAA,uCAAA,EAI9BJ,aAAAA,CAAcC,WAAWI,kBAAkB,CAAA,EAAA,SAAA,EACtDL,cAAcC,UAAAA,CAAWK,eAAe,oDAI7BN,aAAAA,CAAcC,UAAAA,CAAWK,eAAe,CAAA,EAAA,SAAA,EACnDN,aAAAA,CAAcC,WAAWG,gBAAgB,CAAA,EAAA,IAAA,CAAA;AAI1D,MAAMG,KAAAA,iBAAQR,MAAAA,CAAAA,OAAAA,EAAAA;;;;MAQDS,UAAAA,iBAAaT,MAAAA,CAAAA,KAAAA,EAAAA;;;AAMhBQ,CAAAA,CAAAA,CAAAA,4EAAAA,EAAAA,KAAAA,EAAAA,uDAAAA,EAIAA,KAAAA,EAAAA,kDAAAA;AAYV;;;;AAIC,IACD,SAASE,oBAAAA,CAAqBC,KAAuB,EAAEC,YAAyC,EAAA;AAC5F,IAAA,MAAM,EAAEC,KAAK,EAAEC,SAAS,EAAE,GAAGC,MAAM,GAAGJ,KAAAA;AACtC,IAAA,MAAMK,cAAcC,MAAAA,CAAyB,IAAA,CAAA;AAC7C,IAAA,MAAMC,OAAAA,GAAUC,KAAAA,EAAAA;IAEhBC,mBAAAA,CAAoBR,YAAAA,EAAc,IAAMI,WAAAA,CAAYK,OAAO,CAAA;IAE3DC,SAAAA,CAAU,IAAA;QACN,IAAIN,WAAAA,CAAYK,OAAO,EAAE;AACrBL,YAAAA,WAAAA,CAAYK,OAAO,CAACE,iBAAiB,CAACT,SAAAA,IAAa,EAAA,CAAA;AACvD,QAAA;IACJ,CAAA,EAAG;AAACA,QAAAA;AAAU,KAAA,CAAA;AAEd,IAAA,qBACIU,IAAA,CAAChB,KAAAA,EAAAA;;0BACGiB,GAAA,CAAC1B,KAAAA,EAAAA;AACI,gBAAA,GAAGgB,IAAI;gBACRW,IAAAA,EAAK,OAAA;gBACLC,GAAAA,EAAKX,WAAAA;AACLY,gBAAAA,cAAAA,EAAc,CAAC,CAACd,SAAAA;AAChBe,gBAAAA,kBAAAA,EAAkBf,YAAYI,OAAAA,GAAUY;;0BAE5CL,GAAA,CAACM,MAAAA,EAAAA;AAAMlB,gBAAAA,QAAAA,EAAAA;;;;AAGnB;AAEA,MAAMmB,WAAAA,iBAAcC,KAAAA,CAAMC,UAAU,CAACxB,oBAAAA;;;;"}