@cdx-ui/components 0.0.1-beta.65 → 0.0.1-beta.67

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 (242) hide show
  1. package/lib/commonjs/components/AlertDialog/index.js +12 -10
  2. package/lib/commonjs/components/AlertDialog/index.js.map +1 -1
  3. package/lib/commonjs/components/Avatar/index.js +125 -25
  4. package/lib/commonjs/components/Avatar/index.js.map +1 -1
  5. package/lib/commonjs/components/Button/index.js +127 -28
  6. package/lib/commonjs/components/Button/index.js.map +1 -1
  7. package/lib/commonjs/components/Button/styles.js +9 -3
  8. package/lib/commonjs/components/Button/styles.js.map +1 -1
  9. package/lib/commonjs/components/CLAUDE.md +115 -11
  10. package/lib/commonjs/components/Checkbox/index.js +69 -22
  11. package/lib/commonjs/components/Checkbox/index.js.map +1 -1
  12. package/lib/commonjs/components/Checkbox/styles.js +1 -1
  13. package/lib/commonjs/components/Checkbox/styles.js.map +1 -1
  14. package/lib/commonjs/components/Chip/index.js +44 -36
  15. package/lib/commonjs/components/Chip/index.js.map +1 -1
  16. package/lib/commonjs/components/Chip/styles.js +6 -35
  17. package/lib/commonjs/components/Chip/styles.js.map +1 -1
  18. package/lib/commonjs/components/Dialog/index.js +92 -72
  19. package/lib/commonjs/components/Dialog/index.js.map +1 -1
  20. package/lib/commonjs/components/Field/index.js +70 -26
  21. package/lib/commonjs/components/Field/index.js.map +1 -1
  22. package/lib/commonjs/components/Form/index.js +5 -12
  23. package/lib/commonjs/components/Form/index.js.map +1 -1
  24. package/lib/commonjs/components/IconButton/index.js +5 -33
  25. package/lib/commonjs/components/IconButton/index.js.map +1 -1
  26. package/lib/commonjs/components/Input/index.js +50 -20
  27. package/lib/commonjs/components/Input/index.js.map +1 -1
  28. package/lib/commonjs/components/Link/index.js +14 -7
  29. package/lib/commonjs/components/Link/index.js.map +1 -1
  30. package/lib/commonjs/components/ListItem/index.js +129 -54
  31. package/lib/commonjs/components/ListItem/index.js.map +1 -1
  32. package/lib/commonjs/components/OtpInput/index.js +94 -28
  33. package/lib/commonjs/components/OtpInput/index.js.map +1 -1
  34. package/lib/commonjs/components/ProgressBar/index.js +8 -13
  35. package/lib/commonjs/components/ProgressBar/index.js.map +1 -1
  36. package/lib/commonjs/components/Radio/index.js +51 -53
  37. package/lib/commonjs/components/Radio/index.js.map +1 -1
  38. package/lib/commonjs/components/Select/index.js +112 -46
  39. package/lib/commonjs/components/Select/index.js.map +1 -1
  40. package/lib/commonjs/components/Select/styles.js +2 -2
  41. package/lib/commonjs/components/Select/styles.js.map +1 -1
  42. package/lib/commonjs/components/Switch/BaseSwitch.js +23 -13
  43. package/lib/commonjs/components/Switch/BaseSwitch.js.map +1 -1
  44. package/lib/commonjs/components/Switch/BaseSwitch.web.js +25 -21
  45. package/lib/commonjs/components/Switch/BaseSwitch.web.js.map +1 -1
  46. package/lib/commonjs/components/Switch/index.js +34 -3
  47. package/lib/commonjs/components/Switch/index.js.map +1 -1
  48. package/lib/commonjs/components/Tile/index.js +150 -77
  49. package/lib/commonjs/components/Tile/index.js.map +1 -1
  50. package/lib/commonjs/figma/Chip.figma.js +2 -2
  51. package/lib/commonjs/figma/Chip.figma.js.map +1 -1
  52. package/lib/commonjs/utils/positionToDataIcon.js +41 -0
  53. package/lib/commonjs/utils/positionToDataIcon.js.map +1 -0
  54. package/lib/module/components/AlertDialog/index.js +13 -11
  55. package/lib/module/components/AlertDialog/index.js.map +1 -1
  56. package/lib/module/components/Avatar/index.js +128 -28
  57. package/lib/module/components/Avatar/index.js.map +1 -1
  58. package/lib/module/components/Button/index.js +130 -32
  59. package/lib/module/components/Button/index.js.map +1 -1
  60. package/lib/module/components/Button/styles.js +8 -2
  61. package/lib/module/components/Button/styles.js.map +1 -1
  62. package/lib/module/components/CLAUDE.md +115 -11
  63. package/lib/module/components/Checkbox/index.js +72 -25
  64. package/lib/module/components/Checkbox/index.js.map +1 -1
  65. package/lib/module/components/Checkbox/styles.js +1 -1
  66. package/lib/module/components/Checkbox/styles.js.map +1 -1
  67. package/lib/module/components/Chip/index.js +47 -39
  68. package/lib/module/components/Chip/index.js.map +1 -1
  69. package/lib/module/components/Chip/styles.js +6 -35
  70. package/lib/module/components/Chip/styles.js.map +1 -1
  71. package/lib/module/components/Dialog/index.js +96 -76
  72. package/lib/module/components/Dialog/index.js.map +1 -1
  73. package/lib/module/components/Field/index.js +74 -31
  74. package/lib/module/components/Field/index.js.map +1 -1
  75. package/lib/module/components/Form/index.js +7 -14
  76. package/lib/module/components/Form/index.js.map +1 -1
  77. package/lib/module/components/IconButton/index.js +6 -34
  78. package/lib/module/components/IconButton/index.js.map +1 -1
  79. package/lib/module/components/Input/index.js +53 -23
  80. package/lib/module/components/Input/index.js.map +1 -1
  81. package/lib/module/components/Link/index.js +16 -8
  82. package/lib/module/components/Link/index.js.map +1 -1
  83. package/lib/module/components/ListItem/index.js +134 -59
  84. package/lib/module/components/ListItem/index.js.map +1 -1
  85. package/lib/module/components/OtpInput/index.js +94 -28
  86. package/lib/module/components/OtpInput/index.js.map +1 -1
  87. package/lib/module/components/ProgressBar/index.js +9 -14
  88. package/lib/module/components/ProgressBar/index.js.map +1 -1
  89. package/lib/module/components/Radio/index.js +54 -57
  90. package/lib/module/components/Radio/index.js.map +1 -1
  91. package/lib/module/components/Select/index.js +118 -52
  92. package/lib/module/components/Select/index.js.map +1 -1
  93. package/lib/module/components/Select/styles.js +2 -2
  94. package/lib/module/components/Select/styles.js.map +1 -1
  95. package/lib/module/components/Switch/BaseSwitch.js +24 -14
  96. package/lib/module/components/Switch/BaseSwitch.js.map +1 -1
  97. package/lib/module/components/Switch/BaseSwitch.web.js +26 -22
  98. package/lib/module/components/Switch/BaseSwitch.web.js.map +1 -1
  99. package/lib/module/components/Switch/index.js +35 -4
  100. package/lib/module/components/Switch/index.js.map +1 -1
  101. package/lib/module/components/Tile/index.js +155 -83
  102. package/lib/module/components/Tile/index.js.map +1 -1
  103. package/lib/module/figma/Chip.figma.js +2 -2
  104. package/lib/module/figma/Chip.figma.js.map +1 -1
  105. package/lib/module/utils/positionToDataIcon.js +38 -0
  106. package/lib/module/utils/positionToDataIcon.js.map +1 -0
  107. package/lib/typescript/components/AlertDialog/index.d.ts.map +1 -1
  108. package/lib/typescript/components/Avatar/index.d.ts +6 -2
  109. package/lib/typescript/components/Avatar/index.d.ts.map +1 -1
  110. package/lib/typescript/components/Button/index.d.ts +31 -8
  111. package/lib/typescript/components/Button/index.d.ts.map +1 -1
  112. package/lib/typescript/components/Button/styles.d.ts +2 -1
  113. package/lib/typescript/components/Button/styles.d.ts.map +1 -1
  114. package/lib/typescript/components/Checkbox/index.d.ts +3 -1
  115. package/lib/typescript/components/Checkbox/index.d.ts.map +1 -1
  116. package/lib/typescript/components/Chip/index.d.ts +19 -9
  117. package/lib/typescript/components/Chip/index.d.ts.map +1 -1
  118. package/lib/typescript/components/Chip/styles.d.ts +0 -1
  119. package/lib/typescript/components/Chip/styles.d.ts.map +1 -1
  120. package/lib/typescript/components/Dialog/index.d.ts +12 -6
  121. package/lib/typescript/components/Dialog/index.d.ts.map +1 -1
  122. package/lib/typescript/components/Dialog/styles.d.ts +1 -1
  123. package/lib/typescript/components/Field/index.d.ts +14 -7
  124. package/lib/typescript/components/Field/index.d.ts.map +1 -1
  125. package/lib/typescript/components/Form/index.d.ts +4 -4
  126. package/lib/typescript/components/Form/index.d.ts.map +1 -1
  127. package/lib/typescript/components/IconButton/index.d.ts.map +1 -1
  128. package/lib/typescript/components/Input/index.d.ts +11 -3
  129. package/lib/typescript/components/Input/index.d.ts.map +1 -1
  130. package/lib/typescript/components/Link/index.d.ts +2 -0
  131. package/lib/typescript/components/Link/index.d.ts.map +1 -1
  132. package/lib/typescript/components/ListItem/index.d.ts +28 -6
  133. package/lib/typescript/components/ListItem/index.d.ts.map +1 -1
  134. package/lib/typescript/components/OtpInput/index.d.ts +1 -1
  135. package/lib/typescript/components/OtpInput/index.d.ts.map +1 -1
  136. package/lib/typescript/components/ProgressBar/index.d.ts +4 -4
  137. package/lib/typescript/components/ProgressBar/index.d.ts.map +1 -1
  138. package/lib/typescript/components/Radio/index.d.ts +4 -0
  139. package/lib/typescript/components/Radio/index.d.ts.map +1 -1
  140. package/lib/typescript/components/Select/index.d.ts +35 -2
  141. package/lib/typescript/components/Select/index.d.ts.map +1 -1
  142. package/lib/typescript/components/Select/styles.d.ts.map +1 -1
  143. package/lib/typescript/components/Switch/BaseSwitch.d.ts +12 -5
  144. package/lib/typescript/components/Switch/BaseSwitch.d.ts.map +1 -1
  145. package/lib/typescript/components/Switch/BaseSwitch.web.d.ts +11 -5
  146. package/lib/typescript/components/Switch/BaseSwitch.web.d.ts.map +1 -1
  147. package/lib/typescript/components/Switch/index.d.ts +5 -1
  148. package/lib/typescript/components/Switch/index.d.ts.map +1 -1
  149. package/lib/typescript/components/Tile/index.d.ts +8 -2
  150. package/lib/typescript/components/Tile/index.d.ts.map +1 -1
  151. package/lib/typescript/utils/positionToDataIcon.d.ts +29 -0
  152. package/lib/typescript/utils/positionToDataIcon.d.ts.map +1 -0
  153. package/package.json +5 -5
  154. package/src/components/AlertDialog/index.tsx +13 -14
  155. package/src/components/Avatar/index.tsx +134 -44
  156. package/src/components/Button/index.tsx +216 -44
  157. package/src/components/Button/styles.ts +50 -38
  158. package/src/components/CLAUDE.md +115 -11
  159. package/src/components/Checkbox/index.tsx +93 -32
  160. package/src/components/Checkbox/styles.ts +1 -1
  161. package/src/components/Chip/index.tsx +88 -61
  162. package/src/components/Chip/styles.ts +6 -18
  163. package/src/components/Dialog/index.tsx +139 -99
  164. package/src/components/Field/index.tsx +113 -49
  165. package/src/components/Form/index.tsx +18 -14
  166. package/src/components/IconButton/index.tsx +7 -31
  167. package/src/components/Input/index.tsx +75 -32
  168. package/src/components/Link/index.tsx +38 -12
  169. package/src/components/ListItem/index.tsx +158 -73
  170. package/src/components/OtpInput/index.tsx +126 -43
  171. package/src/components/ProgressBar/index.tsx +11 -16
  172. package/src/components/Radio/index.tsx +76 -54
  173. package/src/components/Select/index.tsx +174 -59
  174. package/src/components/Select/styles.ts +1 -2
  175. package/src/components/Switch/BaseSwitch.tsx +38 -16
  176. package/src/components/Switch/BaseSwitch.web.tsx +28 -35
  177. package/src/components/Switch/index.tsx +51 -4
  178. package/src/components/Tile/index.tsx +145 -94
  179. package/src/utils/positionToDataIcon.ts +34 -0
  180. package/lib/commonjs/components/Field/FieldLabel.js +0 -33
  181. package/lib/commonjs/components/Field/FieldLabel.js.map +0 -1
  182. package/lib/commonjs/components/Field/FieldLabel.web.js +0 -22
  183. package/lib/commonjs/components/Field/FieldLabel.web.js.map +0 -1
  184. package/lib/commonjs/components/Form/FormRoot.js +0 -25
  185. package/lib/commonjs/components/Form/FormRoot.js.map +0 -1
  186. package/lib/commonjs/components/Form/FormRoot.web.js +0 -17
  187. package/lib/commonjs/components/Form/FormRoot.web.js.map +0 -1
  188. package/lib/commonjs/components/Input/BaseInput.android.js +0 -20
  189. package/lib/commonjs/components/Input/BaseInput.android.js.map +0 -1
  190. package/lib/commonjs/components/Input/BaseInput.js +0 -13
  191. package/lib/commonjs/components/Input/BaseInput.js.map +0 -1
  192. package/lib/commonjs/components/Input/BaseInput.web.js +0 -50
  193. package/lib/commonjs/components/Input/BaseInput.web.js.map +0 -1
  194. package/lib/commonjs/components/Select/SelectTriggerHost.js +0 -10
  195. package/lib/commonjs/components/Select/SelectTriggerHost.js.map +0 -1
  196. package/lib/commonjs/components/Select/SelectTriggerHost.web.js +0 -102
  197. package/lib/commonjs/components/Select/SelectTriggerHost.web.js.map +0 -1
  198. package/lib/module/components/Field/FieldLabel.js +0 -29
  199. package/lib/module/components/Field/FieldLabel.js.map +0 -1
  200. package/lib/module/components/Field/FieldLabel.web.js +0 -17
  201. package/lib/module/components/Field/FieldLabel.web.js.map +0 -1
  202. package/lib/module/components/Form/FormRoot.js +0 -21
  203. package/lib/module/components/Form/FormRoot.js.map +0 -1
  204. package/lib/module/components/Form/FormRoot.web.js +0 -12
  205. package/lib/module/components/Form/FormRoot.web.js.map +0 -1
  206. package/lib/module/components/Input/BaseInput.android.js +0 -16
  207. package/lib/module/components/Input/BaseInput.android.js.map +0 -1
  208. package/lib/module/components/Input/BaseInput.js +0 -4
  209. package/lib/module/components/Input/BaseInput.js.map +0 -1
  210. package/lib/module/components/Input/BaseInput.web.js +0 -45
  211. package/lib/module/components/Input/BaseInput.web.js.map +0 -1
  212. package/lib/module/components/Select/SelectTriggerHost.js +0 -7
  213. package/lib/module/components/Select/SelectTriggerHost.js.map +0 -1
  214. package/lib/module/components/Select/SelectTriggerHost.web.js +0 -97
  215. package/lib/module/components/Select/SelectTriggerHost.web.js.map +0 -1
  216. package/lib/typescript/components/Field/FieldLabel.d.ts +0 -18
  217. package/lib/typescript/components/Field/FieldLabel.d.ts.map +0 -1
  218. package/lib/typescript/components/Field/FieldLabel.web.d.ts +0 -16
  219. package/lib/typescript/components/Field/FieldLabel.web.d.ts.map +0 -1
  220. package/lib/typescript/components/Form/FormRoot.d.ts +0 -14
  221. package/lib/typescript/components/Form/FormRoot.d.ts.map +0 -1
  222. package/lib/typescript/components/Form/FormRoot.web.d.ts +0 -10
  223. package/lib/typescript/components/Form/FormRoot.web.d.ts.map +0 -1
  224. package/lib/typescript/components/Input/BaseInput.android.d.ts +0 -3
  225. package/lib/typescript/components/Input/BaseInput.android.d.ts.map +0 -1
  226. package/lib/typescript/components/Input/BaseInput.d.ts +0 -2
  227. package/lib/typescript/components/Input/BaseInput.d.ts.map +0 -1
  228. package/lib/typescript/components/Input/BaseInput.web.d.ts +0 -3
  229. package/lib/typescript/components/Input/BaseInput.web.d.ts.map +0 -1
  230. package/lib/typescript/components/Select/SelectTriggerHost.d.ts +0 -3
  231. package/lib/typescript/components/Select/SelectTriggerHost.d.ts.map +0 -1
  232. package/lib/typescript/components/Select/SelectTriggerHost.web.d.ts +0 -16
  233. package/lib/typescript/components/Select/SelectTriggerHost.web.d.ts.map +0 -1
  234. package/src/components/Field/FieldLabel.tsx +0 -33
  235. package/src/components/Field/FieldLabel.web.tsx +0 -25
  236. package/src/components/Form/FormRoot.tsx +0 -20
  237. package/src/components/Form/FormRoot.web.tsx +0 -12
  238. package/src/components/Input/BaseInput.android.tsx +0 -13
  239. package/src/components/Input/BaseInput.tsx +0 -1
  240. package/src/components/Input/BaseInput.web.tsx +0 -41
  241. package/src/components/Select/SelectTriggerHost.tsx +0 -4
  242. package/src/components/Select/SelectTriggerHost.web.tsx +0 -143
@@ -1,44 +1,32 @@
1
- import { forwardRef } from 'react';
2
- import { Text, View } from 'react-native';
1
+ import { forwardRef, useEffect, type ReactNode } from 'react';
2
+ import { Text, type TextProps, View, type ViewProps } from 'react-native';
3
3
  import { ErrorIcon } from '@cdx-ui/icons';
4
4
  import {
5
- createField,
6
- IFieldErrorProps,
7
- IFieldHelperProps,
8
- IFieldLabelProps,
9
- type IFieldRootProps,
5
+ FieldLabel as FieldLabelPrimitive,
6
+ FieldRoot as FieldRootPrimitive,
7
+ Slot,
8
+ dataAttributes,
9
+ mergeDataAttributes,
10
+ useFormControlContext,
11
+ type FieldLabelProps as FieldLabelPrimitiveProps,
12
+ type FieldRootProps as FieldRootPrimitiveProps,
10
13
  } from '@cdx-ui/primitives';
11
- import { cn, useFormControlContext } from '@cdx-ui/utils';
14
+ import { cn } from '@cdx-ui/utils';
12
15
  import { Icon } from '../Icon';
13
- import { BaseFieldLabel } from './FieldLabel';
14
16
  import {
15
17
  fieldErrorIconVariants,
16
18
  fieldErrorTextVariants,
17
19
  fieldErrorVariants,
18
- fieldHelperVariants,
19
20
  fieldHelperTextVariants,
21
+ fieldHelperVariants,
20
22
  fieldLabelVariants,
21
23
  fieldRootVariants,
22
- type FieldRootVariantProps,
23
- type FieldLabelVariantProps,
24
- type FieldHelperVariantProps,
25
24
  type FieldErrorVariantProps,
25
+ type FieldHelperVariantProps,
26
+ type FieldLabelVariantProps,
27
+ type FieldRootVariantProps,
26
28
  } from './styles';
27
29
 
28
- // =============================================================================
29
- // PRIMITIVE
30
- // =============================================================================
31
-
32
- const FieldPrimitive = createField({
33
- Root: View,
34
- Label: BaseFieldLabel,
35
- Helper: View,
36
- HelperText: Text,
37
- Error: View,
38
- ErrorText: Text,
39
- ErrorIcon: View,
40
- });
41
-
42
30
  // =============================================================================
43
31
  // FIELD ROOT
44
32
  // =============================================================================
@@ -46,16 +34,22 @@ const FieldPrimitive = createField({
46
34
  /**
47
35
  * Field wrapper + context. For **initial focus**, pass `autoFocus` on `Input.Field` (not here).
48
36
  */
49
- export interface FieldRootProps extends IFieldRootProps, FieldRootVariantProps {}
37
+ export interface FieldRootProps extends FieldRootPrimitiveProps, FieldRootVariantProps {}
50
38
 
51
39
  const FieldRoot = forwardRef<View, FieldRootProps>(
52
40
  ({ className, children, style, ...props }, ref) => {
53
41
  const computedClassName = cn(fieldRootVariants(), className);
54
42
 
55
43
  return (
56
- <FieldPrimitive ref={ref} className={computedClassName} style={style} {...props}>
44
+ <FieldRootPrimitive
45
+ ref={ref}
46
+ className={computedClassName}
47
+ style={style}
48
+ {...props}
49
+ {...mergeDataAttributes(props, dataAttributes({ slot: 'field' }))}
50
+ >
57
51
  {children}
58
- </FieldPrimitive>
52
+ </FieldRootPrimitive>
59
53
  );
60
54
  },
61
55
  );
@@ -66,7 +60,7 @@ FieldRoot.displayName = 'Field';
66
60
  // FIELD LABEL
67
61
  // =============================================================================
68
62
 
69
- export interface FieldLabelProps extends IFieldLabelProps, FieldLabelVariantProps {}
63
+ export interface FieldLabelProps extends FieldLabelPrimitiveProps, FieldLabelVariantProps {}
70
64
 
71
65
  const FieldLabel = forwardRef<View, FieldLabelProps>(
72
66
  ({ className, children, style, htmlFor, ...props }, ref) => {
@@ -80,7 +74,7 @@ const FieldLabel = forwardRef<View, FieldLabelProps>(
80
74
  );
81
75
 
82
76
  return (
83
- <FieldPrimitive.Label
77
+ <FieldLabelPrimitive
84
78
  ref={ref}
85
79
  className={labelClassName}
86
80
  style={style}
@@ -91,9 +85,10 @@ const FieldLabel = forwardRef<View, FieldLabelProps>(
91
85
  </Text>
92
86
  }
93
87
  {...props}
88
+ {...mergeDataAttributes(props, dataAttributes({ slot: 'field-label' }))}
94
89
  >
95
90
  {children}
96
- </FieldPrimitive.Label>
91
+ </FieldLabelPrimitive>
97
92
  );
98
93
  },
99
94
  );
@@ -101,20 +96,50 @@ const FieldLabel = forwardRef<View, FieldLabelProps>(
101
96
  FieldLabel.displayName = 'Field.Label';
102
97
 
103
98
  // =============================================================================
104
- // FIELD HELPER
99
+ // FIELD HELPER (styled-only — reads form context directly)
105
100
  // =============================================================================
106
101
 
107
- export interface FieldHelperProps extends IFieldHelperProps, FieldHelperVariantProps {}
102
+ export interface FieldHelperProps extends ViewProps, FieldHelperVariantProps {
103
+ asChild?: boolean;
104
+ className?: string;
105
+ children?: ReactNode;
106
+ }
108
107
 
109
108
  const FieldHelper = forwardRef<View, FieldHelperProps>(
110
- ({ className, children, style, ...props }, ref) => {
109
+ ({ asChild, className, children, style, ...props }, ref) => {
110
+ const { helpTextId, setHasHelpText, isInvalid } = useFormControlContext();
111
+
112
+ useEffect(() => {
113
+ if (isInvalid) {
114
+ setHasHelpText?.(false);
115
+ return undefined;
116
+ }
117
+ setHasHelpText?.(true);
118
+ return () => {
119
+ setHasHelpText?.(false);
120
+ };
121
+ }, [setHasHelpText, isInvalid]);
122
+
123
+ if (isInvalid) {
124
+ return null;
125
+ }
126
+
111
127
  const containerClassName = cn(fieldHelperVariants(), className);
112
128
  const textClassName = cn(fieldHelperTextVariants());
129
+ const Comp = asChild ? Slot : View;
113
130
 
114
131
  return (
115
- <FieldPrimitive.Helper ref={ref} className={containerClassName} style={style} {...props}>
116
- <FieldPrimitive.HelperText className={textClassName}>{children}</FieldPrimitive.HelperText>
117
- </FieldPrimitive.Helper>
132
+ <Comp
133
+ ref={ref}
134
+ className={containerClassName}
135
+ style={style}
136
+ {...props}
137
+ {...mergeDataAttributes(props, dataAttributes({ slot: 'field-helper' }))}
138
+ >
139
+ <Text id={helpTextId} className={textClassName}>
140
+ {children}
141
+ </Text>
142
+ </Comp>
118
143
  );
119
144
  },
120
145
  );
@@ -122,10 +147,17 @@ const FieldHelper = forwardRef<View, FieldHelperProps>(
122
147
  FieldHelper.displayName = 'Field.Helper';
123
148
 
124
149
  // =============================================================================
125
- // FIELD ERROR (internal icon + text composition)
150
+ // FIELD ERROR (styled-only — reads form context directly)
126
151
  // =============================================================================
127
152
 
128
- const FieldErrorIcon = ({ className, style, ...props }: { className?: string; style?: any }) => {
153
+ const FieldErrorIcon = ({
154
+ className,
155
+ style,
156
+ ...props
157
+ }: {
158
+ className?: string;
159
+ style?: TextProps['style'];
160
+ }) => {
129
161
  const computedClassName = cn(fieldErrorIconVariants(), className);
130
162
 
131
163
  return (
@@ -135,26 +167,58 @@ const FieldErrorIcon = ({ className, style, ...props }: { className?: string; st
135
167
  style={style}
136
168
  aria-hidden={true}
137
169
  {...props}
170
+ {...mergeDataAttributes(props, dataAttributes({ slot: 'field-error-icon' }))}
138
171
  />
139
172
  );
140
173
  };
141
174
 
142
175
  FieldErrorIcon.displayName = 'Field.ErrorIcon';
143
176
 
144
- export interface FieldErrorProps extends IFieldErrorProps, FieldErrorVariantProps {}
177
+ export interface FieldErrorProps extends ViewProps, FieldErrorVariantProps {
178
+ asChild?: boolean;
179
+ className?: string;
180
+ children?: ReactNode;
181
+ }
145
182
 
146
183
  const FieldError = forwardRef<View, FieldErrorProps>(
147
- ({ className, children, style, ...props }, ref) => {
184
+ ({ asChild, className, children, style, ...props }, ref) => {
185
+ const { isInvalid, feedbackId, setHasFeedbackText } = useFormControlContext();
186
+
187
+ const visible = Boolean(isInvalid && children);
188
+
189
+ useEffect(() => {
190
+ if (!visible) {
191
+ setHasFeedbackText?.(false);
192
+ return undefined;
193
+ }
194
+ setHasFeedbackText?.(true);
195
+ return () => {
196
+ setHasFeedbackText?.(false);
197
+ };
198
+ }, [setHasFeedbackText, visible]);
199
+
200
+ if (!visible) {
201
+ return null;
202
+ }
203
+
148
204
  const containerClassName = cn(fieldErrorVariants(), className);
149
205
  const textClassName = cn(fieldErrorTextVariants());
206
+ const Comp = asChild ? Slot : View;
150
207
 
151
208
  return (
152
- <FieldPrimitive.Error ref={ref} className={containerClassName} style={style} {...props}>
153
- <FieldPrimitive.ErrorIcon>
154
- <FieldErrorIcon />
155
- </FieldPrimitive.ErrorIcon>
156
- <FieldPrimitive.ErrorText className={textClassName}>{children}</FieldPrimitive.ErrorText>
157
- </FieldPrimitive.Error>
209
+ <Comp
210
+ ref={ref}
211
+ id={feedbackId}
212
+ accessibilityRole="alert"
213
+ accessibilityLiveRegion="assertive"
214
+ className={containerClassName}
215
+ style={style}
216
+ {...props}
217
+ {...mergeDataAttributes(props, dataAttributes({ slot: 'field-error' }))}
218
+ >
219
+ <FieldErrorIcon />
220
+ <Text className={textClassName}>{children}</Text>
221
+ </Comp>
158
222
  );
159
223
  },
160
224
  );
@@ -1,31 +1,35 @@
1
- import React, { forwardRef } from 'react';
1
+ import { forwardRef } from 'react';
2
2
  import { View } from 'react-native';
3
- import { createForm } from '@cdx-ui/primitives';
3
+ import {
4
+ FormRoot as FormRootPrimitive,
5
+ dataAttributes,
6
+ mergeDataAttributes,
7
+ type FormRootProps,
8
+ } from '@cdx-ui/primitives';
4
9
  import { cn } from '@cdx-ui/utils';
5
- import { BaseFormRoot, type BaseFormRootProps } from './FormRoot';
6
10
  import { formRootVariants } from './styles';
7
11
 
8
- // =============================================================================
9
- // PRIMITIVE
10
- // =============================================================================
11
-
12
- const FormPrimitive = createForm({ Root: BaseFormRoot });
13
-
14
- FormPrimitive.displayName = 'FormPrimitive';
15
-
16
12
  // =============================================================================
17
13
  // FORM ROOT (container — <form> on web, <View> on RN)
18
14
  // =============================================================================
19
15
 
20
- export interface FormProps extends BaseFormRootProps {}
16
+ export interface FormProps extends FormRootProps {
17
+ className?: string;
18
+ }
21
19
 
22
20
  const FormRoot = forwardRef<View, FormProps>(({ className, children, style, ...props }, ref) => {
23
21
  const computedClassName = cn(formRootVariants(), className);
24
22
 
25
23
  return (
26
- <FormPrimitive ref={ref} className={computedClassName} style={style} {...props}>
24
+ <FormRootPrimitive
25
+ ref={ref}
26
+ className={computedClassName}
27
+ style={style}
28
+ {...props}
29
+ {...mergeDataAttributes(props, dataAttributes({ slot: 'form' }))}
30
+ >
27
31
  {children}
28
- </FormPrimitive>
32
+ </FormRootPrimitive>
29
33
  );
30
34
  });
31
35
 
@@ -1,10 +1,10 @@
1
1
  import { forwardRef } from 'react';
2
- import { ActivityIndicator, Pressable, Text, View, type PressableProps } from 'react-native';
2
+ import { View, type PressableProps } from 'react-native';
3
3
  import {
4
- createButton,
4
+ ButtonRoot,
5
5
  dataAttributes,
6
+ mergeDataAttributes,
6
7
  type IButtonProps,
7
- useButtonContext,
8
8
  } from '@cdx-ui/primitives';
9
9
  import type { ForgeIcon } from '@cdx-ui/icons';
10
10
  import { cn } from '@cdx-ui/utils';
@@ -16,31 +16,6 @@ import {
16
16
  iconButtonRootVariants,
17
17
  } from './styles';
18
18
 
19
- const IconButtonPrimitive = createButton({
20
- Root: Pressable,
21
- Text,
22
- Group: View,
23
- Spinner: ActivityIndicator,
24
- Icon: View,
25
- });
26
-
27
- function IconButtonGlyph({ as: IconComponent, className }: { as: ForgeIcon; className: string }) {
28
- const { hover, focus, active, disabled, focusVisible } = useButtonContext();
29
- return (
30
- <Icon
31
- as={IconComponent}
32
- className={className}
33
- {...dataAttributes({
34
- hover,
35
- focus,
36
- active,
37
- disabled,
38
- focusVisible,
39
- })}
40
- />
41
- );
42
- }
43
-
44
19
  export interface IconButtonProps extends PressableProps, IButtonProps, IconButtonVariantProps {
45
20
  className?: string;
46
21
  /** Forge icon component to render (icon-only control). */
@@ -73,15 +48,16 @@ const IconButtonRoot = forwardRef<View, IconButtonProps>(
73
48
  );
74
49
 
75
50
  return (
76
- <IconButtonPrimitive
51
+ <ButtonRoot
77
52
  ref={ref}
78
53
  accessibilityRole={accessibilityRole}
79
54
  className={rootClassName}
80
55
  style={style}
81
56
  {...props}
57
+ {...mergeDataAttributes(props, dataAttributes({ slot: 'icon-button' }))}
82
58
  >
83
- <IconButtonGlyph as={IconComponent} className={glyphClassName} />
84
- </IconButtonPrimitive>
59
+ <Icon as={IconComponent} className={glyphClassName} />
60
+ </ButtonRoot>
85
61
  );
86
62
  },
87
63
  );
@@ -1,14 +1,17 @@
1
- import { forwardRef, type ReactNode } from 'react';
1
+ import { forwardRef, useMemo, type ReactNode } from 'react';
2
2
  import { type TextInput, View, type ViewProps } from 'react-native';
3
3
  import {
4
- createInput,
4
+ InputField as InputFieldPrimitive,
5
+ InputRoot as InputRootPrimitive,
6
+ Slot,
7
+ dataAttributes,
8
+ mergeDataAttributes,
5
9
  type IInputFieldProps,
6
10
  type IInputProps,
7
11
  type IInputSlotProps,
8
12
  } from '@cdx-ui/primitives';
9
- import { cn, useStyleContext, withStyleContext } from '@cdx-ui/utils';
10
- import { Icon, IconProps } from '../Icon';
11
- import { BaseInput } from './BaseInput';
13
+ import { ParentContext, cn, useParentContext, useStyleContext } from '@cdx-ui/utils';
14
+ import { Icon, type IconProps } from '../Icon';
12
15
  import {
13
16
  type InputVariantProps,
14
17
  inputFieldPlaceholderVariants,
@@ -20,39 +23,41 @@ import {
20
23
 
21
24
  const SCOPE = 'INPUT';
22
25
 
23
- const Root = withStyleContext(View, SCOPE);
24
-
25
26
  const useInputStyleContext = () => useStyleContext(SCOPE) as InputVariantProps;
26
27
 
27
- const InputPrimitive = createInput({
28
- Root,
29
- Slot: View,
30
- Field: BaseInput,
31
- });
32
-
33
28
  // =============================================================================
34
29
  // INPUT (ROOT)
35
30
  // =============================================================================
36
31
 
37
32
  export interface InputProps extends ViewProps, IInputFieldProps, InputVariantProps {
33
+ asChild?: boolean;
38
34
  className?: string;
39
35
  children?: ReactNode;
40
36
  }
41
37
 
42
38
  const InputRoot = forwardRef<View, InputProps>(
43
- ({ variant = 'outline', size = 'default', className, children, style, ...props }, ref) => {
39
+ (
40
+ { asChild, variant = 'outline', size = 'default', className, children, style, ...props },
41
+ ref,
42
+ ) => {
44
43
  const computedClassName = cn(inputRootVariants({ variant, size }), className);
45
44
 
45
+ const parent = useParentContext();
46
+ const ctx = useMemo(() => ({ ...parent, [SCOPE]: { variant, size } }), [parent, variant, size]);
47
+
46
48
  return (
47
- <InputPrimitive
48
- ref={ref}
49
- className={computedClassName}
50
- style={style}
51
- context={{ variant, size }}
52
- {...props}
53
- >
54
- {children}
55
- </InputPrimitive>
49
+ <ParentContext.Provider value={ctx}>
50
+ <InputRootPrimitive
51
+ ref={ref}
52
+ asChild={asChild}
53
+ className={computedClassName}
54
+ style={style}
55
+ {...props}
56
+ {...mergeDataAttributes(props, dataAttributes({ slot: 'input' }))}
57
+ >
58
+ {children}
59
+ </InputRootPrimitive>
60
+ </ParentContext.Provider>
56
61
  );
57
62
  },
58
63
  );
@@ -79,12 +84,13 @@ const InputField = forwardRef<TextInput, InputFieldProps>(
79
84
  );
80
85
 
81
86
  return (
82
- <InputPrimitive.Field
87
+ <InputFieldPrimitive
83
88
  ref={ref}
84
89
  className={computedClassName}
85
90
  placeholderTextColorClassName={computedPlaceholderColorClassName}
86
91
  style={style}
87
92
  {...rest}
93
+ {...mergeDataAttributes(rest, dataAttributes({ slot: 'input-field' }))}
88
94
  />
89
95
  );
90
96
  },
@@ -93,22 +99,30 @@ const InputField = forwardRef<TextInput, InputFieldProps>(
93
99
  InputField.displayName = 'Input.Field';
94
100
 
95
101
  // =============================================================================
96
- // INPUT SLOT
102
+ // INPUT SLOT — styled-only (Standard 3: no behavior beyond layout)
97
103
  // =============================================================================
98
104
 
99
105
  export interface InputSlotProps extends ViewProps, IInputSlotProps {
106
+ asChild?: boolean;
100
107
  className?: string;
101
108
  children?: ReactNode;
102
109
  }
103
110
 
104
111
  const InputSlot = forwardRef<View, InputSlotProps>(
105
- ({ className, children, style, ...props }, ref) => {
112
+ ({ asChild, className, children, style, ...props }, ref) => {
106
113
  const computedClassName = cn(inputSlotVariants(), className);
114
+ const Comp = asChild ? Slot : View;
107
115
 
108
116
  return (
109
- <InputPrimitive.Slot ref={ref} className={computedClassName} style={style} {...props}>
117
+ <Comp
118
+ ref={ref}
119
+ className={computedClassName}
120
+ style={style}
121
+ {...props}
122
+ {...mergeDataAttributes(props, dataAttributes({ slot: 'input-slot' }))}
123
+ >
110
124
  {children}
111
- </InputPrimitive.Slot>
125
+ </Comp>
112
126
  );
113
127
  },
114
128
  );
@@ -119,14 +133,43 @@ InputSlot.displayName = 'Input.Slot';
119
133
  // INPUT ICON
120
134
  // =============================================================================
121
135
 
122
- export interface InputIconProps extends Omit<IconProps, 'children'> {}
136
+ export interface InputIconProps extends Omit<IconProps, 'children' | 'as'> {
137
+ asChild?: boolean;
138
+ /**
139
+ * Forge icon component to render. Required unless `asChild` is set, in which
140
+ * case the consumer's substituted element is rendered instead.
141
+ */
142
+ as?: IconProps['as'];
143
+ }
123
144
 
124
- const InputIcon = ({ className, style, as, ...props }: InputIconProps) => {
145
+ const InputIcon = ({ asChild, className, style, as, ...props }: InputIconProps) => {
125
146
  const { size } = useInputStyleContext();
126
-
127
147
  const computedClassName = cn(inputIconVariants({ size }), className);
128
148
 
129
- return <Icon as={as} className={computedClassName} style={style} {...props} />;
149
+ if (asChild) {
150
+ return (
151
+ <Slot
152
+ className={computedClassName}
153
+ style={style}
154
+ {...props}
155
+ {...mergeDataAttributes(props, dataAttributes({ slot: 'input-icon' }))}
156
+ />
157
+ );
158
+ }
159
+
160
+ if (!as) {
161
+ return null;
162
+ }
163
+
164
+ return (
165
+ <Icon
166
+ as={as}
167
+ className={computedClassName}
168
+ style={style}
169
+ {...props}
170
+ {...mergeDataAttributes(props, dataAttributes({ slot: 'input-icon' }))}
171
+ />
172
+ );
130
173
  };
131
174
 
132
175
  InputIcon.displayName = 'Input.Icon';
@@ -1,6 +1,13 @@
1
1
  import { forwardRef, type ReactNode } from 'react';
2
- import { Platform, Pressable, Text, View, type TextProps } from 'react-native';
3
- import { createLink, useLinkInteractionContext, type ILinkProps } from '@cdx-ui/primitives';
2
+ import { Platform, Text, View, type TextProps } from 'react-native';
3
+ import {
4
+ LinkRoot as LinkRootPrimitive,
5
+ Slot,
6
+ dataAttributes,
7
+ mergeDataAttributes,
8
+ useLinkInteractionContext,
9
+ type ILinkProps,
10
+ } from '@cdx-ui/primitives';
4
11
  import { cn } from '@cdx-ui/utils';
5
12
  import { Icon, type IconProps } from '../Icon';
6
13
  import {
@@ -12,25 +19,28 @@ import {
12
19
 
13
20
  export { LinkProvider, type LinkConfig, type LinkAction } from '@cdx-ui/primitives';
14
21
 
15
- const LinkPrimitive = createLink({
16
- Root: Pressable,
17
- });
18
-
19
22
  // =============================================================================
20
23
  // STYLED ROOT COMPONENT
21
24
  // =============================================================================
22
25
 
23
26
  export interface LinkProps extends ILinkProps {
24
27
  className?: string;
28
+ children?: ReactNode;
25
29
  }
26
30
 
27
31
  const LinkRoot = forwardRef<View, LinkProps>(({ className, children, style, ...props }, ref) => {
28
32
  const rootClassName = cn(linkRootVariants(), className);
29
33
 
30
34
  return (
31
- <LinkPrimitive ref={ref} className={rootClassName} style={style} {...props}>
35
+ <LinkRootPrimitive
36
+ ref={ref}
37
+ className={rootClassName}
38
+ style={style}
39
+ {...props}
40
+ {...mergeDataAttributes(props, dataAttributes({ slot: 'link' }))}
41
+ >
32
42
  {children}
33
- </LinkPrimitive>
43
+ </LinkRootPrimitive>
34
44
  );
35
45
  });
36
46
 
@@ -41,19 +51,27 @@ LinkRoot.displayName = 'Link';
41
51
  // =============================================================================
42
52
 
43
53
  export interface LinkLabelProps extends TextProps {
54
+ asChild?: boolean;
44
55
  className?: string;
45
56
  children?: ReactNode;
46
57
  }
47
58
 
48
59
  const LinkLabel = forwardRef<Text, LinkLabelProps>(
49
- ({ className, children, style, ...props }, ref) => {
60
+ ({ asChild, className, children, style, ...props }, ref) => {
50
61
  const { visited } = useLinkInteractionContext();
51
62
  const computedClassName = cn(linkLabelVariants({ visited }), className);
63
+ const Comp = asChild ? Slot : Text;
52
64
 
53
65
  const textElement = (
54
- <Text ref={ref} className={computedClassName} style={style} {...props}>
66
+ <Comp
67
+ ref={ref}
68
+ className={computedClassName}
69
+ style={style}
70
+ {...props}
71
+ {...mergeDataAttributes(props, dataAttributes({ slot: 'link-label' }))}
72
+ >
55
73
  {children}
56
- </Text>
74
+ </Comp>
57
75
  );
58
76
 
59
77
  if (Platform.OS === 'web') {
@@ -76,7 +94,15 @@ const LinkIcon = ({ className, style, as, ...props }: LinkIconProps) => {
76
94
  const { visited } = useLinkInteractionContext();
77
95
  const computedClassName = cn(linkIconVariants({ visited }), className);
78
96
 
79
- return <Icon as={as} className={computedClassName} style={style} {...props} />;
97
+ return (
98
+ <Icon
99
+ as={as}
100
+ className={computedClassName}
101
+ style={style}
102
+ {...props}
103
+ {...mergeDataAttributes(props, dataAttributes({ slot: 'link-icon' }))}
104
+ />
105
+ );
80
106
  };
81
107
 
82
108
  LinkIcon.displayName = 'Link.Icon';