@iclips/ui 2.0.3 → 3.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (130) hide show
  1. package/DESIGN.md +246 -0
  2. package/MIGRATION-v3.md +244 -0
  3. package/README.md +4 -0
  4. package/dist/alert-theme.css +20 -79
  5. package/dist/components/ui/charts/donut-chart.cjs +1 -1
  6. package/dist/components/ui/charts/donut-chart.cjs.map +1 -1
  7. package/dist/components/ui/charts/donut-chart.js +39 -60
  8. package/dist/components/ui/charts/donut-chart.js.map +1 -1
  9. package/dist/components/ui/charts/kpi-card.cjs +1 -1
  10. package/dist/components/ui/charts/kpi-card.cjs.map +1 -1
  11. package/dist/components/ui/charts/kpi-card.js +19 -19
  12. package/dist/components/ui/charts/kpi-card.js.map +1 -1
  13. package/dist/components/ui/data/comment-system.cjs +1 -1
  14. package/dist/components/ui/data/comment-system.cjs.map +1 -1
  15. package/dist/components/ui/data/comment-system.js +67 -67
  16. package/dist/components/ui/data/comment-system.js.map +1 -1
  17. package/dist/components/ui/data/data-table.cjs +1 -1
  18. package/dist/components/ui/data/data-table.cjs.map +1 -1
  19. package/dist/components/ui/data/data-table.js +112 -101
  20. package/dist/components/ui/data/data-table.js.map +1 -1
  21. package/dist/components/ui/data/editorial-calendar.cjs +1 -1
  22. package/dist/components/ui/data/editorial-calendar.cjs.map +1 -1
  23. package/dist/components/ui/data/editorial-calendar.js +291 -291
  24. package/dist/components/ui/data/editorial-calendar.js.map +1 -1
  25. package/dist/components/ui/data/filter-builder.cjs +1 -1
  26. package/dist/components/ui/data/filter-builder.cjs.map +1 -1
  27. package/dist/components/ui/data/filter-builder.js +1 -1
  28. package/dist/components/ui/data/filter-builder.js.map +1 -1
  29. package/dist/components/ui/feedback/empty-state.cjs +1 -1
  30. package/dist/components/ui/feedback/empty-state.cjs.map +1 -1
  31. package/dist/components/ui/feedback/empty-state.js +14 -14
  32. package/dist/components/ui/feedback/empty-state.js.map +1 -1
  33. package/dist/components/ui/feedback/toast.cjs +1 -1
  34. package/dist/components/ui/feedback/toast.cjs.map +1 -1
  35. package/dist/components/ui/feedback/toast.js +53 -22
  36. package/dist/components/ui/feedback/toast.js.map +1 -1
  37. package/dist/components/ui/forms/calendar.cjs +1 -1
  38. package/dist/components/ui/forms/calendar.cjs.map +1 -1
  39. package/dist/components/ui/forms/calendar.js +16 -16
  40. package/dist/components/ui/forms/calendar.js.map +1 -1
  41. package/dist/components/ui/forms/combobox.cjs +1 -1
  42. package/dist/components/ui/forms/combobox.cjs.map +1 -1
  43. package/dist/components/ui/forms/combobox.js +78 -76
  44. package/dist/components/ui/forms/combobox.js.map +1 -1
  45. package/dist/components/ui/forms/file-attachment-list.cjs +1 -1
  46. package/dist/components/ui/forms/file-attachment-list.cjs.map +1 -1
  47. package/dist/components/ui/forms/file-attachment-list.js +4 -4
  48. package/dist/components/ui/forms/file-attachment-list.js.map +1 -1
  49. package/dist/components/ui/forms/file-upload-zone.cjs +2 -2
  50. package/dist/components/ui/forms/file-upload-zone.cjs.map +1 -1
  51. package/dist/components/ui/forms/file-upload-zone.js +55 -49
  52. package/dist/components/ui/forms/file-upload-zone.js.map +1 -1
  53. package/dist/components/ui/forms/form.cjs +1 -1
  54. package/dist/components/ui/forms/form.cjs.map +1 -1
  55. package/dist/components/ui/forms/form.js +11 -11
  56. package/dist/components/ui/forms/form.js.map +1 -1
  57. package/dist/components/ui/forms/input-validation.cjs +1 -1
  58. package/dist/components/ui/forms/input-validation.cjs.map +1 -1
  59. package/dist/components/ui/forms/input-validation.js +20 -20
  60. package/dist/components/ui/forms/input-validation.js.map +1 -1
  61. package/dist/components/ui/forms/multi-select.cjs +1 -1
  62. package/dist/components/ui/forms/multi-select.cjs.map +1 -1
  63. package/dist/components/ui/forms/multi-select.js +69 -67
  64. package/dist/components/ui/forms/multi-select.js.map +1 -1
  65. package/dist/components/ui/forms/radio-group.cjs +1 -1
  66. package/dist/components/ui/forms/radio-group.cjs.map +1 -1
  67. package/dist/components/ui/forms/radio-group.js +19 -19
  68. package/dist/components/ui/forms/radio-group.js.map +1 -1
  69. package/dist/components/ui/forms/social-button.cjs +1 -1
  70. package/dist/components/ui/forms/social-button.cjs.map +1 -1
  71. package/dist/components/ui/forms/social-button.js +6 -6
  72. package/dist/components/ui/forms/social-button.js.map +1 -1
  73. package/dist/components/ui/forms/toggle.cjs +1 -1
  74. package/dist/components/ui/forms/toggle.cjs.map +1 -1
  75. package/dist/components/ui/forms/toggle.js +7 -7
  76. package/dist/components/ui/forms/toggle.js.map +1 -1
  77. package/dist/components/ui/navigation/navigation-menu.cjs +1 -1
  78. package/dist/components/ui/navigation/navigation-menu.cjs.map +1 -1
  79. package/dist/components/ui/navigation/navigation-menu.js +14 -14
  80. package/dist/components/ui/navigation/navigation-menu.js.map +1 -1
  81. package/dist/components/ui/navigation/sidebar.cjs +1 -1
  82. package/dist/components/ui/navigation/sidebar.cjs.map +1 -1
  83. package/dist/components/ui/navigation/sidebar.js +44 -44
  84. package/dist/components/ui/navigation/sidebar.js.map +1 -1
  85. package/dist/components/ui/overlays/context-menu.cjs +1 -1
  86. package/dist/components/ui/overlays/context-menu.cjs.map +1 -1
  87. package/dist/components/ui/overlays/context-menu.js +1 -1
  88. package/dist/components/ui/overlays/context-menu.js.map +1 -1
  89. package/dist/components/ui/overlays/dropdown-menu.cjs +1 -1
  90. package/dist/components/ui/overlays/dropdown-menu.cjs.map +1 -1
  91. package/dist/components/ui/overlays/dropdown-menu.js +5 -5
  92. package/dist/components/ui/overlays/dropdown-menu.js.map +1 -1
  93. package/dist/components/ui/overlays/menubar.cjs +1 -1
  94. package/dist/components/ui/overlays/menubar.cjs.map +1 -1
  95. package/dist/components/ui/overlays/menubar.js +29 -29
  96. package/dist/components/ui/overlays/menubar.js.map +1 -1
  97. package/dist/components/ui/overlays/tooltip.cjs +1 -1
  98. package/dist/components/ui/overlays/tooltip.cjs.map +1 -1
  99. package/dist/components/ui/overlays/tooltip.js +12 -12
  100. package/dist/components/ui/overlays/tooltip.js.map +1 -1
  101. package/dist/components/ui/primitives/avatar.cjs +1 -1
  102. package/dist/components/ui/primitives/avatar.cjs.map +1 -1
  103. package/dist/components/ui/primitives/avatar.js +20 -27
  104. package/dist/components/ui/primitives/avatar.js.map +1 -1
  105. package/dist/components/ui/primitives/badge.cjs +1 -1
  106. package/dist/components/ui/primitives/badge.cjs.map +1 -1
  107. package/dist/components/ui/primitives/badge.js +21 -18
  108. package/dist/components/ui/primitives/badge.js.map +1 -1
  109. package/dist/components/ui/primitives/button.cjs +1 -1
  110. package/dist/components/ui/primitives/button.cjs.map +1 -1
  111. package/dist/components/ui/primitives/button.js +11 -8
  112. package/dist/components/ui/primitives/button.js.map +1 -1
  113. package/dist/index.cjs +1 -1
  114. package/dist/index.css +1 -1
  115. package/dist/index.d.cts +6 -6
  116. package/dist/index.d.ts +6 -6
  117. package/dist/index.js +34 -35
  118. package/dist/index.js.map +1 -1
  119. package/dist/preset.css +1 -2
  120. package/dist/toast-theme.css +100 -64
  121. package/dist/tokens.css +59 -159
  122. package/docs/README.md +44 -0
  123. package/docs/acoes.md +103 -0
  124. package/docs/escolha.md +171 -0
  125. package/docs/formularios.md +137 -0
  126. package/docs/mensagens.md +114 -0
  127. package/docs/overlays.md +192 -0
  128. package/docs/status.md +71 -0
  129. package/package.json +7 -3
  130. package/scripts/check-colors.mjs +208 -0
package/dist/tokens.css CHANGED
@@ -11,8 +11,9 @@
11
11
  :root {
12
12
  --font-size: 16px;
13
13
 
14
- /* Custom Color Palette - Base Colors */
15
- /* Grays */
14
+ /* Paleta iClips — só o que algum token semântico usa. Primitivos não viram
15
+ classe (o @theme só mapeia semânticos): escreva bg-primary, nunca bg-purple-500 (check-colors-ignore). */
16
+ /* Neutros — estrutura */
16
17
  --gray-50: #F2F6FA;
17
18
  --gray-100: #E9EEF5;
18
19
  --gray-200: #DAE1EB;
@@ -24,79 +25,23 @@
24
25
  --gray-800: #1A1F26;
25
26
  --gray-900: #000000;
26
27
  --white: #FFFFFF;
27
-
28
- /* Purple (Primary Brand Color) */
28
+
29
+ /* Roxo — ação (exclusivo) */
29
30
  --purple-50: #F6E9FF;
30
31
  --purple-100: #DAA6FF;
31
32
  --purple-200: #BB6DF2;
33
+ --purple-300: #A855E0;
34
+ --purple-400: #913DD0;
32
35
  --purple-500: #7F26BF;
33
- --purple-600: #5B158C;
34
36
  --purple-700: #420F66;
35
-
36
- /* Blue */
37
- --blue-50: #E2E9FF;
38
- --blue-100: #AABCF2;
39
- --blue-200: #667FCC;
40
- --blue-500: #1C2F8C;
41
- --blue-600: #0F1E66;
42
- --blue-700: #061040;
43
-
44
- /* Cyan */
45
- --cyan-50: #D8EFFF;
46
- --cyan-100: #8CCFFF;
47
- --cyan-200: #3DA7F2;
48
- --cyan-500: #0086E6;
49
- --cyan-600: #0053A6;
50
- --cyan-700: #003066;
51
-
52
- /* Teal */
53
- --teal-50: #D4F5F5;
54
- --teal-100: #9DF2F2;
55
- --teal-200: #5CE6E6;
56
- --teal-500: #14CCCC;
57
- --teal-600: #00A7A7;
58
- --teal-700: #045659;
59
-
60
- /* Green */
61
- --green-50: #D3FBDD;
62
- --green-100: #91F2AA;
63
- --green-200: #57D977;
64
- --green-500: #24B347;
65
- --green-600: #007F2A;
66
- --green-700: #004D19;
67
-
68
- /* Yellow */
69
- --yellow-50: #FFF7CC;
70
- --yellow-100: #FFDD99;
71
- --yellow-200: #FFC859;
72
- --yellow-500: #FAB325;
73
- --yellow-600: #E6960B;
74
- --yellow-700: #CC7C04;
75
-
76
- /* Orange */
77
- --orange-50: #FFECE1;
78
- --orange-100: #FFB68C;
79
- --orange-200: #FF8E4C;
80
- --orange-500: #F26924;
81
- --orange-600: #E64D0B;
82
- --orange-700: #BF3000;
83
-
84
- /* Red */
85
- --red-50: #FFE9EC;
86
- --red-100: #FFB2B9;
87
- --red-200: #FF5967;
88
- --red-500: #F22435;
89
- --red-600: #CC0A1A;
90
- --red-700: #99000D;
91
-
92
- /* Pink */
93
- --pink-50: #FFECF9;
94
- --pink-100: #FFB2E8;
95
- --pink-200: #FF66CC;
96
- --pink-500: #E62EA8;
97
- --pink-600: #BF0A89;
98
- --pink-700: #99086D;
99
-
37
+
38
+ /* Estado — feedback, nunca decoração */
39
+ --red-600: #AB4A43;
40
+ --green-600: #427748;
41
+ --yellow-500: #E4BB78;
42
+ --yellow-600: #CFA066;
43
+ --cyan-600: #315687;
44
+
100
45
  /* Semantic Colors - Light Mode */
101
46
  --background: var(--white);
102
47
  --foreground: var(--gray-800);
@@ -112,8 +57,8 @@
112
57
  /* gray-600 (não gray-500): passa AA também sobre `bg-muted`/`bg-accent`
113
58
  (gray-500 dava ~4:1 sobre gray-100). No dark segue gray-300. */
114
59
  --muted-foreground: var(--gray-600);
115
- --accent: var(--purple-50);
116
- --accent-foreground: var(--purple-600);
60
+ --accent: var(--gray-100);
61
+ --accent-foreground: var(--foreground);
117
62
  --destructive: var(--red-600);
118
63
  --destructive-foreground: var(--white);
119
64
  --success: var(--green-600);
@@ -156,13 +101,13 @@
156
101
 
157
102
  /* Charts - Acessibilidade melhorada com Balanceamento Óptico */
158
103
  --chart-1: var(--purple-500); /* Brand Color (Vibrante) */
159
- --chart-2: var(--cyan-600); /* Darkened for contrast */
160
- --chart-3: var(--green-600); /* Darkened for contrast */
161
- --chart-4: var(--orange-600); /* Darkened for contrast */
162
- --chart-5: var(--pink-600); /* Darkened for contrast */
163
- --chart-6: var(--blue-600); /* Darkened for contrast */
164
- --chart-7: var(--teal-600); /* Darkened for contrast */
165
- --chart-8: var(--yellow-600); /* Darkened for contrast */
104
+ --chart-2: var(--gray-400); /* 500: separa de chart-1 em luminância */
105
+ --chart-3: var(--purple-700); /* Darkened for contrast */
106
+ --chart-4: var(--purple-200); /* Darkened for contrast */
107
+ --chart-5: var(--gray-600); /* Darkened for contrast */
108
+ --chart-6: var(--purple-100); /* 200: separa de chart-2 (eram dois azul-marinho) */
109
+ --chart-7: var(--gray-700); /* Darkened for contrast */
110
+ --chart-8: var(--purple-300); /* Darkened for contrast */
166
111
 
167
112
  /* Border Radius */
168
113
  --radius: 0.625rem;
@@ -172,8 +117,10 @@
172
117
  --sidebar-foreground: var(--gray-800);
173
118
  --sidebar-primary: var(--purple-500);
174
119
  --sidebar-primary-foreground: var(--white);
175
- --sidebar-accent: var(--purple-50);
176
- --sidebar-accent-foreground: var(--purple-700);
120
+ --sidebar-accent: var(--gray-100);
121
+ --sidebar-accent-foreground: var(--sidebar-foreground);
122
+ --sidebar-selected: var(--purple-50);
123
+ --sidebar-selected-foreground: var(--purple-700);
177
124
  --sidebar-border: var(--gray-200);
178
125
  --sidebar-ring: var(--purple-500);
179
126
 
@@ -229,14 +176,14 @@
229
176
  --card-foreground: var(--gray-50);
230
177
  --popover: var(--gray-700);
231
178
  --popover-foreground: var(--gray-50);
232
- --primary: var(--purple-200);
179
+ --primary: var(--purple-100);
233
180
  --primary-foreground: var(--gray-900);
234
- --secondary: var(--gray-700);
235
- --secondary-foreground: var(--gray-50);
181
+ --secondary: var(--purple-700);
182
+ --secondary-foreground: var(--purple-100);
236
183
  --muted: var(--gray-600);
237
184
  --muted-foreground: var(--gray-300);
238
- --accent: var(--purple-700);
239
- --accent-foreground: var(--purple-100);
185
+ --accent: var(--gray-600);
186
+ --accent-foreground: var(--gray-50);
240
187
  --destructive: var(--red-600);
241
188
  --destructive-foreground: var(--white);
242
189
  --success: var(--green-600);
@@ -245,6 +192,15 @@
245
192
  --warning-foreground: var(--gray-800);
246
193
  --info: var(--cyan-600);
247
194
  --info-foreground: var(--white);
195
+ /* Redeclarados aqui porque var() dentro de custom property resolve onde é
196
+ declarada: sem isso, um .dark que não esteja no <html> herda a mistura do
197
+ :root, feita com o --foreground claro. 80% também não passa AA sobre
198
+ popover/card escuros; 45% passa até sobre o tint de foco (bg-<token>/20).
199
+ warning mantém 32%, que já passa. */
200
+ --success-emphasis: color-mix(in oklab, var(--success) 45%, var(--foreground));
201
+ --info-emphasis: color-mix(in oklab, var(--info) 45%, var(--foreground));
202
+ --destructive-emphasis: color-mix(in oklab, var(--destructive) 45%, var(--foreground));
203
+ --warning-emphasis: color-mix(in oklab, var(--warning) 32%, var(--foreground));
248
204
  --border: var(--gray-600);
249
205
  --input: var(--gray-600);
250
206
  --input-background: var(--gray-700);
@@ -253,13 +209,13 @@
253
209
 
254
210
  /* Charts - Dark Mode */
255
211
  --chart-1: var(--purple-200);
256
- --chart-2: var(--cyan-200);
257
- --chart-3: var(--green-200);
258
- --chart-4: var(--orange-200);
259
- --chart-5: var(--pink-200);
260
- --chart-6: var(--blue-200);
261
- --chart-7: var(--teal-200);
262
- --chart-8: var(--yellow-200);
212
+ --chart-2: var(--gray-50);
213
+ --chart-3: var(--purple-300);
214
+ --chart-4: var(--purple-50);
215
+ --chart-5: var(--purple-400);
216
+ --chart-6: var(--gray-100);
217
+ --chart-7: var(--gray-500);
218
+ --chart-8: var(--gray-200);
263
219
 
264
220
  /* Sidebar - Dark Mode */
265
221
  --sidebar: var(--gray-800);
@@ -267,7 +223,9 @@
267
223
  --sidebar-primary: var(--purple-200);
268
224
  --sidebar-primary-foreground: var(--gray-900);
269
225
  --sidebar-accent: var(--gray-700);
270
- --sidebar-accent-foreground: var(--purple-100);
226
+ --sidebar-accent-foreground: var(--gray-50);
227
+ --sidebar-selected: var(--purple-700);
228
+ --sidebar-selected-foreground: var(--purple-100);
271
229
  --sidebar-border: var(--gray-600);
272
230
  --sidebar-ring: var(--purple-200);
273
231
  }
@@ -299,6 +257,11 @@
299
257
  }
300
258
 
301
259
  @theme inline {
260
+ --color-*: initial;
261
+ /* ↑ só tokens semânticos viram classe: zera a paleta padrão do Tailwind. */
262
+ --color-white: #FFFFFF;
263
+ --color-black: #000000;
264
+
302
265
  /* Typography */
303
266
  --font-sans: var(--font-sans);
304
267
 
@@ -358,6 +321,8 @@
358
321
  --color-sidebar-primary-foreground: var(--sidebar-primary-foreground);
359
322
  --color-sidebar-accent: var(--sidebar-accent);
360
323
  --color-sidebar-accent-foreground: var(--sidebar-accent-foreground);
324
+ --color-sidebar-selected: var(--sidebar-selected);
325
+ --color-sidebar-selected-foreground: var(--sidebar-selected-foreground);
361
326
  --color-sidebar-border: var(--sidebar-border);
362
327
  --color-sidebar-ring: var(--sidebar-ring);
363
328
 
@@ -403,69 +368,4 @@
403
368
  --spacing-inline-sm: var(--space-inline-sm);
404
369
  --spacing-inline-md: var(--space-inline-md);
405
370
  --spacing-inline-lg: var(--space-inline-lg);
406
-
407
- /* Raw Color Palette */
408
- --color-gray-50: var(--gray-50);
409
- --color-gray-100: var(--gray-100);
410
- --color-gray-200: var(--gray-200);
411
- --color-gray-300: var(--gray-300);
412
- --color-gray-400: var(--gray-400);
413
- --color-gray-500: var(--gray-500);
414
- --color-gray-600: var(--gray-600);
415
- --color-gray-700: var(--gray-700);
416
- --color-gray-800: var(--gray-800);
417
- --color-purple-50: var(--purple-50);
418
- --color-purple-100: var(--purple-100);
419
- --color-purple-200: var(--purple-200);
420
- --color-purple-500: var(--purple-500);
421
- --color-purple-600: var(--purple-600);
422
- --color-purple-700: var(--purple-700);
423
- --color-blue-50: var(--blue-50);
424
- --color-blue-100: var(--blue-100);
425
- --color-blue-200: var(--blue-200);
426
- --color-blue-500: var(--blue-500);
427
- --color-blue-600: var(--blue-600);
428
- --color-blue-700: var(--blue-700);
429
- --color-cyan-50: var(--cyan-50);
430
- --color-cyan-100: var(--cyan-100);
431
- --color-cyan-200: var(--cyan-200);
432
- --color-cyan-500: var(--cyan-500);
433
- --color-cyan-600: var(--cyan-600);
434
- --color-cyan-700: var(--cyan-700);
435
- --color-teal-50: var(--teal-50);
436
- --color-teal-100: var(--teal-100);
437
- --color-teal-200: var(--teal-200);
438
- --color-teal-500: var(--teal-500);
439
- --color-teal-600: var(--teal-600);
440
- --color-teal-700: var(--teal-700);
441
- --color-green-50: var(--green-50);
442
- --color-green-100: var(--green-100);
443
- --color-green-200: var(--green-200);
444
- --color-green-500: var(--green-500);
445
- --color-green-600: var(--green-600);
446
- --color-green-700: var(--green-700);
447
- --color-yellow-50: var(--yellow-50);
448
- --color-yellow-100: var(--yellow-100);
449
- --color-yellow-200: var(--yellow-200);
450
- --color-yellow-500: var(--yellow-500);
451
- --color-yellow-600: var(--yellow-600);
452
- --color-yellow-700: var(--yellow-700);
453
- --color-orange-50: var(--orange-50);
454
- --color-orange-100: var(--orange-100);
455
- --color-orange-200: var(--orange-200);
456
- --color-orange-500: var(--orange-500);
457
- --color-orange-600: var(--orange-600);
458
- --color-orange-700: var(--orange-700);
459
- --color-red-50: var(--red-50);
460
- --color-red-100: var(--red-100);
461
- --color-red-200: var(--red-200);
462
- --color-red-500: var(--red-500);
463
- --color-red-600: var(--red-600);
464
- --color-red-700: var(--red-700);
465
- --color-pink-50: var(--pink-50);
466
- --color-pink-100: var(--pink-100);
467
- --color-pink-200: var(--pink-200);
468
- --color-pink-500: var(--pink-500);
469
- --color-pink-600: var(--pink-600);
470
- --color-pink-700: var(--pink-700);
471
371
  }
package/docs/README.md ADDED
@@ -0,0 +1,44 @@
1
+ # @iclips/ui — como usar
2
+
3
+ Leia isto antes de montar uma tela com a `@iclips/ui`. Os guias abaixo dizem **qual componente usar em cada situação** e trazem código pronto para copiar. Eles vêm no pacote, então descrevem exatamente a versão instalada.
4
+
5
+ Todo import vem do barrel: `import { Button } from "@iclips/ui"`. Os componentes de edição rica (`DocumentEditor`, `CommentSystem`, `EditorialCalendar`, `MentionList`) vêm de `@iclips/ui/editor`. Importe `@iclips/ui/styles.css` uma vez na raiz do app.
6
+
7
+ ## Guias
8
+
9
+ - [Ações e navegação](acoes.md) — botão, link ou ícone; hierarquia de variantes.
10
+ - [Escolha em lista](escolha.md) — Select, Combobox, RadioGroup, Checkbox, Switch, ToggleGroup.
11
+ - [Formulários](formularios.md) — anatomia do campo, validação, layout, react-hook-form.
12
+ - [Mensagens ao usuário](mensagens.md) — erro de campo, Alert, Toast, AlertDialog.
13
+ - [Overlays](overlays.md) — Tooltip, HoverCard, Popover, Dialog, AlertDialog, Sheet, Drawer.
14
+ - [Status](status.md) — badge de status, valor positivo/negativo.
15
+ - [Linguagem visual](../DESIGN.md) — as quatro camadas de cor, tipografia, raio, botões e superfícies.
16
+
17
+ ## Troque isto por aquilo
18
+
19
+ As classes cruas da paleta do Tailwind **não geram CSS** na `@iclips/ui` 3.x: o elemento fica sem cor, em silêncio. Use o token semântico ou o componente.
20
+
21
+ | Em vez de | Use |
22
+ | --- | --- |
23
+ | `text-gray-500` | `text-muted-foreground` |
24
+ | `text-gray-600` | `text-muted-foreground` |
25
+ | `text-gray-900` | `text-foreground` |
26
+ | `border-gray-200` | `border-border` |
27
+ | `border-gray-300` | `border-input` |
28
+ | `text-red-500` | `text-destructive-emphasis` |
29
+ | `text-green-500` | `text-success-emphasis` |
30
+ | `bg-green-50` | `Badge` ou `Alert` com `variant="success"` — ver [Status](status.md) |
31
+ | `bg-orange-100` | `Badge` ou `Alert` com `variant="warning"` — ver [Status](status.md) |
32
+ | `<button>` | `Button` — ver [Ações](acoes.md) |
33
+ | `<input>` | `Input` (ou `NumberInput`, `CurrencyInput`, `DatePicker`, `PasswordInput`) |
34
+ | `<select>` | `Select` (ou `Combobox` para lista longa) — ver [Escolha](escolha.md) |
35
+
36
+ Para achar cor crua no app: `node node_modules/@iclips/ui/scripts/check-colors.mjs src`.
37
+
38
+ ## Quando não houver guia
39
+
40
+ 1. Procure o componente no barrel antes de montar um na mão. Elemento HTML cru (`<button>`, `<input>`, `<select>`, `<div onClick>`) quase sempre tem equivalente.
41
+ 2. Cor sempre por token semântico: `bg-background`, `bg-card`, `bg-muted`, `text-foreground`, `text-muted-foreground`, `border-border`, `bg-primary`. Nunca cor crua da paleta.
42
+ 3. Espaçamento e tamanho pela escala (`gap-4`, `p-6`, `max-w-sm`). Nunca valor arbitrário (`p-[13px]`) nem `style={{}}` com valor literal.
43
+ 4. Ícones de `lucide-react`.
44
+ 5. Estado (erro, sucesso, aviso, informação) segue a receita suave: `bg-<status>/10 text-<status>-emphasis border-<status>/20` — de preferência pelo componente que já a aplica (`Badge`, `Alert`, `Button`).
package/docs/acoes.md ADDED
@@ -0,0 +1,103 @@
1
+ # Botão, link ou ícone
2
+
3
+ A regra de ouro: **link leva a algum lugar** (muda a URL), **botão faz alguma coisa** (dispara uma ação na página). Escolher errado quebra abrir-em-nova-aba, o botão voltar e o leitor de tela.
4
+
5
+ ## Elemento certo
6
+
7
+ | Elemento | Escolha quando | Evite quando |
8
+ | --- | --- | --- |
9
+ | `<a>` / `<Link>` | o clique navega para outra rota, âncora ou recurso externo. Suporta Ctrl+clique, botão do meio, "copiar link". | o clique só muda estado na tela (abrir modal, submeter, alternar) → `<button>`. |
10
+ | `Button` | dispara uma ação: salvar, abrir overlay, adicionar item, filtrar. É o padrão para quase tudo que não é navegação. | o destino é uma URL → renderize um link (use `asChild`). |
11
+ | `Button variant="link"` | uma ação secundária que precisa parecer texto ("Esqueci a senha", "ver todos") dentro de um parágrafo ou rodapé. | é a ação principal do bloco → `default`/`secondary`. É navegação de verdade → `<a>` estilizado. |
12
+ | `Button size="icon"` | ação repetida numa linha/toolbar onde o texto polui (excluir linha, favoritar). Sempre com `aria-label`. | a ação é rara ou ambígua — aí o texto ajuda. Ou é a ação primária de um formulário. |
13
+ | `SocialButton` | login/conexão com provedor (Google, Facebook…) — já traz ícone e rótulo do provedor. | qualquer outra ação. |
14
+
15
+ ## Hierarquia de variantes
16
+
17
+ Uma ação primária por bloco. O resto desce na escala.
18
+
19
+ ### Ordem de ênfase
20
+
21
+ Rótulo em peso 600 (semibold) — no sistema, 600 significa ação. Hover de `outline` e `ghost` é cinza; lavanda fica para selecionado.
22
+
23
+ ```tsx
24
+ import { Button } from "@iclips/ui";
25
+
26
+ <Button>Primária — salvar, confirmar, criar</Button>
27
+ <Button variant="secondary">Secundária — ação alternativa</Button>
28
+ <Button variant="outline">Terciária — cancelar, voltar</Button>
29
+ <Button variant="ghost">Discreta — em toolbars, dentro de cards</Button>
30
+ <Button variant="link">Link — ação textual inline</Button>
31
+ ```
32
+
33
+ ### Semânticas
34
+
35
+ `destructive` só para remoção/irreversível. `success` é raro — normalmente o `default` basta.
36
+
37
+ ```tsx
38
+ import { Button } from "@iclips/ui";
39
+ import { Trash2 } from "lucide-react";
40
+
41
+ <Button variant="destructive"><Trash2 /> Excluir</Button>
42
+ <Button variant="success">Aprovar</Button>
43
+ ```
44
+
45
+ ### Com ícone
46
+
47
+ Ícone à esquerda reforça o verbo; à direita sugere avanço/navegação.
48
+
49
+ ```tsx
50
+ import { Button } from "@iclips/ui";
51
+ import { ArrowRight, Download, Plus } from "lucide-react";
52
+
53
+ <Button><Plus /> Nova campanha</Button>
54
+ <Button variant="outline">Exportar <Download /></Button>
55
+ <Button variant="link">Ver relatório <ArrowRight /></Button>
56
+ ```
57
+
58
+ ## Trilha rápida
59
+
60
+ 1. **O clique muda a URL / abre outra página?** Sim: é um link. Renderize `<a>` (ou `<Link>` do router) — via `Button asChild` se quiser o visual de botão. Não: continue.
61
+ 2. **É a ação principal deste bloco/formulário?** Sim: `Button variant="default"`. Não: continue.
62
+ 3. **Remove ou desfaz algo de forma difícil de reverter?** Sim: `variant="destructive"` + confirmação (ver [Overlays](overlays.md)). Não: continue.
63
+ 4. **Está numa linha de tabela / toolbar densa e o verbo é óbvio pelo ícone?** Sim: `size="icon"` + `aria-label`. Não: variant `secondary` / `outline` / `ghost` conforme a ênfase.
64
+
65
+ ## Link com aparência de botão
66
+
67
+ Quando o destino é uma URL mas o design pede um botão, use `asChild` — o elemento vira `<a>`, o estilo continua.
68
+
69
+ ### asChild
70
+
71
+ Renderiza `<a href>` com as classes do `Button`. Mantém Ctrl+clique e menu de contexto.
72
+
73
+ ```tsx
74
+ import { Button } from "@iclips/ui";
75
+ import { ArrowRight } from "lucide-react";
76
+
77
+ <Button asChild>
78
+ <a href="/projetos/42">Abrir projeto</a>
79
+ </Button>
80
+ <Button asChild variant="outline">
81
+ <a href="https://iclips.com.br" target="_blank" rel="noreferrer">
82
+ Site da iClips <ArrowRight />
83
+ </a>
84
+ </Button>
85
+ ```
86
+
87
+ ## Faça / evite
88
+
89
+ #### Faça
90
+
91
+ - Comece o rótulo com um verbo: "Salvar alterações", não "OK".
92
+ - Toda ação só-ícone leva `aria-label` com o mesmo verbo que um Tooltip mostraria.
93
+ - Use `isLoading` para travar o botão durante a requisição — ele já seta `aria-busy` e bloqueia o clique.
94
+ - Um `<a>` para navegação mesmo que estilizado como botão — o usuário espera Ctrl+clique.
95
+
96
+ #### Evite
97
+
98
+ - `onClick={() => navigate("/rota")}` num `<button>` — quebra abrir em nova aba e o histórico.
99
+ - Dois botões primários lado a lado — o olho não sabe qual é o caminho feliz.
100
+ - `<div onClick>` — sem foco, sem Enter/Espaço, invisível para leitor de tela.
101
+ - `variant="link"` para a ação principal de um formulário.
102
+
103
+ **Acessibilidade:** o `Button` já traz anel de foco visível, `active:scale` e trata `disabled`. Um link precisa de `href` real para ser focável e anunciado como link — `role="button"` num `<a>` ou vice-versa confunde a tecnologia assistiva. Ícone sem texto *sempre* com `aria-label`.
@@ -0,0 +1,171 @@
1
+ # Como o usuário escolhe de uma lista
2
+
3
+ Duas perguntas resolvem quase tudo: **uma opção ou várias?** e **quantas opções existem** — porque abaixo de ~7 vale mostrar todas, e acima disso é preciso busca.
4
+
5
+ ## Uma única escolha
6
+
7
+ | Componente | Escolha quando | Evite quando |
8
+ | --- | --- | --- |
9
+ | RadioGroup | 2 a 5 opções que valem ser vistas todas de uma vez, e a escolha é importante (plano, forma de pagamento). | mais de ~6 opções, ou espaço vertical apertado → `Select`. |
10
+ | Select | 6 a ~25 opções conhecidas e curtas (estado, categoria, status). Economiza espaço. | a lista é longa ou o usuário sabe o nome do que quer → `Combobox`. |
11
+ | Combobox | lista longa (>25) ou dinâmica: cidade, cliente, produto. Filtra enquanto digita. | são poucas opções fixas — o campo de busca vira fricção → `Select` ou Radio. |
12
+ | ToggleGroup (single) | 2 a 4 opções mutuamente exclusivas que mudam a visão na hora: alinhamento, período (dia/semana/mês), modo de exibição. | é um dado do formulário a ser submetido, não uma alternância de UI → Radio. |
13
+
14
+ ## Várias escolhas (ou liga/desliga)
15
+
16
+ | Componente | Escolha quando | Evite quando |
17
+ | --- | --- | --- |
18
+ | Checkbox (grupo) | 2 a ~8 opções independentes visíveis de uma vez: permissões, dias da semana, filtros marcáveis. | a lista é longa → `MultiSelect`. É uma única opção booleana isolada → Checkbox sozinho ou `Switch`. |
19
+ | MultiSelect | escolher vários de uma lista longa: responsáveis, tags, canais. Mostra chips do que foi escolhido + busca. | poucas opções fixas → grupo de Checkbox mostra tudo sem cliques extras. |
20
+ | ToggleGroup (multiple) | conjunto pequeno de formatações/filtros que ligam e desligam juntos: negrito/itálico, tipos de mídia. | opções com rótulos longos, ou muitas → Checkbox. |
21
+ | Checkbox (isolado) | uma afirmação que o usuário aceita ou não: "Aceito os termos", "Lembrar de mim". Faz parte de um envio. | liga um comportamento imediatamente, sem submit → `Switch`. |
22
+ | Switch | liga/desliga uma configuração com efeito imediato: notificações, modo escuro, tema. | o efeito só acontece ao salvar o formulário → Checkbox. |
23
+
24
+ ## Trilha rápida
25
+
26
+ 1. **O usuário pode escolher mais de uma opção?** Sim: poucas e fixas → grupo de `Checkbox`; muitas/dinâmicas → `MultiSelect`. Não: continue.
27
+ 2. **É um liga/desliga com efeito imediato (sem salvar)?** Sim: `Switch`. Não: continue.
28
+ 3. **A escolha muda a visão da tela na hora (período, layout)?** Sim: `ToggleGroup type="single"`. Não: continue.
29
+ 4. **Quantas opções?** Até 5 e importantes → `RadioGroup` · 6 a 25 → `Select` · mais que isso ou dinâmica → `Combobox`.
30
+
31
+ ## Exemplos
32
+
33
+ Os exemplos usam esta lista:
34
+
35
+ ```tsx
36
+ const canais = [
37
+ { value: "ig", label: "Instagram" },
38
+ { value: "fb", label: "Facebook" },
39
+ { value: "li", label: "LinkedIn" },
40
+ { value: "tt", label: "TikTok" },
41
+ { value: "yt", label: "YouTube" },
42
+ ];
43
+ ```
44
+
45
+ ### RadioGroup — poucas, todas visíveis
46
+
47
+ ```tsx
48
+ import { Label, RadioGroup, RadioGroupItem } from "@iclips/ui";
49
+
50
+ <RadioGroup defaultValue="anual" className="gap-2">
51
+ {["mensal", "anual", "vitalício"].map((v) => (
52
+ <div key={v} className="flex items-center gap-2">
53
+ <RadioGroupItem value={v} id={`plano-${v}`} />
54
+ <Label htmlFor={`plano-${v}`} className="capitalize">{v}</Label>
55
+ </div>
56
+ ))}
57
+ </RadioGroup>
58
+ ```
59
+
60
+ ### Select — lista média conhecida
61
+
62
+ ```tsx
63
+ import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@iclips/ui";
64
+
65
+ <Select>
66
+ <SelectTrigger className="w-56" aria-label="Canal"><SelectValue placeholder="Selecione o canal" /></SelectTrigger>
67
+ <SelectContent>
68
+ {canais.map((c) => (
69
+ <SelectItem key={c.value} value={c.value}>{c.label}</SelectItem>
70
+ ))}
71
+ </SelectContent>
72
+ </Select>
73
+ ```
74
+
75
+ ### Combobox — busca em lista longa
76
+
77
+ ```tsx
78
+ import { Combobox } from "@iclips/ui";
79
+
80
+ const [canal, setCanal] = React.useState("");
81
+
82
+ <Combobox options={canais} value={canal} onValueChange={setCanal} placeholder="Buscar canal" aria-label="Canal" />
83
+ ```
84
+
85
+ ### MultiSelect — vários, com chips
86
+
87
+ ```tsx
88
+ import { MultiSelect } from "@iclips/ui";
89
+
90
+ const [selecionados, setSelecionados] = React.useState<string[]>(["ig"]);
91
+
92
+ <MultiSelect
93
+ options={canais}
94
+ value={selecionados}
95
+ onValueChange={setSelecionados}
96
+ placeholder="Canais da campanha"
97
+ aria-label="Canais da campanha"
98
+ />
99
+ ```
100
+
101
+ ### Checkbox (grupo) — independentes, visíveis
102
+
103
+ ```tsx
104
+ import { Checkbox } from "@iclips/ui";
105
+
106
+ <div className="space-y-2">
107
+ {["Ler", "Escrever", "Excluir"].map((p) => (
108
+ <label key={p} className="flex items-center gap-2 text-sm">
109
+ <Checkbox defaultChecked={p === "Ler"} /> {p}
110
+ </label>
111
+ ))}
112
+ </div>
113
+ ```
114
+
115
+ ### Switch — efeito imediato
116
+
117
+ Muda algo agora. Checkbox seria para um valor a ser salvo.
118
+
119
+ ```tsx
120
+ import { Switch } from "@iclips/ui";
121
+
122
+ <label className="flex items-center gap-2 text-sm">
123
+ <Switch defaultChecked /> Notificações por e-mail
124
+ </label>
125
+ ```
126
+
127
+ ### ToggleGroup — troca de visão
128
+
129
+ ```tsx
130
+ import { ToggleGroup, ToggleGroupItem } from "@iclips/ui";
131
+
132
+ <ToggleGroup type="single" defaultValue="semana">
133
+ <ToggleGroupItem value="dia">Dia</ToggleGroupItem>
134
+ <ToggleGroupItem value="semana">Semana</ToggleGroupItem>
135
+ <ToggleGroupItem value="mes">Mês</ToggleGroupItem>
136
+ </ToggleGroup>
137
+ ```
138
+
139
+ ## Estados do item: selecionado > focado > sob o cursor
140
+
141
+ Os três podem coexistir no mesmo item e cada um usa um sinal diferente, para continuarem legíveis empilhados. `Combobox` e `MultiSelect` já seguem essa regra; siga-a em listas próprias.
142
+
143
+ | Estado | Como se pinta | Por quê |
144
+ | --- | --- | --- |
145
+ | Selecionado | `bg-secondary text-secondary-foreground font-medium` | matiz + tinta + peso: três sinais, sobrevive ao hover por cima. |
146
+ | Focado por teclado | `focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-inset` | anel, não fundo — sobrevive sobre qualquer fundo. |
147
+ | Sob o cursor | `hover:bg-accent` | cinza, transitório, sem peso. |
148
+
149
+ Hover e seleção são ambos `bg-*`: quem vence é a ordem do CSS gerado, não a do `className`. Guarde o hover pelo estado (`not-aria-selected:hover:bg-accent`) ou inclua `hover:bg-secondary` na classe de selecionado, para o `cn` descartar o hover conflitante.
150
+
151
+ ### Ilustração estática — os três estados na mesma lista
152
+
153
+ Numa mesma lista, o item selecionado fica lavanda com peso maior, o focado ganha só o anel e o que está sob o cursor fica cinza — nunca lavanda, que significa selecionado.
154
+
155
+ ## Faça / evite
156
+
157
+ #### Faça
158
+
159
+ - Todo controle com `<Label htmlFor>` — clicar no texto ativa o controle.
160
+ - `Combobox` e `MultiSelect` quando a lista vem da API ou passa de ~25 itens.
161
+ - `RadioGroup` com um default sensato já selecionado (evita estado "nada escolhido").
162
+ - `Switch` só para o que aplica na hora; se tem botão "Salvar", é `Checkbox`.
163
+
164
+ #### Evite
165
+
166
+ - `Select` com 3 opções — `RadioGroup` mostra as 3 sem um clique a mais.
167
+ - Grupo de `Checkbox` com 40 itens — vira uma parede; use `MultiSelect`.
168
+ - Radio e Checkbox trocados: Radio = uma; Checkbox = zero ou mais.
169
+ - `Combobox` para sim/não.
170
+
171
+ **Acessibilidade:** `Select`, `Combobox`, `RadioGroup`, `Checkbox` e `Switch` já trazem navegação por seta, Home/End, digitar-para-focar e os papéis ARIA. O `MultiSelect` é custom: ele já trata teclado, mas confirme o `aria-label` quando não houver rótulo visível.