@wow-two-beta/ui 0.0.3 → 0.0.5
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/dist/actions/index.d.ts +240 -2
- package/dist/actions/index.js +5 -2
- package/dist/chunk-33IOXQYO.js +47 -0
- package/dist/chunk-33IOXQYO.js.map +1 -0
- package/dist/chunk-4CIRBYYP.js +120 -0
- package/dist/chunk-4CIRBYYP.js.map +1 -0
- package/dist/chunk-6NYTRHP7.js +168 -0
- package/dist/chunk-6NYTRHP7.js.map +1 -0
- package/dist/chunk-77WSI427.js +39 -0
- package/dist/chunk-77WSI427.js.map +1 -0
- package/dist/chunk-BMBIZLO4.js +34 -0
- package/dist/chunk-BMBIZLO4.js.map +1 -0
- package/dist/chunk-D67WGR7Y.js +212 -0
- package/dist/chunk-D67WGR7Y.js.map +1 -0
- package/dist/chunk-DN7WBRIV.js +17 -0
- package/dist/chunk-DN7WBRIV.js.map +1 -0
- package/dist/chunk-JCMV6IT4.js +268 -0
- package/dist/chunk-JCMV6IT4.js.map +1 -0
- package/dist/chunk-JTJEI6MF.js +11 -0
- package/dist/chunk-JTJEI6MF.js.map +1 -0
- package/dist/chunk-KSJE3JAI.js +604 -0
- package/dist/chunk-KSJE3JAI.js.map +1 -0
- package/dist/chunk-KZ4VFY2T.js +11 -0
- package/dist/chunk-KZ4VFY2T.js.map +1 -0
- package/dist/chunk-MP4OTUFA.js +318 -0
- package/dist/chunk-MP4OTUFA.js.map +1 -0
- package/dist/chunk-Q27NAHVB.js +34 -0
- package/dist/chunk-Q27NAHVB.js.map +1 -0
- package/dist/chunk-SYG6ZE42.js +218 -0
- package/dist/chunk-SYG6ZE42.js.map +1 -0
- package/dist/chunk-TDX22OWF.js +33 -0
- package/dist/chunk-TDX22OWF.js.map +1 -0
- package/dist/chunk-YLN7VMYU.js +275 -0
- package/dist/chunk-YLN7VMYU.js.map +1 -0
- package/dist/display/index.d.ts +805 -1
- package/dist/display/index.js +6 -1
- package/dist/feedback/index.d.ts +506 -1
- package/dist/feedback/index.js +5 -1
- package/dist/forms/index.d.ts +217 -1
- package/dist/forms/index.js +8 -1
- package/dist/hooks/index.d.ts +2 -5
- package/dist/hooks/index.js +4 -1
- package/dist/icons/index.d.ts +2 -5
- package/dist/icons/index.js +3 -1
- package/dist/index-Bk6CuDNT.d.ts +247 -0
- package/dist/index-C0IDphm_.d.ts +61 -0
- package/dist/index-CEAM9LLM.d.ts +37 -0
- package/dist/index-PAuwodyY.d.ts +103 -0
- package/dist/index-goThcZ1E.d.ts +416 -0
- package/dist/index.d.ts +13 -5
- package/dist/index.js +16 -9
- package/dist/layout/index.d.ts +605 -1
- package/dist/layout/index.js +5 -1
- package/dist/primitives/index.d.ts +5 -0
- package/dist/primitives/index.js +10 -0
- package/dist/primitives/index.js.map +1 -0
- package/dist/tailwind/index.js +8 -2
- package/dist/tailwind/index.js.map +1 -1
- package/dist/tokens/index.d.ts +1 -1
- package/dist/tokens/index.js +1 -1
- package/dist/utils/index.d.ts +3 -1
- package/dist/utils/index.js +3 -1
- package/package.json +8 -1
- package/dist/chunk-6YKPUEHU.js +0 -47
- package/dist/chunk-6YKPUEHU.js.map +0 -1
- package/dist/chunk-7CP7KR5F.js +0 -41
- package/dist/chunk-7CP7KR5F.js.map +0 -1
- package/dist/chunk-A2OBJDIK.js +0 -3
- package/dist/chunk-A2OBJDIK.js.map +0 -1
- package/dist/chunk-CTVGU35H.js +0 -6
- package/dist/chunk-CTVGU35H.js.map +0 -1
- package/dist/chunk-ECZ4YFAI.js +0 -16
- package/dist/chunk-ECZ4YFAI.js.map +0 -1
- package/dist/chunk-PSDQXPUE.js +0 -3
- package/dist/chunk-PSDQXPUE.js.map +0 -1
- package/dist/chunk-U4JXXIE2.js +0 -6
- package/dist/chunk-U4JXXIE2.js.map +0 -1
- package/dist/chunk-YP4MAZRQ.js +0 -3
- package/dist/chunk-YP4MAZRQ.js.map +0 -1
- package/dist/chunk-ZDU7SROW.js +0 -3
- package/dist/chunk-ZDU7SROW.js.map +0 -1
- package/dist/index-CdSRWb8y.d.ts +0 -78
- package/dist/index-D-adCzNR.d.ts +0 -14
package/dist/actions/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as react from 'react';
|
|
2
|
-
import { ButtonHTMLAttributes } from 'react';
|
|
2
|
+
import { ButtonHTMLAttributes, ReactNode, AnchorHTMLAttributes } from 'react';
|
|
3
3
|
import * as tailwind_variants from 'tailwind-variants';
|
|
4
4
|
import { VariantProps } from 'tailwind-variants';
|
|
5
5
|
import * as tailwind_variants_dist_config_js from 'tailwind-variants/dist/config.js';
|
|
@@ -88,4 +88,242 @@ interface ButtonProps extends ButtonHTMLAttributes<HTMLButtonElement>, ButtonVar
|
|
|
88
88
|
}
|
|
89
89
|
declare const Button: react.ForwardRefExoticComponent<ButtonProps & react.RefAttributes<HTMLButtonElement>>;
|
|
90
90
|
|
|
91
|
-
|
|
91
|
+
declare const iconButtonVariants: tailwind_variants.TVReturnType<{
|
|
92
|
+
variant: {
|
|
93
|
+
solid: string;
|
|
94
|
+
soft: string;
|
|
95
|
+
outline: string;
|
|
96
|
+
ghost: string;
|
|
97
|
+
danger: string;
|
|
98
|
+
};
|
|
99
|
+
size: {
|
|
100
|
+
xs: string;
|
|
101
|
+
sm: string;
|
|
102
|
+
md: string;
|
|
103
|
+
lg: string;
|
|
104
|
+
};
|
|
105
|
+
shape: {
|
|
106
|
+
square: string;
|
|
107
|
+
circle: string;
|
|
108
|
+
};
|
|
109
|
+
}, undefined, "inline-flex items-center justify-center transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-brand-500 disabled:pointer-events-none disabled:opacity-50", tailwind_variants_dist_config_js.TVConfig<{
|
|
110
|
+
variant: {
|
|
111
|
+
solid: string;
|
|
112
|
+
soft: string;
|
|
113
|
+
outline: string;
|
|
114
|
+
ghost: string;
|
|
115
|
+
danger: string;
|
|
116
|
+
};
|
|
117
|
+
size: {
|
|
118
|
+
xs: string;
|
|
119
|
+
sm: string;
|
|
120
|
+
md: string;
|
|
121
|
+
lg: string;
|
|
122
|
+
};
|
|
123
|
+
shape: {
|
|
124
|
+
square: string;
|
|
125
|
+
circle: string;
|
|
126
|
+
};
|
|
127
|
+
}, {
|
|
128
|
+
variant: {
|
|
129
|
+
solid: string;
|
|
130
|
+
soft: string;
|
|
131
|
+
outline: string;
|
|
132
|
+
ghost: string;
|
|
133
|
+
danger: string;
|
|
134
|
+
};
|
|
135
|
+
size: {
|
|
136
|
+
xs: string;
|
|
137
|
+
sm: string;
|
|
138
|
+
md: string;
|
|
139
|
+
lg: string;
|
|
140
|
+
};
|
|
141
|
+
shape: {
|
|
142
|
+
square: string;
|
|
143
|
+
circle: string;
|
|
144
|
+
};
|
|
145
|
+
}>, {
|
|
146
|
+
variant: {
|
|
147
|
+
solid: string;
|
|
148
|
+
soft: string;
|
|
149
|
+
outline: string;
|
|
150
|
+
ghost: string;
|
|
151
|
+
danger: string;
|
|
152
|
+
};
|
|
153
|
+
size: {
|
|
154
|
+
xs: string;
|
|
155
|
+
sm: string;
|
|
156
|
+
md: string;
|
|
157
|
+
lg: string;
|
|
158
|
+
};
|
|
159
|
+
shape: {
|
|
160
|
+
square: string;
|
|
161
|
+
circle: string;
|
|
162
|
+
};
|
|
163
|
+
}, undefined, tailwind_variants.TVReturnType<{
|
|
164
|
+
variant: {
|
|
165
|
+
solid: string;
|
|
166
|
+
soft: string;
|
|
167
|
+
outline: string;
|
|
168
|
+
ghost: string;
|
|
169
|
+
danger: string;
|
|
170
|
+
};
|
|
171
|
+
size: {
|
|
172
|
+
xs: string;
|
|
173
|
+
sm: string;
|
|
174
|
+
md: string;
|
|
175
|
+
lg: string;
|
|
176
|
+
};
|
|
177
|
+
shape: {
|
|
178
|
+
square: string;
|
|
179
|
+
circle: string;
|
|
180
|
+
};
|
|
181
|
+
}, undefined, "inline-flex items-center justify-center transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-brand-500 disabled:pointer-events-none disabled:opacity-50", tailwind_variants_dist_config_js.TVConfig<{
|
|
182
|
+
variant: {
|
|
183
|
+
solid: string;
|
|
184
|
+
soft: string;
|
|
185
|
+
outline: string;
|
|
186
|
+
ghost: string;
|
|
187
|
+
danger: string;
|
|
188
|
+
};
|
|
189
|
+
size: {
|
|
190
|
+
xs: string;
|
|
191
|
+
sm: string;
|
|
192
|
+
md: string;
|
|
193
|
+
lg: string;
|
|
194
|
+
};
|
|
195
|
+
shape: {
|
|
196
|
+
square: string;
|
|
197
|
+
circle: string;
|
|
198
|
+
};
|
|
199
|
+
}, {
|
|
200
|
+
variant: {
|
|
201
|
+
solid: string;
|
|
202
|
+
soft: string;
|
|
203
|
+
outline: string;
|
|
204
|
+
ghost: string;
|
|
205
|
+
danger: string;
|
|
206
|
+
};
|
|
207
|
+
size: {
|
|
208
|
+
xs: string;
|
|
209
|
+
sm: string;
|
|
210
|
+
md: string;
|
|
211
|
+
lg: string;
|
|
212
|
+
};
|
|
213
|
+
shape: {
|
|
214
|
+
square: string;
|
|
215
|
+
circle: string;
|
|
216
|
+
};
|
|
217
|
+
}>, unknown, unknown, undefined>>;
|
|
218
|
+
type IconButtonVariants = VariantProps<typeof iconButtonVariants>;
|
|
219
|
+
|
|
220
|
+
interface IconButtonProps extends ButtonHTMLAttributes<HTMLButtonElement>, IconButtonVariants {
|
|
221
|
+
/** REQUIRED accessible label. IconButton has no visible text. */
|
|
222
|
+
'aria-label': string;
|
|
223
|
+
children: ReactNode;
|
|
224
|
+
}
|
|
225
|
+
/**
|
|
226
|
+
* Square / circular button containing only an icon. `aria-label` is
|
|
227
|
+
* required by the type — there is no visible text fallback.
|
|
228
|
+
*/
|
|
229
|
+
declare const IconButton: react.ForwardRefExoticComponent<IconButtonProps & react.RefAttributes<HTMLButtonElement>>;
|
|
230
|
+
|
|
231
|
+
declare const linkVariants: tailwind_variants.TVReturnType<{
|
|
232
|
+
variant: {
|
|
233
|
+
default: string;
|
|
234
|
+
subtle: string;
|
|
235
|
+
muted: string;
|
|
236
|
+
inherit: string;
|
|
237
|
+
};
|
|
238
|
+
size: {
|
|
239
|
+
sm: string;
|
|
240
|
+
md: string;
|
|
241
|
+
lg: string;
|
|
242
|
+
};
|
|
243
|
+
}, undefined, "inline-flex items-center transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-brand-500 rounded-sm", tailwind_variants_dist_config_js.TVConfig<{
|
|
244
|
+
variant: {
|
|
245
|
+
default: string;
|
|
246
|
+
subtle: string;
|
|
247
|
+
muted: string;
|
|
248
|
+
inherit: string;
|
|
249
|
+
};
|
|
250
|
+
size: {
|
|
251
|
+
sm: string;
|
|
252
|
+
md: string;
|
|
253
|
+
lg: string;
|
|
254
|
+
};
|
|
255
|
+
}, {
|
|
256
|
+
variant: {
|
|
257
|
+
default: string;
|
|
258
|
+
subtle: string;
|
|
259
|
+
muted: string;
|
|
260
|
+
inherit: string;
|
|
261
|
+
};
|
|
262
|
+
size: {
|
|
263
|
+
sm: string;
|
|
264
|
+
md: string;
|
|
265
|
+
lg: string;
|
|
266
|
+
};
|
|
267
|
+
}>, {
|
|
268
|
+
variant: {
|
|
269
|
+
default: string;
|
|
270
|
+
subtle: string;
|
|
271
|
+
muted: string;
|
|
272
|
+
inherit: string;
|
|
273
|
+
};
|
|
274
|
+
size: {
|
|
275
|
+
sm: string;
|
|
276
|
+
md: string;
|
|
277
|
+
lg: string;
|
|
278
|
+
};
|
|
279
|
+
}, undefined, tailwind_variants.TVReturnType<{
|
|
280
|
+
variant: {
|
|
281
|
+
default: string;
|
|
282
|
+
subtle: string;
|
|
283
|
+
muted: string;
|
|
284
|
+
inherit: string;
|
|
285
|
+
};
|
|
286
|
+
size: {
|
|
287
|
+
sm: string;
|
|
288
|
+
md: string;
|
|
289
|
+
lg: string;
|
|
290
|
+
};
|
|
291
|
+
}, undefined, "inline-flex items-center transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-brand-500 rounded-sm", tailwind_variants_dist_config_js.TVConfig<{
|
|
292
|
+
variant: {
|
|
293
|
+
default: string;
|
|
294
|
+
subtle: string;
|
|
295
|
+
muted: string;
|
|
296
|
+
inherit: string;
|
|
297
|
+
};
|
|
298
|
+
size: {
|
|
299
|
+
sm: string;
|
|
300
|
+
md: string;
|
|
301
|
+
lg: string;
|
|
302
|
+
};
|
|
303
|
+
}, {
|
|
304
|
+
variant: {
|
|
305
|
+
default: string;
|
|
306
|
+
subtle: string;
|
|
307
|
+
muted: string;
|
|
308
|
+
inherit: string;
|
|
309
|
+
};
|
|
310
|
+
size: {
|
|
311
|
+
sm: string;
|
|
312
|
+
md: string;
|
|
313
|
+
lg: string;
|
|
314
|
+
};
|
|
315
|
+
}>, unknown, unknown, undefined>>;
|
|
316
|
+
type LinkVariants = VariantProps<typeof linkVariants>;
|
|
317
|
+
|
|
318
|
+
interface LinkProps extends AnchorHTMLAttributes<HTMLAnchorElement>, LinkVariants {
|
|
319
|
+
/** When true, render the child element as the link instead of an `<a>`.
|
|
320
|
+
* Use for router `<Link>` components from Next.js / React Router. */
|
|
321
|
+
asChild?: boolean;
|
|
322
|
+
}
|
|
323
|
+
/**
|
|
324
|
+
* Anchor with consistent focus / hover styling. Pass `asChild` to render a
|
|
325
|
+
* router `<Link>` while inheriting our visuals.
|
|
326
|
+
*/
|
|
327
|
+
declare const Link: react.ForwardRefExoticComponent<LinkProps & react.RefAttributes<HTMLAnchorElement>>;
|
|
328
|
+
|
|
329
|
+
export { Button, type ButtonProps, type ButtonVariants, IconButton, type IconButtonProps, type IconButtonVariants, Link, type LinkProps, type LinkVariants, buttonVariants, iconButtonVariants, linkVariants };
|
package/dist/actions/index.js
CHANGED
|
@@ -1,5 +1,8 @@
|
|
|
1
|
-
export { Button, buttonVariants } from '../chunk-
|
|
2
|
-
import '../chunk-
|
|
1
|
+
export { Button, IconButton, Link, buttonVariants, iconButtonVariants, linkVariants } from '../chunk-4CIRBYYP.js';
|
|
2
|
+
import '../chunk-BMBIZLO4.js';
|
|
3
|
+
import '../chunk-33IOXQYO.js';
|
|
4
|
+
import '../chunk-DN7WBRIV.js';
|
|
5
|
+
import '../chunk-KZ4VFY2T.js';
|
|
3
6
|
import '../chunk-PZ5AY32C.js';
|
|
4
7
|
//# sourceMappingURL=index.js.map
|
|
5
8
|
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { composeRefs } from './chunk-DN7WBRIV.js';
|
|
2
|
+
import { forwardRef, isValidElement, Children, cloneElement } from 'react';
|
|
3
|
+
|
|
4
|
+
function mergeProps(slotProps, childProps) {
|
|
5
|
+
const merged = { ...childProps };
|
|
6
|
+
for (const key of Object.keys(slotProps)) {
|
|
7
|
+
const slotVal = slotProps[key];
|
|
8
|
+
const childVal = childProps[key];
|
|
9
|
+
if (key === "className") {
|
|
10
|
+
merged.className = [slotVal, childVal].filter(Boolean).join(" ");
|
|
11
|
+
} else if (key === "style") {
|
|
12
|
+
merged.style = { ...slotVal, ...childVal };
|
|
13
|
+
} else if (/^on[A-Z]/.test(key)) {
|
|
14
|
+
const slotFn = slotVal;
|
|
15
|
+
const childFn = childVal;
|
|
16
|
+
if (slotFn && childFn) {
|
|
17
|
+
merged[key] = (...args) => {
|
|
18
|
+
childFn(...args);
|
|
19
|
+
slotFn(...args);
|
|
20
|
+
};
|
|
21
|
+
} else if (slotFn) {
|
|
22
|
+
merged[key] = slotFn;
|
|
23
|
+
}
|
|
24
|
+
} else if (childVal === void 0) {
|
|
25
|
+
merged[key] = slotVal;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
return merged;
|
|
29
|
+
}
|
|
30
|
+
var Slot = forwardRef(
|
|
31
|
+
({ children, ...slotProps }, forwardedRef) => {
|
|
32
|
+
if (!isValidElement(children)) {
|
|
33
|
+
return Children.count(children) > 1 ? Children.only(null) : null;
|
|
34
|
+
}
|
|
35
|
+
const child = children;
|
|
36
|
+
const merged = mergeProps(slotProps, child.props ?? {});
|
|
37
|
+
return cloneElement(child, {
|
|
38
|
+
...merged,
|
|
39
|
+
ref: composeRefs(forwardedRef, child.ref)
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
);
|
|
43
|
+
Slot.displayName = "Slot";
|
|
44
|
+
|
|
45
|
+
export { Slot };
|
|
46
|
+
//# sourceMappingURL=chunk-33IOXQYO.js.map
|
|
47
|
+
//# sourceMappingURL=chunk-33IOXQYO.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/primitives/slot/Slot.tsx"],"names":[],"mappings":";;;AAkBA,SAAS,UAAA,CAAW,WAAqB,UAAA,EAAgC;AACvE,EAAA,MAAM,MAAA,GAAmB,EAAE,GAAG,UAAA,EAAW;AACzC,EAAA,KAAA,MAAW,GAAA,IAAO,MAAA,CAAO,IAAA,CAAK,SAAS,CAAA,EAAG;AACxC,IAAA,MAAM,OAAA,GAAU,UAAU,GAAG,CAAA;AAC7B,IAAA,MAAM,QAAA,GAAW,WAAW,GAAG,CAAA;AAC/B,IAAA,IAAI,QAAQ,WAAA,EAAa;AACvB,MAAA,MAAA,CAAO,SAAA,GAAY,CAAC,OAAA,EAAS,QAAQ,EAAE,MAAA,CAAO,OAAO,CAAA,CAAE,IAAA,CAAK,GAAG,CAAA;AAAA,IACjE,CAAA,MAAA,IAAW,QAAQ,OAAA,EAAS;AAC1B,MAAA,MAAA,CAAO,KAAA,GAAQ,EAAE,GAAI,OAAA,EAA2B,GAAI,QAAA,EAA2B;AAAA,IACjF,CAAA,MAAA,IAAW,UAAA,CAAW,IAAA,CAAK,GAAG,CAAA,EAAG;AAC/B,MAAA,MAAM,MAAA,GAAS,OAAA;AACf,MAAA,MAAM,OAAA,GAAU,QAAA;AAChB,MAAA,IAAI,UAAU,OAAA,EAAS;AACrB,QAAA,MAAA,CAAO,GAAG,CAAA,GAAI,CAAA,GAAI,IAAA,KAAoB;AACpC,UAAA,OAAA,CAAQ,GAAG,IAAI,CAAA;AACf,UAAA,MAAA,CAAO,GAAG,IAAI,CAAA;AAAA,QAChB,CAAA;AAAA,MACF,WAAW,MAAA,EAAQ;AACjB,QAAA,MAAA,CAAO,GAAG,CAAA,GAAI,MAAA;AAAA,MAChB;AAAA,IACF,CAAA,MAAA,IAAW,aAAa,MAAA,EAAW;AACjC,MAAA,MAAA,CAAO,GAAG,CAAA,GAAI,OAAA;AAAA,IAChB;AAAA,EACF;AACA,EAAA,OAAO,MAAA;AACT;AAWO,IAAM,IAAA,GAAO,UAAA;AAAA,EAClB,CAAC,EAAE,QAAA,EAAU,GAAG,SAAA,IAAa,YAAA,KAAiB;AAC5C,IAAA,IAAI,CAAC,cAAA,CAAe,QAAQ,CAAA,EAAG;AAC7B,MAAA,OAAO,QAAA,CAAS,MAAM,QAAQ,CAAA,GAAI,IAAI,QAAA,CAAS,IAAA,CAAK,IAAI,CAAA,GAAI,IAAA;AAAA,IAC9D;AACA,IAAA,MAAM,KAAA,GAAQ,QAAA;AACd,IAAA,MAAM,SAAS,UAAA,CAAW,SAAA,EAAwB,KAAA,CAAM,KAAA,IAAS,EAAe,CAAA;AAChF,IAAA,OAAO,aAAa,KAAA,EAAO;AAAA,MACzB,GAAG,MAAA;AAAA,MACH,GAAA,EAAK,WAAA,CAAY,YAAA,EAAc,KAAA,CAAM,GAAG;AAAA,KACzC,CAAA;AAAA,EACH;AACF;AACA,IAAA,CAAK,WAAA,GAAc,MAAA","file":"chunk-33IOXQYO.js","sourcesContent":["import {\n Children,\n cloneElement,\n forwardRef,\n isValidElement,\n type CSSProperties,\n type HTMLAttributes,\n type ReactElement,\n type Ref,\n} from 'react';\nimport { composeRefs } from '../../utils/composeRefs';\n\nexport interface SlotProps extends HTMLAttributes<HTMLElement> {\n children?: React.ReactNode;\n}\n\ntype AnyProps = Record<string, unknown>;\n\nfunction mergeProps(slotProps: AnyProps, childProps: AnyProps): AnyProps {\n const merged: AnyProps = { ...childProps };\n for (const key of Object.keys(slotProps)) {\n const slotVal = slotProps[key];\n const childVal = childProps[key];\n if (key === 'className') {\n merged.className = [slotVal, childVal].filter(Boolean).join(' ');\n } else if (key === 'style') {\n merged.style = { ...(slotVal as CSSProperties), ...(childVal as CSSProperties) };\n } else if (/^on[A-Z]/.test(key)) {\n const slotFn = slotVal as ((...args: unknown[]) => void) | undefined;\n const childFn = childVal as ((...args: unknown[]) => void) | undefined;\n if (slotFn && childFn) {\n merged[key] = (...args: unknown[]) => {\n childFn(...args);\n slotFn(...args);\n };\n } else if (slotFn) {\n merged[key] = slotFn;\n }\n } else if (childVal === undefined) {\n merged[key] = slotVal;\n }\n }\n return merged;\n}\n\n/**\n * Polymorphic slot — renders the single child element with the parent's props\n * merged in (className concatenated, handlers chained, refs composed).\n *\n * Use to enable an `asChild` API on a component:\n * ```tsx\n * <Button asChild><a href=\"/x\">Open</a></Button>\n * ```\n */\nexport const Slot = forwardRef<HTMLElement, SlotProps>(\n ({ children, ...slotProps }, forwardedRef) => {\n if (!isValidElement(children)) {\n return Children.count(children) > 1 ? Children.only(null) : null;\n }\n const child = children as ReactElement<AnyProps> & { ref?: Ref<HTMLElement> };\n const merged = mergeProps(slotProps as AnyProps, (child.props ?? {}) as AnyProps);\n return cloneElement(child, {\n ...merged,\n ref: composeRefs(forwardedRef, child.ref),\n });\n },\n);\nSlot.displayName = 'Slot';\n"]}
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
import { tv as tv$1 } from './chunk-BMBIZLO4.js';
|
|
2
|
+
import { Slot } from './chunk-33IOXQYO.js';
|
|
3
|
+
import { cn } from './chunk-KZ4VFY2T.js';
|
|
4
|
+
import { forwardRef } from 'react';
|
|
5
|
+
import { tv } from 'tailwind-variants';
|
|
6
|
+
import { jsx } from 'react/jsx-runtime';
|
|
7
|
+
|
|
8
|
+
var buttonVariants = tv({
|
|
9
|
+
base: "inline-flex items-center justify-center font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-brand-500 disabled:pointer-events-none disabled:opacity-50",
|
|
10
|
+
variants: {
|
|
11
|
+
variant: {
|
|
12
|
+
primary: "bg-brand-600 text-white hover:bg-brand-700",
|
|
13
|
+
secondary: "bg-neutral-200 text-neutral-900 hover:bg-neutral-100",
|
|
14
|
+
ghost: "bg-transparent text-neutral-900 hover:bg-neutral-100"
|
|
15
|
+
},
|
|
16
|
+
size: {
|
|
17
|
+
sm: "h-8 px-3 text-sm rounded-md",
|
|
18
|
+
md: "h-10 px-4 text-sm rounded-md",
|
|
19
|
+
lg: "h-12 px-6 text-base rounded-lg"
|
|
20
|
+
}
|
|
21
|
+
},
|
|
22
|
+
defaultVariants: {
|
|
23
|
+
variant: "primary",
|
|
24
|
+
size: "md"
|
|
25
|
+
}
|
|
26
|
+
});
|
|
27
|
+
var Button = forwardRef(
|
|
28
|
+
({ className, variant, size, ...props }, ref) => {
|
|
29
|
+
return /* @__PURE__ */ jsx(
|
|
30
|
+
"button",
|
|
31
|
+
{
|
|
32
|
+
ref,
|
|
33
|
+
className: cn(buttonVariants({ variant, size }), className),
|
|
34
|
+
...props
|
|
35
|
+
}
|
|
36
|
+
);
|
|
37
|
+
}
|
|
38
|
+
);
|
|
39
|
+
Button.displayName = "Button";
|
|
40
|
+
|
|
41
|
+
// src/actions/iconButton/IconButton.variants.ts
|
|
42
|
+
var iconButtonVariants = tv$1({
|
|
43
|
+
base: "inline-flex items-center justify-center transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-brand-500 disabled:pointer-events-none disabled:opacity-50",
|
|
44
|
+
variants: {
|
|
45
|
+
variant: {
|
|
46
|
+
solid: "bg-brand-600 text-white hover:bg-brand-700",
|
|
47
|
+
soft: "bg-brand-50 text-brand-700 hover:bg-brand-100",
|
|
48
|
+
outline: "border border-neutral-300 bg-white text-neutral-900 hover:bg-neutral-50",
|
|
49
|
+
ghost: "bg-transparent text-neutral-900 hover:bg-neutral-100",
|
|
50
|
+
danger: "bg-danger-600 text-white hover:bg-danger-700"
|
|
51
|
+
},
|
|
52
|
+
size: {
|
|
53
|
+
xs: "h-6 w-6 rounded-sm",
|
|
54
|
+
sm: "h-8 w-8 rounded-md",
|
|
55
|
+
md: "h-10 w-10 rounded-md",
|
|
56
|
+
lg: "h-12 w-12 rounded-lg"
|
|
57
|
+
},
|
|
58
|
+
shape: {
|
|
59
|
+
square: "",
|
|
60
|
+
circle: "rounded-full"
|
|
61
|
+
}
|
|
62
|
+
},
|
|
63
|
+
defaultVariants: {
|
|
64
|
+
variant: "ghost",
|
|
65
|
+
size: "md",
|
|
66
|
+
shape: "square"
|
|
67
|
+
}
|
|
68
|
+
});
|
|
69
|
+
var IconButton = forwardRef(
|
|
70
|
+
({ className, variant, size, shape, type = "button", ...props }, ref) => /* @__PURE__ */ jsx(
|
|
71
|
+
"button",
|
|
72
|
+
{
|
|
73
|
+
ref,
|
|
74
|
+
type,
|
|
75
|
+
className: cn(iconButtonVariants({ variant, size, shape }), className),
|
|
76
|
+
...props
|
|
77
|
+
}
|
|
78
|
+
)
|
|
79
|
+
);
|
|
80
|
+
IconButton.displayName = "IconButton";
|
|
81
|
+
|
|
82
|
+
// src/actions/link/Link.variants.ts
|
|
83
|
+
var linkVariants = tv$1({
|
|
84
|
+
base: "inline-flex items-center transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-brand-500 rounded-sm",
|
|
85
|
+
variants: {
|
|
86
|
+
variant: {
|
|
87
|
+
default: "text-brand-600 hover:text-brand-700 hover:underline",
|
|
88
|
+
subtle: "text-neutral-700 hover:text-neutral-900 hover:underline",
|
|
89
|
+
muted: "text-neutral-500 hover:text-neutral-700 hover:underline",
|
|
90
|
+
inherit: "text-current underline-offset-2 hover:underline"
|
|
91
|
+
},
|
|
92
|
+
size: {
|
|
93
|
+
sm: "text-sm",
|
|
94
|
+
md: "text-base",
|
|
95
|
+
lg: "text-lg"
|
|
96
|
+
}
|
|
97
|
+
},
|
|
98
|
+
defaultVariants: {
|
|
99
|
+
variant: "default",
|
|
100
|
+
size: "md"
|
|
101
|
+
}
|
|
102
|
+
});
|
|
103
|
+
var Link = forwardRef(
|
|
104
|
+
({ className, variant, size, asChild = false, ...props }, ref) => {
|
|
105
|
+
const Comp = asChild ? Slot : "a";
|
|
106
|
+
return /* @__PURE__ */ jsx(
|
|
107
|
+
Comp,
|
|
108
|
+
{
|
|
109
|
+
ref,
|
|
110
|
+
className: cn(linkVariants({ variant, size }), className),
|
|
111
|
+
...props
|
|
112
|
+
}
|
|
113
|
+
);
|
|
114
|
+
}
|
|
115
|
+
);
|
|
116
|
+
Link.displayName = "Link";
|
|
117
|
+
|
|
118
|
+
export { Button, IconButton, Link, buttonVariants, iconButtonVariants, linkVariants };
|
|
119
|
+
//# sourceMappingURL=chunk-4CIRBYYP.js.map
|
|
120
|
+
//# sourceMappingURL=chunk-4CIRBYYP.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/actions/button/Button.variants.ts","../src/actions/button/Button.tsx","../src/actions/iconButton/IconButton.variants.ts","../src/actions/iconButton/IconButton.tsx","../src/actions/link/Link.variants.ts","../src/actions/link/Link.tsx"],"names":["tv","forwardRef","jsx"],"mappings":"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","file":"chunk-4CIRBYYP.js","sourcesContent":["import { tv, type VariantProps } from 'tailwind-variants';\n\nexport const buttonVariants = tv({\n base: 'inline-flex items-center justify-center font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-brand-500 disabled:pointer-events-none disabled:opacity-50',\n variants: {\n variant: {\n primary: 'bg-brand-600 text-white hover:bg-brand-700',\n secondary: 'bg-neutral-200 text-neutral-900 hover:bg-neutral-100',\n ghost: 'bg-transparent text-neutral-900 hover:bg-neutral-100',\n },\n size: {\n sm: 'h-8 px-3 text-sm rounded-md',\n md: 'h-10 px-4 text-sm rounded-md',\n lg: 'h-12 px-6 text-base rounded-lg',\n },\n },\n defaultVariants: {\n variant: 'primary',\n size: 'md',\n },\n});\n\nexport type ButtonVariants = VariantProps<typeof buttonVariants>;\n","import { forwardRef, type ButtonHTMLAttributes } from 'react';\nimport { cn } from '../../utils';\nimport { buttonVariants, type ButtonVariants } from './Button.variants';\n\nexport interface ButtonProps extends ButtonHTMLAttributes<HTMLButtonElement>, ButtonVariants {}\n\nexport const Button = forwardRef<HTMLButtonElement, ButtonProps>(\n ({ className, variant, size, ...props }, ref) => {\n return (\n <button\n ref={ref}\n className={cn(buttonVariants({ variant, size }), className)}\n {...props}\n />\n );\n },\n);\n\nButton.displayName = 'Button';\n","import { tv, type VariantProps } from '../../utils';\n\nexport const iconButtonVariants = tv({\n base: 'inline-flex items-center justify-center transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-brand-500 disabled:pointer-events-none disabled:opacity-50',\n variants: {\n variant: {\n solid: 'bg-brand-600 text-white hover:bg-brand-700',\n soft: 'bg-brand-50 text-brand-700 hover:bg-brand-100',\n outline: 'border border-neutral-300 bg-white text-neutral-900 hover:bg-neutral-50',\n ghost: 'bg-transparent text-neutral-900 hover:bg-neutral-100',\n danger: 'bg-danger-600 text-white hover:bg-danger-700',\n },\n size: {\n xs: 'h-6 w-6 rounded-sm',\n sm: 'h-8 w-8 rounded-md',\n md: 'h-10 w-10 rounded-md',\n lg: 'h-12 w-12 rounded-lg',\n },\n shape: {\n square: '',\n circle: 'rounded-full',\n },\n },\n defaultVariants: {\n variant: 'ghost',\n size: 'md',\n shape: 'square',\n },\n});\n\nexport type IconButtonVariants = VariantProps<typeof iconButtonVariants>;\n","import { forwardRef, type ButtonHTMLAttributes, type ReactNode } from 'react';\nimport { cn } from '../../utils';\nimport { iconButtonVariants, type IconButtonVariants } from './IconButton.variants';\n\nexport interface IconButtonProps\n extends ButtonHTMLAttributes<HTMLButtonElement>,\n IconButtonVariants {\n /** REQUIRED accessible label. IconButton has no visible text. */\n 'aria-label': string;\n children: ReactNode;\n}\n\n/**\n * Square / circular button containing only an icon. `aria-label` is\n * required by the type — there is no visible text fallback.\n */\nexport const IconButton = forwardRef<HTMLButtonElement, IconButtonProps>(\n ({ className, variant, size, shape, type = 'button', ...props }, ref) => (\n <button\n ref={ref}\n type={type}\n className={cn(iconButtonVariants({ variant, size, shape }), className)}\n {...props}\n />\n ),\n);\nIconButton.displayName = 'IconButton';\n","import { tv, type VariantProps } from '../../utils';\n\nexport const linkVariants = tv({\n base: 'inline-flex items-center transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-brand-500 rounded-sm',\n variants: {\n variant: {\n default: 'text-brand-600 hover:text-brand-700 hover:underline',\n subtle: 'text-neutral-700 hover:text-neutral-900 hover:underline',\n muted: 'text-neutral-500 hover:text-neutral-700 hover:underline',\n inherit: 'text-current underline-offset-2 hover:underline',\n },\n size: {\n sm: 'text-sm',\n md: 'text-base',\n lg: 'text-lg',\n },\n },\n defaultVariants: {\n variant: 'default',\n size: 'md',\n },\n});\n\nexport type LinkVariants = VariantProps<typeof linkVariants>;\n","import { forwardRef, type AnchorHTMLAttributes } from 'react';\nimport { cn } from '../../utils';\nimport { Slot } from '../../primitives/slot/Slot';\nimport { linkVariants, type LinkVariants } from './Link.variants';\n\nexport interface LinkProps extends AnchorHTMLAttributes<HTMLAnchorElement>, LinkVariants {\n /** When true, render the child element as the link instead of an `<a>`.\n * Use for router `<Link>` components from Next.js / React Router. */\n asChild?: boolean;\n}\n\n/**\n * Anchor with consistent focus / hover styling. Pass `asChild` to render a\n * router `<Link>` while inheriting our visuals.\n */\nexport const Link = forwardRef<HTMLAnchorElement, LinkProps>(\n ({ className, variant, size, asChild = false, ...props }, ref) => {\n const Comp = asChild ? Slot : 'a';\n return (\n <Comp\n ref={ref}\n className={cn(linkVariants({ variant, size }), className)}\n {...(props as AnchorHTMLAttributes<HTMLAnchorElement>)}\n />\n );\n },\n);\nLink.displayName = 'Link';\n"]}
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
import { useScrollLock } from './chunk-77WSI427.js';
|
|
2
|
+
import { useId } from './chunk-JTJEI6MF.js';
|
|
3
|
+
import { __export } from './chunk-PZ5AY32C.js';
|
|
4
|
+
import { useState, useRef, useCallback, useLayoutEffect, useEffect } from 'react';
|
|
5
|
+
|
|
6
|
+
// src/hooks/index.ts
|
|
7
|
+
var hooks_exports = {};
|
|
8
|
+
__export(hooks_exports, {
|
|
9
|
+
useControlled: () => useControlled,
|
|
10
|
+
useDisclosure: () => useDisclosure,
|
|
11
|
+
useEscape: () => useEscape,
|
|
12
|
+
useEventListener: () => useEventListener,
|
|
13
|
+
useFocusTrap: () => useFocusTrap,
|
|
14
|
+
useId: () => useId,
|
|
15
|
+
useMediaQuery: () => useMediaQuery,
|
|
16
|
+
useOutsideClick: () => useOutsideClick,
|
|
17
|
+
useResizeObserver: () => useResizeObserver,
|
|
18
|
+
useScrollLock: () => useScrollLock
|
|
19
|
+
});
|
|
20
|
+
function useControlled({
|
|
21
|
+
controlled,
|
|
22
|
+
default: defaultValue,
|
|
23
|
+
onChange
|
|
24
|
+
}) {
|
|
25
|
+
const [uncontrolled, setUncontrolled] = useState(defaultValue);
|
|
26
|
+
const onChangeRef = useRef(onChange);
|
|
27
|
+
onChangeRef.current = onChange;
|
|
28
|
+
const isControlled = controlled !== void 0;
|
|
29
|
+
const value = isControlled ? controlled : uncontrolled;
|
|
30
|
+
const setValue = useCallback(
|
|
31
|
+
(next) => {
|
|
32
|
+
if (!isControlled) setUncontrolled(next);
|
|
33
|
+
onChangeRef.current?.(next);
|
|
34
|
+
},
|
|
35
|
+
[isControlled]
|
|
36
|
+
);
|
|
37
|
+
return [value, setValue];
|
|
38
|
+
}
|
|
39
|
+
function useDisclosure(initial = false) {
|
|
40
|
+
const [isOpen, setIsOpen] = useState(initial);
|
|
41
|
+
const open = useCallback(() => setIsOpen(true), []);
|
|
42
|
+
const close = useCallback(() => setIsOpen(false), []);
|
|
43
|
+
const toggle = useCallback(() => setIsOpen((o) => !o), []);
|
|
44
|
+
return { isOpen, open, close, toggle, setOpen: setIsOpen };
|
|
45
|
+
}
|
|
46
|
+
function useEventListener(event, handler, target = document, options) {
|
|
47
|
+
const handlerRef = useRef(handler);
|
|
48
|
+
useLayoutEffect(() => {
|
|
49
|
+
handlerRef.current = handler;
|
|
50
|
+
}, [handler]);
|
|
51
|
+
useEffect(() => {
|
|
52
|
+
if (!target) return;
|
|
53
|
+
const listener = (e) => handlerRef.current(e);
|
|
54
|
+
target.addEventListener(event, listener, options);
|
|
55
|
+
return () => target.removeEventListener(event, listener, options);
|
|
56
|
+
}, [event, target, options]);
|
|
57
|
+
}
|
|
58
|
+
function useOutsideClick(refs, handler, enabled = true) {
|
|
59
|
+
const handlerRef = useRef(handler);
|
|
60
|
+
handlerRef.current = handler;
|
|
61
|
+
useEffect(() => {
|
|
62
|
+
if (!enabled) return;
|
|
63
|
+
const refList = Array.isArray(refs) ? refs : [refs];
|
|
64
|
+
const onPointerDown = (e) => {
|
|
65
|
+
const target = e.target;
|
|
66
|
+
if (!target) return;
|
|
67
|
+
for (const ref of refList) {
|
|
68
|
+
if (ref.current && ref.current.contains(target)) return;
|
|
69
|
+
}
|
|
70
|
+
handlerRef.current(e);
|
|
71
|
+
};
|
|
72
|
+
document.addEventListener("pointerdown", onPointerDown, true);
|
|
73
|
+
return () => document.removeEventListener("pointerdown", onPointerDown, true);
|
|
74
|
+
}, [refs, enabled]);
|
|
75
|
+
}
|
|
76
|
+
function useEscape(handler, enabled = true) {
|
|
77
|
+
const handlerRef = useRef(handler);
|
|
78
|
+
handlerRef.current = handler;
|
|
79
|
+
useEffect(() => {
|
|
80
|
+
if (!enabled) return;
|
|
81
|
+
const onKeyDown = (e) => {
|
|
82
|
+
if (e.key === "Escape") handlerRef.current(e);
|
|
83
|
+
};
|
|
84
|
+
document.addEventListener("keydown", onKeyDown);
|
|
85
|
+
return () => document.removeEventListener("keydown", onKeyDown);
|
|
86
|
+
}, [enabled]);
|
|
87
|
+
}
|
|
88
|
+
var FOCUSABLE_SELECTOR = [
|
|
89
|
+
"a[href]",
|
|
90
|
+
"button:not([disabled])",
|
|
91
|
+
"input:not([disabled])",
|
|
92
|
+
"select:not([disabled])",
|
|
93
|
+
"textarea:not([disabled])",
|
|
94
|
+
'[tabindex]:not([tabindex="-1"])',
|
|
95
|
+
'[contenteditable="true"]'
|
|
96
|
+
].join(",");
|
|
97
|
+
function getFocusable(container) {
|
|
98
|
+
return Array.from(container.querySelectorAll(FOCUSABLE_SELECTOR)).filter(
|
|
99
|
+
(el) => !el.hasAttribute("aria-hidden") && el.offsetParent !== null
|
|
100
|
+
);
|
|
101
|
+
}
|
|
102
|
+
function useFocusTrap(ref, enabled = true) {
|
|
103
|
+
useEffect(() => {
|
|
104
|
+
if (!enabled || !ref.current) return;
|
|
105
|
+
const container = ref.current;
|
|
106
|
+
const previouslyFocused = document.activeElement;
|
|
107
|
+
const focusables = getFocusable(container);
|
|
108
|
+
if (focusables.length > 0 && !container.contains(document.activeElement)) {
|
|
109
|
+
focusables[0]?.focus();
|
|
110
|
+
} else if (focusables.length === 0) {
|
|
111
|
+
container.tabIndex = -1;
|
|
112
|
+
container.focus();
|
|
113
|
+
}
|
|
114
|
+
const onKeyDown = (e) => {
|
|
115
|
+
if (e.key !== "Tab") return;
|
|
116
|
+
const items = getFocusable(container);
|
|
117
|
+
if (items.length === 0) {
|
|
118
|
+
e.preventDefault();
|
|
119
|
+
return;
|
|
120
|
+
}
|
|
121
|
+
const first = items[0];
|
|
122
|
+
const last = items[items.length - 1];
|
|
123
|
+
if (!first || !last) return;
|
|
124
|
+
const active = document.activeElement;
|
|
125
|
+
if (e.shiftKey && active === first) {
|
|
126
|
+
e.preventDefault();
|
|
127
|
+
last.focus();
|
|
128
|
+
} else if (!e.shiftKey && active === last) {
|
|
129
|
+
e.preventDefault();
|
|
130
|
+
first.focus();
|
|
131
|
+
}
|
|
132
|
+
};
|
|
133
|
+
container.addEventListener("keydown", onKeyDown);
|
|
134
|
+
return () => {
|
|
135
|
+
container.removeEventListener("keydown", onKeyDown);
|
|
136
|
+
previouslyFocused?.focus?.();
|
|
137
|
+
};
|
|
138
|
+
}, [ref, enabled]);
|
|
139
|
+
}
|
|
140
|
+
function useResizeObserver(ref, callback, enabled = true) {
|
|
141
|
+
const callbackRef = useRef(callback);
|
|
142
|
+
callbackRef.current = callback;
|
|
143
|
+
useEffect(() => {
|
|
144
|
+
if (!enabled || !ref.current || typeof ResizeObserver === "undefined") return;
|
|
145
|
+
const element = ref.current;
|
|
146
|
+
const observer = new ResizeObserver((entries) => {
|
|
147
|
+
const entry = entries[0];
|
|
148
|
+
if (entry) callbackRef.current(entry);
|
|
149
|
+
});
|
|
150
|
+
observer.observe(element);
|
|
151
|
+
return () => observer.disconnect();
|
|
152
|
+
}, [ref, enabled]);
|
|
153
|
+
}
|
|
154
|
+
function useMediaQuery(query) {
|
|
155
|
+
const [matches, setMatches] = useState(() => window.matchMedia(query).matches);
|
|
156
|
+
useEffect(() => {
|
|
157
|
+
const mql = window.matchMedia(query);
|
|
158
|
+
setMatches(mql.matches);
|
|
159
|
+
const onChange = (e) => setMatches(e.matches);
|
|
160
|
+
mql.addEventListener("change", onChange);
|
|
161
|
+
return () => mql.removeEventListener("change", onChange);
|
|
162
|
+
}, [query]);
|
|
163
|
+
return matches;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
export { hooks_exports, useControlled, useDisclosure, useEscape, useEventListener, useFocusTrap, useMediaQuery, useOutsideClick, useResizeObserver };
|
|
167
|
+
//# sourceMappingURL=chunk-6NYTRHP7.js.map
|
|
168
|
+
//# sourceMappingURL=chunk-6NYTRHP7.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/hooks/index.ts","../src/hooks/useControlled.ts","../src/hooks/useDisclosure.ts","../src/hooks/useEventListener.ts","../src/hooks/useOutsideClick.ts","../src/hooks/useEscape.ts","../src/hooks/useFocusTrap.ts","../src/hooks/useResizeObserver.ts","../src/hooks/useMediaQuery.ts"],"names":["useState","useCallback","useRef","useEffect"],"mappings":"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","file":"chunk-6NYTRHP7.js","sourcesContent":["export { useId } from './useId';\nexport { useControlled } from './useControlled';\nexport { useDisclosure, type DisclosureControls } from './useDisclosure';\nexport { useEventListener } from './useEventListener';\nexport { useOutsideClick } from './useOutsideClick';\nexport { useEscape } from './useEscape';\nexport { useFocusTrap } from './useFocusTrap';\nexport { useScrollLock } from './useScrollLock';\nexport { useResizeObserver } from './useResizeObserver';\nexport { useMediaQuery } from './useMediaQuery';\n","import { useCallback, useRef, useState } from 'react';\n\ninterface UseControlledOptions<T> {\n controlled: T | undefined;\n default: T;\n onChange?: (value: T) => void;\n}\n\n/**\n * Standard controlled/uncontrolled pattern.\n *\n * - If `controlled` is defined, the component is controlled — internal state is\n * ignored, `setValue` only fires `onChange`.\n * - Otherwise the component owns its state, `setValue` updates it, and `onChange`\n * still fires for consumers that want to observe changes.\n */\nexport function useControlled<T>({\n controlled,\n default: defaultValue,\n onChange,\n}: UseControlledOptions<T>): [T, (value: T) => void] {\n const [uncontrolled, setUncontrolled] = useState<T>(defaultValue);\n const onChangeRef = useRef(onChange);\n onChangeRef.current = onChange;\n\n const isControlled = controlled !== undefined;\n const value = isControlled ? controlled : uncontrolled;\n\n const setValue = useCallback(\n (next: T) => {\n if (!isControlled) setUncontrolled(next);\n onChangeRef.current?.(next);\n },\n [isControlled],\n );\n\n return [value, setValue];\n}\n","import { useCallback, useState } from 'react';\n\nexport interface DisclosureControls {\n isOpen: boolean;\n open: () => void;\n close: () => void;\n toggle: () => void;\n setOpen: (next: boolean) => void;\n}\n\n/**\n * Minimal open/close state with stable callbacks. The standard backbone for\n * Modal, Drawer, Popover, Menu, Accordion, etc. Use `useControlled` underneath\n * when the consumer may also pass a controlled `open` prop.\n */\nexport function useDisclosure(initial = false): DisclosureControls {\n const [isOpen, setIsOpen] = useState(initial);\n const open = useCallback(() => setIsOpen(true), []);\n const close = useCallback(() => setIsOpen(false), []);\n const toggle = useCallback(() => setIsOpen((o) => !o), []);\n return { isOpen, open, close, toggle, setOpen: setIsOpen };\n}\n","import { useEffect, useLayoutEffect, useRef } from 'react';\n\ntype Target = Window | Document | HTMLElement | null;\n\n/**\n * Add an event listener and clean it up automatically. Handler is read from\n * a ref so consumers don't need to memoize it.\n */\nexport function useEventListener<K extends string>(\n event: K,\n handler: (event: Event) => void,\n target: Target = document,\n options?: boolean | AddEventListenerOptions,\n): void {\n const handlerRef = useRef(handler);\n useLayoutEffect(() => {\n handlerRef.current = handler;\n }, [handler]);\n\n useEffect(() => {\n if (!target) return;\n const listener = (e: Event) => handlerRef.current(e);\n target.addEventListener(event, listener, options);\n return () => target.removeEventListener(event, listener, options);\n }, [event, target, options]);\n}\n","import { useEffect, useRef, type RefObject } from 'react';\n\n/**\n * Fire `handler` when the user clicks outside any of the provided refs.\n * Uses `pointerdown` so it fires before focus shifts (avoids losing focus\n * inside an overlay before a click on a trigger registers).\n */\nexport function useOutsideClick(\n refs: RefObject<HTMLElement | null> | RefObject<HTMLElement | null>[],\n handler: (event: PointerEvent) => void,\n enabled = true,\n): void {\n const handlerRef = useRef(handler);\n handlerRef.current = handler;\n\n useEffect(() => {\n if (!enabled) return;\n const refList = Array.isArray(refs) ? refs : [refs];\n\n const onPointerDown = (e: PointerEvent) => {\n const target = e.target as Node | null;\n if (!target) return;\n for (const ref of refList) {\n if (ref.current && ref.current.contains(target)) return;\n }\n handlerRef.current(e);\n };\n\n document.addEventListener('pointerdown', onPointerDown, true);\n return () => document.removeEventListener('pointerdown', onPointerDown, true);\n }, [refs, enabled]);\n}\n","import { useEffect, useRef } from 'react';\n\n/**\n * Fire `handler` when the Escape key is pressed at the document level.\n * For nested overlays, the topmost should call `event.stopPropagation()` in\n * its handler — `DismissableLayer` handles this stack-style.\n */\nexport function useEscape(handler: (event: KeyboardEvent) => void, enabled = true): void {\n const handlerRef = useRef(handler);\n handlerRef.current = handler;\n\n useEffect(() => {\n if (!enabled) return;\n const onKeyDown = (e: KeyboardEvent) => {\n if (e.key === 'Escape') handlerRef.current(e);\n };\n document.addEventListener('keydown', onKeyDown);\n return () => document.removeEventListener('keydown', onKeyDown);\n }, [enabled]);\n}\n","import { useEffect, type RefObject } from 'react';\n\nconst FOCUSABLE_SELECTOR = [\n 'a[href]',\n 'button:not([disabled])',\n 'input:not([disabled])',\n 'select:not([disabled])',\n 'textarea:not([disabled])',\n '[tabindex]:not([tabindex=\"-1\"])',\n '[contenteditable=\"true\"]',\n].join(',');\n\nfunction getFocusable(container: HTMLElement): HTMLElement[] {\n return Array.from(container.querySelectorAll<HTMLElement>(FOCUSABLE_SELECTOR)).filter(\n (el) => !el.hasAttribute('aria-hidden') && el.offsetParent !== null,\n );\n}\n\n/**\n * Trap Tab / Shift+Tab focus inside the referenced element. On mount, focuses\n * the first focusable child (unless already focused inside). On unmount,\n * returns focus to the element that had it before mounting.\n *\n * For richer behavior (sentinels, nested traps), wrap `FocusScope` instead —\n * this hook is the lower primitive.\n */\nexport function useFocusTrap(ref: RefObject<HTMLElement | null>, enabled = true): void {\n useEffect(() => {\n if (!enabled || !ref.current) return;\n const container = ref.current;\n const previouslyFocused = document.activeElement as HTMLElement | null;\n\n const focusables = getFocusable(container);\n if (focusables.length > 0 && !container.contains(document.activeElement)) {\n focusables[0]?.focus();\n } else if (focusables.length === 0) {\n container.tabIndex = -1;\n container.focus();\n }\n\n const onKeyDown = (e: KeyboardEvent) => {\n if (e.key !== 'Tab') return;\n const items = getFocusable(container);\n if (items.length === 0) {\n e.preventDefault();\n return;\n }\n const first = items[0];\n const last = items[items.length - 1];\n if (!first || !last) return;\n const active = document.activeElement;\n if (e.shiftKey && active === first) {\n e.preventDefault();\n last.focus();\n } else if (!e.shiftKey && active === last) {\n e.preventDefault();\n first.focus();\n }\n };\n\n container.addEventListener('keydown', onKeyDown);\n return () => {\n container.removeEventListener('keydown', onKeyDown);\n previouslyFocused?.focus?.();\n };\n }, [ref, enabled]);\n}\n","import { useEffect, useRef, type RefObject } from 'react';\n\n/**\n * Run `callback` whenever the referenced element's size changes. Returns\n * synchronously after layout, before paint. Cleans up automatically.\n */\nexport function useResizeObserver<T extends HTMLElement>(\n ref: RefObject<T | null>,\n callback: (entry: ResizeObserverEntry) => void,\n enabled = true,\n): void {\n const callbackRef = useRef(callback);\n callbackRef.current = callback;\n\n useEffect(() => {\n if (!enabled || !ref.current || typeof ResizeObserver === 'undefined') return;\n const element = ref.current;\n const observer = new ResizeObserver((entries) => {\n const entry = entries[0];\n if (entry) callbackRef.current(entry);\n });\n observer.observe(element);\n return () => observer.disconnect();\n }, [ref, enabled]);\n}\n","import { useEffect, useState } from 'react';\n\n/**\n * Reactively follow a CSS media query. Pass a query string like\n * `'(min-width: 768px)'` or `'(prefers-reduced-motion: reduce)'`.\n */\nexport function useMediaQuery(query: string): boolean {\n const [matches, setMatches] = useState(() => window.matchMedia(query).matches);\n\n useEffect(() => {\n const mql = window.matchMedia(query);\n setMatches(mql.matches);\n const onChange = (e: MediaQueryListEvent) => setMatches(e.matches);\n mql.addEventListener('change', onChange);\n return () => mql.removeEventListener('change', onChange);\n }, [query]);\n\n return matches;\n}\n"]}
|