quickit-ui 0.1.17 → 0.1.20

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.
package/README.md CHANGED
@@ -14,6 +14,17 @@ Importa los estilos una sola vez:
14
14
  import "quickit-ui/styles.css";
15
15
  ```
16
16
 
17
+ Si tu app también usa utilidades propias de Tailwind con `dark:`, declara esto en tu CSS global:
18
+
19
+ ```css
20
+ @import "tailwindcss";
21
+ @import "quickit-ui/styles.css";
22
+
23
+ @custom-variant dark (&:where(.dark, .dark *));
24
+ ```
25
+
26
+ Eso hace que tu app y Quickit reaccionen a la misma clase `dark`.
27
+
17
28
  ## Uso rápido
18
29
 
19
30
  ```jsx
@@ -34,7 +45,7 @@ export default function App() {
34
45
 
35
46
  ## Tema
36
47
 
37
- Quickit UI trabaja con `light` y `dark`. El estado del tema vive en tu app; `QuickitProvider` solo lo distribuye al resto de componentes.
48
+ Quickit UI trabaja con `light` y `dark`. Si ya gestionas el tema en tu app, `QuickitProvider` solo lo distribuye al resto de componentes.
38
49
 
39
50
  ```jsx
40
51
  import "quickit-ui/styles.css";
@@ -49,12 +60,122 @@ export default function App() {
49
60
  }
50
61
  ```
51
62
 
52
- También puedes controlar el focus ring globalmente desde el provider:
63
+ Si prefieres que Quickit gestione el toggle y la persistencia, usa `QuickitThemeProvider` con `useQuickitThemeController`:
64
+
65
+ ```jsx
66
+ import "quickit-ui/styles.css";
67
+ import {
68
+ Button,
69
+ QuickitThemeProvider,
70
+ useQuickitThemeController,
71
+ } from "quickit-ui";
72
+
73
+ function ThemeControls() {
74
+ const { resolvedTheme, setTheme, systemTheme, theme, toggleTheme } =
75
+ useQuickitThemeController();
76
+
77
+ return (
78
+ <div className="space-y-4">
79
+ <p>
80
+ Preferencia: {theme}. Sistema: {systemTheme}. Tema activo: {resolvedTheme}
81
+ </p>
82
+
83
+ <div className="flex flex-wrap gap-3">
84
+ <Button onClick={() => setTheme("system")}>Sistema</Button>
85
+ <Button onClick={() => setTheme("light")}>Claro</Button>
86
+ <Button onClick={() => setTheme("dark")}>Oscuro</Button>
87
+ <Button color="brand" variant="outline" onClick={toggleTheme}>
88
+ Alternar desde {resolvedTheme}
89
+ </Button>
90
+ </div>
91
+ </div>
92
+ );
93
+ }
94
+
95
+ export default function App() {
96
+ return (
97
+ <QuickitThemeProvider
98
+ defaultTheme="system"
99
+ storageKey="ava-quickit-theme"
100
+ >
101
+ <ThemeControls />
102
+ </QuickitThemeProvider>
103
+ );
104
+ }
105
+ ```
106
+
107
+ Notas:
108
+
109
+ - el storage key por defecto es `quickit-ui-theme`
110
+ - `defaultTheme` ahora soporta `system | light | dark`
111
+ - `QuickitThemeProvider` aplica la clase `dark` sobre `document.documentElement`
112
+ - puedes sobrescribir el storage key con `storageKey`
113
+ - `useQuickitThemeController()` expone `theme`, `resolvedTheme`, `systemTheme`, `setTheme` y `toggleTheme`
114
+ - `theme` es la preferencia persistida; `resolvedTheme` es el modo que Quickit está aplicando realmente
115
+ - si usas clases propias como `dark:bg-zinc-950`, añade `@custom-variant dark (&:where(.dark, .dark *));` a tu CSS global
116
+
117
+ Si tu layout propio también depende del tema:
118
+
119
+ ```jsx
120
+ import { useQuickitThemeController } from "quickit-ui";
121
+
122
+ function Shell() {
123
+ const { theme, resolvedTheme } = useQuickitThemeController();
124
+
125
+ return (
126
+ <div className="bg-white text-zinc-950 dark:bg-zinc-950 dark:text-white">
127
+ <header className="border-b border-zinc-200 px-6 py-4 dark:border-zinc-800">
128
+ Preferencia: {theme}. Tema efectivo: {resolvedTheme}
129
+ </header>
130
+ <main className="p-6">
131
+ <Dashboard />
132
+ </main>
133
+ </div>
134
+ );
135
+ }
136
+ ```
137
+
138
+ Patrón con `Switch`:
139
+
140
+ ```jsx
141
+ import {
142
+ QuickitThemeProvider,
143
+ Switch,
144
+ Tooltip,
145
+ useQuickitThemeController,
146
+ } from "quickit-ui";
147
+
148
+ function ToggleTheme() {
149
+ const { resolvedTheme, theme, toggleTheme } = useQuickitThemeController();
150
+
151
+ return (
152
+ <Tooltip content="Alternar tema">
153
+ <Switch
154
+ color="brand"
155
+ checked={resolvedTheme === "dark"}
156
+ onCheckedChange={toggleTheme}
157
+ />
158
+ </Tooltip>
159
+ );
160
+ }
161
+
162
+ export function App() {
163
+ return (
164
+ <QuickitThemeProvider storageKey="ava-quickit-theme">
165
+ <ToggleTheme />
166
+ </QuickitThemeProvider>
167
+ );
168
+ }
169
+ ```
170
+
171
+ También puedes controlar el focus ring y el efecto de presión globalmente desde el provider:
53
172
 
54
173
  ```jsx
55
174
  <QuickitProvider
56
175
  theme="dark"
57
176
  focusRing={{ disabledComponents: ["input", "textarea"] }}
177
+ pressEffect="ripple"
178
+ ripple={{ disabledComponents: ["link"] }}
58
179
  >
59
180
  <App />
60
181
  </QuickitProvider>
@@ -65,17 +186,28 @@ Reglas:
65
186
  - por defecto Quickit mantiene focus visible accesible en componentes interactivos
66
187
  - `focusRing={false}` lo desactiva en toda la librería
67
188
  - `focusRing={{ disabledComponents: [...] }}` lo desactiva solo en componentes específicos
189
+ - por defecto Quickit usa `pressEffect="transform"` en `Button` y en `Link` con `appearance="button"`
190
+ - `pressEffect="ripple"` cambia esa política global para usar ripple en lugar de transform
191
+ - `ripple={false}` lo desactiva en toda la librería cuando `pressEffect="ripple"`
192
+ - `ripple={{ disabledComponents: [...] }}` lo desactiva solo en botones o links cuando `pressEffect="ripple"`
68
193
 
69
194
  Si necesitas leer esa decisión desde tu app o desde wrappers propios:
70
195
 
71
196
  ```jsx
72
- import { useQuickitFocusRing } from "quickit-ui";
197
+ import {
198
+ useQuickitFocusRing,
199
+ useQuickitPressEffect,
200
+ useQuickitRipple,
201
+ } from "quickit-ui";
73
202
 
74
203
  function Toolbar() {
75
204
  const buttonFocusRing = useQuickitFocusRing("button");
76
205
  const linkFocusRing = useQuickitFocusRing("link");
77
206
  const checkboxFocusRing = useQuickitFocusRing("checkbox");
78
207
  const radioFocusRing = useQuickitFocusRing("radio");
208
+ const pressEffect = useQuickitPressEffect();
209
+ const buttonRipple = useQuickitRipple("button");
210
+ const linkRipple = useQuickitRipple("link");
79
211
 
80
212
  return (
81
213
  <div>
@@ -83,6 +215,9 @@ function Toolbar() {
83
215
  <span>link focus: {String(linkFocusRing)}</span>
84
216
  <span>checkbox focus: {String(checkboxFocusRing)}</span>
85
217
  <span>radio focus: {String(radioFocusRing)}</span>
218
+ <span>pressEffect: {pressEffect}</span>
219
+ <span>button ripple: {String(buttonRipple)}</span>
220
+ <span>link ripple: {String(linkRipple)}</span>
86
221
  </div>
87
222
  );
88
223
  }
@@ -102,6 +237,7 @@ import {
102
237
  export function LoginOptions() {
103
238
  return (
104
239
  <QuickitProvider
240
+ pressEffect="ripple"
105
241
  focusRing={{ disabledComponents: ["link", "checkbox", "radio"] }}
106
242
  >
107
243
  <div className="flex flex-wrap items-center gap-4">
@@ -186,6 +322,33 @@ import {
186
322
  } from "quickit-ui";
187
323
  ```
188
324
 
325
+ ## InputGroup
326
+
327
+ Usa `InputGroupAddon` para segmentos pasivos y `InputGroupAction` para segmentos interactivos.
328
+ `InputGroupAction` reutiliza `Button` y renderiza un `<button>` real, así que soporta `type`, `onClick`, `disabled`, foco y teclado.
329
+
330
+ ```jsx
331
+ import {
332
+ Input,
333
+ InputGroup,
334
+ InputGroupAction,
335
+ } from "quickit-ui";
336
+
337
+ export function Filters() {
338
+ return (
339
+ <InputGroup attached>
340
+ <InputGroupAction variant="outline" onClick={() => console.log("todo")}>
341
+ Todo
342
+ </InputGroupAction>
343
+ <Input placeholder="Filtra por nombre o etiqueta" />
344
+ <InputGroupAction variant="outline" onClick={() => console.log("estado")}>
345
+ Estado
346
+ </InputGroupAction>
347
+ </InputGroup>
348
+ );
349
+ }
350
+ ```
351
+
189
352
  ## Ejemplos
190
353
 
191
354
  ### Button
@@ -212,6 +375,9 @@ Notas rápidas de `Button`:
212
375
 
213
376
  - `shape="square"` y `shape="circle"` están pensados para icon buttons.
214
377
  - `shape="square"` y `shape="circle"` salen con `activeMotion` desactivado por defecto.
378
+ - `Button` y `Link` con `appearance="button"` usan `pressEffect="transform"` por defecto.
379
+ - Si quieres ripple, usa `pressEffect="ripple"` en esa instancia o en `QuickitProvider`.
380
+ - Cuando `pressEffect="ripple"`, puedes apagarlo con `ripple={false}`.
215
381
  - Si quieres esa animación en un icon button, usa `activeMotion={true}`.
216
382
 
217
383
  ```jsx