@cdx-ui/primitives 0.0.1-beta.6 → 0.0.1-beta.61

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 (297) hide show
  1. package/README.md +51 -25
  2. package/lib/commonjs/CLAUDE.md +32 -0
  3. package/lib/commonjs/avatar/createAvatarText.js +9 -1
  4. package/lib/commonjs/avatar/createAvatarText.js.map +1 -1
  5. package/lib/commonjs/button/createButtonText.js +1 -0
  6. package/lib/commonjs/button/createButtonText.js.map +1 -1
  7. package/lib/commonjs/checkbox/createCheckboxRoot.web.js +8 -3
  8. package/lib/commonjs/checkbox/createCheckboxRoot.web.js.map +1 -1
  9. package/lib/commonjs/chip/createChipRoot.js +132 -0
  10. package/lib/commonjs/chip/createChipRoot.js.map +1 -0
  11. package/lib/commonjs/chip/index.js +16 -0
  12. package/lib/commonjs/chip/index.js.map +1 -0
  13. package/lib/commonjs/chip/types.js +6 -0
  14. package/lib/commonjs/chip/types.js.map +1 -0
  15. package/lib/commonjs/dialog/createDialogContent.js +7 -127
  16. package/lib/commonjs/dialog/createDialogContent.js.map +1 -1
  17. package/lib/commonjs/dialog/createDialogPopup.js +157 -0
  18. package/lib/commonjs/dialog/createDialogPopup.js.map +1 -0
  19. package/lib/commonjs/dialog/index.js +8 -8
  20. package/lib/commonjs/dialog/index.js.map +1 -1
  21. package/lib/commonjs/field/createFieldLabel.js.map +1 -1
  22. package/lib/commonjs/index.js +45 -1
  23. package/lib/commonjs/index.js.map +1 -1
  24. package/lib/commonjs/input/createInputField.js +5 -0
  25. package/lib/commonjs/input/createInputField.js.map +1 -1
  26. package/lib/commonjs/link/context.js +11 -0
  27. package/lib/commonjs/link/context.js.map +1 -0
  28. package/lib/commonjs/link/createLink.js +28 -14
  29. package/lib/commonjs/link/createLink.js.map +1 -1
  30. package/lib/commonjs/link/index.js +13 -0
  31. package/lib/commonjs/link/index.js.map +1 -1
  32. package/lib/commonjs/list-item/createListItemRoot.js +64 -37
  33. package/lib/commonjs/list-item/createListItemRoot.js.map +1 -1
  34. package/lib/commonjs/list-item/index.js.map +1 -1
  35. package/lib/commonjs/radio/context.js +14 -0
  36. package/lib/commonjs/radio/context.js.map +1 -0
  37. package/lib/commonjs/radio/createRadioGroup.js +66 -0
  38. package/lib/commonjs/radio/createRadioGroup.js.map +1 -0
  39. package/lib/commonjs/radio/createRadioIndicator.js +43 -0
  40. package/lib/commonjs/radio/createRadioIndicator.js.map +1 -0
  41. package/lib/commonjs/radio/createRadioLabel.js +38 -0
  42. package/lib/commonjs/radio/createRadioLabel.js.map +1 -0
  43. package/lib/commonjs/radio/createRadioRoot.js +95 -0
  44. package/lib/commonjs/radio/createRadioRoot.js.map +1 -0
  45. package/lib/commonjs/radio/createRadioRoot.web.js +87 -0
  46. package/lib/commonjs/radio/createRadioRoot.web.js.map +1 -0
  47. package/lib/commonjs/radio/index.js +26 -0
  48. package/lib/commonjs/radio/index.js.map +1 -0
  49. package/lib/commonjs/radio/types.js +6 -0
  50. package/lib/commonjs/radio/types.js.map +1 -0
  51. package/lib/commonjs/radio/useRadioRoot.js +64 -0
  52. package/lib/commonjs/radio/useRadioRoot.js.map +1 -0
  53. package/lib/commonjs/select/createSelectIcon.js +3 -1
  54. package/lib/commonjs/select/createSelectIcon.js.map +1 -1
  55. package/lib/commonjs/select/createSelectTrigger.js +17 -4
  56. package/lib/commonjs/select/createSelectTrigger.js.map +1 -1
  57. package/lib/commonjs/tile/context.js +30 -0
  58. package/lib/commonjs/tile/context.js.map +1 -0
  59. package/lib/commonjs/tile/createTileContent.js +30 -0
  60. package/lib/commonjs/tile/createTileContent.js.map +1 -0
  61. package/lib/commonjs/tile/createTileDescription.js +28 -0
  62. package/lib/commonjs/tile/createTileDescription.js.map +1 -0
  63. package/lib/commonjs/tile/createTileGroup.js +112 -0
  64. package/lib/commonjs/tile/createTileGroup.js.map +1 -0
  65. package/lib/commonjs/tile/createTileIndicator.js +46 -0
  66. package/lib/commonjs/tile/createTileIndicator.js.map +1 -0
  67. package/lib/commonjs/tile/createTileLeadingSlot.js +34 -0
  68. package/lib/commonjs/tile/createTileLeadingSlot.js.map +1 -0
  69. package/lib/commonjs/tile/createTileRoot.js +133 -0
  70. package/lib/commonjs/tile/createTileRoot.js.map +1 -0
  71. package/lib/commonjs/{dialog/createDialogBody.js → tile/createTileTitle.js} +18 -11
  72. package/lib/commonjs/tile/createTileTitle.js.map +1 -0
  73. package/lib/commonjs/tile/createTileTrailingSlot.js +35 -0
  74. package/lib/commonjs/tile/createTileTrailingSlot.js.map +1 -0
  75. package/lib/commonjs/tile/index.js +55 -0
  76. package/lib/commonjs/tile/index.js.map +1 -0
  77. package/lib/commonjs/tile/types.js +6 -0
  78. package/lib/commonjs/tile/types.js.map +1 -0
  79. package/lib/commonjs/utils/dataAttributes.js +6 -25
  80. package/lib/commonjs/utils/dataAttributes.js.map +1 -1
  81. package/lib/commonjs/utils/domDataAttributes.js +34 -0
  82. package/lib/commonjs/utils/domDataAttributes.js.map +1 -0
  83. package/lib/module/CLAUDE.md +32 -0
  84. package/lib/module/avatar/createAvatarText.js +9 -1
  85. package/lib/module/avatar/createAvatarText.js.map +1 -1
  86. package/lib/module/button/createButtonText.js +1 -0
  87. package/lib/module/button/createButtonText.js.map +1 -1
  88. package/lib/module/checkbox/createCheckboxRoot.web.js +8 -2
  89. package/lib/module/checkbox/createCheckboxRoot.web.js.map +1 -1
  90. package/lib/module/chip/createChipRoot.js +126 -0
  91. package/lib/module/chip/createChipRoot.js.map +1 -0
  92. package/lib/module/chip/index.js +12 -0
  93. package/lib/module/chip/index.js.map +1 -0
  94. package/lib/module/chip/types.js +4 -0
  95. package/lib/module/chip/types.js.map +1 -0
  96. package/lib/module/dialog/createDialogContent.js +7 -128
  97. package/lib/module/dialog/createDialogContent.js.map +1 -1
  98. package/lib/module/dialog/createDialogPopup.js +152 -0
  99. package/lib/module/dialog/createDialogPopup.js.map +1 -0
  100. package/lib/module/dialog/index.js +8 -8
  101. package/lib/module/dialog/index.js.map +1 -1
  102. package/lib/module/field/createFieldLabel.js.map +1 -1
  103. package/lib/module/index.js +4 -0
  104. package/lib/module/index.js.map +1 -1
  105. package/lib/module/input/createInputField.js +5 -0
  106. package/lib/module/input/createInputField.js.map +1 -1
  107. package/lib/module/link/context.js +5 -0
  108. package/lib/module/link/context.js.map +1 -0
  109. package/lib/module/link/createLink.js +29 -15
  110. package/lib/module/link/createLink.js.map +1 -1
  111. package/lib/module/link/index.js +1 -0
  112. package/lib/module/link/index.js.map +1 -1
  113. package/lib/module/list-item/createListItemRoot.js +64 -37
  114. package/lib/module/list-item/createListItemRoot.js.map +1 -1
  115. package/lib/module/list-item/index.js.map +1 -1
  116. package/lib/module/radio/context.js +7 -0
  117. package/lib/module/radio/context.js.map +1 -0
  118. package/lib/module/radio/createRadioGroup.js +61 -0
  119. package/lib/module/radio/createRadioGroup.js.map +1 -0
  120. package/lib/module/radio/createRadioIndicator.js +38 -0
  121. package/lib/module/radio/createRadioIndicator.js.map +1 -0
  122. package/lib/module/radio/createRadioLabel.js +33 -0
  123. package/lib/module/radio/createRadioLabel.js.map +1 -0
  124. package/lib/module/radio/createRadioRoot.js +90 -0
  125. package/lib/module/radio/createRadioRoot.js.map +1 -0
  126. package/lib/module/radio/createRadioRoot.web.js +82 -0
  127. package/lib/module/radio/createRadioRoot.web.js.map +1 -0
  128. package/lib/module/radio/index.js +22 -0
  129. package/lib/module/radio/index.js.map +1 -0
  130. package/lib/module/radio/types.js +4 -0
  131. package/lib/module/radio/types.js.map +1 -0
  132. package/lib/module/radio/useRadioRoot.js +60 -0
  133. package/lib/module/radio/useRadioRoot.js.map +1 -0
  134. package/lib/module/select/createSelectIcon.js +3 -1
  135. package/lib/module/select/createSelectIcon.js.map +1 -1
  136. package/lib/module/select/createSelectTrigger.js +19 -6
  137. package/lib/module/select/createSelectTrigger.js.map +1 -1
  138. package/lib/module/tile/context.js +21 -0
  139. package/lib/module/tile/context.js.map +1 -0
  140. package/lib/module/tile/createTileContent.js +24 -0
  141. package/lib/module/tile/createTileContent.js.map +1 -0
  142. package/lib/module/tile/createTileDescription.js +22 -0
  143. package/lib/module/tile/createTileDescription.js.map +1 -0
  144. package/lib/module/tile/createTileGroup.js +106 -0
  145. package/lib/module/tile/createTileGroup.js.map +1 -0
  146. package/lib/module/tile/createTileIndicator.js +40 -0
  147. package/lib/module/tile/createTileIndicator.js.map +1 -0
  148. package/lib/module/tile/createTileLeadingSlot.js +28 -0
  149. package/lib/module/tile/createTileLeadingSlot.js.map +1 -0
  150. package/lib/module/tile/createTileRoot.js +127 -0
  151. package/lib/module/tile/createTileRoot.js.map +1 -0
  152. package/lib/module/tile/createTileTitle.js +22 -0
  153. package/lib/module/tile/createTileTitle.js.map +1 -0
  154. package/lib/module/tile/createTileTrailingSlot.js +29 -0
  155. package/lib/module/tile/createTileTrailingSlot.js.map +1 -0
  156. package/lib/module/tile/index.js +39 -0
  157. package/lib/module/tile/index.js.map +1 -0
  158. package/lib/module/tile/types.js +4 -0
  159. package/lib/module/tile/types.js.map +1 -0
  160. package/lib/module/utils/dataAttributes.js +4 -22
  161. package/lib/module/utils/dataAttributes.js.map +1 -1
  162. package/lib/module/utils/domDataAttributes.js +30 -0
  163. package/lib/module/utils/domDataAttributes.js.map +1 -0
  164. package/lib/typescript/avatar/createAvatarText.d.ts.map +1 -1
  165. package/lib/typescript/button/createButtonText.d.ts.map +1 -1
  166. package/lib/typescript/checkbox/createCheckboxRoot.web.d.ts +4 -0
  167. package/lib/typescript/checkbox/createCheckboxRoot.web.d.ts.map +1 -1
  168. package/lib/typescript/checkbox/useCheckboxRoot.d.ts +2 -0
  169. package/lib/typescript/checkbox/useCheckboxRoot.d.ts.map +1 -1
  170. package/lib/typescript/chip/createChipRoot.d.ts +4 -0
  171. package/lib/typescript/chip/createChipRoot.d.ts.map +1 -0
  172. package/lib/typescript/chip/index.d.ts +9 -0
  173. package/lib/typescript/chip/index.d.ts.map +1 -0
  174. package/lib/typescript/chip/types.d.ts +17 -0
  175. package/lib/typescript/chip/types.d.ts.map +1 -0
  176. package/lib/typescript/dialog/createDialogContent.d.ts +2 -2
  177. package/lib/typescript/dialog/createDialogContent.d.ts.map +1 -1
  178. package/lib/typescript/dialog/createDialogPopup.d.ts +4 -0
  179. package/lib/typescript/dialog/createDialogPopup.d.ts.map +1 -0
  180. package/lib/typescript/dialog/index.d.ts +5 -5
  181. package/lib/typescript/dialog/index.d.ts.map +1 -1
  182. package/lib/typescript/dialog/types.d.ts +16 -5
  183. package/lib/typescript/dialog/types.d.ts.map +1 -1
  184. package/lib/typescript/field/createFieldLabel.d.ts.map +1 -1
  185. package/lib/typescript/index.d.ts +4 -0
  186. package/lib/typescript/index.d.ts.map +1 -1
  187. package/lib/typescript/input/createInputField.d.ts.map +1 -1
  188. package/lib/typescript/link/context.d.ts +10 -0
  189. package/lib/typescript/link/context.d.ts.map +1 -0
  190. package/lib/typescript/link/createLink.d.ts.map +1 -1
  191. package/lib/typescript/link/index.d.ts +2 -0
  192. package/lib/typescript/link/index.d.ts.map +1 -1
  193. package/lib/typescript/link/types.d.ts +1 -0
  194. package/lib/typescript/link/types.d.ts.map +1 -1
  195. package/lib/typescript/list-item/createListItemRoot.d.ts.map +1 -1
  196. package/lib/typescript/list-item/index.d.ts +1 -1
  197. package/lib/typescript/list-item/index.d.ts.map +1 -1
  198. package/lib/typescript/list-item/types.d.ts +1 -7
  199. package/lib/typescript/list-item/types.d.ts.map +1 -1
  200. package/lib/typescript/radio/context.d.ts +21 -0
  201. package/lib/typescript/radio/context.d.ts.map +1 -0
  202. package/lib/typescript/radio/createRadioGroup.d.ts +3 -0
  203. package/lib/typescript/radio/createRadioGroup.d.ts.map +1 -0
  204. package/lib/typescript/radio/createRadioIndicator.d.ts +5 -0
  205. package/lib/typescript/radio/createRadioIndicator.d.ts.map +1 -0
  206. package/lib/typescript/radio/createRadioLabel.d.ts +5 -0
  207. package/lib/typescript/radio/createRadioLabel.d.ts.map +1 -0
  208. package/lib/typescript/radio/createRadioRoot.d.ts +3 -0
  209. package/lib/typescript/radio/createRadioRoot.d.ts.map +1 -0
  210. package/lib/typescript/radio/createRadioRoot.web.d.ts +3 -0
  211. package/lib/typescript/radio/createRadioRoot.web.d.ts.map +1 -0
  212. package/lib/typescript/radio/index.d.ts +10 -0
  213. package/lib/typescript/radio/index.d.ts.map +1 -0
  214. package/lib/typescript/radio/types.d.ts +54 -0
  215. package/lib/typescript/radio/types.d.ts.map +1 -0
  216. package/lib/typescript/radio/useRadioRoot.d.ts +151 -0
  217. package/lib/typescript/radio/useRadioRoot.d.ts.map +1 -0
  218. package/lib/typescript/select/createSelectIcon.d.ts.map +1 -1
  219. package/lib/typescript/select/createSelectTrigger.d.ts.map +1 -1
  220. package/lib/typescript/tile/context.d.ts +9 -0
  221. package/lib/typescript/tile/context.d.ts.map +1 -0
  222. package/lib/typescript/tile/createTileContent.d.ts +3 -0
  223. package/lib/typescript/tile/createTileContent.d.ts.map +1 -0
  224. package/lib/typescript/tile/createTileDescription.d.ts +3 -0
  225. package/lib/typescript/tile/createTileDescription.d.ts.map +1 -0
  226. package/lib/typescript/tile/createTileGroup.d.ts +4 -0
  227. package/lib/typescript/tile/createTileGroup.d.ts.map +1 -0
  228. package/lib/typescript/tile/createTileIndicator.d.ts +4 -0
  229. package/lib/typescript/tile/createTileIndicator.d.ts.map +1 -0
  230. package/lib/typescript/tile/createTileLeadingSlot.d.ts +4 -0
  231. package/lib/typescript/tile/createTileLeadingSlot.d.ts.map +1 -0
  232. package/lib/typescript/tile/createTileRoot.d.ts +4 -0
  233. package/lib/typescript/tile/createTileRoot.d.ts.map +1 -0
  234. package/lib/typescript/tile/createTileTitle.d.ts +3 -0
  235. package/lib/typescript/tile/createTileTitle.d.ts.map +1 -0
  236. package/lib/typescript/tile/createTileTrailingSlot.d.ts +9 -0
  237. package/lib/typescript/tile/createTileTrailingSlot.d.ts.map +1 -0
  238. package/lib/typescript/tile/index.d.ts +15 -0
  239. package/lib/typescript/tile/index.d.ts.map +1 -0
  240. package/lib/typescript/tile/types.d.ts +119 -0
  241. package/lib/typescript/tile/types.d.ts.map +1 -0
  242. package/lib/typescript/utils/dataAttributes.d.ts +4 -10
  243. package/lib/typescript/utils/dataAttributes.d.ts.map +1 -1
  244. package/lib/typescript/utils/domDataAttributes.d.ts +15 -0
  245. package/lib/typescript/utils/domDataAttributes.d.ts.map +1 -0
  246. package/package.json +5 -2
  247. package/src/CLAUDE.md +32 -0
  248. package/src/avatar/createAvatarText.tsx +10 -1
  249. package/src/button/createButtonText.tsx +1 -0
  250. package/src/checkbox/createCheckboxRoot.web.tsx +6 -2
  251. package/src/chip/createChipRoot.tsx +144 -0
  252. package/src/chip/index.ts +18 -0
  253. package/src/chip/types.ts +23 -0
  254. package/src/dialog/createDialogContent.tsx +6 -117
  255. package/src/dialog/createDialogPopup.tsx +146 -0
  256. package/src/dialog/index.tsx +16 -16
  257. package/src/dialog/types.ts +20 -9
  258. package/src/field/createFieldLabel.tsx +4 -1
  259. package/src/index.ts +4 -0
  260. package/src/input/createInputField.tsx +6 -0
  261. package/src/link/context.tsx +10 -0
  262. package/src/link/createLink.tsx +41 -23
  263. package/src/link/index.tsx +2 -0
  264. package/src/link/types.ts +1 -0
  265. package/src/list-item/createListItemRoot.tsx +68 -36
  266. package/src/list-item/index.ts +0 -1
  267. package/src/list-item/types.ts +1 -8
  268. package/src/radio/context.tsx +21 -0
  269. package/src/radio/createRadioGroup.tsx +67 -0
  270. package/src/radio/createRadioIndicator.tsx +32 -0
  271. package/src/radio/createRadioLabel.tsx +28 -0
  272. package/src/radio/createRadioRoot.tsx +100 -0
  273. package/src/radio/createRadioRoot.web.tsx +81 -0
  274. package/src/radio/index.ts +37 -0
  275. package/src/radio/types.ts +67 -0
  276. package/src/radio/useRadioRoot.ts +69 -0
  277. package/src/select/createSelectIcon.tsx +2 -1
  278. package/src/select/createSelectTrigger.tsx +26 -3
  279. package/src/tile/context.tsx +23 -0
  280. package/src/tile/createTileContent.tsx +23 -0
  281. package/src/tile/createTileDescription.tsx +19 -0
  282. package/src/tile/createTileGroup.tsx +134 -0
  283. package/src/tile/createTileIndicator.tsx +38 -0
  284. package/src/tile/createTileLeadingSlot.tsx +30 -0
  285. package/src/tile/createTileRoot.tsx +124 -0
  286. package/src/tile/createTileTitle.tsx +19 -0
  287. package/src/tile/createTileTrailingSlot.tsx +25 -0
  288. package/src/tile/index.ts +88 -0
  289. package/src/tile/types.ts +153 -0
  290. package/src/utils/dataAttributes.ts +4 -25
  291. package/src/utils/domDataAttributes.ts +32 -0
  292. package/lib/commonjs/dialog/createDialogBody.js.map +0 -1
  293. package/lib/module/dialog/createDialogBody.js +0 -15
  294. package/lib/module/dialog/createDialogBody.js.map +0 -1
  295. package/lib/typescript/dialog/createDialogBody.d.ts +0 -4
  296. package/lib/typescript/dialog/createDialogBody.d.ts.map +0 -1
  297. package/src/dialog/createDialogBody.tsx +0 -11
@@ -24,8 +24,19 @@ export interface IDialogTriggerProps extends PressableProps {
24
24
  readonly asChild?: boolean;
25
25
  }
26
26
 
27
- export interface IDialogContentProps extends ViewProps {
27
+ export interface IDialogPopupProps extends ViewProps {
28
28
  readonly forceMount?: boolean;
29
+ /**
30
+ * Whether the popup shifts up to clear the on-screen keyboard (native only).
31
+ * No-op on web. Defaults to `true`.
32
+ */
33
+ readonly avoidKeyboard?: boolean;
34
+ /**
35
+ * Distance (in px) between the keyboard and the popup when keyboard avoidance
36
+ * is active. Forwarded to the underlying keyboard-avoiding layer on native.
37
+ * Defaults to `0`.
38
+ */
39
+ readonly keyboardVerticalOffset?: number;
29
40
  }
30
41
 
31
42
  export interface IDialogOverlayProps extends PressableProps {}
@@ -36,7 +47,7 @@ export interface IDialogTitleProps extends TextProps {}
36
47
 
37
48
  export interface IDialogDescriptionProps extends TextProps {}
38
49
 
39
- export interface IDialogBodyProps extends ViewProps {}
50
+ export interface IDialogContentProps extends ViewProps {}
40
51
 
41
52
  export interface IDialogFooterProps extends ViewProps {}
42
53
 
@@ -48,14 +59,14 @@ export interface IDialogCloseProps extends PressableProps {
48
59
  export type IDialogComponentType<
49
60
  RootProps,
50
61
  TriggerProps,
51
- ContentProps,
62
+ PopupProps,
52
63
  HeaderProps,
53
64
  TitleProps,
54
65
  DescriptionProps,
55
- BodyProps,
66
+ ContentProps,
56
67
  FooterProps,
57
68
  CloseProps,
58
- ContentRef = unknown,
69
+ PopupRef = unknown,
59
70
  TriggerRef = unknown,
60
71
  CloseRef = unknown,
61
72
  > = React.ForwardRefExoticComponent<
@@ -64,8 +75,8 @@ export type IDialogComponentType<
64
75
  Trigger: React.ForwardRefExoticComponent<
65
76
  PropsWithoutRef<TriggerProps & IDialogTriggerProps> & RefAttributes<TriggerRef>
66
77
  >;
67
- Content: React.ForwardRefExoticComponent<
68
- PropsWithoutRef<ContentProps & IDialogContentProps> & RefAttributes<ContentRef>
78
+ Popup: React.ForwardRefExoticComponent<
79
+ PropsWithoutRef<PopupProps & IDialogPopupProps> & RefAttributes<PopupRef>
69
80
  >;
70
81
  Header: React.ForwardRefExoticComponent<
71
82
  PropsWithoutRef<HeaderProps & IDialogHeaderProps> & RefAttributes<unknown>
@@ -76,8 +87,8 @@ export type IDialogComponentType<
76
87
  Description: React.ForwardRefExoticComponent<
77
88
  PropsWithoutRef<DescriptionProps & IDialogDescriptionProps> & RefAttributes<unknown>
78
89
  >;
79
- Body: React.ForwardRefExoticComponent<
80
- PropsWithoutRef<BodyProps & IDialogBodyProps> & RefAttributes<unknown>
90
+ Content: React.ForwardRefExoticComponent<
91
+ PropsWithoutRef<ContentProps & IDialogContentProps> & RefAttributes<unknown>
81
92
  >;
82
93
  Footer: React.ForwardRefExoticComponent<
83
94
  PropsWithoutRef<FooterProps & IDialogFooterProps> & RefAttributes<unknown>
@@ -20,7 +20,10 @@ export const createFieldLabel = <T,>(BaseFormLabel: React.ComponentType<T>) =>
20
20
  {...(props as T)}
21
21
  id={labelId}
22
22
  htmlFor={htmlFor}
23
- {...dataAttributes({ invalid: field.isInvalid, required: field.isRequired })}
23
+ {...dataAttributes({
24
+ invalid: field.isInvalid,
25
+ required: field.isRequired,
26
+ })}
24
27
  >
25
28
  {children}
26
29
  {field.isRequired ? requiredIndicator : null}
package/src/index.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  export * from './avatar';
2
2
  export * from './button';
3
+ export * from './chip';
3
4
  export * from './checkbox';
4
5
  export * from './dialog';
5
6
  export * from './field';
@@ -11,6 +12,9 @@ export * from './list-item';
11
12
  export { type EdgeInsets, OverlayInsetsProvider } from './overlay';
12
13
  export * from './select';
13
14
  export * from './switch';
15
+ export * from './tile';
14
16
  export * from './progress';
17
+ export * from './radio';
15
18
  export type { InteractionState } from './types';
16
19
  export { dataAttributes } from './utils/dataAttributes';
20
+ export { domDataAttributes, type DomDataAttributeValue } from './utils/domDataAttributes';
@@ -49,8 +49,14 @@ export const createInputField = <T,>(BaseInputField: React.ComponentType<T>) =>
49
49
 
50
50
  const field = useFormControlContext();
51
51
 
52
+ const reportLabelFocus = (focused: boolean) => {
53
+ const active = focused && !(isDisabled || inputProps.disabled);
54
+ field.setIsLabelFocused?.(active);
55
+ };
56
+
52
57
  const handleFocus = (focusState: boolean, callback: any) => {
53
58
  setIsFocused(focusState);
59
+ reportLabelFocus(focusState);
54
60
  callback();
55
61
  };
56
62
 
@@ -0,0 +1,10 @@
1
+ import { createContext } from '@cdx-ui/utils';
2
+
3
+ export interface LinkInteractionState {
4
+ hover: boolean;
5
+ visited: boolean;
6
+ focusVisible: boolean;
7
+ }
8
+
9
+ export const [LinkInteractionProvider, useLinkInteractionContext] =
10
+ createContext<LinkInteractionState>('LinkInteractionContext');
@@ -1,8 +1,9 @@
1
- import React, { forwardRef } from 'react';
1
+ import React, { forwardRef, useMemo } from 'react';
2
2
  import { composeEventHandlers } from '@cdx-ui/utils';
3
3
  import { useFocusRing, useFocus } from '@react-native-aria/focus';
4
4
  import { useHover, usePress } from '@react-native-aria/interactions';
5
5
  import { dataAttributes } from '../utils/dataAttributes';
6
+ import { LinkInteractionProvider } from './context';
6
7
  import { useLink } from './useLink';
7
8
  import type { ILinkProps } from './types';
8
9
 
@@ -15,6 +16,7 @@ export const createLink = <RootT, R = unknown>({ Root }: { Root: React.Component
15
16
  isPressed: isPressedProp,
16
17
  isFocused: isFocusedProp,
17
18
  isFocusVisible: isFocusVisibleProp,
19
+ isVisited: isVisitedProp,
18
20
  href,
19
21
  onPress,
20
22
  action,
@@ -38,34 +40,50 @@ export const createLink = <RootT, R = unknown>({ Root }: { Root: React.Component
38
40
  webProps,
39
41
  });
40
42
 
43
+ const hover = isHoveredProp || isHovered;
44
+ const visited = isVisitedProp ?? false;
45
+ const focusVisible = isFocusVisibleProp || isFocusVisible;
46
+
47
+ const interactionState = useMemo(
48
+ () => ({
49
+ hover,
50
+ visited,
51
+ focusVisible,
52
+ }),
53
+ [hover, visited, focusVisible],
54
+ );
55
+
41
56
  const interactionAttrs = dataAttributes({
42
- hover: isHoveredProp || isHovered,
57
+ hover,
43
58
  focus: isFocusedProp || isFocused,
44
59
  active: isPressedProp || isPressed,
45
- focusVisible: isFocusVisibleProp || isFocusVisible,
60
+ focusVisible,
61
+ visited,
46
62
  });
47
63
 
48
64
  return (
49
- <Root
50
- ref={ref}
51
- {...interactionAttrs}
52
- {...linkProps}
53
- {...(props as RootT)}
54
- onPressIn={composeEventHandlers(props?.onPressIn, pressProps.onPressIn)}
55
- onPressOut={composeEventHandlers(props?.onPressOut, pressProps.onPressOut)}
56
- onHoverIn={composeEventHandlers(props?.onHoverIn, hoverProps.onHoverIn)}
57
- onHoverOut={composeEventHandlers(props?.onHoverOut, hoverProps.onHoverOut)}
58
- onFocus={composeEventHandlers(
59
- composeEventHandlers(props?.onFocus, focusProps.onFocus),
60
- focusRingProps.onFocus,
61
- )}
62
- onBlur={composeEventHandlers(
63
- composeEventHandlers(props?.onBlur, focusProps.onBlur),
64
- focusRingProps.onBlur,
65
- )}
66
- >
67
- {children}
68
- </Root>
65
+ <LinkInteractionProvider value={interactionState}>
66
+ <Root
67
+ ref={ref}
68
+ {...interactionAttrs}
69
+ {...linkProps}
70
+ {...(props as RootT)}
71
+ onPressIn={composeEventHandlers(props?.onPressIn, pressProps.onPressIn)}
72
+ onPressOut={composeEventHandlers(props?.onPressOut, pressProps.onPressOut)}
73
+ onHoverIn={composeEventHandlers(props?.onHoverIn, hoverProps.onHoverIn)}
74
+ onHoverOut={composeEventHandlers(props?.onHoverOut, hoverProps.onHoverOut)}
75
+ onFocus={composeEventHandlers(
76
+ composeEventHandlers(props?.onFocus, focusProps.onFocus),
77
+ focusRingProps.onFocus,
78
+ )}
79
+ onBlur={composeEventHandlers(
80
+ composeEventHandlers(props?.onBlur, focusProps.onBlur),
81
+ focusRingProps.onBlur,
82
+ )}
83
+ >
84
+ {children}
85
+ </Root>
86
+ </LinkInteractionProvider>
69
87
  );
70
88
  },
71
89
  );
@@ -1,4 +1,6 @@
1
1
  export { createLink } from './createLink';
2
+ export { LinkInteractionProvider, useLinkInteractionContext } from './context';
3
+ export type { LinkInteractionState } from './context';
2
4
  export { LinkProvider } from './LinkProvider';
3
5
  export type { LinkConfig } from './LinkProvider';
4
6
  export { useLink } from './useLink';
package/src/link/types.ts CHANGED
@@ -32,6 +32,7 @@ export interface ILinkProps extends PressableProps {
32
32
  isHovered?: boolean;
33
33
  isFocused?: boolean;
34
34
  isFocusVisible?: boolean;
35
+ isVisited?: boolean;
35
36
  /**
36
37
  * HTML anchor attributes applied only on web. Ignored on native platforms.
37
38
  * `target`, `rel`, and `download` are forwarded via react-native-web's `hrefAttrs`.
@@ -1,6 +1,7 @@
1
1
  import React, { forwardRef, useMemo } from 'react';
2
2
  import type { PressableProps } from 'react-native';
3
3
  import { composeEventHandlers, mergeRefs } from '@cdx-ui/utils';
4
+ import { useFocus, useFocusRing } from '@react-native-aria/focus';
4
5
  import { useHover, usePress } from '@react-native-aria/interactions';
5
6
  import { dataAttributes } from '../utils/dataAttributes';
6
7
  import { ListItemProvider } from './context';
@@ -8,14 +9,12 @@ import type { IListItemProps, IListItemPressablePassthrough } from './types';
8
9
 
9
10
  function listItemRootDataAttrs(
10
11
  size: IListItemProps['size'],
11
- surface: IListItemProps['surface'],
12
12
  showSeparator: boolean | undefined,
13
13
  crossAlign: IListItemProps['crossAlign'],
14
14
  ) {
15
15
  return dataAttributes({
16
16
  slot: 'list-item',
17
17
  size: size ?? 'default',
18
- surface: surface ?? 'default',
19
18
  separator: showSeparator ?? true,
20
19
  crossAlign: crossAlign ?? 'center',
21
20
  });
@@ -40,48 +39,79 @@ export const createListItemRoot = <V, P>(
40
39
  children,
41
40
  onPress,
42
41
  size = 'default',
43
- surface = 'default',
44
42
  showSeparator = true,
45
43
  crossAlign = 'center',
46
- disabled = false,
44
+ isDisabled = false,
47
45
  style,
48
46
  ...restProps
49
47
  }: IListItemProps,
50
48
  ref: React.Ref<unknown>,
51
49
  ) => {
52
- const asChildInteractive = asChild && !!onPress && React.isValidElement(children);
50
+ const childOnPress = React.isValidElement(children)
51
+ ? ((children.props as { onPress?: unknown }).onPress as
52
+ | IListItemProps['onPress']
53
+ | undefined)
54
+ : undefined;
55
+
56
+ // asChild always wins when explicitly set with a valid element — even when the press
57
+ // surface is built internally by the child (e.g. `Link` adds its onPress via `useLink`,
58
+ // not as a JSX-level prop). The clone path below preserves the child's own press by
59
+ // *omitting* `onPress` when there is nothing to compose.
60
+ const asChildInteractive = asChild && React.isValidElement(children);
53
61
  const isPressableRoot = !!onPress && !asChildInteractive;
54
62
 
55
63
  const pressState = usePress({
56
- isDisabled: !isPressableRoot || disabled,
64
+ isDisabled: !isPressableRoot || isDisabled,
57
65
  });
58
66
  const isPressed = pressState.isPressed;
59
67
  const pressProps = pressState.pressProps as Pick<PressableProps, 'onPressIn' | 'onPressOut'>;
60
68
  const { hoverProps, isHovered } = useHover();
69
+ const { isFocused, focusProps } = useFocus();
70
+ const { isFocusVisible, focusProps: focusRingProps } = useFocusRing() as {
71
+ isFocusVisible: boolean;
72
+ focusProps: typeof focusProps;
73
+ };
61
74
 
62
- const slotAttrs = listItemRootDataAttrs(size, surface, showSeparator, crossAlign);
75
+ const slotAttrs = listItemRootDataAttrs(size, showSeparator, crossAlign);
63
76
 
64
77
  const contextValue = useMemo(
65
78
  () => ({
66
79
  isPressed: isPressableRoot ? isPressed : false,
67
80
  isHovered,
68
- isDisabled: disabled,
81
+ isDisabled,
69
82
  crossAlign: crossAlign ?? 'center',
70
83
  }),
71
- [isPressableRoot, isPressed, isHovered, disabled, crossAlign],
84
+ [isPressableRoot, isPressed, isHovered, isDisabled, crossAlign],
72
85
  );
73
86
 
74
87
  if (asChildInteractive) {
75
88
  const child = children as React.ReactElement<Record<string, unknown>>;
76
89
 
77
- const mergedOnPress = composeEventHandlers(
78
- child.props.onPress as IListItemProps['onPress'],
79
- onPress,
80
- );
90
+ const childProps = child.props as { disabled?: boolean; isDisabled?: boolean };
91
+ const childDisabled = !!(childProps.isDisabled ?? childProps.disabled);
92
+ const resolvedDisabled = isDisabled || childDisabled;
81
93
 
82
- const childDisabled = !!(child.props as { disabled?: boolean }).disabled;
94
+ const cloneProps: Record<string, unknown> = {
95
+ ...restProps,
96
+ ...slotAttrs,
97
+ ...dataAttributes({
98
+ disabled: resolvedDisabled,
99
+ }),
100
+ ...(resolvedDisabled && { accessibilityState: { disabled: true } }),
101
+ disabled: resolvedDisabled,
102
+ ref: mergeRefs(ref, child.props.ref as React.Ref<unknown>),
103
+ style: [rowStyleForCrossAlign(crossAlign), style, child.props.style],
104
+ };
83
105
 
84
- const resolvedDisabled = disabled || childDisabled;
106
+ // Only override the child's `onPress` when we have something to add (a parent handler)
107
+ // or need to suppress (disabled). Otherwise leave the child's own onPress alone — e.g.
108
+ // `Link` builds its navigation handler inside `useLink`, not as a JSX-level prop, and
109
+ // overriding here would shadow it.
110
+ if (resolvedDisabled) {
111
+ cloneProps.onPress = undefined;
112
+ } else if (onPress) {
113
+ cloneProps.onPress = composeEventHandlers(childOnPress, onPress);
114
+ }
85
115
 
86
116
  return (
87
117
  <ListItemProvider
@@ -92,20 +122,7 @@ export const createListItemRoot = <V, P>(
92
122
  crossAlign: crossAlign ?? 'center',
93
123
  }}
94
124
  >
95
- {React.cloneElement(child, {
96
- ...restProps,
97
- ...slotAttrs,
98
- ...dataAttributes({
99
- active: false,
100
- hovered: false,
101
- disabled: resolvedDisabled,
102
- }),
103
- ...(resolvedDisabled && { accessibilityState: { disabled: true } }),
104
- disabled: resolvedDisabled,
105
- onPress: resolvedDisabled ? undefined : mergedOnPress,
106
- ref: mergeRefs(ref, child.props.ref as React.Ref<unknown>),
107
- style: [rowStyleForCrossAlign(crossAlign), style, child.props.style],
108
- })}
125
+ {React.cloneElement(child, cloneProps)}
109
126
  </ListItemProvider>
110
127
  );
111
128
  }
@@ -113,8 +130,10 @@ export const createListItemRoot = <V, P>(
113
130
  if (isPressableRoot) {
114
131
  const interactionAttrs = dataAttributes({
115
132
  active: isPressed,
116
- hovered: isHovered,
117
- disabled,
133
+ hover: isHovered,
134
+ focus: isFocused,
135
+ focusVisible: isFocusVisible,
136
+ disabled: isDisabled,
118
137
  });
119
138
 
120
139
  const {
@@ -122,7 +141,12 @@ export const createListItemRoot = <V, P>(
122
141
  onPressOut: onPressOutProp,
123
142
  onHoverIn: onHoverInProp,
124
143
  onHoverOut: onHoverOutProp,
125
- } = restProps as IListItemPressablePassthrough;
144
+ onFocus: onFocusProp,
145
+ onBlur: onBlurProp,
146
+ } = restProps as IListItemPressablePassthrough & {
147
+ onFocus?: (...args: unknown[]) => unknown;
148
+ onBlur?: (...args: unknown[]) => unknown;
149
+ };
126
150
 
127
151
  return (
128
152
  <ListItemProvider value={contextValue}>
@@ -130,15 +154,23 @@ export const createListItemRoot = <V, P>(
130
154
  {...(restProps as P)}
131
155
  {...slotAttrs}
132
156
  {...interactionAttrs}
133
- {...(disabled && { accessibilityState: { disabled: true } })}
134
- disabled={disabled}
157
+ {...(isDisabled && { accessibilityState: { disabled: true } })}
158
+ disabled={isDisabled}
135
159
  ref={ref as React.Ref<P>}
136
160
  style={[rowStyleForCrossAlign(crossAlign), style]}
137
- onPress={disabled ? undefined : onPress}
161
+ onPress={isDisabled ? undefined : onPress}
138
162
  onPressIn={composeEventHandlers(onPressInProp, pressProps.onPressIn)}
139
163
  onPressOut={composeEventHandlers(onPressOutProp, pressProps.onPressOut)}
140
164
  onHoverIn={composeEventHandlers(onHoverInProp, hoverProps.onHoverIn)}
141
165
  onHoverOut={composeEventHandlers(onHoverOutProp, hoverProps.onHoverOut)}
166
+ onFocus={composeEventHandlers(
167
+ composeEventHandlers(onFocusProp, focusProps.onFocus),
168
+ focusRingProps.onFocus,
169
+ )}
170
+ onBlur={composeEventHandlers(
171
+ composeEventHandlers(onBlurProp, focusProps.onBlur),
172
+ focusRingProps.onBlur,
173
+ )}
142
174
  >
143
175
  {children}
144
176
  </BasePressable>
@@ -151,7 +183,7 @@ export const createListItemRoot = <V, P>(
151
183
  <BaseView
152
184
  {...(restProps as V)}
153
185
  {...slotAttrs}
154
- {...(disabled ? dataAttributes({ disabled: true }) : undefined)}
186
+ {...(isDisabled ? dataAttributes({ disabled: true }) : undefined)}
155
187
  ref={ref as React.Ref<V>}
156
188
  style={[rowStyleForCrossAlign(crossAlign), style]}
157
189
  >
@@ -23,7 +23,6 @@ export type {
23
23
  IListItemTrailingSlotProps,
24
24
  ListItemCrossAlign,
25
25
  ListItemSize,
26
- ListItemSurface,
27
26
  } from './types';
28
27
 
29
28
  export { ListItemProvider, useListItemContext } from './context';
@@ -3,8 +3,6 @@ import type { PressableProps, TextProps, ViewProps } from 'react-native';
3
3
 
4
4
  export type ListItemSize = 'default' | 'compact';
5
5
 
6
- export type ListItemSurface = 'default' | 'negative';
7
-
8
6
  /**
9
7
  * Cross-axis alignment for the row (`flex-direction: row`).
10
8
  * - **center**: Leading, content, and trailing are vertically centered (typical transactions).
@@ -20,7 +18,7 @@ export interface IListItemProps extends ViewProps, IListItemPressablePassthrough
20
18
  /**
21
19
  * Disables press handling when the root is pressable (maps to Pressable `disabled`).
22
20
  */
23
- disabled?: boolean;
21
+ isDisabled?: boolean;
24
22
  /**
25
23
  * When set (and `asChild` is not used), root renders as pressable with interaction props.
26
24
  */
@@ -30,11 +28,6 @@ export interface IListItemProps extends ViewProps, IListItemPressablePassthrough
30
28
  * @default 'default'
31
29
  */
32
30
  size?: ListItemSize;
33
- /**
34
- * Semantic row surface (e.g. canceled transaction); mapped via `data-surface`.
35
- * @default 'default'
36
- */
37
- surface?: ListItemSurface;
38
31
  /**
39
32
  * Whether the row shows a bottom separator; mapped via `data-separator`.
40
33
  * @default true
@@ -0,0 +1,21 @@
1
+ import React from 'react';
2
+ import { createContext } from '@cdx-ui/utils';
3
+ import type { RadioGroupState } from '@react-stately/radio';
4
+ import type { IRadioContextValue } from './types';
5
+
6
+ export const [RadioProvider, useRadioContext] = createContext<IRadioContextValue>('RadioContext');
7
+
8
+ export interface IRadioGroupState {
9
+ isReadOnly: boolean;
10
+ isDisabled: boolean;
11
+ isInvalid: boolean;
12
+ isRequired: boolean;
13
+ isSelected: (value: string) => boolean;
14
+ selectValue: (value: string) => void;
15
+ }
16
+
17
+ export const RadioGroupContext = React.createContext<{
18
+ state: IRadioGroupState;
19
+ radioGroupState: RadioGroupState;
20
+ name?: string;
21
+ } | null>(null);
@@ -0,0 +1,67 @@
1
+ import { forwardRef } from 'react';
2
+ import { useFormControlContext } from '@cdx-ui/utils';
3
+ import { useRadioGroup } from '@react-native-aria/radio';
4
+ import { useRadioGroupState } from '@react-stately/radio';
5
+ import { dataAttributes } from '../utils/dataAttributes';
6
+ import { RadioGroupContext } from './context';
7
+ import type { IRadioGroupProps } from './types';
8
+
9
+ export const createRadioGroup = <T,>(BaseRadioGroup: React.ComponentType<T>) =>
10
+ forwardRef(({ children, ...props }: IRadioGroupProps, ref?: React.Ref<T>) => {
11
+ const formControlContext = useFormControlContext();
12
+
13
+ const combinedProps = {
14
+ ...formControlContext,
15
+ ...props,
16
+ };
17
+
18
+ const radioGroupState = useRadioGroupState({
19
+ ...combinedProps,
20
+ validationState: combinedProps.isInvalid ? 'invalid' : 'valid',
21
+ });
22
+
23
+ const { radioGroupProps } = useRadioGroup(
24
+ {
25
+ ...combinedProps,
26
+ 'aria-label': combinedProps['aria-label'],
27
+ },
28
+ radioGroupState,
29
+ );
30
+
31
+ const isDisabled = combinedProps.isDisabled ?? false;
32
+ const isInvalid = combinedProps.isInvalid ?? false;
33
+ const isRequired = combinedProps.isRequired ?? false;
34
+ const isReadOnly = combinedProps.isReadOnly ?? false;
35
+
36
+ return (
37
+ <RadioGroupContext.Provider
38
+ value={{
39
+ state: {
40
+ isDisabled,
41
+ isInvalid,
42
+ isRequired,
43
+ isReadOnly,
44
+ isSelected: (value: string) => radioGroupState.selectedValue === value,
45
+ selectValue: (value: string) => radioGroupState.setSelectedValue(value),
46
+ },
47
+ radioGroupState,
48
+ name: combinedProps.name,
49
+ }}
50
+ >
51
+ <BaseRadioGroup
52
+ {...radioGroupProps}
53
+ {...(combinedProps as unknown as T)}
54
+ ref={ref}
55
+ aria-required={isRequired || undefined}
56
+ aria-readonly={isReadOnly || undefined}
57
+ {...dataAttributes({
58
+ slot: 'radio-group',
59
+ disabled: isDisabled,
60
+ invalid: isInvalid,
61
+ })}
62
+ >
63
+ {children}
64
+ </BaseRadioGroup>
65
+ </RadioGroupContext.Provider>
66
+ );
67
+ });
@@ -0,0 +1,32 @@
1
+ import { forwardRef } from 'react';
2
+ import { dataAttributes } from '../utils/dataAttributes';
3
+ import { useRadioContext } from './context';
4
+ import type { IRadioIndicatorProps } from './types';
5
+
6
+ export const createRadioIndicator = <T,>(BaseRadioIndicator: React.ComponentType<T>) =>
7
+ forwardRef<unknown, IRadioIndicatorProps & { className?: string }>(
8
+ ({ children, className, ...props }, ref) => {
9
+ const { isChecked, isDisabled, isHovered, isInvalid, isReadOnly, isPressed, isFocusVisible } =
10
+ useRadioContext();
11
+
12
+ return (
13
+ <BaseRadioIndicator
14
+ className={className}
15
+ {...dataAttributes({
16
+ slot: 'radio-indicator',
17
+ hover: isHovered,
18
+ checked: isChecked,
19
+ disabled: isDisabled,
20
+ focusVisible: isFocusVisible,
21
+ invalid: isInvalid,
22
+ readonly: isReadOnly,
23
+ active: isPressed,
24
+ })}
25
+ {...(props as T)}
26
+ ref={ref}
27
+ >
28
+ {children}
29
+ </BaseRadioIndicator>
30
+ );
31
+ },
32
+ );
@@ -0,0 +1,28 @@
1
+ import { forwardRef } from 'react';
2
+ import { dataAttributes } from '../utils/dataAttributes';
3
+ import { useRadioContext } from './context';
4
+ import type { IRadioLabelProps } from './types';
5
+
6
+ export const createRadioLabel = <T,>(BaseRadioLabel: React.ComponentType<T>) =>
7
+ forwardRef<unknown, IRadioLabelProps & { className?: string }>(
8
+ ({ children, className, ...props }, ref) => {
9
+ const { isChecked, isDisabled, isHovered, isInvalid, isReadOnly } = useRadioContext();
10
+
11
+ return (
12
+ <BaseRadioLabel
13
+ className={className}
14
+ {...dataAttributes({
15
+ hover: isHovered,
16
+ checked: isChecked,
17
+ disabled: isDisabled,
18
+ invalid: isInvalid,
19
+ readonly: isReadOnly,
20
+ })}
21
+ {...(props as T)}
22
+ ref={ref}
23
+ >
24
+ {children}
25
+ </BaseRadioLabel>
26
+ );
27
+ },
28
+ );