@cdx-ui/components 0.0.1-alpha.25 → 0.0.1-alpha.27

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 (36) hide show
  1. package/lib/commonjs/components/Button/buttonSharedVariants.js +200 -0
  2. package/lib/commonjs/components/Button/buttonSharedVariants.js.map +1 -0
  3. package/lib/commonjs/components/Button/styles.js +21 -222
  4. package/lib/commonjs/components/Button/styles.js.map +1 -1
  5. package/lib/commonjs/components/IconButton/index.js +80 -0
  6. package/lib/commonjs/components/IconButton/index.js.map +1 -0
  7. package/lib/commonjs/components/IconButton/styles.js +91 -0
  8. package/lib/commonjs/components/IconButton/styles.js.map +1 -0
  9. package/lib/commonjs/components/index.js +12 -0
  10. package/lib/commonjs/components/index.js.map +1 -1
  11. package/lib/module/components/Button/buttonSharedVariants.js +195 -0
  12. package/lib/module/components/Button/buttonSharedVariants.js.map +1 -0
  13. package/lib/module/components/Button/styles.js +21 -223
  14. package/lib/module/components/Button/styles.js.map +1 -1
  15. package/lib/module/components/IconButton/index.js +76 -0
  16. package/lib/module/components/IconButton/index.js.map +1 -0
  17. package/lib/module/components/IconButton/styles.js +87 -0
  18. package/lib/module/components/IconButton/styles.js.map +1 -0
  19. package/lib/module/components/index.js +1 -0
  20. package/lib/module/components/index.js.map +1 -1
  21. package/lib/typescript/components/Button/buttonSharedVariants.d.ts +29 -0
  22. package/lib/typescript/components/Button/buttonSharedVariants.d.ts.map +1 -0
  23. package/lib/typescript/components/Button/styles.d.ts +6 -6
  24. package/lib/typescript/components/Button/styles.d.ts.map +1 -1
  25. package/lib/typescript/components/IconButton/index.d.ts +15 -0
  26. package/lib/typescript/components/IconButton/index.d.ts.map +1 -0
  27. package/lib/typescript/components/IconButton/styles.d.ts +16 -0
  28. package/lib/typescript/components/IconButton/styles.d.ts.map +1 -0
  29. package/lib/typescript/components/index.d.ts +1 -0
  30. package/lib/typescript/components/index.d.ts.map +1 -1
  31. package/package.json +4 -4
  32. package/src/components/Button/buttonSharedVariants.ts +281 -0
  33. package/src/components/Button/styles.ts +32 -275
  34. package/src/components/IconButton/index.tsx +93 -0
  35. package/src/components/IconButton/styles.ts +131 -0
  36. package/src/components/index.ts +1 -0
@@ -0,0 +1,281 @@
1
+ /**
2
+ * Neutral compound-variant **slices** shared by Button and IconButton (no consumer `variant` keys).
3
+ *
4
+ * Each consumer maps these into its own CVA, e.g. filled surface → Button `strong` or IconButton `solid`;
5
+ * ghost surface / outline+ghost foreground → attach the appropriate `variant` / tuple for that component.
6
+ *
7
+ * Button-only outline **surface** (borders) stays in `Button/styles.ts`.
8
+ */
9
+ import { Platform } from 'react-native';
10
+ import { SEMANTIC_COLORS } from '../../styles/primitives';
11
+
12
+ export type SharedButtonSemanticColor = 'action' | 'danger' | 'warning' | 'success' | 'info';
13
+
14
+ /** Root surface: filled semantic background (maps to Button `strong`, IconButton `solid`). */
15
+ export const sharedFilledSurfaceCompounds: {
16
+ color: SharedButtonSemanticColor;
17
+ mode?: 'dark';
18
+ className: string | string[];
19
+ }[] = [
20
+ {
21
+ color: 'action',
22
+ className: [
23
+ SEMANTIC_COLORS.action.bg,
24
+ Platform.select({
25
+ default: 'data-[active=true]:bg-slate-700',
26
+ web: 'data-[hover=true]:bg-slate-800 data-[active=true]:data-[hover=true]:bg-slate-700',
27
+ }),
28
+ ],
29
+ },
30
+ {
31
+ color: 'danger',
32
+ className: [
33
+ SEMANTIC_COLORS.danger.bg,
34
+ Platform.select({
35
+ default: 'data-[active=true]:bg-red-800',
36
+ web: 'data-[hover=true]:bg-red-700 data-[active=true]:data-[hover=true]:bg-red-800',
37
+ }),
38
+ ],
39
+ },
40
+ {
41
+ color: 'warning',
42
+ className: [
43
+ SEMANTIC_COLORS.warning.bg,
44
+ Platform.select({
45
+ default: 'data-[active=true]:bg-amber-700',
46
+ web: 'data-[hover=true]:bg-amber-600 data-[active=true]:data-[hover=true]:bg-amber-700',
47
+ }),
48
+ ],
49
+ },
50
+ {
51
+ color: 'success',
52
+ className: [
53
+ SEMANTIC_COLORS.success.bg,
54
+ Platform.select({
55
+ default: 'data-[active=true]:bg-green-800',
56
+ web: 'data-[hover=true]:bg-green-700 data-[active=true]:data-[hover=true]:bg-green-800',
57
+ }),
58
+ ],
59
+ },
60
+ {
61
+ color: 'info',
62
+ className: [
63
+ SEMANTIC_COLORS.info.bg,
64
+ Platform.select({
65
+ default: 'data-[active=true]:bg-sky-700',
66
+ web: 'data-[hover=true]:bg-sky-600 data-[active=true]:data-[hover=true]:bg-sky-700',
67
+ }),
68
+ ],
69
+ },
70
+ {
71
+ color: 'action',
72
+ mode: 'dark',
73
+ className: [
74
+ 'bg-slate-200',
75
+ Platform.select({
76
+ default: 'data-[active=true]:bg-slate-400',
77
+ web: 'data-[hover=true]:bg-slate-300 data-[active=true]:data-[hover=true]:bg-slate-400',
78
+ }),
79
+ ],
80
+ },
81
+ ];
82
+
83
+ /** Root surface: ghost hover/active fills (maps to `variant: 'ghost'` on Button and IconButton). */
84
+ export const sharedGhostSurfaceCompounds: {
85
+ color: SharedButtonSemanticColor;
86
+ mode?: 'dark';
87
+ className: string | string[];
88
+ }[] = [
89
+ {
90
+ color: 'danger',
91
+ className: [
92
+ Platform.select({
93
+ default: 'data-[active=true]:bg-red-100',
94
+ web: 'data-[hover=true]:bg-red-50 data-[active=true]:data-[hover=true]:bg-red-100',
95
+ }),
96
+ ],
97
+ },
98
+ {
99
+ color: 'warning',
100
+ className: [
101
+ Platform.select({
102
+ default: 'data-[active=true]:bg-amber-100',
103
+ web: 'data-[hover=true]:bg-amber-50 data-[active=true]:data-[hover=true]:bg-amber-100',
104
+ }),
105
+ ],
106
+ },
107
+ {
108
+ color: 'success',
109
+ className: [
110
+ Platform.select({
111
+ default: 'data-[active=true]:bg-green-100',
112
+ web: 'data-[hover=true]:bg-green-50 data-[active=true]:data-[hover=true]:bg-green-100',
113
+ }),
114
+ ],
115
+ },
116
+ {
117
+ color: 'info',
118
+ className: [
119
+ Platform.select({
120
+ default: 'data-[active=true]:bg-sky-100',
121
+ web: 'data-[hover=true]:bg-sky-50 data-[active=true]:data-[hover=true]:bg-sky-100',
122
+ }),
123
+ ],
124
+ },
125
+ {
126
+ color: 'action',
127
+ mode: 'dark',
128
+ className: [
129
+ Platform.select({
130
+ default: 'data-[active=true]:bg-slate-700',
131
+ web: 'data-[hover=true]:bg-slate-800 data-[active=true]:data-[hover=true]:bg-slate-700',
132
+ }),
133
+ ],
134
+ },
135
+ {
136
+ color: 'danger',
137
+ mode: 'dark',
138
+ className: [
139
+ Platform.select({
140
+ default: 'data-[active=true]:bg-red-950',
141
+ web: 'data-[hover=true]:bg-red-950/50 data-[active=true]:data-[hover=true]:bg-red-950',
142
+ }),
143
+ ],
144
+ },
145
+ {
146
+ color: 'warning',
147
+ mode: 'dark',
148
+ className: [
149
+ Platform.select({
150
+ default: 'data-[active=true]:bg-amber-950',
151
+ web: 'data-[hover=true]:bg-amber-950/50 data-[active=true]:data-[hover=true]:bg-amber-950',
152
+ }),
153
+ ],
154
+ },
155
+ {
156
+ color: 'success',
157
+ mode: 'dark',
158
+ className: [
159
+ Platform.select({
160
+ default: 'data-[active=true]:bg-green-950',
161
+ web: 'data-[hover=true]:bg-green-950/50 data-[active=true]:data-[hover=true]:bg-green-950',
162
+ }),
163
+ ],
164
+ },
165
+ {
166
+ color: 'info',
167
+ mode: 'dark',
168
+ className: [
169
+ Platform.select({
170
+ default: 'data-[active=true]:bg-sky-950',
171
+ web: 'data-[hover=true]:bg-sky-950/50 data-[active=true]:data-[hover=true]:bg-sky-950',
172
+ }),
173
+ ],
174
+ },
175
+ ];
176
+
177
+ /** Foreground on filled controls (maps to Button `strong`, IconButton `solid`). */
178
+ export const sharedFilledForegroundTextCompounds: {
179
+ color: SharedButtonSemanticColor;
180
+ mode?: 'dark';
181
+ className: string | string[];
182
+ }[] = [
183
+ { color: 'action', className: 'text-white' },
184
+ { color: 'danger', className: 'text-white' },
185
+ { color: 'warning', className: 'text-white' },
186
+ { color: 'success', className: 'text-white' },
187
+ { color: 'info', className: 'text-white' },
188
+ { color: 'action', mode: 'dark', className: 'text-slate-900' },
189
+ ];
190
+
191
+ /**
192
+ * Foreground for transparent controls: same class names for Button `outline` and `ghost`, and for IconButton `ghost`.
193
+ * Consumers attach their own `variant` key(s).
194
+ */
195
+ export const sharedOutlineGhostForegroundTextCompounds: {
196
+ color: SharedButtonSemanticColor;
197
+ mode?: 'dark';
198
+ className: string | string[];
199
+ }[] = [
200
+ {
201
+ color: 'action',
202
+ className: [
203
+ 'text-slate-900',
204
+ Platform.select({
205
+ default: 'data-[active=true]:text-slate-700',
206
+ web: 'data-[hover=true]:text-slate-800 data-[active=true]:data-[hover=true]:text-slate-700',
207
+ }),
208
+ ],
209
+ },
210
+ {
211
+ color: 'danger',
212
+ className: [
213
+ 'text-red-600',
214
+ Platform.select({
215
+ default: 'data-[active=true]:text-red-800',
216
+ web: 'data-[hover=true]:text-red-700 data-[active=true]:data-[hover=true]:text-red-800',
217
+ }),
218
+ ],
219
+ },
220
+ {
221
+ color: 'warning',
222
+ className: [
223
+ 'text-amber-600',
224
+ Platform.select({
225
+ default: 'data-[active=true]:text-amber-800',
226
+ web: 'data-[hover=true]:text-amber-700 data-[active=true]:data-[hover=true]:text-amber-800',
227
+ }),
228
+ ],
229
+ },
230
+ {
231
+ color: 'success',
232
+ className: [
233
+ 'text-green-600',
234
+ Platform.select({
235
+ default: 'data-[active=true]:text-green-800',
236
+ web: 'data-[hover=true]:text-green-700 data-[active=true]:data-[hover=true]:text-green-800',
237
+ }),
238
+ ],
239
+ },
240
+ {
241
+ color: 'info',
242
+ className: [
243
+ 'text-sky-600',
244
+ Platform.select({
245
+ default: 'data-[active=true]:text-sky-800',
246
+ web: 'data-[hover=true]:text-sky-700 data-[active=true]:data-[hover=true]:text-sky-800',
247
+ }),
248
+ ],
249
+ },
250
+ {
251
+ color: 'action',
252
+ mode: 'dark',
253
+ className: [
254
+ 'text-white',
255
+ Platform.select({
256
+ default: 'data-[active=true]:text-white',
257
+ web: 'data-[hover=true]:text-white data-[active=true]:data-[hover=true]:text-white',
258
+ }),
259
+ ],
260
+ },
261
+ {
262
+ color: 'danger',
263
+ mode: 'dark',
264
+ className: 'text-red-400',
265
+ },
266
+ {
267
+ color: 'warning',
268
+ mode: 'dark',
269
+ className: 'text-amber-400',
270
+ },
271
+ {
272
+ color: 'success',
273
+ mode: 'dark',
274
+ className: 'text-green-400',
275
+ },
276
+ {
277
+ color: 'info',
278
+ mode: 'dark',
279
+ className: 'text-sky-400',
280
+ },
281
+ ];
@@ -5,9 +5,36 @@ import {
5
5
  DISABLED_CURSOR,
6
6
  DISABLED_OPACITY,
7
7
  RADIUS_SM,
8
- SEMANTIC_COLORS,
9
8
  TRANSITION_COLORS,
10
9
  } from '../../styles/primitives';
10
+ import {
11
+ sharedFilledForegroundTextCompounds,
12
+ sharedFilledSurfaceCompounds,
13
+ sharedGhostSurfaceCompounds,
14
+ sharedOutlineGhostForegroundTextCompounds,
15
+ } from './buttonSharedVariants';
16
+
17
+ const buttonStrongSurfaceCompounds = sharedFilledSurfaceCompounds.map((c) => ({
18
+ variant: 'strong' as const,
19
+ ...c,
20
+ }));
21
+
22
+ const buttonGhostSurfaceCompounds = sharedGhostSurfaceCompounds.map((c) => ({
23
+ variant: 'ghost' as const,
24
+ ...c,
25
+ }));
26
+
27
+ const buttonStrongForegroundTextCompounds = sharedFilledForegroundTextCompounds.map((c) => ({
28
+ variant: 'strong' as const,
29
+ ...c,
30
+ }));
31
+
32
+ const buttonOutlineGhostForegroundTextCompounds = sharedOutlineGhostForegroundTextCompounds.map(
33
+ (c) => ({
34
+ variant: ['outline', 'ghost'] as ('outline' | 'ghost')[],
35
+ ...c,
36
+ }),
37
+ );
11
38
 
12
39
  // TODO: Split into 2 files
13
40
  // TODO: Create cva wrapper
@@ -59,76 +86,7 @@ export const buttonRootVariants = cva(
59
86
  },
60
87
  },
61
88
  compoundVariants: [
62
- // --- strong × color (light mode) ---
63
- {
64
- variant: 'strong',
65
- color: 'action',
66
- className: [
67
- SEMANTIC_COLORS.action.bg,
68
- Platform.select({
69
- default: 'data-[active=true]:bg-slate-700',
70
- web: 'data-[hover=true]:bg-slate-800 data-[active=true]:data-[hover=true]:bg-slate-700',
71
- }),
72
- ],
73
- },
74
- {
75
- variant: 'strong',
76
- color: 'danger',
77
- className: [
78
- SEMANTIC_COLORS.danger.bg,
79
- Platform.select({
80
- default: 'data-[active=true]:bg-red-800',
81
- web: 'data-[hover=true]:bg-red-700 data-[active=true]:data-[hover=true]:bg-red-800',
82
- }),
83
- ],
84
- },
85
- {
86
- variant: 'strong',
87
- color: 'warning',
88
- className: [
89
- SEMANTIC_COLORS.warning.bg,
90
- Platform.select({
91
- default: 'data-[active=true]:bg-amber-700',
92
- web: 'data-[hover=true]:bg-amber-600 data-[active=true]:data-[hover=true]:bg-amber-700',
93
- }),
94
- ],
95
- },
96
- {
97
- variant: 'strong',
98
- color: 'success',
99
- className: [
100
- SEMANTIC_COLORS.success.bg,
101
- Platform.select({
102
- default: 'data-[active=true]:bg-green-800',
103
- web: 'data-[hover=true]:bg-green-700 data-[active=true]:data-[hover=true]:bg-green-800',
104
- }),
105
- ],
106
- },
107
- {
108
- variant: 'strong',
109
- color: 'info',
110
- className: [
111
- SEMANTIC_COLORS.info.bg,
112
- Platform.select({
113
- default: 'data-[active=true]:bg-sky-700',
114
- web: 'data-[hover=true]:bg-sky-600 data-[active=true]:data-[hover=true]:bg-sky-700',
115
- }),
116
- ],
117
- },
118
-
119
- // --- strong × action × mode: dark ---
120
- {
121
- variant: 'strong',
122
- color: 'action',
123
- mode: 'dark',
124
- className: [
125
- 'bg-slate-200',
126
- Platform.select({
127
- default: 'data-[active=true]:bg-slate-400',
128
- web: 'data-[hover=true]:bg-slate-300 data-[active=true]:data-[hover=true]:bg-slate-400',
129
- }),
130
- ],
131
- },
89
+ ...buttonStrongSurfaceCompounds,
132
90
 
133
91
  // --- outline × color (light mode) ---
134
92
  {
@@ -250,105 +208,7 @@ export const buttonRootVariants = cva(
250
208
  ],
251
209
  },
252
210
 
253
- // --- ghost × color (light mode, non-action) ---
254
- {
255
- variant: 'ghost',
256
- color: 'danger',
257
- className: [
258
- Platform.select({
259
- default: 'data-[active=true]:bg-red-100',
260
- web: 'data-[hover=true]:bg-red-50 data-[active=true]:data-[hover=true]:bg-red-100',
261
- }),
262
- ],
263
- },
264
- {
265
- variant: 'ghost',
266
- color: 'warning',
267
- className: [
268
- Platform.select({
269
- default: 'data-[active=true]:bg-amber-100',
270
- web: 'data-[hover=true]:bg-amber-50 data-[active=true]:data-[hover=true]:bg-amber-100',
271
- }),
272
- ],
273
- },
274
- {
275
- variant: 'ghost',
276
- color: 'success',
277
- className: [
278
- Platform.select({
279
- default: 'data-[active=true]:bg-green-100',
280
- web: 'data-[hover=true]:bg-green-50 data-[active=true]:data-[hover=true]:bg-green-100',
281
- }),
282
- ],
283
- },
284
- {
285
- variant: 'ghost',
286
- color: 'info',
287
- className: [
288
- Platform.select({
289
- default: 'data-[active=true]:bg-sky-100',
290
- web: 'data-[hover=true]:bg-sky-50 data-[active=true]:data-[hover=true]:bg-sky-100',
291
- }),
292
- ],
293
- },
294
-
295
- // --- ghost × action × mode: dark ---
296
- {
297
- variant: 'ghost',
298
- color: 'action',
299
- mode: 'dark',
300
- className: [
301
- Platform.select({
302
- default: 'data-[active=true]:bg-slate-700',
303
- web: 'data-[hover=true]:bg-slate-800 data-[active=true]:data-[hover=true]:bg-slate-700',
304
- }),
305
- ],
306
- },
307
- // --- ghost × semantic colors × mode: dark ---
308
- {
309
- variant: 'ghost',
310
- color: 'danger',
311
- mode: 'dark',
312
- className: [
313
- Platform.select({
314
- default: 'data-[active=true]:bg-red-950',
315
- web: 'data-[hover=true]:bg-red-950/50 data-[active=true]:data-[hover=true]:bg-red-950',
316
- }),
317
- ],
318
- },
319
- {
320
- variant: 'ghost',
321
- color: 'warning',
322
- mode: 'dark',
323
- className: [
324
- Platform.select({
325
- default: 'data-[active=true]:bg-amber-950',
326
- web: 'data-[hover=true]:bg-amber-950/50 data-[active=true]:data-[hover=true]:bg-amber-950',
327
- }),
328
- ],
329
- },
330
- {
331
- variant: 'ghost',
332
- color: 'success',
333
- mode: 'dark',
334
- className: [
335
- Platform.select({
336
- default: 'data-[active=true]:bg-green-950',
337
- web: 'data-[hover=true]:bg-green-950/50 data-[active=true]:data-[hover=true]:bg-green-950',
338
- }),
339
- ],
340
- },
341
- {
342
- variant: 'ghost',
343
- color: 'info',
344
- mode: 'dark',
345
- className: [
346
- Platform.select({
347
- default: 'data-[active=true]:bg-sky-950',
348
- web: 'data-[hover=true]:bg-sky-950/50 data-[active=true]:data-[hover=true]:bg-sky-950',
349
- }),
350
- ],
351
- },
211
+ ...buttonGhostSurfaceCompounds,
352
212
  ],
353
213
  defaultVariants: {
354
214
  variant: 'strong',
@@ -384,111 +244,8 @@ export const buttonTextVariants = cva(['font-medium', 'text-center'], {
384
244
  },
385
245
  },
386
246
  compoundVariants: [
387
- // --- strong × color (light mode) — always white text ---
388
- { variant: 'strong', color: 'action', className: 'text-white' },
389
- { variant: 'strong', color: 'danger', className: 'text-white' },
390
- { variant: 'strong', color: 'warning', className: 'text-white' },
391
- { variant: 'strong', color: 'success', className: 'text-white' },
392
- { variant: 'strong', color: 'info', className: 'text-white' },
393
-
394
- // --- strong × action × mode: dark ---
395
- { variant: 'strong', color: 'action', mode: 'dark', className: 'text-slate-900' },
396
-
397
- // --- outline/ghost × color (light mode text) ---
398
- {
399
- variant: ['outline', 'ghost'],
400
- color: 'action',
401
- className: [
402
- 'text-slate-900',
403
- Platform.select({
404
- default: 'data-[active=true]:text-slate-700',
405
- web: 'data-[hover=true]:text-slate-800 data-[active=true]:data-[hover=true]:text-slate-700',
406
- }),
407
- ],
408
- },
409
- {
410
- variant: ['outline', 'ghost'],
411
- color: 'danger',
412
- className: [
413
- 'text-red-600',
414
- Platform.select({
415
- default: 'data-[active=true]:text-red-800',
416
- web: 'data-[hover=true]:text-red-700 data-[active=true]:data-[hover=true]:text-red-800',
417
- }),
418
- ],
419
- },
420
- {
421
- variant: ['outline', 'ghost'],
422
- color: 'warning',
423
- className: [
424
- 'text-amber-600',
425
- Platform.select({
426
- default: 'data-[active=true]:text-amber-800',
427
- web: 'data-[hover=true]:text-amber-700 data-[active=true]:data-[hover=true]:text-amber-800',
428
- }),
429
- ],
430
- },
431
- {
432
- variant: ['outline', 'ghost'],
433
- color: 'success',
434
- className: [
435
- 'text-green-600',
436
- Platform.select({
437
- default: 'data-[active=true]:text-green-800',
438
- web: 'data-[hover=true]:text-green-700 data-[active=true]:data-[hover=true]:text-green-800',
439
- }),
440
- ],
441
- },
442
- {
443
- variant: ['outline', 'ghost'],
444
- color: 'info',
445
- className: [
446
- 'text-sky-600',
447
- Platform.select({
448
- default: 'data-[active=true]:text-sky-800',
449
- web: 'data-[hover=true]:text-sky-700 data-[active=true]:data-[hover=true]:text-sky-800',
450
- }),
451
- ],
452
- },
453
-
454
- // --- outline/ghost × action × mode: dark ---
455
- {
456
- variant: ['outline', 'ghost'],
457
- color: 'action',
458
- mode: 'dark',
459
- className: [
460
- 'text-white',
461
- Platform.select({
462
- default: 'data-[active=true]:text-white',
463
- web: 'data-[hover=true]:text-white data-[active=true]:data-[hover=true]:text-white',
464
- }),
465
- ],
466
- },
467
- // --- outline/ghost × semantic colors × mode: dark ---
468
- {
469
- variant: ['outline', 'ghost'],
470
- color: 'danger',
471
- mode: 'dark',
472
- className: 'text-red-400',
473
- },
474
- {
475
- variant: ['outline', 'ghost'],
476
- color: 'warning',
477
- mode: 'dark',
478
- className: 'text-amber-400',
479
- },
480
- {
481
- variant: ['outline', 'ghost'],
482
- color: 'success',
483
- mode: 'dark',
484
- className: 'text-green-400',
485
- },
486
- {
487
- variant: ['outline', 'ghost'],
488
- color: 'info',
489
- mode: 'dark',
490
- className: 'text-sky-400',
491
- },
247
+ ...buttonStrongForegroundTextCompounds,
248
+ ...buttonOutlineGhostForegroundTextCompounds,
492
249
  ],
493
250
  defaultVariants: {
494
251
  variant: 'strong',
@@ -0,0 +1,93 @@
1
+ import { forwardRef } from 'react';
2
+ import { ActivityIndicator, Pressable, Text, View, type PressableProps } from 'react-native';
3
+ import {
4
+ createButton,
5
+ dataAttributes,
6
+ type IButtonProps,
7
+ useButtonContext,
8
+ } from '@cdx-ui/primitives';
9
+ import type { CdxIcon } from '@cdx-ui/icons';
10
+ import { cn } from '@cdx-ui/utils';
11
+ import { Icon, type IconProps } from '../Icon';
12
+ import {
13
+ type IconButtonVariantProps,
14
+ iconButtonGlyphVariants,
15
+ iconButtonIconColorVariants,
16
+ iconButtonRootVariants,
17
+ } from './styles';
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: CdxIcon; 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
+ export interface IconButtonProps extends PressableProps, IButtonProps, IconButtonVariantProps {
45
+ className?: string;
46
+ /** CDX icon component to render (icon-only control). */
47
+ as: CdxIcon;
48
+ /** Passed through to the underlying `Icon`. */
49
+ iconClassName?: IconProps['className'];
50
+ }
51
+
52
+ const IconButtonRoot = forwardRef<View, IconButtonProps>(
53
+ (
54
+ {
55
+ variant = 'solid',
56
+ size = 'default',
57
+ mode = 'light',
58
+ className,
59
+ style,
60
+ as: IconComponent,
61
+ iconClassName,
62
+ accessibilityRole = 'button',
63
+ ...props
64
+ },
65
+ ref,
66
+ ) => {
67
+ const rootClassName = cn(iconButtonRootVariants({ variant, size, mode }), className);
68
+
69
+ const glyphClassName = cn(
70
+ iconButtonGlyphVariants({ size }),
71
+ iconButtonIconColorVariants({ variant, mode }),
72
+ iconClassName,
73
+ );
74
+
75
+ return (
76
+ <IconButtonPrimitive
77
+ ref={ref}
78
+ accessibilityRole={accessibilityRole}
79
+ className={rootClassName}
80
+ style={style}
81
+ {...props}
82
+ >
83
+ <IconButtonGlyph as={IconComponent} className={glyphClassName} />
84
+ </IconButtonPrimitive>
85
+ );
86
+ },
87
+ );
88
+
89
+ IconButtonRoot.displayName = 'IconButton';
90
+
91
+ export const IconButton = IconButtonRoot;
92
+
93
+ export type { IconButtonVariantProps };