@cdx-ui/primitives 0.1.7 → 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 (278) hide show
  1. package/lib/commonjs/color/Color.js +69 -0
  2. package/lib/commonjs/color/Color.js.map +1 -0
  3. package/lib/commonjs/color/index.js +13 -0
  4. package/lib/commonjs/color/index.js.map +1 -0
  5. package/lib/commonjs/color/types.js +2 -0
  6. package/lib/commonjs/color/types.js.map +1 -0
  7. package/lib/commonjs/color-area/ColorAreaAccessibility.js +100 -0
  8. package/lib/commonjs/color-area/ColorAreaAccessibility.js.map +1 -0
  9. package/lib/commonjs/color-area/ColorAreaAccessibility.web.js +58 -0
  10. package/lib/commonjs/color-area/ColorAreaAccessibility.web.js.map +1 -0
  11. package/lib/commonjs/color-area/ColorAreaRoot.js +240 -0
  12. package/lib/commonjs/color-area/ColorAreaRoot.js.map +1 -0
  13. package/lib/commonjs/color-area/ColorAreaThumb.js +71 -0
  14. package/lib/commonjs/color-area/ColorAreaThumb.js.map +1 -0
  15. package/lib/commonjs/color-area/context.js +11 -0
  16. package/lib/commonjs/color-area/context.js.map +1 -0
  17. package/lib/commonjs/color-area/index.js +27 -0
  18. package/lib/commonjs/color-area/index.js.map +1 -0
  19. package/lib/commonjs/color-area/types.js +6 -0
  20. package/lib/commonjs/color-area/types.js.map +1 -0
  21. package/lib/commonjs/color-area/utils.js +51 -0
  22. package/lib/commonjs/color-area/utils.js.map +1 -0
  23. package/lib/commonjs/color-field/ColorFieldInput.js +67 -0
  24. package/lib/commonjs/color-field/ColorFieldInput.js.map +1 -0
  25. package/lib/commonjs/color-field/ColorFieldRoot.js +104 -0
  26. package/lib/commonjs/color-field/ColorFieldRoot.js.map +1 -0
  27. package/lib/commonjs/color-field/context.js +11 -0
  28. package/lib/commonjs/color-field/context.js.map +1 -0
  29. package/lib/commonjs/color-field/index.js +27 -0
  30. package/lib/commonjs/color-field/index.js.map +1 -0
  31. package/lib/commonjs/color-field/types.js +6 -0
  32. package/lib/commonjs/color-field/types.js.map +1 -0
  33. package/lib/commonjs/color-field/utils.js +60 -0
  34. package/lib/commonjs/color-field/utils.js.map +1 -0
  35. package/lib/commonjs/color-picker/ColorPickerRoot.js +69 -0
  36. package/lib/commonjs/color-picker/ColorPickerRoot.js.map +1 -0
  37. package/lib/commonjs/color-picker/ColorPickerTrigger.js +98 -0
  38. package/lib/commonjs/color-picker/ColorPickerTrigger.js.map +1 -0
  39. package/lib/commonjs/color-picker/context.js +32 -0
  40. package/lib/commonjs/color-picker/context.js.map +1 -0
  41. package/lib/commonjs/color-picker/index.js +51 -0
  42. package/lib/commonjs/color-picker/index.js.map +1 -0
  43. package/lib/commonjs/color-picker/types.js +6 -0
  44. package/lib/commonjs/color-picker/types.js.map +1 -0
  45. package/lib/commonjs/color-slider/ColorSliderRail.js +119 -0
  46. package/lib/commonjs/color-slider/ColorSliderRail.js.map +1 -0
  47. package/lib/commonjs/color-slider/ColorSliderRoot.js +153 -0
  48. package/lib/commonjs/color-slider/ColorSliderRoot.js.map +1 -0
  49. package/lib/commonjs/color-slider/ColorSliderThumb.js +265 -0
  50. package/lib/commonjs/color-slider/ColorSliderThumb.js.map +1 -0
  51. package/lib/commonjs/color-slider/context.js +11 -0
  52. package/lib/commonjs/color-slider/context.js.map +1 -0
  53. package/lib/commonjs/color-slider/index.js +34 -0
  54. package/lib/commonjs/color-slider/index.js.map +1 -0
  55. package/lib/commonjs/color-slider/types.js +6 -0
  56. package/lib/commonjs/color-slider/types.js.map +1 -0
  57. package/lib/commonjs/color-slider/utils.js +75 -0
  58. package/lib/commonjs/color-slider/utils.js.map +1 -0
  59. package/lib/commonjs/color-swatch-picker/ColorSwatchPickerItem.js +46 -0
  60. package/lib/commonjs/color-swatch-picker/ColorSwatchPickerItem.js.map +1 -0
  61. package/lib/commonjs/color-swatch-picker/ColorSwatchPickerRoot.js +71 -0
  62. package/lib/commonjs/color-swatch-picker/ColorSwatchPickerRoot.js.map +1 -0
  63. package/lib/commonjs/color-swatch-picker/context.js +22 -0
  64. package/lib/commonjs/color-swatch-picker/context.js.map +1 -0
  65. package/lib/commonjs/color-swatch-picker/index.js +33 -0
  66. package/lib/commonjs/color-swatch-picker/index.js.map +1 -0
  67. package/lib/commonjs/color-swatch-picker/types.js +6 -0
  68. package/lib/commonjs/color-swatch-picker/types.js.map +1 -0
  69. package/lib/commonjs/index.js +80 -0
  70. package/lib/commonjs/index.js.map +1 -1
  71. package/lib/commonjs/react-native-web.d.js +2 -0
  72. package/lib/commonjs/react-native-web.d.js.map +1 -0
  73. package/lib/commonjs/slider/useSliderPointer.js +2 -0
  74. package/lib/commonjs/slider/useSliderPointer.js.map +1 -1
  75. package/lib/commonjs/utils/createPortal.web.js +10 -1
  76. package/lib/commonjs/utils/createPortal.web.js.map +1 -1
  77. package/lib/commonjs/utils/textAncestor.js +25 -0
  78. package/lib/commonjs/utils/textAncestor.js.map +1 -0
  79. package/lib/commonjs/utils/textAncestor.web.js +27 -0
  80. package/lib/commonjs/utils/textAncestor.web.js.map +1 -0
  81. package/lib/module/color/Color.js +65 -0
  82. package/lib/module/color/Color.js.map +1 -0
  83. package/lib/module/color/index.js +4 -0
  84. package/lib/module/color/index.js.map +1 -0
  85. package/lib/module/color/types.js +2 -0
  86. package/lib/module/color/types.js.map +1 -0
  87. package/lib/module/color-area/ColorAreaAccessibility.js +96 -0
  88. package/lib/module/color-area/ColorAreaAccessibility.js.map +1 -0
  89. package/lib/module/color-area/ColorAreaAccessibility.web.js +54 -0
  90. package/lib/module/color-area/ColorAreaAccessibility.web.js.map +1 -0
  91. package/lib/module/color-area/ColorAreaRoot.js +236 -0
  92. package/lib/module/color-area/ColorAreaRoot.js.map +1 -0
  93. package/lib/module/color-area/ColorAreaThumb.js +67 -0
  94. package/lib/module/color-area/ColorAreaThumb.js.map +1 -0
  95. package/lib/module/color-area/context.js +5 -0
  96. package/lib/module/color-area/context.js.map +1 -0
  97. package/lib/module/color-area/index.js +6 -0
  98. package/lib/module/color-area/index.js.map +1 -0
  99. package/lib/module/color-area/types.js +4 -0
  100. package/lib/module/color-area/types.js.map +1 -0
  101. package/lib/module/color-area/utils.js +45 -0
  102. package/lib/module/color-area/utils.js.map +1 -0
  103. package/lib/module/color-field/ColorFieldInput.js +63 -0
  104. package/lib/module/color-field/ColorFieldInput.js.map +1 -0
  105. package/lib/module/color-field/ColorFieldRoot.js +100 -0
  106. package/lib/module/color-field/ColorFieldRoot.js.map +1 -0
  107. package/lib/module/color-field/context.js +5 -0
  108. package/lib/module/color-field/context.js.map +1 -0
  109. package/lib/module/color-field/index.js +6 -0
  110. package/lib/module/color-field/index.js.map +1 -0
  111. package/lib/module/color-field/types.js +4 -0
  112. package/lib/module/color-field/types.js.map +1 -0
  113. package/lib/module/color-field/utils.js +55 -0
  114. package/lib/module/color-field/utils.js.map +1 -0
  115. package/lib/module/color-picker/ColorPickerRoot.js +65 -0
  116. package/lib/module/color-picker/ColorPickerRoot.js.map +1 -0
  117. package/lib/module/color-picker/ColorPickerTrigger.js +94 -0
  118. package/lib/module/color-picker/ColorPickerTrigger.js.map +1 -0
  119. package/lib/module/color-picker/context.js +25 -0
  120. package/lib/module/color-picker/context.js.map +1 -0
  121. package/lib/module/color-picker/index.js +6 -0
  122. package/lib/module/color-picker/index.js.map +1 -0
  123. package/lib/module/color-picker/types.js +4 -0
  124. package/lib/module/color-picker/types.js.map +1 -0
  125. package/lib/module/color-slider/ColorSliderRail.js +115 -0
  126. package/lib/module/color-slider/ColorSliderRail.js.map +1 -0
  127. package/lib/module/color-slider/ColorSliderRoot.js +149 -0
  128. package/lib/module/color-slider/ColorSliderRoot.js.map +1 -0
  129. package/lib/module/color-slider/ColorSliderThumb.js +261 -0
  130. package/lib/module/color-slider/ColorSliderThumb.js.map +1 -0
  131. package/lib/module/color-slider/context.js +5 -0
  132. package/lib/module/color-slider/context.js.map +1 -0
  133. package/lib/module/color-slider/index.js +7 -0
  134. package/lib/module/color-slider/index.js.map +1 -0
  135. package/lib/module/color-slider/types.js +4 -0
  136. package/lib/module/color-slider/types.js.map +1 -0
  137. package/lib/module/color-slider/utils.js +66 -0
  138. package/lib/module/color-slider/utils.js.map +1 -0
  139. package/lib/module/color-swatch-picker/ColorSwatchPickerItem.js +42 -0
  140. package/lib/module/color-swatch-picker/ColorSwatchPickerItem.js.map +1 -0
  141. package/lib/module/color-swatch-picker/ColorSwatchPickerRoot.js +67 -0
  142. package/lib/module/color-swatch-picker/ColorSwatchPickerRoot.js.map +1 -0
  143. package/lib/module/color-swatch-picker/context.js +15 -0
  144. package/lib/module/color-swatch-picker/context.js.map +1 -0
  145. package/lib/module/color-swatch-picker/index.js +6 -0
  146. package/lib/module/color-swatch-picker/index.js.map +1 -0
  147. package/lib/module/color-swatch-picker/types.js +4 -0
  148. package/lib/module/color-swatch-picker/types.js.map +1 -0
  149. package/lib/module/index.js +7 -0
  150. package/lib/module/index.js.map +1 -1
  151. package/lib/module/react-native-web.d.js +2 -0
  152. package/lib/module/react-native-web.d.js.map +1 -0
  153. package/lib/module/slider/useSliderPointer.js +2 -0
  154. package/lib/module/slider/useSliderPointer.js.map +1 -1
  155. package/lib/module/utils/createPortal.web.js +9 -1
  156. package/lib/module/utils/createPortal.web.js.map +1 -1
  157. package/lib/module/utils/textAncestor.js +20 -0
  158. package/lib/module/utils/textAncestor.js.map +1 -0
  159. package/lib/module/utils/textAncestor.web.js +22 -0
  160. package/lib/module/utils/textAncestor.web.js.map +1 -0
  161. package/lib/typescript/color/Color.d.ts +3 -0
  162. package/lib/typescript/color/Color.d.ts.map +1 -0
  163. package/lib/typescript/color/index.d.ts +3 -0
  164. package/lib/typescript/color/index.d.ts.map +1 -0
  165. package/lib/typescript/color/types.d.ts +13 -0
  166. package/lib/typescript/color/types.d.ts.map +1 -0
  167. package/lib/typescript/color-area/ColorAreaAccessibility.d.ts +8 -0
  168. package/lib/typescript/color-area/ColorAreaAccessibility.d.ts.map +1 -0
  169. package/lib/typescript/color-area/ColorAreaAccessibility.web.d.ts +8 -0
  170. package/lib/typescript/color-area/ColorAreaAccessibility.web.d.ts.map +1 -0
  171. package/lib/typescript/color-area/ColorAreaRoot.d.ts +7 -0
  172. package/lib/typescript/color-area/ColorAreaRoot.d.ts.map +1 -0
  173. package/lib/typescript/color-area/ColorAreaThumb.d.ts +6 -0
  174. package/lib/typescript/color-area/ColorAreaThumb.d.ts.map +1 -0
  175. package/lib/typescript/color-area/context.d.ts +6 -0
  176. package/lib/typescript/color-area/context.d.ts.map +1 -0
  177. package/lib/typescript/color-area/index.d.ts +5 -0
  178. package/lib/typescript/color-area/index.d.ts.map +1 -0
  179. package/lib/typescript/color-area/types.d.ts +65 -0
  180. package/lib/typescript/color-area/types.d.ts.map +1 -0
  181. package/lib/typescript/color-area/utils.d.ts +5 -0
  182. package/lib/typescript/color-area/utils.d.ts.map +1 -0
  183. package/lib/typescript/color-field/ColorFieldInput.d.ts +5 -0
  184. package/lib/typescript/color-field/ColorFieldInput.d.ts.map +1 -0
  185. package/lib/typescript/color-field/ColorFieldRoot.d.ts +7 -0
  186. package/lib/typescript/color-field/ColorFieldRoot.d.ts.map +1 -0
  187. package/lib/typescript/color-field/context.d.ts +6 -0
  188. package/lib/typescript/color-field/context.d.ts.map +1 -0
  189. package/lib/typescript/color-field/index.d.ts +7 -0
  190. package/lib/typescript/color-field/index.d.ts.map +1 -0
  191. package/lib/typescript/color-field/types.d.ts +39 -0
  192. package/lib/typescript/color-field/types.d.ts.map +1 -0
  193. package/lib/typescript/color-field/utils.d.ts +5 -0
  194. package/lib/typescript/color-field/utils.d.ts.map +1 -0
  195. package/lib/typescript/color-picker/ColorPickerRoot.d.ts +7 -0
  196. package/lib/typescript/color-picker/ColorPickerRoot.d.ts.map +1 -0
  197. package/lib/typescript/color-picker/ColorPickerTrigger.d.ts +4 -0
  198. package/lib/typescript/color-picker/ColorPickerTrigger.d.ts.map +1 -0
  199. package/lib/typescript/color-picker/context.d.ts +19 -0
  200. package/lib/typescript/color-picker/context.d.ts.map +1 -0
  201. package/lib/typescript/color-picker/index.d.ts +5 -0
  202. package/lib/typescript/color-picker/index.d.ts.map +1 -0
  203. package/lib/typescript/color-picker/types.d.ts +24 -0
  204. package/lib/typescript/color-picker/types.d.ts.map +1 -0
  205. package/lib/typescript/color-slider/ColorSliderRail.d.ts +6 -0
  206. package/lib/typescript/color-slider/ColorSliderRail.d.ts.map +1 -0
  207. package/lib/typescript/color-slider/ColorSliderRoot.d.ts +7 -0
  208. package/lib/typescript/color-slider/ColorSliderRoot.d.ts.map +1 -0
  209. package/lib/typescript/color-slider/ColorSliderThumb.d.ts +6 -0
  210. package/lib/typescript/color-slider/ColorSliderThumb.d.ts.map +1 -0
  211. package/lib/typescript/color-slider/context.d.ts +6 -0
  212. package/lib/typescript/color-slider/context.d.ts.map +1 -0
  213. package/lib/typescript/color-slider/index.d.ts +6 -0
  214. package/lib/typescript/color-slider/index.d.ts.map +1 -0
  215. package/lib/typescript/color-slider/types.d.ts +82 -0
  216. package/lib/typescript/color-slider/types.d.ts.map +1 -0
  217. package/lib/typescript/color-slider/utils.d.ts +12 -0
  218. package/lib/typescript/color-slider/utils.d.ts.map +1 -0
  219. package/lib/typescript/color-swatch-picker/ColorSwatchPickerItem.d.ts +6 -0
  220. package/lib/typescript/color-swatch-picker/ColorSwatchPickerItem.d.ts.map +1 -0
  221. package/lib/typescript/color-swatch-picker/ColorSwatchPickerRoot.d.ts +7 -0
  222. package/lib/typescript/color-swatch-picker/ColorSwatchPickerRoot.d.ts.map +1 -0
  223. package/lib/typescript/color-swatch-picker/context.d.ts +8 -0
  224. package/lib/typescript/color-swatch-picker/context.d.ts.map +1 -0
  225. package/lib/typescript/color-swatch-picker/index.d.ts +5 -0
  226. package/lib/typescript/color-swatch-picker/index.d.ts.map +1 -0
  227. package/lib/typescript/color-swatch-picker/types.d.ts +26 -0
  228. package/lib/typescript/color-swatch-picker/types.d.ts.map +1 -0
  229. package/lib/typescript/index.d.ts +7 -0
  230. package/lib/typescript/index.d.ts.map +1 -1
  231. package/lib/typescript/slider/useSliderPointer.d.ts.map +1 -1
  232. package/lib/typescript/utils/createPortal.web.d.ts +6 -2
  233. package/lib/typescript/utils/createPortal.web.d.ts.map +1 -1
  234. package/lib/typescript/utils/textAncestor.d.ts +13 -0
  235. package/lib/typescript/utils/textAncestor.d.ts.map +1 -0
  236. package/lib/typescript/utils/textAncestor.web.d.ts +15 -0
  237. package/lib/typescript/utils/textAncestor.web.d.ts.map +1 -0
  238. package/package.json +4 -3
  239. package/src/color/Color.ts +95 -0
  240. package/src/color/index.ts +2 -0
  241. package/src/color/types.ts +19 -0
  242. package/src/color-area/ColorAreaAccessibility.tsx +94 -0
  243. package/src/color-area/ColorAreaAccessibility.web.tsx +52 -0
  244. package/src/color-area/ColorAreaRoot.tsx +326 -0
  245. package/src/color-area/ColorAreaThumb.tsx +56 -0
  246. package/src/color-area/context.tsx +5 -0
  247. package/src/color-area/index.ts +10 -0
  248. package/src/color-area/types.ts +69 -0
  249. package/src/color-area/utils.ts +51 -0
  250. package/src/color-field/ColorFieldInput.tsx +66 -0
  251. package/src/color-field/ColorFieldRoot.tsx +132 -0
  252. package/src/color-field/context.tsx +5 -0
  253. package/src/color-field/index.ts +11 -0
  254. package/src/color-field/types.ts +46 -0
  255. package/src/color-field/utils.ts +75 -0
  256. package/src/color-picker/ColorPickerRoot.tsx +91 -0
  257. package/src/color-picker/ColorPickerTrigger.tsx +96 -0
  258. package/src/color-picker/context.tsx +47 -0
  259. package/src/color-picker/index.ts +12 -0
  260. package/src/color-picker/types.ts +25 -0
  261. package/src/color-slider/ColorSliderRail.tsx +130 -0
  262. package/src/color-slider/ColorSliderRoot.tsx +222 -0
  263. package/src/color-slider/ColorSliderThumb.tsx +294 -0
  264. package/src/color-slider/context.tsx +5 -0
  265. package/src/color-slider/index.ts +16 -0
  266. package/src/color-slider/types.ts +94 -0
  267. package/src/color-slider/utils.ts +79 -0
  268. package/src/color-swatch-picker/ColorSwatchPickerItem.tsx +54 -0
  269. package/src/color-swatch-picker/ColorSwatchPickerRoot.tsx +94 -0
  270. package/src/color-swatch-picker/context.tsx +22 -0
  271. package/src/color-swatch-picker/index.ts +4 -0
  272. package/src/color-swatch-picker/types.ts +29 -0
  273. package/src/index.ts +7 -0
  274. package/src/react-native-web.d.ts +6 -0
  275. package/src/slider/useSliderPointer.ts +3 -0
  276. package/src/utils/createPortal.web.ts +9 -3
  277. package/src/utils/textAncestor.ts +19 -0
  278. package/src/utils/textAncestor.web.ts +19 -0
@@ -0,0 +1,16 @@
1
+ export { ColorSliderRoot, type ColorSliderRootProps } from './ColorSliderRoot';
2
+ export { ColorSliderRail, type ColorSliderRailProps } from './ColorSliderRail';
3
+ export { ColorSliderThumb, type ColorSliderThumbProps } from './ColorSliderThumb';
4
+ export { useColorSliderContext } from './context';
5
+ export type {
6
+ ColorSliderCommonProps,
7
+ ColorSliderConfiguration,
8
+ ColorSliderContextValue,
9
+ ColorSliderKeyboardEvent,
10
+ ColorSliderLayout,
11
+ ColorSliderOrientation,
12
+ ColorSliderSize,
13
+ IColorSliderProps,
14
+ IColorSliderRailProps,
15
+ IColorSliderThumbProps,
16
+ } from './types';
@@ -0,0 +1,94 @@
1
+ import type { ReactNode } from 'react';
2
+ import type { PressableProps, ViewProps } from 'react-native';
3
+ import type { Color } from '../color';
4
+
5
+ export type ColorSliderOrientation = 'horizontal' | 'vertical';
6
+
7
+ export type ColorSliderConfiguration =
8
+ | {
9
+ readonly colorSpace: 'rgb';
10
+ readonly channel: 'red' | 'green' | 'blue';
11
+ }
12
+ | {
13
+ readonly colorSpace: 'hsl';
14
+ readonly channel: 'hue' | 'saturation' | 'lightness';
15
+ }
16
+ | {
17
+ readonly colorSpace: 'hsb';
18
+ readonly channel: 'hue' | 'saturation' | 'brightness';
19
+ };
20
+
21
+ export interface ColorSliderCommonProps extends Omit<ViewProps, 'children'> {
22
+ /** Current controlled color. */
23
+ readonly value?: Color;
24
+ /** Initial color for uncontrolled usage. */
25
+ readonly defaultValue?: Color;
26
+ /** Called while the selected channel changes. */
27
+ readonly onValueChange?: (value: Color) => void;
28
+ /** Called when a pointer, keyboard, or screen reader interaction completes. */
29
+ readonly onValueChangeComplete?: (value: Color) => void;
30
+ /** Slider axis. @default `'horizontal'` */
31
+ readonly orientation?: ColorSliderOrientation;
32
+ /** Channel increment. Defaults to the channel's natural increment. */
33
+ readonly step?: number;
34
+ /** Shift-arrow and page-key increment. @default `10` */
35
+ readonly pageStep?: number;
36
+ /** Disables pointer, keyboard, and screen reader interaction. @default `false` */
37
+ readonly isDisabled?: boolean;
38
+ readonly children?: ReactNode;
39
+ }
40
+
41
+ export type IColorSliderProps = ColorSliderCommonProps & ColorSliderConfiguration;
42
+
43
+ export interface IColorSliderRailProps extends ViewProps {
44
+ readonly asChild?: boolean;
45
+ readonly children?: ReactNode;
46
+ }
47
+
48
+ export interface IColorSliderThumbProps extends PressableProps {
49
+ readonly asChild?: boolean;
50
+ readonly children?: ReactNode;
51
+ }
52
+
53
+ export interface ColorSliderSize {
54
+ readonly width: number;
55
+ readonly height: number;
56
+ }
57
+
58
+ export interface ColorSliderLayout extends ColorSliderSize {
59
+ readonly x: number;
60
+ readonly y: number;
61
+ }
62
+
63
+ export type ColorSliderContextValue = ColorSliderConfiguration & {
64
+ readonly value: Color;
65
+ readonly channelValue: number;
66
+ readonly valueLabel: string;
67
+ readonly min: number;
68
+ readonly max: number;
69
+ readonly step: number;
70
+ readonly pageStep: number;
71
+ readonly percent: number;
72
+ readonly orientation: ColorSliderOrientation;
73
+ readonly isDisabled: boolean;
74
+ readonly isDragging: boolean;
75
+ readonly accessibilityLabel?: string;
76
+ readonly layout: ColorSliderLayout | null;
77
+ readonly thumbSize: ColorSliderSize;
78
+ readonly gradientColors: readonly string[];
79
+ readonly setLayout: (layout: ColorSliderLayout) => void;
80
+ readonly setThumbSize: (size: ColorSliderSize) => void;
81
+ readonly setIsDragging: (dragging: boolean) => void;
82
+ readonly setChannelValue: (value: number, complete?: boolean) => void;
83
+ readonly setValueFromRatio: (ratio: number, complete?: boolean) => void;
84
+ };
85
+
86
+ export interface ColorSliderKeyboardEvent {
87
+ readonly nativeEvent?: {
88
+ readonly key?: string;
89
+ readonly shiftKey?: boolean;
90
+ };
91
+ readonly key?: string;
92
+ readonly shiftKey?: boolean;
93
+ preventDefault?: () => void;
94
+ }
@@ -0,0 +1,79 @@
1
+ import type { Color } from '../color';
2
+ import type { ColorSliderConfiguration } from './types';
3
+
4
+ const HUE_STOPS = [0, 60, 120, 180, 240, 300, 360] as const;
5
+
6
+ export function clampColorSliderValue(value: number, min: number, max: number): number {
7
+ return Math.min(max, Math.max(min, value));
8
+ }
9
+
10
+ export function getColorSliderRange({ colorSpace, channel }: ColorSliderConfiguration): {
11
+ min: number;
12
+ max: number;
13
+ } {
14
+ if (colorSpace === 'rgb') {
15
+ return { min: 0, max: 255 };
16
+ }
17
+ if (channel === 'hue') {
18
+ return { min: 0, max: 360 };
19
+ }
20
+ return { min: 0, max: 100 };
21
+ }
22
+
23
+ export function getColorSliderChannelValue(
24
+ color: Color,
25
+ configuration: ColorSliderConfiguration,
26
+ ): number {
27
+ if (configuration.colorSpace === 'rgb') {
28
+ return color.getChannel('rgb', configuration.channel);
29
+ }
30
+ if (configuration.colorSpace === 'hsl') {
31
+ return color.getChannel('hsl', configuration.channel);
32
+ }
33
+ return color.getChannel('hsb', configuration.channel);
34
+ }
35
+
36
+ export function withColorSliderChannel(
37
+ color: Color,
38
+ configuration: ColorSliderConfiguration,
39
+ value: number,
40
+ ): Color {
41
+ if (configuration.colorSpace === 'rgb') {
42
+ return color.withChannel('rgb', configuration.channel, value);
43
+ }
44
+ if (configuration.colorSpace === 'hsl') {
45
+ return color.withChannel('hsl', configuration.channel, value);
46
+ }
47
+ return color.withChannel('hsb', configuration.channel, value);
48
+ }
49
+
50
+ export function formatColorSliderValue(
51
+ value: number,
52
+ configuration: ColorSliderConfiguration,
53
+ ): string {
54
+ const formatted = Number.isInteger(value) ? String(value) : value.toFixed(1);
55
+ if (configuration.channel === 'hue') {
56
+ return `${formatted}°`;
57
+ }
58
+ if (configuration.colorSpace !== 'rgb') {
59
+ return `${formatted}%`;
60
+ }
61
+ return formatted;
62
+ }
63
+
64
+ export function getColorSliderGradientColors(
65
+ color: Color,
66
+ configuration: ColorSliderConfiguration,
67
+ ): readonly string[] {
68
+ if (configuration.channel === 'hue') {
69
+ return HUE_STOPS.map((value) =>
70
+ withColorSliderChannel(color, configuration, value).toString('hex'),
71
+ );
72
+ }
73
+
74
+ const { min, max } = getColorSliderRange(configuration);
75
+ return [
76
+ withColorSliderChannel(color, configuration, min).toString('hex'),
77
+ withColorSliderChannel(color, configuration, max).toString('hex'),
78
+ ];
79
+ }
@@ -0,0 +1,54 @@
1
+ import { forwardRef, useEffect, useMemo, type ComponentRef } from 'react';
2
+ import { Pressable } from 'react-native';
3
+ import { RadioRoot } from '../radio';
4
+ import { ColorSwatchPickerItemProvider, useColorSwatchPickerContext } from './context';
5
+ import type { IColorSwatchPickerItemProps } from './types';
6
+
7
+ export interface ColorSwatchPickerItemProps extends IColorSwatchPickerItemProps {
8
+ asChild?: boolean;
9
+ }
10
+
11
+ export const ColorSwatchPickerItem = forwardRef<
12
+ ComponentRef<typeof Pressable>,
13
+ ColorSwatchPickerItemProps
14
+ >(
15
+ (
16
+ {
17
+ asChild,
18
+ color,
19
+ isDisabled,
20
+ disabled,
21
+ accessibilityLabel,
22
+ 'aria-label': ariaLabelProp,
23
+ children,
24
+ ...props
25
+ },
26
+ ref,
27
+ ) => {
28
+ const { registerColor } = useColorSwatchPickerContext();
29
+ const colorValue = color.toString('hex');
30
+ const label = ariaLabelProp ?? accessibilityLabel ?? colorValue;
31
+ const contextValue = useMemo(() => ({ color }), [color]);
32
+
33
+ useEffect(() => registerColor(color), [color, registerColor]);
34
+
35
+ return (
36
+ <ColorSwatchPickerItemProvider value={contextValue}>
37
+ <RadioRoot
38
+ ref={ref}
39
+ asChild={asChild}
40
+ value={colorValue}
41
+ isDisabled={!!(isDisabled || disabled)}
42
+ disabled={disabled}
43
+ aria-label={label}
44
+ accessibilityLabel={label}
45
+ {...props}
46
+ >
47
+ {children}
48
+ </RadioRoot>
49
+ </ColorSwatchPickerItemProvider>
50
+ );
51
+ },
52
+ );
53
+
54
+ ColorSwatchPickerItem.displayName = 'ColorSwatchPickerItem';
@@ -0,0 +1,94 @@
1
+ import { forwardRef, useCallback, useMemo, useRef, type ComponentRef } from 'react';
2
+ import { View } from 'react-native';
3
+ import { useControllableState } from '@cdx-ui/utils';
4
+ import { RadioGroup } from '../radio';
5
+ import { useOptionalColorPickerContext } from '../color-picker';
6
+ import type { Color } from '../color';
7
+ import { ColorSwatchPickerProvider } from './context';
8
+ import type { IColorSwatchPickerProps } from './types';
9
+
10
+ export interface ColorSwatchPickerRootProps extends IColorSwatchPickerProps {
11
+ asChild?: boolean;
12
+ }
13
+
14
+ export const ColorSwatchPickerRoot = forwardRef<
15
+ ComponentRef<typeof View>,
16
+ ColorSwatchPickerRootProps
17
+ >(
18
+ (
19
+ {
20
+ asChild,
21
+ value: valueProp,
22
+ defaultValue,
23
+ onValueChange,
24
+ isDisabled,
25
+ accessibilityLabel,
26
+ children,
27
+ ...props
28
+ },
29
+ ref,
30
+ ) => {
31
+ const picker = useOptionalColorPickerContext();
32
+ const usesPickerContext =
33
+ picker !== null && valueProp === undefined && defaultValue === undefined;
34
+
35
+ const [localValue, setLocalValue] = useControllableState<Color>({
36
+ prop: valueProp,
37
+ defaultProp: defaultValue,
38
+ onChange: onValueChange,
39
+ });
40
+
41
+ const value = usesPickerContext ? picker.value : localValue;
42
+ const colorsRef = useRef(new Map<string, Color>());
43
+
44
+ const registerColor = useCallback((color: Color) => {
45
+ const key = color.toString('hex');
46
+ colorsRef.current.set(key, color);
47
+
48
+ return () => {
49
+ if (colorsRef.current.get(key) === color) {
50
+ colorsRef.current.delete(key);
51
+ }
52
+ };
53
+ }, []);
54
+
55
+ const handleValueChange = useCallback(
56
+ (key: string) => {
57
+ const color = colorsRef.current.get(key);
58
+
59
+ if (!color) {
60
+ return;
61
+ }
62
+
63
+ if (usesPickerContext) {
64
+ onValueChange?.(color);
65
+ picker.onValueChange(color);
66
+ return;
67
+ }
68
+
69
+ setLocalValue(color);
70
+ },
71
+ [onValueChange, picker, setLocalValue, usesPickerContext],
72
+ );
73
+
74
+ const contextValue = useMemo(() => ({ registerColor }), [registerColor]);
75
+
76
+ return (
77
+ <ColorSwatchPickerProvider value={contextValue}>
78
+ <RadioGroup
79
+ ref={ref}
80
+ asChild={asChild}
81
+ value={value?.toString('hex')}
82
+ onChange={handleValueChange}
83
+ isDisabled={isDisabled}
84
+ aria-label={props['aria-label'] ?? accessibilityLabel}
85
+ {...props}
86
+ >
87
+ {children}
88
+ </RadioGroup>
89
+ </ColorSwatchPickerProvider>
90
+ );
91
+ },
92
+ );
93
+
94
+ ColorSwatchPickerRoot.displayName = 'ColorSwatchPickerRoot';
@@ -0,0 +1,22 @@
1
+ import { createContext as createReactContext, useContext } from 'react';
2
+ import { createContext } from '@cdx-ui/utils';
3
+ import type { ColorSwatchPickerContextValue, ColorSwatchPickerItemContextValue } from './types';
4
+
5
+ export const [ColorSwatchPickerProvider, useColorSwatchPickerContext] =
6
+ createContext<ColorSwatchPickerContextValue>('ColorSwatchPickerContext');
7
+
8
+ const ColorSwatchPickerItemContext = createReactContext<ColorSwatchPickerItemContextValue | null>(
9
+ null,
10
+ );
11
+
12
+ export const ColorSwatchPickerItemProvider = ColorSwatchPickerItemContext.Provider;
13
+
14
+ export function useColorSwatchPickerItemContext(): ColorSwatchPickerItemContextValue {
15
+ const context = useContext(ColorSwatchPickerItemContext);
16
+
17
+ if (!context) {
18
+ throw new Error('ColorSwatchPicker item slots must be used within ColorSwatchPicker.Item');
19
+ }
20
+
21
+ return context;
22
+ }
@@ -0,0 +1,4 @@
1
+ export { ColorSwatchPickerRoot, type ColorSwatchPickerRootProps } from './ColorSwatchPickerRoot';
2
+ export { ColorSwatchPickerItem, type ColorSwatchPickerItemProps } from './ColorSwatchPickerItem';
3
+ export { useColorSwatchPickerContext, useColorSwatchPickerItemContext } from './context';
4
+ export type { IColorSwatchPickerItemProps, IColorSwatchPickerProps } from './types';
@@ -0,0 +1,29 @@
1
+ import type { ReactNode } from 'react';
2
+ import type { PressableProps, ViewProps } from 'react-native';
3
+ import type { Color } from '../color';
4
+
5
+ export interface IColorSwatchPickerProps extends Omit<ViewProps, 'children'> {
6
+ value?: Color;
7
+ defaultValue?: Color;
8
+ onValueChange?: (value: Color) => void;
9
+ isDisabled?: boolean;
10
+ children?: ReactNode;
11
+ }
12
+
13
+ export interface IColorSwatchPickerItemProps extends Omit<PressableProps, 'children'> {
14
+ color: Color;
15
+ isDisabled?: boolean;
16
+ isHovered?: boolean;
17
+ isActive?: boolean;
18
+ isFocused?: boolean;
19
+ isFocusVisible?: boolean;
20
+ children?: ReactNode;
21
+ }
22
+
23
+ export interface ColorSwatchPickerContextValue {
24
+ registerColor: (color: Color) => () => void;
25
+ }
26
+
27
+ export interface ColorSwatchPickerItemContextValue {
28
+ color: Color;
29
+ }
package/src/index.ts CHANGED
@@ -3,6 +3,12 @@ export * from './breadcrumbs';
3
3
  export * from './button';
4
4
  export * from './chip';
5
5
  export * from './checkbox';
6
+ export * from './color';
7
+ export * from './color-area';
8
+ export * from './color-field';
9
+ export * from './color-picker';
10
+ export * from './color-slider';
11
+ export * from './color-swatch-picker';
6
12
  export * from './dialog';
7
13
  export * from './drawer';
8
14
  export * from './field';
@@ -80,4 +86,5 @@ export {
80
86
  export { mapViewPropsToDom, type MapViewPropsToDomOptions } from './utils/mapViewPropsToDom';
81
87
  export { assignRef } from './utils/assignRef';
82
88
  export { createPortalFn } from './utils/createPortal';
89
+ export { useHasTextAncestor } from './utils/textAncestor';
83
90
  export { Slot } from './slot';
@@ -0,0 +1,6 @@
1
+ declare module 'react-native-web/dist/exports/Text/TextAncestorContext' {
2
+ import type { Context } from 'react';
3
+
4
+ const TextAncestorContext: Context<boolean>;
5
+ export default TextAncestorContext;
6
+ }
@@ -97,6 +97,9 @@ export function useWebSliderDrag({
97
97
  return;
98
98
  }
99
99
 
100
+ cleanupRef.current?.();
101
+ cleanupRef.current = null;
102
+
100
103
  const trackSize = orientation === 'horizontal' ? layout.width : layout.height;
101
104
  const travel = getThumbTravel(trackSize, thumbSize);
102
105
  if (travel <= 0) {
@@ -1,7 +1,8 @@
1
- import type React from 'react';
1
+ import { createElement, type ReactNode, type ReactPortal } from 'react';
2
2
  import { createPortal } from 'react-dom';
3
+ import { TextAncestorContext } from './textAncestor';
3
4
 
4
- type CreatePortalFn = (children: React.ReactNode, container: Element) => React.ReactPortal;
5
+ type CreatePortalFn = (children: ReactNode, container: Element) => ReactPortal;
5
6
 
6
7
  /**
7
8
  * Web implementation — statically imports `ReactDOM.createPortal`.
@@ -14,5 +15,10 @@ type CreatePortalFn = (children: React.ReactNode, container: Element) => React.R
14
15
  * layout-animation path, leaving web overlays (Select, DatePicker) stuck at
15
16
  * opacity 0. A static ESM import guarantees `createPortalFn` resolves on web
16
17
  * regardless of the bundler's CommonJS interop.
18
+ *
19
+ * Portaled content leaves the DOM subtree of any `Text` it was rendered from,
20
+ * so the text-ancestor context is reset; otherwise a `Text` inside an overlay
21
+ * opened from a `Text` would skip its own typography and inherit nothing.
17
22
  */
18
- export const createPortalFn: CreatePortalFn = createPortal;
23
+ export const createPortalFn: CreatePortalFn = (children, container) =>
24
+ createPortal(createElement(TextAncestorContext.Provider, { value: false }, children), container);
@@ -0,0 +1,19 @@
1
+ import { createContext, useContext, type Context } from 'react';
2
+ import * as ReactNative from 'react-native';
3
+
4
+ /**
5
+ * React Native's own text-ancestor context: `Text` provides `true`, and `View`
6
+ * (including the one inside `Modal`) resets it to `false`.
7
+ *
8
+ * It is exported as `unstable_`, so a React Native release that drops it falls
9
+ * back to a context nothing provides — every `Text` then styles itself as
10
+ * top-level instead of the module failing to load.
11
+ */
12
+ export const TextAncestorContext: Context<boolean> =
13
+ (ReactNative as { unstable_TextAncestorContext?: Context<boolean> })
14
+ .unstable_TextAncestorContext ?? createContext(false);
15
+
16
+ /** `true` when the calling component renders inside a host `Text`. */
17
+ export function useHasTextAncestor(): boolean {
18
+ return useContext(TextAncestorContext);
19
+ }
@@ -0,0 +1,19 @@
1
+ import { useContext, type Context } from 'react';
2
+ import RNWTextAncestorContext from 'react-native-web/dist/exports/Text/TextAncestorContext';
3
+
4
+ /**
5
+ * React Native Web's text-ancestor context, which its `Text` provides. RNW does
6
+ * not export it, so this is a deep import. RNW's ESM and CommonJS builds each
7
+ * create their own context, so this must stay on the ESM path: it is the build
8
+ * bundlers resolve `react-native-web` to, and the path `babel-preset-expo`
9
+ * rewrites `react-native` imports to under Jest.
10
+ *
11
+ * Unlike native, RNW's `View` does not reset the context — CSS inherits through
12
+ * an inline `View` inside `Text`. DOM portals reset it in `createPortal.web.ts`.
13
+ */
14
+ export const TextAncestorContext: Context<boolean> = RNWTextAncestorContext;
15
+
16
+ /** `true` when the calling component renders inside a host `Text`. */
17
+ export function useHasTextAncestor(): boolean {
18
+ return useContext(TextAncestorContext);
19
+ }