@chayns-ui/core 0.3.2 → 0.4.1

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 (95) hide show
  1. package/README.md +5 -1
  2. package/dist/button.css +16 -0
  3. package/dist/checkbox.css +83 -0
  4. package/dist/components/accordion/Accordion.d.ts.map +1 -1
  5. package/dist/components/accordion/Accordion.js +3 -0
  6. package/dist/components/accordion/Accordion.js.map +1 -1
  7. package/dist/components/checkbox/Checkbox.d.ts +4 -0
  8. package/dist/components/checkbox/Checkbox.d.ts.map +1 -0
  9. package/dist/components/checkbox/Checkbox.js +27 -0
  10. package/dist/components/checkbox/Checkbox.js.map +1 -0
  11. package/dist/components/checkbox/Checkbox.types.d.ts +9 -0
  12. package/dist/components/checkbox/Checkbox.types.d.ts.map +1 -0
  13. package/dist/components/list/List.d.ts +14 -2
  14. package/dist/components/list/List.d.ts.map +1 -1
  15. package/dist/components/list/List.js +79 -6
  16. package/dist/components/list/List.js.map +1 -1
  17. package/dist/components/list/List.types.d.ts +17 -77
  18. package/dist/components/list/List.types.d.ts.map +1 -1
  19. package/dist/components/list/ListContext.d.ts +6 -0
  20. package/dist/components/list/ListContext.d.ts.map +1 -0
  21. package/dist/components/list/ListContext.js +14 -0
  22. package/dist/components/list/ListContext.js.map +1 -0
  23. package/dist/components/message-box/MessageBox.d.ts +4 -0
  24. package/dist/components/message-box/MessageBox.d.ts.map +1 -0
  25. package/dist/components/message-box/MessageBox.js +19 -0
  26. package/dist/components/message-box/MessageBox.js.map +1 -0
  27. package/dist/components/message-box/MessageBox.types.d.ts +13 -0
  28. package/dist/components/message-box/MessageBox.types.d.ts.map +1 -0
  29. package/dist/components/popup/Popup.d.ts +6 -3
  30. package/dist/components/popup/Popup.d.ts.map +1 -1
  31. package/dist/components/popup/Popup.js +102 -90
  32. package/dist/components/popup/Popup.js.map +1 -1
  33. package/dist/components/popup/Popup.types.d.ts +17 -7
  34. package/dist/components/popup/Popup.types.d.ts.map +1 -1
  35. package/dist/components/popup/PopupList.d.ts.map +1 -1
  36. package/dist/components/popup/PopupList.js +7 -5
  37. package/dist/components/popup/PopupList.js.map +1 -1
  38. package/dist/components/radio-group/RadioGroup.d.ts +6 -0
  39. package/dist/components/radio-group/RadioGroup.d.ts.map +1 -0
  40. package/dist/components/radio-group/RadioGroup.js +69 -0
  41. package/dist/components/radio-group/RadioGroup.js.map +1 -0
  42. package/dist/components/radio-group/RadioGroup.types.d.ts +30 -0
  43. package/dist/components/radio-group/RadioGroup.types.d.ts.map +1 -0
  44. package/dist/components/radio-group/RadioGroupContext.d.ts +11 -0
  45. package/dist/components/radio-group/RadioGroupContext.d.ts.map +1 -0
  46. package/dist/components/radio-group/RadioGroupContext.js +12 -0
  47. package/dist/components/radio-group/RadioGroupContext.js.map +1 -0
  48. package/dist/components/segmented-control/SegmentedControl.d.ts +16 -0
  49. package/dist/components/segmented-control/SegmentedControl.d.ts.map +1 -0
  50. package/dist/components/segmented-control/SegmentedControl.js +146 -0
  51. package/dist/components/segmented-control/SegmentedControl.js.map +1 -0
  52. package/dist/components/segmented-control/SegmentedControl.types.d.ts +41 -0
  53. package/dist/components/segmented-control/SegmentedControl.types.d.ts.map +1 -0
  54. package/dist/components/segmented-control/SegmentedControlContext.d.ts +11 -0
  55. package/dist/components/segmented-control/SegmentedControlContext.d.ts.map +1 -0
  56. package/dist/components/segmented-control/SegmentedControlContext.js +12 -0
  57. package/dist/components/segmented-control/SegmentedControlContext.js.map +1 -0
  58. package/dist/components/switch/Switch.d.ts +4 -0
  59. package/dist/components/switch/Switch.d.ts.map +1 -0
  60. package/dist/components/switch/Switch.js +28 -0
  61. package/dist/components/switch/Switch.js.map +1 -0
  62. package/dist/components/switch/Switch.types.d.ts +9 -0
  63. package/dist/components/switch/Switch.types.d.ts.map +1 -0
  64. package/dist/components/text-area/TextArea.d.ts +4 -0
  65. package/dist/components/text-area/TextArea.d.ts.map +1 -0
  66. package/dist/components/text-area/TextArea.js +45 -0
  67. package/dist/components/text-area/TextArea.js.map +1 -0
  68. package/dist/components/text-area/TextArea.types.d.ts +15 -0
  69. package/dist/components/text-area/TextArea.types.d.ts.map +1 -0
  70. package/dist/components/text-field/TextField.d.ts +4 -0
  71. package/dist/components/text-field/TextField.d.ts.map +1 -0
  72. package/dist/components/text-field/TextField.js +45 -0
  73. package/dist/components/text-field/TextField.js.map +1 -0
  74. package/dist/components/text-field/TextField.types.d.ts +15 -0
  75. package/dist/components/text-field/TextField.types.d.ts.map +1 -0
  76. package/dist/index.d.ts +15 -2
  77. package/dist/index.d.ts.map +1 -1
  78. package/dist/index.js +9 -3
  79. package/dist/list.css +33 -44
  80. package/dist/message-box.css +26 -0
  81. package/dist/radio-group.css +102 -0
  82. package/dist/segmented-control.css +79 -0
  83. package/dist/styles.css +7 -0
  84. package/dist/switch.css +76 -0
  85. package/dist/text-area.css +136 -0
  86. package/dist/text-field.css +138 -0
  87. package/package.json +8 -1
  88. package/dist/components/list-item/ListItem.d.ts +0 -4
  89. package/dist/components/list-item/ListItem.d.ts.map +0 -1
  90. package/dist/components/list-item/ListItem.js +0 -42
  91. package/dist/components/list-item/ListItem.js.map +0 -1
  92. package/dist/components/list-item/list-item-body/ListItemBody.d.ts +0 -10
  93. package/dist/components/list-item/list-item-body/ListItemBody.d.ts.map +0 -1
  94. package/dist/components/list-item/list-item-body/ListItemBody.js +0 -30
  95. package/dist/components/list-item/list-item-body/ListItemBody.js.map +0 -1
@@ -1,107 +1,119 @@
1
- import { Fragment, jsx, jsxs } from "react/jsx-runtime";
2
- import { cloneElement, useCallback, useEffect, useId, useLayoutEffect, useRef, useState } from "react";
1
+ import { jsx } from "react/jsx-runtime";
2
+ import { cloneElement, createContext, forwardRef, isValidElement, useCallback, useContext, useEffect, useId, useRef, useState } from "react";
3
3
  import { createPortal } from "react-dom";
4
4
  //#region src/components/popup/Popup.tsx
5
- var Popup = ({ children, className, trigger }) => {
6
- const [open, setOpen] = useState(false);
7
- const [position, setPosition] = useState({
8
- left: 0,
9
- top: 0
10
- });
11
- const triggerRef = useRef(null);
12
- const popupRef = useRef(null);
13
- const popupId = useId();
14
- const updatePosition = () => {
15
- const anchor = triggerRef.current;
16
- if (!anchor) return;
17
- const rect = anchor.getBoundingClientRect();
18
- const popup = popupRef.current;
19
- const popupWidth = popup?.offsetWidth ?? 0;
20
- const popupHeight = popup?.offsetHeight ?? 0;
21
- const gap = 8;
22
- const margin = 8;
23
- const left = Math.min(Math.max(margin, rect.left), Math.max(margin, window.innerWidth - popupWidth - margin));
24
- const below = rect.bottom + gap;
25
- const top = below + popupHeight <= window.innerHeight - margin ? below : Math.max(margin, rect.top - popupHeight - gap);
26
- setPosition({
27
- left,
28
- top
29
- });
5
+ var PopupContext = createContext(null);
6
+ function usePopup(part) {
7
+ const context = useContext(PopupContext);
8
+ if (!context) throw new Error(`Popup.${part} must be rendered within Popup.`);
9
+ return context;
10
+ }
11
+ var Trigger = forwardRef(function Trigger({ asChild = false, children, onClick, ...props }, ref) {
12
+ const popup = usePopup("Trigger");
13
+ const setRef = (node) => {
14
+ popup.setTriggerElement(node);
15
+ if (typeof ref === "function") ref(node);
16
+ else if (ref) ref.current = node;
30
17
  };
31
- const close = (restoreFocus) => {
32
- setOpen(false);
33
- if (restoreFocus) queueMicrotask(() => triggerRef.current?.focus());
18
+ const triggerProps = {
19
+ ...props,
20
+ "aria-controls": popup.contentId,
21
+ "aria-expanded": popup.open,
22
+ onClick: (event) => {
23
+ onClick?.(event);
24
+ if (!event.defaultPrevented) popup.setOpen(!popup.open);
25
+ },
26
+ ref: setRef
34
27
  };
35
- const setTriggerRef = useCallback((node) => {
36
- triggerRef.current = node;
37
- }, []);
38
- useLayoutEffect(() => {
39
- if (!open) return;
40
- updatePosition();
41
- (popupRef.current?.querySelector("[role=\"menuitem\"]"))?.focus();
42
- }, [open]);
28
+ if (asChild && isValidElement(children)) return cloneElement(children, triggerProps);
29
+ return /* @__PURE__ */ jsx("button", {
30
+ ...triggerProps,
31
+ ref: setRef,
32
+ type: "button",
33
+ children
34
+ });
35
+ });
36
+ var Content = forwardRef(function Content({ children, ...props }, ref) {
37
+ const popup = usePopup("Content");
38
+ const contentRef = useRef(null);
43
39
  useEffect(() => {
44
- if (!open) return;
45
- const handlePointerDown = (event) => {
46
- const target = event.target;
47
- if (target instanceof Node && !triggerRef.current?.contains(target) && !popupRef.current?.contains(target)) close(false);
48
- };
49
- const handleKeyDown = (event) => {
50
- if (event.key === "Escape") {
40
+ if (popup.open) contentRef.current?.querySelector("[role=\"menuitem\"]")?.focus();
41
+ }, [popup.open]);
42
+ function setRef(element) {
43
+ contentRef.current = element;
44
+ if (typeof ref === "function") ref(element);
45
+ else if (ref) ref.current = element;
46
+ }
47
+ if (!popup.open || typeof document === "undefined") return null;
48
+ return createPortal(/* @__PURE__ */ jsx("div", {
49
+ ...props,
50
+ className: ["chayns-popup", props.className].filter(Boolean).join(" "),
51
+ id: popup.contentId,
52
+ ref: setRef,
53
+ children
54
+ }), document.body);
55
+ });
56
+ var Root = ({ children, closeOnEscape = true, closeOnOutsidePress = true, defaultOpen = false, onOpenChange, open }) => {
57
+ const [uncontrolledOpen, setUncontrolledOpen] = useState(defaultOpen);
58
+ const [triggerElement, setTriggerElement] = useState(null);
59
+ const contentId = useId();
60
+ const isOpen = open ?? uncontrolledOpen;
61
+ const setOpen = useCallback((next, restore = true) => {
62
+ if (open === void 0) setUncontrolledOpen(next);
63
+ onOpenChange?.(next);
64
+ if (!next && restore) queueMicrotask(() => triggerElement?.focus());
65
+ }, [
66
+ onOpenChange,
67
+ open,
68
+ triggerElement
69
+ ]);
70
+ useEffect(() => {
71
+ if (!isOpen) return;
72
+ const key = (event) => {
73
+ if (event.key === "Escape" && closeOnEscape) {
51
74
  event.preventDefault();
52
- close(true);
75
+ setOpen(false);
53
76
  }
54
- if (event.key === "Tab") close(false);
77
+ if (event.key === "Tab") setOpen(false, false);
55
78
  };
56
- const handleViewportChange = () => updatePosition();
57
- const handlePopupClick = (event) => {
58
- if (event.target.closest("[role=\"menuitem\"]")) close(true);
79
+ const outside = (event) => {
80
+ const target = event.target;
81
+ if (closeOnOutsidePress && target instanceof Node && !triggerElement?.contains(target) && !document.getElementById(contentId)?.contains(target)) setOpen(false, false);
82
+ };
83
+ const menuAction = (event) => {
84
+ if (event.target.closest("[role=\"menuitem\"]")) setOpen(false);
59
85
  };
60
- const popupElement = popupRef.current;
61
- document.addEventListener("pointerdown", handlePointerDown);
62
- document.addEventListener("keydown", handleKeyDown);
63
- window.addEventListener("resize", handleViewportChange);
64
- window.addEventListener("scroll", handleViewportChange, true);
65
- popupElement?.addEventListener("click", handlePopupClick);
86
+ document.addEventListener("keydown", key);
87
+ document.addEventListener("pointerdown", outside);
88
+ document.addEventListener("click", menuAction);
66
89
  return () => {
67
- document.removeEventListener("pointerdown", handlePointerDown);
68
- document.removeEventListener("keydown", handleKeyDown);
69
- window.removeEventListener("resize", handleViewportChange);
70
- window.removeEventListener("scroll", handleViewportChange, true);
71
- popupElement?.removeEventListener("click", handlePopupClick);
90
+ document.removeEventListener("keydown", key);
91
+ document.removeEventListener("pointerdown", outside);
92
+ document.removeEventListener("click", menuAction);
72
93
  };
73
- }, [open]);
74
- const triggerElement = trigger;
75
- const enhancedTrigger = cloneElement(triggerElement, {
76
- "aria-controls": popupId,
77
- "aria-expanded": open,
78
- "aria-haspopup": "menu",
79
- onClick: (event) => {
80
- triggerElement.props.onClick?.(event);
81
- if (!event.defaultPrevented) setOpen((value) => !value);
82
- },
83
- onKeyDown: (event) => {
84
- triggerElement.props.onKeyDown?.(event);
85
- if (event.defaultPrevented) return;
86
- if (event.key === "ArrowDown" || event.key === "ArrowUp") {
87
- event.preventDefault();
88
- setOpen(true);
89
- }
90
- },
91
- ref: setTriggerRef
92
- });
93
- return /* @__PURE__ */ jsxs(Fragment, { children: [enhancedTrigger, open ? createPortal(/* @__PURE__ */ jsx("div", {
94
- className: ["chayns-popup", className].filter(Boolean).join(" "),
95
- id: popupId,
96
- ref: popupRef,
97
- style: {
98
- left: position.left,
99
- top: position.top
94
+ }, [
95
+ isOpen,
96
+ closeOnEscape,
97
+ closeOnOutsidePress,
98
+ contentId,
99
+ setOpen,
100
+ triggerElement
101
+ ]);
102
+ return /* @__PURE__ */ jsx(PopupContext.Provider, {
103
+ value: {
104
+ contentId,
105
+ open: isOpen,
106
+ setOpen,
107
+ setTriggerElement
100
108
  },
101
109
  children
102
- }), document.body) : null] });
110
+ });
103
111
  };
112
+ var Popup_default = Object.assign(Root, {
113
+ Trigger,
114
+ Content
115
+ });
104
116
  //#endregion
105
- export { Popup as default };
117
+ export { Popup_default as default };
106
118
 
107
119
  //# sourceMappingURL=Popup.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"Popup.js","names":[],"sources":["../../../src/components/popup/Popup.tsx"],"sourcesContent":["import {\n cloneElement,\n useCallback,\n useEffect,\n useId,\n useLayoutEffect,\n useRef,\n useState,\n type KeyboardEvent,\n type MouseEvent,\n type Ref,\n type ReactElement,\n} from 'react';\nimport { createPortal } from 'react-dom';\n\nimport type { PopupProps } from './Popup.types.js';\n\ninterface PopupTriggerProps {\n 'aria-controls'?: string;\n 'aria-expanded'?: boolean;\n 'aria-haspopup'?: string;\n onClick?: (event: MouseEvent) => void;\n onKeyDown?: (event: KeyboardEvent) => void;\n}\n\ntype PopupTriggerElement = ReactElement<PopupTriggerProps & { ref?: Ref<HTMLElement> }>;\nconst Popup = ({ children, className, trigger }: PopupProps) => {\n const [open, setOpen] = useState(false);\n const [position, setPosition] = useState({ left: 0, top: 0 });\n const triggerRef = useRef<HTMLElement>(null);\n const popupRef = useRef<HTMLDivElement>(null);\n const popupId = useId();\n\n const updatePosition = () => {\n const anchor = triggerRef.current;\n if (!anchor) return;\n\n const rect = anchor.getBoundingClientRect();\n const popup = popupRef.current;\n const popupWidth = popup?.offsetWidth ?? 0;\n const popupHeight = popup?.offsetHeight ?? 0;\n const gap = 8;\n const margin = 8;\n const left = Math.min(\n Math.max(margin, rect.left),\n Math.max(margin, window.innerWidth - popupWidth - margin),\n );\n const below = rect.bottom + gap;\n const top =\n below + popupHeight <= window.innerHeight - margin\n ? below\n : Math.max(margin, rect.top - popupHeight - gap);\n\n setPosition({ left, top });\n };\n\n const close = (restoreFocus: boolean) => {\n setOpen(false);\n if (restoreFocus) {\n queueMicrotask(() => triggerRef.current?.focus());\n }\n };\n\n const setTriggerRef = useCallback((node: HTMLElement | null) => {\n triggerRef.current = node;\n }, []);\n\n useLayoutEffect(() => {\n if (!open) return;\n updatePosition();\n const firstItem = popupRef.current?.querySelector<HTMLElement>('[role=\"menuitem\"]');\n firstItem?.focus();\n }, [open]);\n\n useEffect(() => {\n if (!open) return;\n\n const handlePointerDown = (event: PointerEvent) => {\n const target = event.target;\n if (\n target instanceof Node &&\n !triggerRef.current?.contains(target) &&\n !popupRef.current?.contains(target)\n ) {\n close(false);\n }\n };\n const handleKeyDown = (event: globalThis.KeyboardEvent) => {\n if (event.key === 'Escape') {\n event.preventDefault();\n close(true);\n }\n if (event.key === 'Tab') close(false);\n };\n const handleViewportChange = () => updatePosition();\n const handlePopupClick = (event: globalThis.MouseEvent) => {\n if ((event.target as HTMLElement).closest('[role=\"menuitem\"]')) {\n close(true);\n }\n };\n\n const popupElement = popupRef.current;\n\n document.addEventListener('pointerdown', handlePointerDown);\n document.addEventListener('keydown', handleKeyDown);\n window.addEventListener('resize', handleViewportChange);\n window.addEventListener('scroll', handleViewportChange, true);\n popupElement?.addEventListener('click', handlePopupClick);\n\n return () => {\n document.removeEventListener('pointerdown', handlePointerDown);\n document.removeEventListener('keydown', handleKeyDown);\n window.removeEventListener('resize', handleViewportChange);\n window.removeEventListener('scroll', handleViewportChange, true);\n popupElement?.removeEventListener('click', handlePopupClick);\n };\n }, [open]);\n\n const triggerElement = trigger as PopupTriggerElement;\n // cloneElement forwards `ref` as a plain prop to merge it with the trigger's own ref; the ref\n // is never read during this render, only later by React when attaching the trigger DOM node.\n // eslint-disable-next-line react-hooks/refs\n const enhancedTrigger = cloneElement(triggerElement, {\n 'aria-controls': popupId,\n 'aria-expanded': open,\n 'aria-haspopup': 'menu',\n onClick: (event: React.MouseEvent) => {\n triggerElement.props.onClick?.(event);\n if (!event.defaultPrevented) setOpen((value) => !value);\n },\n onKeyDown: (event: KeyboardEvent) => {\n triggerElement.props.onKeyDown?.(event);\n if (event.defaultPrevented) return;\n if (event.key === 'ArrowDown' || event.key === 'ArrowUp') {\n event.preventDefault();\n setOpen(true);\n }\n },\n ref: setTriggerRef,\n });\n\n return (\n <>\n {enhancedTrigger}\n {open\n ? createPortal(\n <div\n className={['chayns-popup', className].filter(Boolean).join(' ')}\n id={popupId}\n ref={popupRef}\n style={{ left: position.left, top: position.top }}\n >\n {children}\n </div>,\n document.body,\n )\n : null}\n </>\n );\n};\n\nexport default Popup;\n"],"mappings":"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"}
1
+ {"version":3,"file":"Popup.js","names":[],"sources":["../../../src/components/popup/Popup.tsx"],"sourcesContent":["import {\n cloneElement,\n createContext,\n forwardRef,\n isValidElement,\n useCallback,\n useContext,\n useEffect,\n useId,\n useRef,\n useState,\n} from 'react';\nimport { createPortal } from 'react-dom';\nimport type { PopupContentProps, PopupProps, PopupTriggerProps } from './Popup.types.js';\n\ninterface PopupContextValue {\n contentId: string;\n open: boolean;\n setOpen: (open: boolean, restore?: boolean) => void;\n setTriggerElement: (element: HTMLButtonElement | null) => void;\n}\nconst PopupContext = createContext<PopupContextValue | null>(null);\nfunction usePopup(part: string) {\n const context = useContext(PopupContext);\n if (!context) throw new Error(`Popup.${part} must be rendered within Popup.`);\n return context;\n}\n\nconst Trigger = forwardRef<HTMLButtonElement, PopupTriggerProps>(function Trigger(\n { asChild = false, children, onClick, ...props },\n ref,\n) {\n const popup = usePopup('Trigger');\n const setRef = (node: HTMLButtonElement | null) => {\n popup.setTriggerElement(node);\n if (typeof ref === 'function') ref(node);\n else if (ref) ref.current = node;\n };\n const triggerProps = {\n ...props,\n 'aria-controls': popup.contentId,\n 'aria-expanded': popup.open,\n onClick: (event: React.MouseEvent<HTMLButtonElement>) => {\n onClick?.(event);\n if (!event.defaultPrevented) popup.setOpen(!popup.open);\n },\n ref: setRef,\n };\n\n if (asChild && isValidElement(children)) {\n // eslint-disable-next-line react-hooks/refs\n return cloneElement(children, triggerProps);\n }\n\n return (\n <button {...triggerProps} ref={setRef} type=\"button\">\n {children}\n </button>\n );\n});\nconst Content = forwardRef<HTMLDivElement, PopupContentProps>(function Content(\n { children, ...props },\n ref,\n) {\n const popup = usePopup('Content');\n const contentRef = useRef<HTMLDivElement>(null);\n\n useEffect(() => {\n if (popup.open) {\n contentRef.current?.querySelector<HTMLElement>('[role=\"menuitem\"]')?.focus();\n }\n }, [popup.open]);\n\n function setRef(element: HTMLDivElement | null) {\n contentRef.current = element;\n\n if (typeof ref === 'function') ref(element);\n else if (ref) ref.current = element;\n }\n\n if (!popup.open || typeof document === 'undefined') return null;\n return createPortal(\n <div\n {...props}\n className={['chayns-popup', props.className].filter(Boolean).join(' ')}\n id={popup.contentId}\n ref={setRef}\n >\n {children}\n </div>,\n document.body,\n );\n});\nconst Root = ({\n children,\n closeOnEscape = true,\n closeOnOutsidePress = true,\n defaultOpen = false,\n onOpenChange,\n open,\n}: PopupProps) => {\n const [uncontrolledOpen, setUncontrolledOpen] = useState(defaultOpen);\n const [triggerElement, setTriggerElement] = useState<HTMLButtonElement | null>(null);\n const contentId = useId();\n const isOpen = open ?? uncontrolledOpen;\n const setOpen = useCallback(\n (next: boolean, restore = true) => {\n if (open === undefined) setUncontrolledOpen(next);\n onOpenChange?.(next);\n if (!next && restore) queueMicrotask(() => triggerElement?.focus());\n },\n [onOpenChange, open, triggerElement],\n );\n useEffect(() => {\n if (!isOpen) return;\n const key = (event: KeyboardEvent) => {\n if (event.key === 'Escape' && closeOnEscape) {\n event.preventDefault();\n setOpen(false);\n }\n if (event.key === 'Tab') setOpen(false, false);\n };\n const outside = (event: PointerEvent) => {\n const target = event.target;\n if (\n closeOnOutsidePress &&\n target instanceof Node &&\n !triggerElement?.contains(target) &&\n !document.getElementById(contentId)?.contains(target)\n )\n setOpen(false, false);\n };\n const menuAction = (event: MouseEvent) => {\n if ((event.target as HTMLElement).closest('[role=\"menuitem\"]')) setOpen(false);\n };\n document.addEventListener('keydown', key);\n document.addEventListener('pointerdown', outside);\n document.addEventListener('click', menuAction);\n return () => {\n document.removeEventListener('keydown', key);\n document.removeEventListener('pointerdown', outside);\n document.removeEventListener('click', menuAction);\n };\n }, [isOpen, closeOnEscape, closeOnOutsidePress, contentId, setOpen, triggerElement]);\n return (\n <PopupContext.Provider value={{ contentId, open: isOpen, setOpen, setTriggerElement }}>\n {children}\n </PopupContext.Provider>\n );\n};\nexport default Object.assign(Root, { Trigger, Content });\n"],"mappings":"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"}
@@ -1,17 +1,27 @@
1
- import type { ReactElement, ReactNode } from 'react';
1
+ import type { ComponentPropsWithRef, ReactNode } from 'react';
2
2
  import type { ButtonIcon } from '../button/Button.types.js';
3
+ export interface PopupProps {
4
+ children: ReactNode;
5
+ open?: boolean;
6
+ defaultOpen?: boolean;
7
+ onOpenChange?: (open: boolean) => void;
8
+ closeOnEscape?: boolean;
9
+ closeOnOutsidePress?: boolean;
10
+ }
11
+ export interface PopupTriggerProps extends Omit<ComponentPropsWithRef<'button'>, 'children' | 'type' | 'aria-controls' | 'aria-expanded'> {
12
+ children: ReactNode;
13
+ /** Internal composition escape hatch for PopupList's documented trigger element. */
14
+ asChild?: boolean;
15
+ type?: never;
16
+ }
17
+ export type PopupContentProps = ComponentPropsWithRef<'div'>;
3
18
  export interface PopupListItem {
4
19
  icon: ButtonIcon;
5
20
  text: string;
6
21
  onClick: () => void;
7
22
  }
8
- export interface PopupProps {
9
- trigger: ReactElement;
10
- children: ReactNode;
11
- className?: string;
12
- }
13
23
  export interface PopupListProps {
14
- trigger: ReactElement;
24
+ trigger: ReactNode;
15
25
  items: PopupListItem[];
16
26
  className?: string;
17
27
  }
@@ -1 +1 @@
1
- {"version":3,"file":"Popup.types.d.ts","sourceRoot":"","sources":["../../../src/components/popup/Popup.types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAErD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,2BAA2B,CAAC;AAE5D,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,UAAU,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,IAAI,CAAC;CACrB;AAED,MAAM,WAAW,UAAU;IACzB,OAAO,EAAE,YAAY,CAAC;IACtB,QAAQ,EAAE,SAAS,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,YAAY,CAAC;IACtB,KAAK,EAAE,aAAa,EAAE,CAAC;IACvB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB"}
1
+ {"version":3,"file":"Popup.types.d.ts","sourceRoot":"","sources":["../../../src/components/popup/Popup.types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,qBAAqB,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAC9D,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,2BAA2B,CAAC;AAE5D,MAAM,WAAW,UAAU;IACzB,QAAQ,EAAE,SAAS,CAAC;IACpB,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAC;IACvC,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,mBAAmB,CAAC,EAAE,OAAO,CAAC;CAC/B;AACD,MAAM,WAAW,iBAAkB,SAAQ,IAAI,CAC7C,qBAAqB,CAAC,QAAQ,CAAC,EAC/B,UAAU,GAAG,MAAM,GAAG,eAAe,GAAG,eAAe,CACxD;IACC,QAAQ,EAAE,SAAS,CAAC;IACpB,oFAAoF;IACpF,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,IAAI,CAAC,EAAE,KAAK,CAAC;CACd;AACD,MAAM,MAAM,iBAAiB,GAAG,qBAAqB,CAAC,KAAK,CAAC,CAAC;AAC7D,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,UAAU,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,IAAI,CAAC;CACrB;AACD,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,SAAS,CAAC;IACnB,KAAK,EAAE,aAAa,EAAE,CAAC;IACvB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB"}
@@ -1 +1 @@
1
- {"version":3,"file":"PopupList.d.ts","sourceRoot":"","sources":["../../../src/components/popup/PopupList.tsx"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAEvD,QAAA,MAAM,SAAS,GAAI,+BAA+B,cAAc,gCAwC/D,CAAC;AAEF,eAAe,SAAS,CAAC"}
1
+ {"version":3,"file":"PopupList.d.ts","sourceRoot":"","sources":["../../../src/components/popup/PopupList.tsx"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAEvD,QAAA,MAAM,SAAS,GAAI,+BAA+B,cAAc,gCA2C/D,CAAC;AAEF,eAAe,SAAS,CAAC"}
@@ -1,5 +1,5 @@
1
1
  import ButtonIcon from "../button/button-icon/ButtonIcon.js";
2
- import Popup from "./Popup.js";
2
+ import Popup_default from "./Popup.js";
3
3
  import { jsx, jsxs } from "react/jsx-runtime";
4
4
  import { useRef } from "react";
5
5
  //#region src/components/popup/PopupList.tsx
@@ -18,9 +18,11 @@ var PopupList = ({ className, items, trigger }) => {
18
18
  itemRefs.current[event.key === "Home" ? 0 : items.length - 1]?.focus();
19
19
  }
20
20
  };
21
- return /* @__PURE__ */ jsx(Popup, {
22
- ...className ? { className } : {},
23
- trigger,
21
+ return /* @__PURE__ */ jsxs(Popup_default, { children: [/* @__PURE__ */ jsx(Popup_default.Trigger, {
22
+ asChild: true,
23
+ children: trigger
24
+ }), /* @__PURE__ */ jsx(Popup_default.Content, {
25
+ className,
24
26
  children: /* @__PURE__ */ jsx("div", {
25
27
  onKeyDown: handleKeyDown,
26
28
  role: "menu",
@@ -36,7 +38,7 @@ var PopupList = ({ className, items, trigger }) => {
36
38
  children: [/* @__PURE__ */ jsx(ButtonIcon, { icon: item.icon }), /* @__PURE__ */ jsx("span", { children: item.text })]
37
39
  }, `${item.text}-${index}`))
38
40
  })
39
- });
41
+ })] });
40
42
  };
41
43
  //#endregion
42
44
  export { PopupList as default };
@@ -1 +1 @@
1
- {"version":3,"file":"PopupList.js","names":[],"sources":["../../../src/components/popup/PopupList.tsx"],"sourcesContent":["import { useRef, type KeyboardEvent } from 'react';\n\nimport ButtonIcon from '../button/button-icon/ButtonIcon.js';\nimport Popup from './Popup.js';\nimport type { PopupListProps } from './Popup.types.js';\n\nconst PopupList = ({ className, items, trigger }: PopupListProps) => {\n const itemRefs = useRef<(HTMLButtonElement | null)[]>([]);\n\n const handleKeyDown = (event: KeyboardEvent<HTMLDivElement>) => {\n const index = itemRefs.current.indexOf(document.activeElement as HTMLButtonElement);\n if (index < 0 || items.length === 0) return;\n\n if (event.key === 'ArrowDown' || event.key === 'ArrowUp') {\n event.preventDefault();\n const direction = event.key === 'ArrowDown' ? 1 : -1;\n const nextIndex = (index + direction + items.length) % items.length;\n itemRefs.current[nextIndex]?.focus();\n }\n if (event.key === 'Home' || event.key === 'End') {\n event.preventDefault();\n itemRefs.current[event.key === 'Home' ? 0 : items.length - 1]?.focus();\n }\n };\n\n return (\n <Popup {...(className ? { className } : {})} trigger={trigger}>\n <div onKeyDown={handleKeyDown} role=\"menu\" tabIndex={-1}>\n {items.map((item, index) => (\n <button\n className=\"chayns-popup-list__item\"\n key={`${item.text}-${index}`}\n onClick={item.onClick}\n ref={(element) => {\n itemRefs.current[index] = element;\n }}\n role=\"menuitem\"\n type=\"button\"\n >\n <ButtonIcon icon={item.icon} />\n <span>{item.text}</span>\n </button>\n ))}\n </div>\n </Popup>\n );\n};\n\nexport default PopupList;\n"],"mappings":";;;;;AAMA,IAAM,aAAa,EAAE,WAAW,OAAO,cAA8B;CACnE,MAAM,WAAW,OAAqC,CAAC,CAAC;CAExD,MAAM,iBAAiB,UAAyC;EAC9D,MAAM,QAAQ,SAAS,QAAQ,QAAQ,SAAS,aAAkC;EAClF,IAAI,QAAQ,KAAK,MAAM,WAAW,GAAG;EAErC,IAAI,MAAM,QAAQ,eAAe,MAAM,QAAQ,WAAW;GACxD,MAAM,eAAe;GAErB,MAAM,aAAa,SADD,MAAM,QAAQ,cAAc,IAAI,MACX,MAAM,UAAU,MAAM;GAC7D,SAAS,QAAQ,UAAU,EAAE,MAAM;EACrC;EACA,IAAI,MAAM,QAAQ,UAAU,MAAM,QAAQ,OAAO;GAC/C,MAAM,eAAe;GACrB,SAAS,QAAQ,MAAM,QAAQ,SAAS,IAAI,MAAM,SAAS,EAAE,EAAE,MAAM;EACvE;CACF;CAEA,OACE,oBAAC,OAAD;EAAO,GAAK,YAAY,EAAE,UAAU,IAAI,CAAC;EAAa;EACpD,UAAA,oBAAC,OAAD;GAAK,WAAW;GAAe,MAAK;GAAO,UAAU;GAClD,UAAA,MAAM,KAAK,MAAM,UAChB,qBAAC,UAAD;IACE,WAAU;IAEV,SAAS,KAAK;IACd,MAAM,YAAY;KAChB,SAAS,QAAQ,SAAS;IAC5B;IACA,MAAK;IACL,MAAK;IARP,UAAA,CAUE,oBAAC,YAAD,EAAY,MAAM,KAAK,KAAO,CAAA,GAC9B,oBAAC,QAAD,EAAA,UAAO,KAAK,KAAW,CAAA,CACjB;GAVD,GAAA,GAAG,KAAK,KAAK,GAAG,OAUf,CACT;EACE,CAAA;CACA,CAAA;AAEX"}
1
+ {"version":3,"file":"PopupList.js","names":[],"sources":["../../../src/components/popup/PopupList.tsx"],"sourcesContent":["import { useRef, type KeyboardEvent } from 'react';\n\nimport ButtonIcon from '../button/button-icon/ButtonIcon.js';\nimport Popup from './Popup.js';\nimport type { PopupListProps } from './Popup.types.js';\n\nconst PopupList = ({ className, items, trigger }: PopupListProps) => {\n const itemRefs = useRef<(HTMLButtonElement | null)[]>([]);\n\n const handleKeyDown = (event: KeyboardEvent<HTMLDivElement>) => {\n const index = itemRefs.current.indexOf(document.activeElement as HTMLButtonElement);\n if (index < 0 || items.length === 0) return;\n\n if (event.key === 'ArrowDown' || event.key === 'ArrowUp') {\n event.preventDefault();\n const direction = event.key === 'ArrowDown' ? 1 : -1;\n const nextIndex = (index + direction + items.length) % items.length;\n itemRefs.current[nextIndex]?.focus();\n }\n if (event.key === 'Home' || event.key === 'End') {\n event.preventDefault();\n itemRefs.current[event.key === 'Home' ? 0 : items.length - 1]?.focus();\n }\n };\n\n return (\n <Popup>\n <Popup.Trigger asChild>{trigger}</Popup.Trigger>\n <Popup.Content className={className}>\n <div onKeyDown={handleKeyDown} role=\"menu\" tabIndex={-1}>\n {items.map((item, index) => (\n <button\n className=\"chayns-popup-list__item\"\n key={`${item.text}-${index}`}\n onClick={item.onClick}\n ref={(element) => {\n itemRefs.current[index] = element;\n }}\n role=\"menuitem\"\n type=\"button\"\n >\n <ButtonIcon icon={item.icon} />\n <span>{item.text}</span>\n </button>\n ))}\n </div>\n </Popup.Content>\n </Popup>\n );\n};\n\nexport default PopupList;\n"],"mappings":";;;;;AAMA,IAAM,aAAa,EAAE,WAAW,OAAO,cAA8B;CACnE,MAAM,WAAW,OAAqC,CAAC,CAAC;CAExD,MAAM,iBAAiB,UAAyC;EAC9D,MAAM,QAAQ,SAAS,QAAQ,QAAQ,SAAS,aAAkC;EAClF,IAAI,QAAQ,KAAK,MAAM,WAAW,GAAG;EAErC,IAAI,MAAM,QAAQ,eAAe,MAAM,QAAQ,WAAW;GACxD,MAAM,eAAe;GAErB,MAAM,aAAa,SADD,MAAM,QAAQ,cAAc,IAAI,MACX,MAAM,UAAU,MAAM;GAC7D,SAAS,QAAQ,UAAU,EAAE,MAAM;EACrC;EACA,IAAI,MAAM,QAAQ,UAAU,MAAM,QAAQ,OAAO;GAC/C,MAAM,eAAe;GACrB,SAAS,QAAQ,MAAM,QAAQ,SAAS,IAAI,MAAM,SAAS,EAAE,EAAE,MAAM;EACvE;CACF;CAEA,OACE,qBAAC,eAAD,EAAA,UAAA,CACE,oBAAC,cAAM,SAAP;EAAe,SAAA;EAAS,UAAA;CAAuB,CAAA,GAC/C,oBAAC,cAAM,SAAP;EAA0B;EACxB,UAAA,oBAAC,OAAD;GAAK,WAAW;GAAe,MAAK;GAAO,UAAU;GAClD,UAAA,MAAM,KAAK,MAAM,UAChB,qBAAC,UAAD;IACE,WAAU;IAEV,SAAS,KAAK;IACd,MAAM,YAAY;KAChB,SAAS,QAAQ,SAAS;IAC5B;IACA,MAAK;IACL,MAAK;IARP,UAAA,CAUE,oBAAC,YAAD,EAAY,MAAM,KAAK,KAAO,CAAA,GAC9B,oBAAC,QAAD,EAAA,UAAO,KAAK,KAAW,CAAA,CACjB;GAVD,GAAA,GAAG,KAAK,KAAK,GAAG,OAUf,CACT;EACE,CAAA;CACQ,CAAA,CACV,EAAA,CAAA;AAEX"}
@@ -0,0 +1,6 @@
1
+ import type { RadioGroupProps, RadioProps } from './RadioGroup.types.js';
2
+ declare const RadioGroup: import("react").ForwardRefExoticComponent<Omit<RadioGroupProps, "ref"> & import("react").RefAttributes<HTMLFieldSetElement>> & {
3
+ Radio: import("react").ForwardRefExoticComponent<Omit<RadioProps, "ref"> & import("react").RefAttributes<HTMLInputElement>>;
4
+ };
5
+ export default RadioGroup;
6
+ //# sourceMappingURL=RadioGroup.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"RadioGroup.d.ts","sourceRoot":"","sources":["../../../src/components/radio-group/RadioGroup.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,eAAe,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;AAoEzE,QAAA,MAAM,UAAU;;CAA2C,CAAC;AAE5D,eAAe,UAAU,CAAC"}
@@ -0,0 +1,69 @@
1
+ import { RadioGroupContext, useRadioGroupContext } from "./RadioGroupContext.js";
2
+ import { jsx, jsxs } from "react/jsx-runtime";
3
+ import { forwardRef, useState } from "react";
4
+ //#region src/components/radio-group/RadioGroup.tsx
5
+ var Radio = forwardRef(function Radio({ children, className, disabled, value, ...inputProps }, ref) {
6
+ const group = useRadioGroupContext();
7
+ const isDisabled = group.disabled || disabled === true;
8
+ const inputClassName = ["chayns-radio__input", className].filter(Boolean).join(" ");
9
+ return /* @__PURE__ */ jsxs("label", {
10
+ className: "chayns-radio",
11
+ children: [
12
+ /* @__PURE__ */ jsx("input", {
13
+ ...inputProps,
14
+ checked: group.value === value,
15
+ className: inputClassName,
16
+ disabled: isDisabled,
17
+ name: group.name,
18
+ onChange: () => group.selectValue(value),
19
+ ref,
20
+ type: "radio",
21
+ value
22
+ }),
23
+ /* @__PURE__ */ jsx("span", {
24
+ "aria-hidden": "true",
25
+ className: "chayns-radio__control"
26
+ }),
27
+ /* @__PURE__ */ jsx("span", {
28
+ className: "chayns-radio__label",
29
+ children
30
+ })
31
+ ]
32
+ });
33
+ });
34
+ var RadioGroupRoot = forwardRef(function RadioGroupRoot({ children, className, defaultValue, disabled, label, name, onValueChange, value, ...fieldsetProps }, ref) {
35
+ const [uncontrolledValue, setUncontrolledValue] = useState(defaultValue);
36
+ const isControlled = value !== void 0;
37
+ const selectedValue = isControlled ? value : uncontrolledValue;
38
+ const resolvedClassName = ["chayns-radio-group", className].filter(Boolean).join(" ");
39
+ function selectValue(nextValue) {
40
+ if (!isControlled) setUncontrolledValue(nextValue);
41
+ onValueChange?.(nextValue);
42
+ }
43
+ return /* @__PURE__ */ jsx(RadioGroupContext.Provider, {
44
+ value: {
45
+ disabled: disabled === true,
46
+ name,
47
+ selectValue,
48
+ value: selectedValue
49
+ },
50
+ children: /* @__PURE__ */ jsxs("fieldset", {
51
+ ...fieldsetProps,
52
+ className: resolvedClassName,
53
+ disabled,
54
+ ref,
55
+ children: [/* @__PURE__ */ jsx("legend", {
56
+ className: "chayns-radio-group__legend",
57
+ children: label
58
+ }), /* @__PURE__ */ jsx("div", {
59
+ className: "chayns-radio-group__options",
60
+ children
61
+ })]
62
+ })
63
+ });
64
+ });
65
+ var RadioGroup = Object.assign(RadioGroupRoot, { Radio });
66
+ //#endregion
67
+ export { RadioGroup as default };
68
+
69
+ //# sourceMappingURL=RadioGroup.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"RadioGroup.js","names":[],"sources":["../../../src/components/radio-group/RadioGroup.tsx"],"sourcesContent":["import { forwardRef, useState } from 'react';\n\nimport { RadioGroupContext, useRadioGroupContext } from './RadioGroupContext.js';\nimport type { RadioGroupProps, RadioProps } from './RadioGroup.types.js';\n\nconst Radio = forwardRef<HTMLInputElement, RadioProps>(function Radio(\n { children, className, disabled, value, ...inputProps },\n ref,\n) {\n const group = useRadioGroupContext();\n const isDisabled = group.disabled || disabled === true;\n const inputClassName = ['chayns-radio__input', className].filter(Boolean).join(' ');\n\n return (\n <label className=\"chayns-radio\">\n <input\n {...inputProps}\n checked={group.value === value}\n className={inputClassName}\n disabled={isDisabled}\n name={group.name}\n onChange={() => group.selectValue(value)}\n ref={ref}\n type=\"radio\"\n value={value}\n />\n <span aria-hidden=\"true\" className=\"chayns-radio__control\" />\n <span className=\"chayns-radio__label\">{children}</span>\n </label>\n );\n});\n\nconst RadioGroupRoot = forwardRef<HTMLFieldSetElement, RadioGroupProps>(function RadioGroupRoot(\n {\n children,\n className,\n defaultValue,\n disabled,\n label,\n name,\n onValueChange,\n value,\n ...fieldsetProps\n },\n ref,\n) {\n const [uncontrolledValue, setUncontrolledValue] = useState(defaultValue);\n const isControlled = value !== undefined;\n const selectedValue = isControlled ? value : uncontrolledValue;\n const resolvedClassName = ['chayns-radio-group', className].filter(Boolean).join(' ');\n\n function selectValue(nextValue: string) {\n if (!isControlled) {\n setUncontrolledValue(nextValue);\n }\n\n onValueChange?.(nextValue);\n }\n\n return (\n <RadioGroupContext.Provider\n value={{ disabled: disabled === true, name, selectValue, value: selectedValue }}\n >\n <fieldset {...fieldsetProps} className={resolvedClassName} disabled={disabled} ref={ref}>\n <legend className=\"chayns-radio-group__legend\">{label}</legend>\n <div className=\"chayns-radio-group__options\">{children}</div>\n </fieldset>\n </RadioGroupContext.Provider>\n );\n});\n\nconst RadioGroup = Object.assign(RadioGroupRoot, { Radio });\n\nexport default RadioGroup;\n"],"mappings":";;;;AAKA,IAAM,QAAQ,WAAyC,SAAS,MAC9D,EAAE,UAAU,WAAW,UAAU,OAAO,GAAG,cAC3C,KACA;CACA,MAAM,QAAQ,qBAAqB;CACnC,MAAM,aAAa,MAAM,YAAY,aAAa;CAClD,MAAM,iBAAiB,CAAC,uBAAuB,SAAS,CAAC,CAAC,OAAO,OAAO,CAAC,CAAC,KAAK,GAAG;CAElF,OACE,qBAAC,SAAD;EAAO,WAAU;EAAjB,UAAA;GACE,oBAAC,SAAD;IACE,GAAI;IACJ,SAAS,MAAM,UAAU;IACzB,WAAW;IACX,UAAU;IACV,MAAM,MAAM;IACZ,gBAAgB,MAAM,YAAY,KAAK;IAClC;IACL,MAAK;IACE;GACR,CAAA;GACD,oBAAC,QAAD;IAAM,eAAY;IAAO,WAAU;GAAyB,CAAA;GAC5D,oBAAC,QAAD;IAAM,WAAU;IAAuB;GAAe,CAAA;EACjD;;AAEX,CAAC;AAED,IAAM,iBAAiB,WAAiD,SAAS,eAC/E,EACE,UACA,WACA,cACA,UACA,OACA,MACA,eACA,OACA,GAAG,iBAEL,KACA;CACA,MAAM,CAAC,mBAAmB,wBAAwB,SAAS,YAAY;CACvE,MAAM,eAAe,UAAU,KAAA;CAC/B,MAAM,gBAAgB,eAAe,QAAQ;CAC7C,MAAM,oBAAoB,CAAC,sBAAsB,SAAS,CAAC,CAAC,OAAO,OAAO,CAAC,CAAC,KAAK,GAAG;CAEpF,SAAS,YAAY,WAAmB;EACtC,IAAI,CAAC,cACH,qBAAqB,SAAS;EAGhC,gBAAgB,SAAS;CAC3B;CAEA,OACE,oBAAC,kBAAkB,UAAnB;EACE,OAAO;GAAE,UAAU,aAAa;GAAM;GAAM;GAAa,OAAO;EAAc;EAE9E,UAAA,qBAAC,YAAD;GAAU,GAAI;GAAe,WAAW;GAA6B;GAAe;GAApF,UAAA,CACE,oBAAC,UAAD;IAAQ,WAAU;IAA8B,UAAA;GAAc,CAAA,GAC9D,oBAAC,OAAD;IAAK,WAAU;IAA+B;GAAc,CAAA,CACpD;;CACgB,CAAA;AAEhC,CAAC;AAED,IAAM,aAAa,OAAO,OAAO,gBAAgB,EAAE,MAAM,CAAC"}
@@ -0,0 +1,30 @@
1
+ import type { ComponentPropsWithRef, ReactNode } from 'react';
2
+ /** Props for a labelled native radio fieldset. */
3
+ export interface RadioGroupProps extends Omit<ComponentPropsWithRef<'fieldset'>, 'children' | 'name'> {
4
+ /** Visible, localized group label rendered as its legend. */
5
+ label: Exclude<ReactNode, boolean | null | undefined>;
6
+ /** Shared native name forwarded to every Radio. */
7
+ name: string;
8
+ /** Controlled selected option value. */
9
+ value?: string;
10
+ /** Initial selected option value for uncontrolled use. */
11
+ defaultValue?: string;
12
+ /** Called after native radio selection changes. */
13
+ onValueChange?: (value: string) => void;
14
+ /** RadioGroup.Radio children. */
15
+ children: ReactNode;
16
+ }
17
+ /** Props for a visible-label radio option inside RadioGroup. */
18
+ export interface RadioProps extends Omit<ComponentPropsWithRef<'input'>, 'children' | 'type' | 'name' | 'checked' | 'defaultChecked' | 'onChange'> {
19
+ /** Stable value that identifies this option in its group. */
20
+ value: string;
21
+ /** Visible, localized option label. */
22
+ children: Exclude<ReactNode, boolean | null | undefined>;
23
+ /** RadioGroup owns the input type and selection relationship. */
24
+ type?: never;
25
+ name?: never;
26
+ checked?: never;
27
+ defaultChecked?: never;
28
+ onChange?: never;
29
+ }
30
+ //# sourceMappingURL=RadioGroup.types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"RadioGroup.types.d.ts","sourceRoot":"","sources":["../../../src/components/radio-group/RadioGroup.types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,qBAAqB,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAE9D,kDAAkD;AAClD,MAAM,WAAW,eAAgB,SAAQ,IAAI,CAC3C,qBAAqB,CAAC,UAAU,CAAC,EACjC,UAAU,GAAG,MAAM,CACpB;IACC,6DAA6D;IAC7D,KAAK,EAAE,OAAO,CAAC,SAAS,EAAE,OAAO,GAAG,IAAI,GAAG,SAAS,CAAC,CAAC;IACtD,mDAAmD;IACnD,IAAI,EAAE,MAAM,CAAC;IACb,wCAAwC;IACxC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,0DAA0D;IAC1D,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,mDAAmD;IACnD,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACxC,iCAAiC;IACjC,QAAQ,EAAE,SAAS,CAAC;CACrB;AAED,gEAAgE;AAChE,MAAM,WAAW,UAAW,SAAQ,IAAI,CACtC,qBAAqB,CAAC,OAAO,CAAC,EAC9B,UAAU,GAAG,MAAM,GAAG,MAAM,GAAG,SAAS,GAAG,gBAAgB,GAAG,UAAU,CACzE;IACC,6DAA6D;IAC7D,KAAK,EAAE,MAAM,CAAC;IACd,uCAAuC;IACvC,QAAQ,EAAE,OAAO,CAAC,SAAS,EAAE,OAAO,GAAG,IAAI,GAAG,SAAS,CAAC,CAAC;IAEzD,iEAAiE;IACjE,IAAI,CAAC,EAAE,KAAK,CAAC;IACb,IAAI,CAAC,EAAE,KAAK,CAAC;IACb,OAAO,CAAC,EAAE,KAAK,CAAC;IAChB,cAAc,CAAC,EAAE,KAAK,CAAC;IACvB,QAAQ,CAAC,EAAE,KAAK,CAAC;CAClB"}
@@ -0,0 +1,11 @@
1
+ interface RadioGroupContextValue {
2
+ disabled: boolean;
3
+ name: string;
4
+ selectValue: (value: string) => void;
5
+ value: string | undefined;
6
+ }
7
+ declare const RadioGroupContext: import("react").Context<RadioGroupContextValue | null>;
8
+ declare function useRadioGroupContext(): RadioGroupContextValue;
9
+ export { RadioGroupContext, useRadioGroupContext };
10
+ export type { RadioGroupContextValue };
11
+ //# sourceMappingURL=RadioGroupContext.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"RadioGroupContext.d.ts","sourceRoot":"","sources":["../../../src/components/radio-group/RadioGroupContext.ts"],"names":[],"mappings":"AAEA,UAAU,sBAAsB;IAC9B,QAAQ,EAAE,OAAO,CAAC;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACrC,KAAK,EAAE,MAAM,GAAG,SAAS,CAAC;CAC3B;AAED,QAAA,MAAM,iBAAiB,wDAAqD,CAAC;AAE7E,iBAAS,oBAAoB,2BAQ5B;AAED,OAAO,EAAE,iBAAiB,EAAE,oBAAoB,EAAE,CAAC;AACnD,YAAY,EAAE,sBAAsB,EAAE,CAAC"}
@@ -0,0 +1,12 @@
1
+ import { createContext, useContext } from "react";
2
+ //#region src/components/radio-group/RadioGroupContext.ts
3
+ var RadioGroupContext = createContext(null);
4
+ function useRadioGroupContext() {
5
+ const context = useContext(RadioGroupContext);
6
+ if (context === null) throw new Error("RadioGroup.Radio must be rendered within RadioGroup.");
7
+ return context;
8
+ }
9
+ //#endregion
10
+ export { RadioGroupContext, useRadioGroupContext };
11
+
12
+ //# sourceMappingURL=RadioGroupContext.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"RadioGroupContext.js","names":[],"sources":["../../../src/components/radio-group/RadioGroupContext.ts"],"sourcesContent":["import { createContext, useContext } from 'react';\n\ninterface RadioGroupContextValue {\n disabled: boolean;\n name: string;\n selectValue: (value: string) => void;\n value: string | undefined;\n}\n\nconst RadioGroupContext = createContext<RadioGroupContextValue | null>(null);\n\nfunction useRadioGroupContext() {\n const context = useContext(RadioGroupContext);\n\n if (context === null) {\n throw new Error('RadioGroup.Radio must be rendered within RadioGroup.');\n }\n\n return context;\n}\n\nexport { RadioGroupContext, useRadioGroupContext };\nexport type { RadioGroupContextValue };\n"],"mappings":";;AASA,IAAM,oBAAoB,cAA6C,IAAI;AAE3E,SAAS,uBAAuB;CAC9B,MAAM,UAAU,WAAW,iBAAiB;CAE5C,IAAI,YAAY,MACd,MAAM,IAAI,MAAM,sDAAsD;CAGxE,OAAO;AACT"}
@@ -0,0 +1,16 @@
1
+ import type { SegmentProps } from './SegmentedControl.types.js';
2
+ declare const SegmentedControl: import("react").ForwardRefExoticComponent<(Omit<Omit<import("react").DetailedHTMLProps<import("react").HTMLAttributes<HTMLDivElement>, HTMLDivElement>, "children" | "role" | "aria-labelledby"> & import("./SegmentedControl.types.js").ControlledSelection & {
3
+ label: Exclude<import("react").ReactNode, boolean | null | undefined>;
4
+ children: import("react").ReactNode;
5
+ role?: never;
6
+ 'aria-labelledby'?: never;
7
+ }, "ref"> | Omit<Omit<import("react").DetailedHTMLProps<import("react").HTMLAttributes<HTMLDivElement>, HTMLDivElement>, "children" | "role" | "aria-labelledby"> & import("./SegmentedControl.types.js").UncontrolledSelection & {
8
+ label: Exclude<import("react").ReactNode, boolean | null | undefined>;
9
+ children: import("react").ReactNode;
10
+ role?: never;
11
+ 'aria-labelledby'?: never;
12
+ }, "ref">) & import("react").RefAttributes<HTMLDivElement>> & {
13
+ Segment: import("react").ForwardRefExoticComponent<Omit<SegmentProps, "ref"> & import("react").RefAttributes<HTMLButtonElement>>;
14
+ };
15
+ export default SegmentedControl;
16
+ //# sourceMappingURL=SegmentedControl.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SegmentedControl.d.ts","sourceRoot":"","sources":["../../../src/components/segmented-control/SegmentedControl.tsx"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAyB,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAqMvF,QAAA,MAAM,gBAAgB;;;;;;;;;;;;CAAmD,CAAC;AAE1E,eAAe,gBAAgB,CAAC"}