@inkra/react 0.0.0-stage → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (267) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +316 -2
  3. package/THIRD_PARTY_NOTICES.md +39 -0
  4. package/Yozai-OFL.txt +94 -0
  5. package/dist/Button.d.ts +36 -0
  6. package/dist/Button.js +89 -0
  7. package/dist/PencilIcon.d.ts +22 -0
  8. package/dist/PencilIcon.js +210 -0
  9. package/dist/PencilLine.d.ts +10 -0
  10. package/dist/PencilLine.js +91 -0
  11. package/dist/PencilSurface.d.ts +19 -0
  12. package/dist/PencilSurface.js +19 -0
  13. package/dist/PencilText.d.ts +16 -0
  14. package/dist/PencilText.js +338 -0
  15. package/dist/accordion/Accordion.d.ts +27 -0
  16. package/dist/accordion/Accordion.js +40 -0
  17. package/dist/accordion/index.d.ts +2 -0
  18. package/dist/accordion/index.js +1 -0
  19. package/dist/alert-dialog/index.d.ts +64 -0
  20. package/dist/alert-dialog/index.js +109 -0
  21. package/dist/assets/ui-hand-yozai.woff2 +0 -0
  22. package/dist/audio-player/index.d.ts +60 -0
  23. package/dist/audio-player/index.js +101 -0
  24. package/dist/breadcrumb/index.d.ts +16 -0
  25. package/dist/breadcrumb/index.js +25 -0
  26. package/dist/calendar/index.d.ts +21 -0
  27. package/dist/calendar/index.js +41 -0
  28. package/dist/carousel/index.d.ts +51 -0
  29. package/dist/carousel/index.js +290 -0
  30. package/dist/choice-grid/index.d.ts +38 -0
  31. package/dist/choice-grid/index.js +85 -0
  32. package/dist/color-picker/color.d.ts +15 -0
  33. package/dist/color-picker/color.js +55 -0
  34. package/dist/color-picker/index.d.ts +31 -0
  35. package/dist/color-picker/index.js +69 -0
  36. package/dist/command/index.d.ts +23 -0
  37. package/dist/command/index.js +39 -0
  38. package/dist/content/index.d.ts +106 -0
  39. package/dist/content/index.js +80 -0
  40. package/dist/context-menu/index.d.ts +76 -0
  41. package/dist/context-menu/index.js +240 -0
  42. package/dist/data-table/index.d.ts +47 -0
  43. package/dist/data-table/index.js +91 -0
  44. package/dist/date-picker/index.d.ts +50 -0
  45. package/dist/date-picker/index.js +180 -0
  46. package/dist/day-agenda/index.d.ts +43 -0
  47. package/dist/day-agenda/index.js +47 -0
  48. package/dist/day-agenda/layout.d.ts +20 -0
  49. package/dist/day-agenda/layout.js +60 -0
  50. package/dist/display/ProgressRing.d.ts +6 -0
  51. package/dist/display/ProgressRing.js +146 -0
  52. package/dist/display/index.d.ts +59 -0
  53. package/dist/display/index.js +75 -0
  54. package/dist/dockable-panel/index.d.ts +41 -0
  55. package/dist/dockable-panel/index.js +253 -0
  56. package/dist/dockable-panel/model.d.ts +21 -0
  57. package/dist/dockable-panel/model.js +61 -0
  58. package/dist/drawer/index.d.ts +63 -0
  59. package/dist/drawer/index.js +86 -0
  60. package/dist/dropdown-menu/index.d.ts +34 -0
  61. package/dist/dropdown-menu/index.js +40 -0
  62. package/dist/editable/index.d.ts +53 -0
  63. package/dist/editable/index.js +162 -0
  64. package/dist/empty/index.d.ts +21 -0
  65. package/dist/empty/index.js +23 -0
  66. package/dist/flip/index.d.ts +49 -0
  67. package/dist/flip/index.js +138 -0
  68. package/dist/form/EditablePencilText.d.ts +13 -0
  69. package/dist/form/EditablePencilText.js +323 -0
  70. package/dist/form/Field.d.ts +13 -0
  71. package/dist/form/Field.js +26 -0
  72. package/dist/form/Input.d.ts +27 -0
  73. package/dist/form/Input.js +97 -0
  74. package/dist/form/InputAction.d.ts +7 -0
  75. package/dist/form/InputAction.js +24 -0
  76. package/dist/form/Textarea.d.ts +17 -0
  77. package/dist/form/Textarea.js +102 -0
  78. package/dist/form/context.d.ts +12 -0
  79. package/dist/form/context.js +10 -0
  80. package/dist/form/controlProps.d.ts +23 -0
  81. package/dist/form/controlProps.js +20 -0
  82. package/dist/form/index.d.ts +7 -0
  83. package/dist/form/index.js +3 -0
  84. package/dist/form/types.d.ts +6 -0
  85. package/dist/form/types.js +1 -0
  86. package/dist/heatmap/index.d.ts +59 -0
  87. package/dist/heatmap/index.js +248 -0
  88. package/dist/hotkey/index.d.ts +37 -0
  89. package/dist/hotkey/index.js +130 -0
  90. package/dist/hotkey/model.d.ts +27 -0
  91. package/dist/hotkey/model.js +97 -0
  92. package/dist/hover-card/index.d.ts +33 -0
  93. package/dist/hover-card/index.js +141 -0
  94. package/dist/image-cropper/index.d.ts +82 -0
  95. package/dist/image-cropper/index.js +261 -0
  96. package/dist/image-cropper/model.d.ts +42 -0
  97. package/dist/image-cropper/model.js +94 -0
  98. package/dist/image-viewer/index.d.ts +79 -0
  99. package/dist/image-viewer/index.js +220 -0
  100. package/dist/image-viewer/model.d.ts +9 -0
  101. package/dist/image-viewer/model.js +18 -0
  102. package/dist/images/layers-2x.png +0 -0
  103. package/dist/images/layers.png +0 -0
  104. package/dist/images/marker-icon.png +0 -0
  105. package/dist/index.d.ts +75 -0
  106. package/dist/index.js +69 -0
  107. package/dist/input-number/index.d.ts +16 -0
  108. package/dist/input-number/index.js +77 -0
  109. package/dist/internal/InputActionContext.d.ts +1 -0
  110. package/dist/internal/InputActionContext.js +3 -0
  111. package/dist/internal/cache.d.ts +14 -0
  112. package/dist/internal/cache.js +54 -0
  113. package/dist/internal/line.d.ts +4 -0
  114. package/dist/internal/line.js +21 -0
  115. package/dist/internal/paper.d.ts +1 -0
  116. package/dist/internal/paper.js +65 -0
  117. package/dist/internal/random.d.ts +3 -0
  118. package/dist/internal/random.js +30 -0
  119. package/dist/internal/recovery.d.ts +1 -0
  120. package/dist/internal/recovery.js +52 -0
  121. package/dist/internal/renderTokens.d.ts +10 -0
  122. package/dist/internal/renderTokens.js +13 -0
  123. package/dist/internal/stroke.d.ts +24 -0
  124. package/dist/internal/stroke.js +144 -0
  125. package/dist/internal/surfaceRenderer.d.ts +41 -0
  126. package/dist/internal/surfaceRenderer.js +178 -0
  127. package/dist/internal/textQueue.d.ts +1 -0
  128. package/dist/internal/textQueue.js +37 -0
  129. package/dist/internal/textRenderer.d.ts +28 -0
  130. package/dist/internal/textRenderer.js +239 -0
  131. package/dist/internal/travelIcons.d.ts +24 -0
  132. package/dist/internal/travelIcons.js +14 -0
  133. package/dist/internal/useBrowserLayoutEffect.d.ts +2 -0
  134. package/dist/internal/useBrowserLayoutEffect.js +3 -0
  135. package/dist/internal/usePencilSurface.d.ts +3 -0
  136. package/dist/internal/usePencilSurface.js +116 -0
  137. package/dist/internal/useSelectionDrawing.d.ts +2 -0
  138. package/dist/internal/useSelectionDrawing.js +90 -0
  139. package/dist/internal/wash.d.ts +16 -0
  140. package/dist/internal/wash.js +149 -0
  141. package/dist/journey-map/MapScale.d.ts +4 -0
  142. package/dist/journey-map/MapScale.js +54 -0
  143. package/dist/journey-map/index.d.ts +39 -0
  144. package/dist/journey-map/index.js +197 -0
  145. package/dist/journey-map/terrain.d.ts +8 -0
  146. package/dist/journey-map/terrain.js +127 -0
  147. package/dist/keypad/index.d.ts +23 -0
  148. package/dist/keypad/index.js +63 -0
  149. package/dist/keypad/model.d.ts +20 -0
  150. package/dist/keypad/model.js +33 -0
  151. package/dist/layout/index.d.ts +63 -0
  152. package/dist/layout/index.js +62 -0
  153. package/dist/log/index.d.ts +45 -0
  154. package/dist/log/index.js +159 -0
  155. package/dist/log/model.d.ts +16 -0
  156. package/dist/log/model.js +13 -0
  157. package/dist/node-graph/index.d.ts +123 -0
  158. package/dist/node-graph/index.js +304 -0
  159. package/dist/number-ticker/index.d.ts +29 -0
  160. package/dist/number-ticker/index.js +132 -0
  161. package/dist/number-ticker/model.d.ts +8 -0
  162. package/dist/number-ticker/model.js +34 -0
  163. package/dist/overflow-list/index.d.ts +39 -0
  164. package/dist/overflow-list/index.js +230 -0
  165. package/dist/overflow-list/layout.d.ts +19 -0
  166. package/dist/overflow-list/layout.js +44 -0
  167. package/dist/overlay/Overlay.d.ts +65 -0
  168. package/dist/overlay/Overlay.js +77 -0
  169. package/dist/overlay/Popover.d.ts +43 -0
  170. package/dist/overlay/Popover.js +45 -0
  171. package/dist/overlay/index.d.ts +4 -0
  172. package/dist/overlay/index.js +2 -0
  173. package/dist/overlay/themeBridge.d.ts +8 -0
  174. package/dist/overlay/themeBridge.js +98 -0
  175. package/dist/pagination/index.d.ts +23 -0
  176. package/dist/pagination/index.js +41 -0
  177. package/dist/pagination/model.d.ts +4 -0
  178. package/dist/pagination/model.js +42 -0
  179. package/dist/pan-zoom/index.d.ts +71 -0
  180. package/dist/pan-zoom/index.js +175 -0
  181. package/dist/pencil.d.ts +10 -0
  182. package/dist/pencil.js +39 -0
  183. package/dist/radar/index.d.ts +54 -0
  184. package/dist/radar/index.js +220 -0
  185. package/dist/range-slider/index.d.ts +16 -0
  186. package/dist/range-slider/index.js +22 -0
  187. package/dist/rating/index.d.ts +28 -0
  188. package/dist/rating/index.js +127 -0
  189. package/dist/resizable/index.d.ts +32 -0
  190. package/dist/resizable/index.js +50 -0
  191. package/dist/scroll-area/index.d.ts +36 -0
  192. package/dist/scroll-area/index.js +44 -0
  193. package/dist/segmented-progress/SegmentedProgress.d.ts +17 -0
  194. package/dist/segmented-progress/SegmentedProgress.js +42 -0
  195. package/dist/select/MultipleSelect.d.ts +44 -0
  196. package/dist/select/MultipleSelect.js +124 -0
  197. package/dist/select/SearchableSelect.d.ts +45 -0
  198. package/dist/select/SearchableSelect.js +50 -0
  199. package/dist/select/Select.d.ts +109 -0
  200. package/dist/select/Select.js +205 -0
  201. package/dist/select/index.d.ts +4 -0
  202. package/dist/select/index.js +2 -0
  203. package/dist/selection/Checkbox.d.ts +9 -0
  204. package/dist/selection/Checkbox.js +37 -0
  205. package/dist/selection/RadioGroup.d.ts +23 -0
  206. package/dist/selection/RadioGroup.js +82 -0
  207. package/dist/selection/Switch.d.ts +8 -0
  208. package/dist/selection/Switch.js +36 -0
  209. package/dist/selection/index.d.ts +6 -0
  210. package/dist/selection/index.js +3 -0
  211. package/dist/selection/useNativeChecked.d.ts +13 -0
  212. package/dist/selection/useNativeChecked.js +27 -0
  213. package/dist/slider/index.d.ts +11 -0
  214. package/dist/slider/index.js +45 -0
  215. package/dist/slot/index.d.ts +24 -0
  216. package/dist/slot/index.js +29 -0
  217. package/dist/sortable/index.d.ts +50 -0
  218. package/dist/sortable/index.js +278 -0
  219. package/dist/sortable/model.d.ts +30 -0
  220. package/dist/sortable/model.js +64 -0
  221. package/dist/sparkline/index.d.ts +19 -0
  222. package/dist/sparkline/index.js +240 -0
  223. package/dist/sparkline/model.d.ts +16 -0
  224. package/dist/sparkline/model.js +28 -0
  225. package/dist/steps/index.d.ts +16 -0
  226. package/dist/steps/index.js +37 -0
  227. package/dist/styles.css +8226 -0
  228. package/dist/tabs/index.d.ts +22 -0
  229. package/dist/tabs/index.js +42 -0
  230. package/dist/tag-input/index.d.ts +69 -0
  231. package/dist/tag-input/index.js +325 -0
  232. package/dist/tag-input/model.d.ts +14 -0
  233. package/dist/tag-input/model.js +38 -0
  234. package/dist/time-picker/index.d.ts +15 -0
  235. package/dist/time-picker/index.js +168 -0
  236. package/dist/timeline/index.d.ts +14 -0
  237. package/dist/timeline/index.js +16 -0
  238. package/dist/toast/index.d.ts +27 -0
  239. package/dist/toast/index.js +36 -0
  240. package/dist/toggle-group/index.d.ts +17 -0
  241. package/dist/toggle-group/index.js +26 -0
  242. package/dist/tokens.css +356 -0
  243. package/dist/tooltip/Tooltip.d.ts +24 -0
  244. package/dist/tooltip/Tooltip.js +32 -0
  245. package/dist/tooltip/index.d.ts +2 -0
  246. package/dist/tooltip/index.js +1 -0
  247. package/dist/transfer/index.d.ts +64 -0
  248. package/dist/transfer/index.js +174 -0
  249. package/dist/transfer/model.d.ts +12 -0
  250. package/dist/transfer/model.js +33 -0
  251. package/dist/tree/index.d.ts +39 -0
  252. package/dist/tree/index.js +36 -0
  253. package/dist/tree-select/index.d.ts +59 -0
  254. package/dist/tree-select/index.js +142 -0
  255. package/dist/tree-select/model.d.ts +31 -0
  256. package/dist/tree-select/model.js +135 -0
  257. package/dist/typewriter/index.d.ts +21 -0
  258. package/dist/typewriter/index.js +101 -0
  259. package/dist/typewriter/model.d.ts +7 -0
  260. package/dist/typewriter/model.js +45 -0
  261. package/dist/upload/index.d.ts +59 -0
  262. package/dist/upload/index.js +230 -0
  263. package/dist/virtual-list/index.d.ts +44 -0
  264. package/dist/virtual-list/index.js +128 -0
  265. package/dist/virtual-list/model.d.ts +7 -0
  266. package/dist/virtual-list/model.js +27 -0
  267. package/package.json +119 -4
@@ -0,0 +1,42 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { PencilSurface } from '../PencilSurface.js';
3
+ function segmentFill(index, count, percent, policy) {
4
+ if (percent === null)
5
+ return 1;
6
+ const raw = percent / 100 * count - index;
7
+ if (policy === 'complete')
8
+ return raw >= 1 ? 1 : 0;
9
+ if (policy === 'next')
10
+ return raw > 0 ? 1 : 0;
11
+ return Math.max(0, Math.min(1, raw));
12
+ }
13
+ function thresholdColor(index, count, max, thresholds) {
14
+ if (!thresholds?.length)
15
+ return undefined;
16
+ const segmentValue = index / count * max;
17
+ let color;
18
+ for (const threshold of thresholds) {
19
+ if (!Number.isFinite(threshold.value) || !threshold.color || threshold.value > segmentValue)
20
+ continue;
21
+ color = threshold.color;
22
+ }
23
+ return color;
24
+ }
25
+ export function SegmentedProgress({ count, gap, max, partialSegment, percent, seed, segmentColors, thresholds, }) {
26
+ const normalizedThresholds = thresholds
27
+ ?.filter(threshold => Number.isFinite(threshold.value) && threshold.color)
28
+ .map(threshold => ({ ...threshold, value: Math.max(0, Math.min(max, threshold.value)) }))
29
+ .sort((left, right) => left.value - right.value);
30
+ return (_jsx("span", { "aria-hidden": "true", className: "inkra-progress__segments", style: {
31
+ '--inkra-progress-segment-count': count,
32
+ '--inkra-progress-segment-gap': `${gap}px`,
33
+ }, children: Array.from({ length: count }, (_, index) => {
34
+ const fill = segmentFill(index, count, percent, partialSegment);
35
+ const color = segmentColors?.[index] || thresholdColor(index, count, max, normalizedThresholds);
36
+ const style = {
37
+ '--inkra-progress-segment-fill': `${fill * 100}%`,
38
+ ...(color ? { '--inkra-selection-pigment': color } : {}),
39
+ };
40
+ return (_jsxs("span", { className: "inkra-progress__segment", "data-fill": fill === 0 ? 'empty' : fill === 1 ? 'full' : 'partial', children: [_jsx(PencilSurface, { as: "span", className: "inkra-progress__segment-outline", radius: 3, seed: `${seed}-segment-${index}-outline`, variant: "outline" }), _jsx("span", { className: "inkra-progress__segment-fill-clip", style: style, children: _jsx(PencilSurface, { as: "span", className: "inkra-progress__segment-fill", radius: 3, seed: `${seed}-segment-${index}-fill`, variant: "selection" }) })] }, index));
41
+ }) }));
42
+ }
@@ -0,0 +1,44 @@
1
+ import type * as RadixSelect from '@radix-ui/react-select';
2
+ import type { RefObject } from 'react';
3
+ export interface SelectOption {
4
+ value: string;
5
+ label: string;
6
+ }
7
+ export interface SelectMultipleRootProps extends Omit<RadixSelect.SelectProps, 'value' | 'defaultValue' | 'onValueChange'> {
8
+ multiple: true;
9
+ value?: string[];
10
+ defaultValue?: string[];
11
+ onValueChange?: (values: string[]) => void;
12
+ readOnly?: boolean;
13
+ invalid?: boolean;
14
+ items?: readonly SelectOption[];
15
+ }
16
+ interface MultipleState {
17
+ values: string[];
18
+ labels: ReadonlyMap<string, string>;
19
+ disabled: boolean;
20
+ readOnly: boolean;
21
+ change: (values: string[]) => void;
22
+ triggerRef: RefObject<HTMLButtonElement | null>;
23
+ contentEvents: RefObject<Pick<RadixSelect.SelectContentProps, 'onEscapeKeyDown' | 'onPointerDownOutside'>>;
24
+ }
25
+ export declare const MultipleSelectContext: import("react").Context<MultipleState | null>;
26
+ export declare function MultipleSelectRoot({ value, defaultValue, onValueChange, disabled, readOnly, dir, items, children, multiple: _multiple, invalid: _invalid, onOpenChange, ...props }: SelectMultipleRootProps): import("react").JSX.Element;
27
+ declare function Portal({ container, children }: RadixSelect.SelectPortalProps): import("react").JSX.Element;
28
+ export declare const MultipleSelect: {
29
+ Trigger: import("react").ForwardRefExoticComponent<RadixSelect.SelectTriggerProps & import("react").RefAttributes<HTMLButtonElement>>;
30
+ Value: import("react").ForwardRefExoticComponent<RadixSelect.SelectValueProps & import("react").RefAttributes<HTMLSpanElement>>;
31
+ Icon: import("react").ForwardRefExoticComponent<RadixSelect.SelectIconProps & import("react").RefAttributes<HTMLSpanElement>>;
32
+ Portal: typeof Portal;
33
+ Content: import("react").ForwardRefExoticComponent<RadixSelect.SelectContentProps & import("react").RefAttributes<HTMLDivElement>>;
34
+ Viewport: import("react").ForwardRefExoticComponent<RadixSelect.SelectViewportProps & import("react").RefAttributes<HTMLDivElement>>;
35
+ Group: import("react").ForwardRefExoticComponent<RadixSelect.SelectGroupProps & import("react").RefAttributes<HTMLDivElement>>;
36
+ Label: import("react").ForwardRefExoticComponent<RadixSelect.SelectLabelProps & import("react").RefAttributes<HTMLDivElement>>;
37
+ Item: import("react").ForwardRefExoticComponent<RadixSelect.SelectItemProps & import("react").RefAttributes<HTMLDivElement>>;
38
+ ItemText: import("react").ForwardRefExoticComponent<RadixSelect.SelectItemTextProps & import("react").RefAttributes<HTMLSpanElement>>;
39
+ ItemIndicator: import("react").ForwardRefExoticComponent<RadixSelect.SelectItemIndicatorProps & import("react").RefAttributes<HTMLSpanElement>>;
40
+ ScrollUpButton: import("react").ForwardRefExoticComponent<RadixSelect.SelectScrollUpButtonProps & import("react").RefAttributes<HTMLDivElement>>;
41
+ ScrollDownButton: import("react").ForwardRefExoticComponent<RadixSelect.SelectScrollDownButtonProps & import("react").RefAttributes<HTMLDivElement>>;
42
+ Separator: import("react").ForwardRefExoticComponent<RadixSelect.SelectSeparatorProps & import("react").RefAttributes<HTMLDivElement>>;
43
+ };
44
+ export {};
@@ -0,0 +1,124 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { Select as BaseSelect } from '@base-ui/react/select';
3
+ import { DirectionProvider } from '@base-ui/react/direction-provider';
4
+ import { Children, createContext, forwardRef, useCallback, useContext, useEffect, useMemo, useRef, useState } from 'react';
5
+ import { PencilText } from '../PencilText.js';
6
+ export const MultipleSelectContext = createContext(null);
7
+ const emptyValues = [];
8
+ export function MultipleSelectRoot({ value, defaultValue = emptyValues, onValueChange, disabled = false, readOnly = false, dir, items, children, multiple: _multiple, invalid: _invalid, onOpenChange, ...props }) {
9
+ const [uncontrolled, setUncontrolled] = useState(defaultValue);
10
+ const values = value ?? uncontrolled;
11
+ const triggerRef = useRef(null);
12
+ const inputRef = useRef(null);
13
+ const defaultValueRef = useRef(defaultValue);
14
+ defaultValueRef.current = defaultValue;
15
+ const isControlled = value !== undefined;
16
+ const contentEvents = useRef({});
17
+ const labels = useMemo(() => new Map(items?.map(item => [item.value, item.label])), [items]);
18
+ const change = (next) => {
19
+ if (disabled || readOnly)
20
+ return;
21
+ if (value === undefined)
22
+ setUncontrolled(next);
23
+ onValueChange?.(next);
24
+ };
25
+ useEffect(() => {
26
+ if (isControlled)
27
+ return;
28
+ const form = inputRef.current?.form;
29
+ let timer;
30
+ const reset = (event) => {
31
+ clearTimeout(timer);
32
+ timer = setTimeout(() => {
33
+ if (!event.defaultPrevented)
34
+ setUncontrolled(defaultValueRef.current);
35
+ }, 0);
36
+ };
37
+ form?.addEventListener('reset', reset);
38
+ return () => { clearTimeout(timer); form?.removeEventListener('reset', reset); };
39
+ }, [isControlled, props.form]);
40
+ return (_jsx(MultipleSelectContext.Provider, { value: { values, labels, disabled, readOnly, change, triggerRef, contentEvents }, children: _jsx(DirectionProvider, { direction: dir, children: _jsx(BaseSelect.Root, { ...props, multiple: true, disabled: disabled, readOnly: readOnly, open: readOnly ? false : props.open, value: values, onValueChange: change, items: items, inputRef: inputRef, onOpenChange: (open, details) => {
41
+ if (readOnly && open)
42
+ details.cancel();
43
+ if (details.reason === 'outside-press' || details.reason === 'cancel-open') {
44
+ // Base UI may report mousedown/touchstart; preserve the actual source event.
45
+ const outside = new CustomEvent('pointerDownOutside', { cancelable: true, detail: { originalEvent: details.event } });
46
+ contentEvents.current.onPointerDownOutside?.(outside);
47
+ if (outside.defaultPrevented) {
48
+ details.event.preventDefault();
49
+ details.cancel();
50
+ }
51
+ }
52
+ if (details.reason === 'escape-key' && details.event instanceof KeyboardEvent) {
53
+ contentEvents.current.onEscapeKeyDown?.(details.event);
54
+ if (details.event.defaultPrevented)
55
+ details.cancel();
56
+ }
57
+ if (!details.isCanceled)
58
+ onOpenChange?.(open);
59
+ }, children: children }) }) }));
60
+ }
61
+ // Keep the public compound API stable while Base UI owns the multiple-selection engine.
62
+ const Trigger = forwardRef(function Trigger({ asChild, children, ...props }, ref) {
63
+ const { triggerRef } = useContext(MultipleSelectContext);
64
+ const captureRef = useCallback((node) => {
65
+ triggerRef.current = node;
66
+ if (typeof ref === 'function')
67
+ ref(node);
68
+ else if (ref)
69
+ ref.current = node;
70
+ }, [ref, triggerRef]);
71
+ return _jsx(BaseSelect.Trigger, { ...props, ref: captureRef, render: asChild ? Children.only(children) : undefined, children: asChild ? undefined : children });
72
+ });
73
+ const Value = forwardRef(function Value({ asChild, children, placeholder, ...props }, ref) {
74
+ const state = useContext(MultipleSelectContext);
75
+ return _jsx(BaseSelect.Value, { ...props, ref: ref, render: asChild ? Children.only(children) : undefined, placeholder: placeholder, children: children ?? ((values) => values.length ? _jsx(PencilText, { className: "inkra-select__value-copy", ellipsis: true, children: values.map(value => state.labels.get(value) ?? value).join(', ') }) : placeholder) });
76
+ });
77
+ const Icon = forwardRef(function Icon({ asChild, children, ...props }, ref) {
78
+ return _jsx(BaseSelect.Icon, { ...props, ref: ref, render: asChild ? Children.only(children) : undefined, children: asChild ? undefined : children });
79
+ });
80
+ function Portal({ container, children }) {
81
+ // Both engines ultimately use React DOM portals; retain Radix's broader DOM-root API.
82
+ return _jsx(BaseSelect.Portal, { container: container, children: children });
83
+ }
84
+ const Content = forwardRef(function Content({ asChild, children, position = 'popper', side = 'bottom', sideOffset = 4, align = 'start', alignOffset, avoidCollisions = true, collisionPadding = 8, collisionBoundary, sticky, arrowPadding, forceMount: _forceMount, updatePositionStrategy: _updatePositionStrategy, hideWhenDetached, onCloseAutoFocus, onEscapeKeyDown, onPointerDownOutside, ...props }, ref) {
85
+ const { contentEvents } = useContext(MultipleSelectContext);
86
+ useEffect(() => {
87
+ contentEvents.current = { onEscapeKeyDown, onPointerDownOutside };
88
+ return () => { contentEvents.current = {}; };
89
+ }, [contentEvents, onEscapeKeyDown, onPointerDownOutside]);
90
+ return _jsx(BaseSelect.Positioner, { className: "inkra-select__positioner", "data-hide-when-detached": hideWhenDetached || undefined, sticky: sticky === 'always', arrowPadding: arrowPadding, side: side, sideOffset: sideOffset, align: align, alignOffset: alignOffset, alignItemWithTrigger: position === 'item-aligned', collisionPadding: collisionPadding, collisionBoundary: Array.isArray(collisionBoundary) ? collisionBoundary.filter((entry) => entry != null) : collisionBoundary ?? undefined, collisionAvoidance: avoidCollisions ? undefined : { side: 'none', align: 'none' }, children: _jsx(BaseSelect.Popup, { ...props, ref: ref, render: asChild ? Children.only(children) : undefined, finalFocus: onCloseAutoFocus ? () => { const event = new Event('closeAutoFocus', { cancelable: true }); onCloseAutoFocus(event); return !event.defaultPrevented; } : undefined, children: asChild ? undefined : children }) });
91
+ });
92
+ const Viewport = forwardRef(function Viewport({ asChild, children, nonce: _nonce, ...props }, ref) {
93
+ return _jsx(BaseSelect.List, { ...props, ref: ref, render: asChild ? Children.only(children) : undefined, children: asChild ? undefined : children });
94
+ });
95
+ const Group = forwardRef(function Group({ asChild, children, ...props }, ref) {
96
+ return _jsx(BaseSelect.Group, { ...props, ref: ref, render: asChild ? Children.only(children) : undefined, children: asChild ? undefined : children });
97
+ });
98
+ const Label = forwardRef(function Label({ asChild, children, ...props }, ref) {
99
+ return _jsx(BaseSelect.GroupLabel, { ...props, ref: ref, render: asChild ? Children.only(children) : undefined, children: asChild ? undefined : children });
100
+ });
101
+ const Item = forwardRef(function Item({ asChild, children, textValue, ...props }, ref) {
102
+ return _jsx(BaseSelect.Item, { ...props, label: textValue, ref: ref, render: asChild ? Children.only(children) : undefined, children: asChild ? undefined : children });
103
+ });
104
+ const ItemText = forwardRef(function ItemText({ asChild, children, ...props }, ref) {
105
+ return _jsx(BaseSelect.ItemText, { ...props, ref: node => {
106
+ if (typeof ref === 'function')
107
+ ref(node);
108
+ else if (ref)
109
+ ref.current = node;
110
+ }, render: asChild ? Children.only(children) : _jsx("span", {}), children: asChild ? undefined : children });
111
+ });
112
+ const ItemIndicator = forwardRef(function ItemIndicator({ asChild, children, ...props }, ref) {
113
+ return _jsx(BaseSelect.ItemIndicator, { ...props, ref: ref, render: asChild ? Children.only(children) : undefined, children: asChild ? undefined : children });
114
+ });
115
+ const ScrollUpButton = forwardRef(function ScrollUpButton({ asChild, children, ...props }, ref) {
116
+ return _jsx(BaseSelect.ScrollUpArrow, { ...props, ref: ref, render: asChild ? Children.only(children) : undefined, children: asChild ? undefined : children });
117
+ });
118
+ const ScrollDownButton = forwardRef(function ScrollDownButton({ asChild, children, ...props }, ref) {
119
+ return _jsx(BaseSelect.ScrollDownArrow, { ...props, ref: ref, render: asChild ? Children.only(children) : undefined, children: asChild ? undefined : children });
120
+ });
121
+ const Separator = forwardRef(function Separator({ asChild, children, ...props }, ref) {
122
+ return _jsx(BaseSelect.Separator, { ...props, ref: ref, render: asChild ? Children.only(children) : undefined, children: asChild ? undefined : children });
123
+ });
124
+ export const MultipleSelect = { Trigger, Value, Icon, Portal, Content, Viewport, Group, Label, Item, ItemText, ItemIndicator, ScrollUpButton, ScrollDownButton, Separator };
@@ -0,0 +1,45 @@
1
+ import type { HTMLAttributes, ReactNode } from 'react';
2
+ export interface SearchableSelectOption {
3
+ value: string;
4
+ label: string;
5
+ disabled?: boolean;
6
+ keywords?: string;
7
+ }
8
+ interface SearchableSelectCommonProps extends Omit<HTMLAttributes<HTMLDivElement>, 'defaultValue' | 'onChange' | 'dir'> {
9
+ items: readonly SearchableSelectOption[];
10
+ searchPlacement?: 'trigger' | 'popup';
11
+ placeholder?: string;
12
+ searchPlaceholder?: string;
13
+ emptyContent?: ReactNode;
14
+ clearable?: boolean;
15
+ clearLabel?: string;
16
+ openLabel?: string;
17
+ size?: 'sm' | 'md' | 'lg';
18
+ name?: string;
19
+ form?: string;
20
+ dir?: 'ltr' | 'rtl';
21
+ disabled?: boolean;
22
+ readOnly?: boolean;
23
+ required?: boolean;
24
+ invalid?: boolean;
25
+ open?: boolean;
26
+ defaultOpen?: boolean;
27
+ onOpenChange?: (open: boolean) => void;
28
+ side?: 'top' | 'right' | 'bottom' | 'left';
29
+ align?: 'start' | 'center' | 'end';
30
+ sideOffset?: number;
31
+ collisionPadding?: number;
32
+ }
33
+ export type SearchableSelectProps = SearchableSelectCommonProps & ({
34
+ multiple?: false;
35
+ value?: string | null;
36
+ defaultValue?: string | null;
37
+ onValueChange?: (value: string | null) => void;
38
+ } | {
39
+ multiple: true;
40
+ value?: string[];
41
+ defaultValue?: string[];
42
+ onValueChange?: (value: string[]) => void;
43
+ });
44
+ export declare const SearchableSelect: import("react").ForwardRefExoticComponent<SearchableSelectProps & import("react").RefAttributes<HTMLDivElement>>;
45
+ export {};
@@ -0,0 +1,50 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { Combobox } from '@base-ui/react/combobox';
3
+ import { DirectionProvider } from '@base-ui/react/direction-provider';
4
+ import { forwardRef, useId, useMemo, useRef } from 'react';
5
+ import { Button } from '../Button.js';
6
+ import { Input } from '../form/Input.js';
7
+ import { mergeAriaIds, useFieldContext } from '../form/context.js';
8
+ import { PencilIcon } from '../PencilIcon.js';
9
+ import { PencilSurface } from '../PencilSurface.js';
10
+ import { PencilText } from '../PencilText.js';
11
+ import { PortalThemeBridge, PortalThemeProvider, usePortalTriggerRef } from '../overlay/themeBridge.js';
12
+ const searchPaths = [{ d: 'M21 21l-4.5-4.5' }, { d: 'M18 10a8 8 0 1 1-16 0a8 8 0 1 1 16 0' }];
13
+ const chevronPaths = [{ d: 'M6 9l6 6 6-6' }];
14
+ const checkPaths = [{ d: 'M5 12l4 4L19 6' }];
15
+ const clearPaths = [{ d: 'M6 6l12 12M18 6L6 18' }];
16
+ const SearchableControl = forwardRef(function SearchableControl(props, forwardedRef) {
17
+ const { items, searchPlacement = 'trigger', placeholder = 'Select an option', searchPlaceholder = 'Search options', emptyContent = 'No matching options', clearable = true, clearLabel = 'Clear selection', openLabel = 'Show options', size = 'md', multiple = false, value, defaultValue, onValueChange: _onValueChange, name, form, dir, disabled, readOnly, required, invalid, id, className, children: _children, open, defaultOpen, onOpenChange, side = 'bottom', align = 'start', sideOffset = 8, collisionPadding = 8, 'aria-label': ariaLabel, 'aria-labelledby': ariaLabelledBy, 'aria-describedby': ariaDescribedBy, ...rest } = props;
18
+ const indicatorSize = size === 'sm' ? 24 : size === 'lg' ? 32 : 28;
19
+ const field = useFieldContext();
20
+ const generatedId = useId();
21
+ const controlId = field?.controlId ?? id ?? generatedId;
22
+ const resolvedDisabled = Boolean(disabled || field?.disabled);
23
+ const resolvedReadOnly = Boolean(readOnly || field?.readOnly);
24
+ const resolvedInvalid = Boolean(invalid || field?.invalid);
25
+ const describedBy = mergeAriaIds(ariaDescribedBy, field?.descriptionId, field?.errorId);
26
+ const searchRef = useRef(null);
27
+ const portalRef = usePortalTriggerRef(forwardedRef);
28
+ const lookup = useMemo(() => new Map(items.map(item => [item.value, item])), [items]);
29
+ const values = useMemo(() => items.map(item => item.value), [items]);
30
+ const { contains } = Combobox.useFilter({ sensitivity: 'base' });
31
+ const summary = (selected) => {
32
+ const selectedValues = Array.isArray(selected) ? selected : selected == null ? [] : [selected];
33
+ return selectedValues.map(item => lookup.get(item)?.label ?? item).join(', ');
34
+ };
35
+ const search = _jsx(Combobox.Input, { id: searchPlacement === 'trigger' ? controlId : `${controlId}-search`, "aria-label": searchPlacement === 'trigger' ? ariaLabel : searchPlaceholder, "aria-labelledby": searchPlacement === 'trigger' ? ariaLabelledBy : undefined, "aria-describedby": describedBy, "aria-invalid": resolvedInvalid || undefined, ref: searchRef, placeholder: searchPlacement === 'trigger' ? placeholder : searchPlaceholder, render: _jsx(Input, { size: size, variant: searchPlacement === 'trigger' ? 'outline' : 'underline', startIcon: _jsx(PencilIcon, { paths: searchPaths, size: 22, sourceSize: 24 }) }) });
36
+ return _jsx(DirectionProvider, { direction: dir, children: _jsxs(Combobox.Root, { items: values, multiple: multiple, value: value, defaultValue: defaultValue, disabled: resolvedDisabled, readOnly: resolvedReadOnly, required: Boolean(required || field?.required), name: name, form: form, autoHighlight: true, open: resolvedReadOnly || resolvedDisabled ? false : open, defaultOpen: defaultOpen, onOpenChange: (next, details) => { if (resolvedReadOnly || resolvedDisabled)
37
+ details.cancel();
38
+ else
39
+ onOpenChange?.(next); }, itemToStringLabel: item => lookup.get(item)?.label ?? item, filter: (item, query) => contains(`${lookup.get(item)?.label ?? item} ${lookup.get(item)?.keywords ?? ''}`, query), onValueChange: next => {
40
+ if (resolvedDisabled || resolvedReadOnly)
41
+ return;
42
+ if (props.multiple)
43
+ props.onValueChange?.(Array.isArray(next) ? next : []);
44
+ else
45
+ props.onValueChange?.(typeof next === 'string' ? next : null);
46
+ }, children: [_jsxs("div", { ...rest, ref: portalRef, dir: dir, className: ['inkra-search-select', className].filter(Boolean).join(' '), "data-placement": searchPlacement, "data-invalid": resolvedInvalid || undefined, children: [_jsxs(Combobox.InputGroup, { className: "inkra-search-select__anchor", children: [searchPlacement === 'trigger' ? search : _jsxs(Combobox.Trigger, { id: controlId, "aria-label": ariaLabel, "aria-labelledby": ariaLabelledBy, "aria-describedby": describedBy, "aria-invalid": resolvedInvalid || undefined, "aria-readonly": resolvedReadOnly || undefined, className: "inkra-search-select__trigger", render: _jsx(Button, { variant: "outline", fullWidth: true, size: size, align: "start" }), children: [_jsx(Combobox.Value, { children: (selected) => _jsx(PencilText, { ellipsis: true, children: summary(selected) || placeholder }) }), _jsx(PencilIcon, { paths: chevronPaths, size: indicatorSize, sourceSize: 24 })] }), searchPlacement === 'trigger' && _jsx(Combobox.Trigger, { "aria-label": openLabel, render: _jsx(Button, { variant: "ghost", size: "icon" }), children: _jsx(PencilIcon, { paths: chevronPaths, size: indicatorSize, sourceSize: 24 }) }), clearable && _jsx(Combobox.Clear, { "aria-label": clearLabel, disabled: resolvedReadOnly || resolvedDisabled, render: _jsx(Button, { variant: "ghost", size: "icon" }), children: _jsx(PencilIcon, { paths: clearPaths, size: 24, sourceSize: 24 }) })] }), multiple && searchPlacement === 'trigger' && _jsx(Combobox.Value, { children: (selected) => selected.length ? _jsx(PencilText, { className: "inkra-search-select__summary", children: summary(selected) }) : null })] }), _jsx(Combobox.Portal, { children: _jsx(PortalThemeBridge, { children: _jsx(Combobox.Positioner, { side: side, align: align, sideOffset: sideOffset, collisionPadding: collisionPadding, className: "inkra-select__positioner inkra-search-select__positioner", children: _jsx(Combobox.Popup, { className: "inkra-search-select__popup", initialFocus: searchPlacement === 'popup' ? searchRef : false, children: _jsxs(PencilSurface, { variant: "paper", radius: 8, children: [searchPlacement === 'popup' && _jsx("div", { className: "inkra-search-select__search", children: search }), _jsx(Combobox.Empty, { className: "inkra-search-select__empty", children: typeof emptyContent === 'string' ? _jsx(PencilText, { children: emptyContent }) : emptyContent }), _jsx(Combobox.List, { className: "inkra-select__viewport inkra-search-select__list", children: (item) => _jsx(Combobox.Item, { value: item, disabled: lookup.get(item)?.disabled, className: "inkra-select__item", children: _jsxs(PencilSurface, { className: "inkra-select__item-surface", variant: "selection", seed: `search-option-${item}`, children: [_jsx(PencilText, { children: lookup.get(item)?.label ?? item }), _jsx(Combobox.ItemIndicator, { className: "inkra-select__item-indicator", children: _jsx(PencilIcon, { paths: checkPaths, size: 22, sourceSize: 24 }) })] }) }, item) })] }) }) }) }) })] }) });
47
+ });
48
+ export const SearchableSelect = forwardRef(function SearchableSelect(props, ref) {
49
+ return _jsx(PortalThemeProvider, { children: _jsx(SearchableControl, { ...props, ref: ref }) });
50
+ });
@@ -0,0 +1,109 @@
1
+ import * as SelectPrimitive from '@radix-ui/react-select';
2
+ import type { ButtonHTMLAttributes, ReactNode } from 'react';
3
+ import type { SelectMultipleRootProps } from './MultipleSelect.js';
4
+ import type { PencilSurfaceVariant } from '../PencilSurface.js';
5
+ export type SelectSingleRootProps = SelectPrimitive.SelectProps & {
6
+ multiple?: false;
7
+ readOnly?: boolean;
8
+ invalid?: boolean;
9
+ };
10
+ export type SelectRootProps = SelectSingleRootProps | SelectMultipleRootProps;
11
+ export type { SelectMultipleRootProps, SelectOption } from './MultipleSelect.js';
12
+ export declare function SelectRoot({ dir, disabled, invalid, readOnly, required, ...props }: SelectRootProps): import("react").JSX.Element;
13
+ export type SelectSize = 'sm' | 'md' | 'lg';
14
+ export interface SelectTriggerProps extends SelectPrimitive.SelectTriggerProps {
15
+ /** Decorative slots inside the shared trigger surface. */
16
+ startIcon?: ReactNode;
17
+ endIcon?: ReactNode;
18
+ /** Replaces the dropdown indicator; null removes it. */
19
+ icon?: ReactNode;
20
+ hideValue?: boolean;
21
+ hideIndicator?: boolean;
22
+ /** Shows startIcon, then endIcon, then the indicator as a square control. */
23
+ iconOnly?: boolean;
24
+ fullWidth?: boolean;
25
+ textAlign?: 'start' | 'center' | 'end';
26
+ invalid?: boolean;
27
+ seed?: string | number;
28
+ size?: SelectSize;
29
+ }
30
+ export declare const SelectTrigger: import("react").ForwardRefExoticComponent<SelectTriggerProps & import("react").RefAttributes<HTMLButtonElement>>;
31
+ export interface SelectValueProps extends Omit<SelectPrimitive.SelectValueProps, 'placeholder'> {
32
+ placeholder?: ReactNode;
33
+ seed?: string | number;
34
+ }
35
+ export declare const SelectValue: import("react").ForwardRefExoticComponent<SelectValueProps & import("react").RefAttributes<HTMLSpanElement>>;
36
+ export type SelectPortalProps = SelectPrimitive.SelectPortalProps;
37
+ export declare function SelectPortal({ children, ...props }: SelectPortalProps): import("react").JSX.Element;
38
+ export interface SelectContentProps extends SelectPrimitive.SelectContentProps {
39
+ seed?: string | number;
40
+ surfaceClassName?: string;
41
+ surfaceRadius?: number;
42
+ surfaceVariant?: PencilSurfaceVariant;
43
+ }
44
+ export declare const SelectContent: import("react").ForwardRefExoticComponent<SelectContentProps & import("react").RefAttributes<HTMLDivElement>>;
45
+ export type SelectViewportProps = SelectPrimitive.SelectViewportProps;
46
+ export declare const SelectViewport: import("react").ForwardRefExoticComponent<SelectPrimitive.SelectViewportProps & import("react").RefAttributes<HTMLDivElement>>;
47
+ export type SelectGroupProps = SelectPrimitive.SelectGroupProps;
48
+ export declare const SelectGroup: import("react").ForwardRefExoticComponent<SelectPrimitive.SelectGroupProps & import("react").RefAttributes<HTMLDivElement>>;
49
+ export interface SelectLabelProps extends Omit<SelectPrimitive.SelectLabelProps, 'children'> {
50
+ children: string;
51
+ seed?: string | number;
52
+ }
53
+ export declare const SelectLabel: import("react").ForwardRefExoticComponent<SelectLabelProps & import("react").RefAttributes<HTMLDivElement>>;
54
+ export interface SelectItemProps extends SelectPrimitive.SelectItemProps {
55
+ seed?: string | number;
56
+ surfaceClassName?: string;
57
+ }
58
+ export declare const SelectItem: import("react").ForwardRefExoticComponent<SelectItemProps & import("react").RefAttributes<HTMLDivElement>>;
59
+ export interface SelectItemTextProps extends Omit<SelectPrimitive.SelectItemTextProps, 'children'> {
60
+ children: string;
61
+ seed?: string | number;
62
+ }
63
+ export declare const SelectItemText: import("react").ForwardRefExoticComponent<SelectItemTextProps & import("react").RefAttributes<HTMLSpanElement>>;
64
+ export interface SelectItemIndicatorProps extends SelectPrimitive.SelectItemIndicatorProps {
65
+ seed?: string | number;
66
+ }
67
+ export declare const SelectItemIndicator: import("react").ForwardRefExoticComponent<SelectItemIndicatorProps & import("react").RefAttributes<HTMLSpanElement>>;
68
+ export type SelectScrollUpButtonProps = SelectPrimitive.SelectScrollUpButtonProps & {
69
+ seed?: string | number;
70
+ };
71
+ export declare const SelectScrollUpButton: import("react").ForwardRefExoticComponent<SelectPrimitive.SelectScrollUpButtonProps & {
72
+ seed?: string | number;
73
+ } & import("react").RefAttributes<HTMLDivElement>>;
74
+ export type SelectScrollDownButtonProps = SelectPrimitive.SelectScrollDownButtonProps & {
75
+ seed?: string | number;
76
+ };
77
+ export declare const SelectScrollDownButton: import("react").ForwardRefExoticComponent<SelectPrimitive.SelectScrollDownButtonProps & {
78
+ seed?: string | number;
79
+ } & import("react").RefAttributes<HTMLDivElement>>;
80
+ export interface SelectSeparatorProps extends Omit<SelectPrimitive.SelectSeparatorProps, 'children'> {
81
+ seed?: string | number;
82
+ }
83
+ export declare const SelectSeparator: import("react").ForwardRefExoticComponent<SelectSeparatorProps & import("react").RefAttributes<HTMLDivElement>>;
84
+ export interface SelectClearProps extends ButtonHTMLAttributes<HTMLButtonElement> {
85
+ seed?: string | number;
86
+ }
87
+ export declare const SelectClear: import("react").ForwardRefExoticComponent<SelectClearProps & import("react").RefAttributes<HTMLButtonElement>>;
88
+ export declare const Select: Readonly<{
89
+ Searchable: import("react").ForwardRefExoticComponent<import("./SearchableSelect.js").SearchableSelectProps & import("react").RefAttributes<HTMLDivElement>>;
90
+ Root: typeof SelectRoot;
91
+ Trigger: import("react").ForwardRefExoticComponent<SelectTriggerProps & import("react").RefAttributes<HTMLButtonElement>>;
92
+ Value: import("react").ForwardRefExoticComponent<SelectValueProps & import("react").RefAttributes<HTMLSpanElement>>;
93
+ Portal: typeof SelectPortal;
94
+ Content: import("react").ForwardRefExoticComponent<SelectContentProps & import("react").RefAttributes<HTMLDivElement>>;
95
+ Viewport: import("react").ForwardRefExoticComponent<SelectPrimitive.SelectViewportProps & import("react").RefAttributes<HTMLDivElement>>;
96
+ Group: import("react").ForwardRefExoticComponent<SelectPrimitive.SelectGroupProps & import("react").RefAttributes<HTMLDivElement>>;
97
+ Label: import("react").ForwardRefExoticComponent<SelectLabelProps & import("react").RefAttributes<HTMLDivElement>>;
98
+ Item: import("react").ForwardRefExoticComponent<SelectItemProps & import("react").RefAttributes<HTMLDivElement>>;
99
+ ItemText: import("react").ForwardRefExoticComponent<SelectItemTextProps & import("react").RefAttributes<HTMLSpanElement>>;
100
+ ItemIndicator: import("react").ForwardRefExoticComponent<SelectItemIndicatorProps & import("react").RefAttributes<HTMLSpanElement>>;
101
+ ScrollUpButton: import("react").ForwardRefExoticComponent<SelectPrimitive.SelectScrollUpButtonProps & {
102
+ seed?: string | number;
103
+ } & import("react").RefAttributes<HTMLDivElement>>;
104
+ ScrollDownButton: import("react").ForwardRefExoticComponent<SelectPrimitive.SelectScrollDownButtonProps & {
105
+ seed?: string | number;
106
+ } & import("react").RefAttributes<HTMLDivElement>>;
107
+ Separator: import("react").ForwardRefExoticComponent<SelectSeparatorProps & import("react").RefAttributes<HTMLDivElement>>;
108
+ Clear: import("react").ForwardRefExoticComponent<SelectClearProps & import("react").RefAttributes<HTMLButtonElement>>;
109
+ }>;
@@ -0,0 +1,205 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import * as SelectPrimitive from '@radix-ui/react-select';
3
+ import { createContext, forwardRef, useCallback, useContext, useEffect, useId, useMemo, useRef, useState, } from 'react';
4
+ import { Button } from '../Button.js';
5
+ import { SearchableSelect } from './SearchableSelect.js';
6
+ import { MultipleSelect, MultipleSelectContext, MultipleSelectRoot } from './MultipleSelect.js';
7
+ import { mergeAriaIds, useFieldContext } from '../form/context.js';
8
+ import { PencilIcon } from '../PencilIcon.js';
9
+ import { PencilLine } from '../PencilLine.js';
10
+ import { PencilSurface } from '../PencilSurface.js';
11
+ import { PencilText } from '../PencilText.js';
12
+ import { PortalThemeBridge, PortalThemeProvider, usePortalTriggerRef, } from '../overlay/themeBridge.js';
13
+ const chevronDownPaths = [
14
+ { d: 'M6 9L12 15L18 9' },
15
+ ];
16
+ const chevronUpPaths = [
17
+ { d: 'M6 15L12 9L18 15' },
18
+ ];
19
+ const checkPaths = [
20
+ { d: 'M5 12.5L10 17L19 7' },
21
+ ];
22
+ function classes(...values) {
23
+ return values.filter(Boolean).join(' ');
24
+ }
25
+ function isAriaInvalid(value) {
26
+ return value === true || value === 'true' || value === 'grammar' || value === 'spelling';
27
+ }
28
+ function useItemAppearanceVersion() {
29
+ const copyRef = useRef(null);
30
+ const [version, setVersion] = useState(0);
31
+ useEffect(() => {
32
+ const item = copyRef.current?.closest('[role="option"]');
33
+ if (!item || typeof MutationObserver === 'undefined')
34
+ return undefined;
35
+ const observer = new MutationObserver(() => setVersion(current => current + 1));
36
+ observer.observe(item, {
37
+ attributes: true,
38
+ attributeFilter: ['data-highlighted', 'data-state', 'data-selected'],
39
+ });
40
+ return () => observer.disconnect();
41
+ }, []);
42
+ return { copyRef, version };
43
+ }
44
+ const SelectFieldContext = createContext(null);
45
+ export function SelectRoot({ dir, disabled, invalid = false, readOnly, required, ...props }) {
46
+ const field = useFieldContext();
47
+ const [directionNode, setDirectionNode] = useState(null);
48
+ const [inferredDirection, setInferredDirection] = useState();
49
+ const captureDirectionNode = useCallback((node) => {
50
+ setDirectionNode(node);
51
+ }, []);
52
+ useEffect(() => {
53
+ if (dir || !directionNode || typeof window === 'undefined')
54
+ return undefined;
55
+ const refresh = () => {
56
+ const directionSource = directionNode.parentElement ?? directionNode;
57
+ const direction = getComputedStyle(directionSource).direction === 'rtl' ? 'rtl' : 'ltr';
58
+ setInferredDirection(current => current === direction ? current : direction);
59
+ };
60
+ refresh();
61
+ if (typeof MutationObserver === 'undefined')
62
+ return undefined;
63
+ const observer = new MutationObserver(refresh);
64
+ for (let target = directionNode.parentElement; target; target = target.parentElement) {
65
+ observer.observe(target, {
66
+ attributes: true,
67
+ attributeFilter: ['class', 'data-theme', 'data-inkra-theme', 'dir', 'style'],
68
+ });
69
+ }
70
+ return () => observer.disconnect();
71
+ }, [dir, directionNode]);
72
+ const state = useMemo(() => ({
73
+ captureDirectionNode,
74
+ controlId: field?.controlId,
75
+ descriptionId: field?.descriptionId,
76
+ errorId: field?.errorId,
77
+ disabled: Boolean(disabled || field?.disabled),
78
+ readOnly: Boolean(readOnly || field?.readOnly),
79
+ invalid: Boolean(invalid || field?.invalid),
80
+ required: Boolean(required || field?.required),
81
+ }), [captureDirectionNode, disabled, field, invalid, readOnly, required]);
82
+ return (_jsx(PortalThemeProvider, { children: _jsx(SelectFieldContext.Provider, { value: state, children: props.multiple ? _jsx(MultipleSelectRoot, { ...props, dir: dir ?? inferredDirection, disabled: state.disabled, readOnly: state.readOnly, required: state.required }) : _jsx(SelectPrimitive.Root, { ...props, dir: dir ?? inferredDirection, disabled: state.disabled, required: state.required, onValueChange: value => { if (!state.readOnly)
83
+ props.onValueChange?.(value); }, onOpenChange: open => { if (!state.readOnly)
84
+ props.onOpenChange?.(open); }, open: state.readOnly ? false : props.open }) }) }));
85
+ }
86
+ export const SelectTrigger = forwardRef(function SelectTrigger({ 'aria-describedby': ariaDescribedBy, 'aria-errormessage': ariaErrorMessage, 'aria-invalid': ariaInvalid, children, className, disabled = false, icon, startIcon, endIcon, hideValue = false, hideIndicator = false, iconOnly = false, fullWidth = true, textAlign = 'start', id, invalid = false, seed, size = 'md', ...props }, forwardedRef) {
87
+ const generatedId = useId();
88
+ const multiple = useContext(MultipleSelectContext);
89
+ const Trigger = multiple ? MultipleSelect.Trigger : SelectPrimitive.Trigger;
90
+ const Icon = multiple ? MultipleSelect.Icon : SelectPrimitive.Icon;
91
+ const field = useContext(SelectFieldContext);
92
+ const resolvedId = field?.controlId ?? id;
93
+ const resolvedDisabled = Boolean(disabled || field?.disabled);
94
+ const resolvedInvalid = Boolean(invalid || field?.invalid || isAriaInvalid(ariaInvalid));
95
+ const resolvedSeed = seed ?? `inkra-select-${resolvedId ?? generatedId}`;
96
+ const valueHidden = hideValue || iconOnly;
97
+ const valueId = `${generatedId}-value`;
98
+ const describedBy = mergeAriaIds(ariaDescribedBy, field?.descriptionId, field?.errorId, valueHidden ? valueId : undefined);
99
+ const errorMessage = mergeAriaIds(ariaErrorMessage, resolvedInvalid ? field?.errorId : undefined);
100
+ const portalRef = usePortalTriggerRef(forwardedRef);
101
+ const captureDirectionNode = field?.captureDirectionNode;
102
+ const ref = useCallback((node) => {
103
+ portalRef(node);
104
+ captureDirectionNode?.(node);
105
+ }, [captureDirectionNode, portalRef]);
106
+ const defaultIndicator = (_jsx(PencilIcon, { className: "inkra-select__trigger-glyph", paths: chevronDownPaths, seed: `${resolvedSeed}-chevron`, size: size === 'sm' ? 24 : size === 'lg' ? 32 : 28, sourceSize: 24 }));
107
+ const triggerIcon = icon === undefined ? defaultIndicator : icon;
108
+ return (_jsx(Trigger, { ...props, "aria-describedby": describedBy, "aria-errormessage": errorMessage, "aria-invalid": resolvedInvalid ? true : ariaInvalid, "aria-readonly": field?.readOnly || undefined, className: classes('inkra-select__trigger', className), "data-invalid": resolvedInvalid || undefined, "data-size": size, "data-icon-only": iconOnly || undefined, "data-full-width": fullWidth, "data-text-align": textAlign, disabled: resolvedDisabled, id: resolvedId, ref: ref, onKeyDown: event => {
109
+ props.onKeyDown?.(event);
110
+ if (field?.readOnly && event.key !== 'Tab' && !event.ctrlKey && !event.metaKey)
111
+ event.preventDefault();
112
+ }, onPointerDown: event => {
113
+ props.onPointerDown?.(event);
114
+ if (field?.readOnly)
115
+ event.preventDefault();
116
+ }, children: _jsxs(PencilSurface, { as: "span", className: "inkra-select__trigger-surface", radius: 8, seed: resolvedSeed, variant: resolvedInvalid ? 'danger' : 'outline', children: [_jsx(PencilSurface, { "aria-hidden": "true", as: "span", className: "inkra-select__focus-ring", radius: 8, seed: `${resolvedSeed}-focus`, variant: "outline" }), iconOnly ? (_jsx("span", { className: "inkra-select__trigger-slot", "aria-hidden": "true", children: startIcon ?? endIcon ?? triggerIcon ?? defaultIndicator })) : startIcon != null ? (_jsx("span", { className: "inkra-select__trigger-slot", "aria-hidden": "true", children: startIcon })) : null, _jsx("span", { id: valueId, className: valueHidden ? 'inkra-select__trigger-value-hidden' : 'inkra-select__trigger-value', children: children }), !iconOnly && endIcon != null && _jsx("span", { className: "inkra-select__trigger-slot", "aria-hidden": "true", children: endIcon }), iconOnly || hideIndicator || triggerIcon == null ? null : (_jsx(Icon, { asChild: true, children: _jsx("span", { className: "inkra-select__trigger-icon", children: triggerIcon }) }))] }) }));
117
+ });
118
+ export const SelectValue = forwardRef(function SelectValue({ children, placeholder, seed, ...props }, ref) {
119
+ const generatedId = useId();
120
+ const Value = useContext(MultipleSelectContext) ? MultipleSelect.Value : SelectPrimitive.Value;
121
+ const copy = (value, suffix) => typeof value === 'string' ? (_jsx(PencilText, { className: "inkra-select__value-copy", ellipsis: true, seed: seed ?? `inkra-select-value-${generatedId}-${suffix}`, children: value })) : value;
122
+ return (_jsx(Value, { ...props, placeholder: copy(placeholder, 'placeholder'), ref: ref, children: copy(children, 'value') }));
123
+ });
124
+ export function SelectPortal({ children, ...props }) {
125
+ const Portal = useContext(MultipleSelectContext) ? MultipleSelect.Portal : SelectPrimitive.Portal;
126
+ return (_jsx(Portal, { ...props, children: _jsx(PortalThemeBridge, { children: children }) }));
127
+ }
128
+ export const SelectContent = forwardRef(function SelectContent({ children, className, seed, surfaceClassName, surfaceRadius = 8, surfaceVariant = 'paper', ...props }, ref) {
129
+ const generatedId = useId();
130
+ const Content = useContext(MultipleSelectContext) ? MultipleSelect.Content : SelectPrimitive.Content;
131
+ return (_jsx(Content, { ...props, className: classes('inkra-select__content', className), ref: ref, children: _jsx(PencilSurface, { className: classes('inkra-select__content-surface', surfaceClassName), radius: surfaceRadius, seed: seed ?? `inkra-select-content-${generatedId}`, variant: surfaceVariant, children: children }) }));
132
+ });
133
+ export const SelectViewport = forwardRef(function SelectViewport({ className, ...props }, ref) {
134
+ const Viewport = useContext(MultipleSelectContext) ? MultipleSelect.Viewport : SelectPrimitive.Viewport;
135
+ return (_jsx(Viewport, { ...props, className: classes('inkra-select__viewport', className), ref: ref }));
136
+ });
137
+ export const SelectGroup = forwardRef(function SelectGroup({ className, ...props }, ref) {
138
+ const Group = useContext(MultipleSelectContext) ? MultipleSelect.Group : SelectPrimitive.Group;
139
+ return (_jsx(Group, { ...props, className: classes('inkra-select__group', className), ref: ref }));
140
+ });
141
+ export const SelectLabel = forwardRef(function SelectLabel({ children, className, seed, ...props }, ref) {
142
+ const generatedId = useId();
143
+ const Label = useContext(MultipleSelectContext) ? MultipleSelect.Label : SelectPrimitive.Label;
144
+ return (_jsx(Label, { ...props, className: classes('inkra-select__label', className), ref: ref, children: _jsx(PencilText, { seed: seed ?? `inkra-select-label-${generatedId}`, children: children }) }));
145
+ });
146
+ export const SelectItem = forwardRef(function SelectItem({ children, className, seed, surfaceClassName, value, ...props }, ref) {
147
+ const Item = useContext(MultipleSelectContext) ? MultipleSelect.Item : SelectPrimitive.Item;
148
+ return (_jsx(Item, { ...props, className: classes('inkra-select__item', className), ref: ref, value: value, children: _jsx(PencilSurface, { className: classes('inkra-select__item-surface', surfaceClassName), seed: seed ?? `inkra-select-item-${value}`, variant: "selection", children: children }) }));
149
+ });
150
+ export const SelectItemText = forwardRef(function SelectItemText({ children, seed, ...props }, ref) {
151
+ const generatedId = useId();
152
+ const ItemText = useContext(MultipleSelectContext) ? MultipleSelect.ItemText : SelectPrimitive.ItemText;
153
+ const { copyRef, version } = useItemAppearanceVersion();
154
+ return (_jsx(ItemText, { ...props, ref: ref, children: _jsx(PencilText, { className: "inkra-select__item-text-copy", ref: copyRef, seed: seed ?? `inkra-select-item-text-${generatedId}`, children: children }, version) }));
155
+ });
156
+ export const SelectItemIndicator = forwardRef(function SelectItemIndicator({ children, className, seed, ...props }, ref) {
157
+ const generatedId = useId();
158
+ const ItemIndicator = useContext(MultipleSelectContext) ? MultipleSelect.ItemIndicator : SelectPrimitive.ItemIndicator;
159
+ return (_jsx(ItemIndicator, { ...props, className: classes('inkra-select__item-indicator', className), ref: ref, children: children ?? (_jsx(PencilIcon, { paths: checkPaths, seed: seed ?? `inkra-select-indicator-${generatedId}`, size: 16, sourceSize: 24 })) }));
160
+ });
161
+ export const SelectScrollUpButton = forwardRef(function SelectScrollUpButton({ children, className, seed, ...props }, ref) {
162
+ const generatedId = useId();
163
+ const ScrollUpButton = useContext(MultipleSelectContext) ? MultipleSelect.ScrollUpButton : SelectPrimitive.ScrollUpButton;
164
+ return (_jsx(ScrollUpButton, { ...props, className: classes('inkra-select__scroll-button', className), ref: ref, children: children ?? (_jsx(PencilIcon, { paths: chevronUpPaths, seed: seed ?? `inkra-select-scroll-up-${generatedId}`, size: 16, sourceSize: 24 })) }));
165
+ });
166
+ export const SelectScrollDownButton = forwardRef(function SelectScrollDownButton({ children, className, seed, ...props }, ref) {
167
+ const generatedId = useId();
168
+ const ScrollDownButton = useContext(MultipleSelectContext) ? MultipleSelect.ScrollDownButton : SelectPrimitive.ScrollDownButton;
169
+ return (_jsx(ScrollDownButton, { ...props, className: classes('inkra-select__scroll-button', className), ref: ref, children: children ?? (_jsx(PencilIcon, { paths: chevronDownPaths, seed: seed ?? `inkra-select-scroll-down-${generatedId}`, size: 16, sourceSize: 24 })) }));
170
+ });
171
+ export const SelectSeparator = forwardRef(function SelectSeparator({ className, seed, ...props }, ref) {
172
+ const generatedId = useId();
173
+ const Separator = useContext(MultipleSelectContext) ? MultipleSelect.Separator : SelectPrimitive.Separator;
174
+ return (_jsx(Separator, { ...props, className: classes('inkra-select__separator', className), ref: ref, children: _jsx(PencilLine, { seed: seed ?? `inkra-select-separator-${generatedId}`, weight: 0.8 }) }));
175
+ });
176
+ export const SelectClear = forwardRef(function SelectClear({ children, className, disabled, onClick, ...props }, ref) {
177
+ const state = useContext(MultipleSelectContext);
178
+ if (!state)
179
+ throw new Error('Select.Clear must be used inside Select.Root with multiple.');
180
+ return _jsx(Button, { ...props, className: classes('inkra-select__clear', className), ref: ref, type: "button", variant: "ghost", disabled: disabled || state.disabled || state.readOnly || state.values.length === 0, onClick: event => {
181
+ onClick?.(event);
182
+ if (event.defaultPrevented)
183
+ return;
184
+ state.change([]);
185
+ state.triggerRef.current?.focus({ preventScroll: true });
186
+ }, children: children ?? 'Clear' });
187
+ });
188
+ export const Select = Object.freeze({
189
+ Searchable: SearchableSelect,
190
+ Root: SelectRoot,
191
+ Trigger: SelectTrigger,
192
+ Value: SelectValue,
193
+ Portal: SelectPortal,
194
+ Content: SelectContent,
195
+ Viewport: SelectViewport,
196
+ Group: SelectGroup,
197
+ Label: SelectLabel,
198
+ Item: SelectItem,
199
+ ItemText: SelectItemText,
200
+ ItemIndicator: SelectItemIndicator,
201
+ ScrollUpButton: SelectScrollUpButton,
202
+ ScrollDownButton: SelectScrollDownButton,
203
+ Separator: SelectSeparator,
204
+ Clear: SelectClear,
205
+ });