@yarcl/react 0.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 (79) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +53 -0
  3. package/dist/color.d.ts +12 -0
  4. package/dist/color.js +41 -0
  5. package/dist/css.d.ts +10 -0
  6. package/dist/css.js +175 -0
  7. package/dist/define.d.ts +383 -0
  8. package/dist/define.js +29 -0
  9. package/dist/plugin.d.ts +33 -0
  10. package/dist/plugin.js +80 -0
  11. package/package.json +66 -0
  12. package/src/apply.ts +46 -0
  13. package/src/classes.ts +23 -0
  14. package/src/color.ts +48 -0
  15. package/src/components/Accordion.tsx +274 -0
  16. package/src/components/Alert.tsx +85 -0
  17. package/src/components/Badge.tsx +79 -0
  18. package/src/components/Breadcrumb.tsx +239 -0
  19. package/src/components/Button.tsx +58 -0
  20. package/src/components/ButtonGroup.tsx +61 -0
  21. package/src/components/Card.tsx +50 -0
  22. package/src/components/Checkbox.tsx +49 -0
  23. package/src/components/Combobox.tsx +522 -0
  24. package/src/components/CommandPalette.tsx +452 -0
  25. package/src/components/DatePicker.tsx +432 -0
  26. package/src/components/Dialog.tsx +39 -0
  27. package/src/components/Divider.tsx +34 -0
  28. package/src/components/Drawer.tsx +31 -0
  29. package/src/components/Field.tsx +61 -0
  30. package/src/components/Heading.tsx +40 -0
  31. package/src/components/HoverCard.tsx +108 -0
  32. package/src/components/IconButton.tsx +59 -0
  33. package/src/components/Inline.tsx +42 -0
  34. package/src/components/Input.tsx +28 -0
  35. package/src/components/Label.tsx +58 -0
  36. package/src/components/Link.tsx +41 -0
  37. package/src/components/Menu.tsx +207 -0
  38. package/src/components/Modal.tsx +164 -0
  39. package/src/components/NumberInput.tsx +208 -0
  40. package/src/components/Pagination.tsx +227 -0
  41. package/src/components/Popover.tsx +140 -0
  42. package/src/components/Progress.tsx +122 -0
  43. package/src/components/Radio.tsx +59 -0
  44. package/src/components/RadioGroup.tsx +114 -0
  45. package/src/components/Select.tsx +197 -0
  46. package/src/components/Skeleton.tsx +95 -0
  47. package/src/components/Slider.tsx +315 -0
  48. package/src/components/Spinner.tsx +38 -0
  49. package/src/components/Stack.tsx +57 -0
  50. package/src/components/Switch.tsx +42 -0
  51. package/src/components/Table.tsx +99 -0
  52. package/src/components/Tabs.tsx +159 -0
  53. package/src/components/Text.tsx +67 -0
  54. package/src/components/Textarea.tsx +26 -0
  55. package/src/components/Toast.tsx +190 -0
  56. package/src/components/ToggleGroup.tsx +227 -0
  57. package/src/components/Tooltip.tsx +78 -0
  58. package/src/contrast.ts +82 -0
  59. package/src/css.ts +228 -0
  60. package/src/define.check.ts +259 -0
  61. package/src/define.ts +379 -0
  62. package/src/field-context.ts +31 -0
  63. package/src/floating.tsx +61 -0
  64. package/src/hooks.ts +19 -0
  65. package/src/index.ts +119 -0
  66. package/src/plugin.ts +94 -0
  67. package/src/reference/DesignReference.tsx +374 -0
  68. package/src/reference/index.ts +2 -0
  69. package/src/reference/reference.css +58 -0
  70. package/src/runtime.ts +38 -0
  71. package/src/styles.css +1971 -0
  72. package/src/themes/bloom.ts +72 -0
  73. package/src/themes/brutalist.ts +63 -0
  74. package/src/themes/compact.ts +63 -0
  75. package/src/themes/contract.ts +24 -0
  76. package/src/themes/editorial.ts +55 -0
  77. package/src/themes/index.ts +47 -0
  78. package/src/types.ts +69 -0
  79. package/src/yarcl.config.ts +104 -0
package/src/define.ts ADDED
@@ -0,0 +1,379 @@
1
+ /** A color with a value for each color scheme. Emitted as CSS `light-dark()`. */
2
+ export interface ColorPair {
3
+ /** Value used when the color scheme is light. */
4
+ light: string;
5
+ /** Value used when the color scheme is dark. */
6
+ dark: string;
7
+ }
8
+
9
+ /** A semantic color: one value per color scheme, plus an optional foreground. */
10
+ export interface ColorToken extends ColorPair {
11
+ /**
12
+ * Text color used on top of this color.
13
+ * Computed by contrast (black or white) per scheme when omitted; requires hex values.
14
+ */
15
+ on?: string | ColorPair;
16
+ /**
17
+ * Color used when this color is drawn as text: outline, soft and ghost variants, colored `Text`,
18
+ * `Link`, menu items. Computed per scheme when omitted: the color itself when it has enough
19
+ * contrast on the page, surface and tinted backgrounds, otherwise mixed toward the neutral text
20
+ * color until it does. Requires hex values.
21
+ */
22
+ text?: string | ColorPair;
23
+ }
24
+
25
+ /**
26
+ * A single step of the shared control size scale.
27
+ * Every sized control reads the same entry, so controls of the same size share the same height.
28
+ */
29
+ export interface SizeToken {
30
+ /** Control height, e.g. `'2.5rem'`. */
31
+ height: string;
32
+ /** Horizontal padding, e.g. `'1rem'`. */
33
+ paddingX: string;
34
+ /** Font size, e.g. `'0.875rem'`. */
35
+ fontSize: string;
36
+ /** Size of icons inside controls of this size, e.g. `'1rem'`. */
37
+ iconSize: string;
38
+ }
39
+
40
+ /**
41
+ * A style recipe applied on top of a semantic color.
42
+ * Shared by every component that takes a `variant` prop.
43
+ */
44
+ export interface VariantToken {
45
+ /** `fill`: the color itself; `tint`: a translucent wash of the color; `none`: transparent. */
46
+ background: 'fill' | 'tint' | 'none';
47
+ /** `color`: the semantic color; `neutral`: the neutral border color; `none`: no visible border. */
48
+ border: 'color' | 'neutral' | 'none';
49
+ /** `on`: the color's foreground; `color`: the semantic color; `neutral`: the default text color. */
50
+ text: 'on' | 'color' | 'neutral';
51
+ }
52
+
53
+ /** Cell spacing for tables at one density. */
54
+ export interface DensityToken {
55
+ /** Horizontal cell padding, e.g. `'0.75rem'`. */
56
+ paddingX: string;
57
+ /** Vertical cell padding, e.g. `'0.5rem'`. */
58
+ paddingY: string;
59
+ /** Cell font size, e.g. `'0.875rem'`. */
60
+ fontSize: string;
61
+ }
62
+
63
+ /** A font file to load, emitted as an `@font-face` rule. */
64
+ export interface FontFaceToken {
65
+ /** Family name to reference from `typography.families`, e.g. `'Inter'`. */
66
+ family: string;
67
+ /**
68
+ * Font file URL(s), e.g. `'/fonts/inter.woff2'`, or `'local(Inter)'`.
69
+ * The format is inferred from the extension.
70
+ */
71
+ src: string | string[];
72
+ /** Weight or weight range, e.g. `400` or `'100 900'` for variable fonts. */
73
+ weight?: number | string;
74
+ /** Font style of this file. */
75
+ style?: 'normal' | 'italic';
76
+ /**
77
+ * How the font displays while loading.
78
+ * @default 'swap'
79
+ */
80
+ display?: 'auto' | 'block' | 'swap' | 'fallback' | 'optional';
81
+ }
82
+
83
+ /** A named text style. */
84
+ export interface TextStyleToken {
85
+ /** A key of `typography.families`. */
86
+ family: string;
87
+ /** Font size, e.g. `'1rem'`. */
88
+ size: string;
89
+ /** Font weight, e.g. `400`. */
90
+ weight: number;
91
+ /** Unitless line height, e.g. `1.5`. */
92
+ lineHeight: number;
93
+ /** Letter spacing, e.g. `'-0.01em'`. */
94
+ letterSpacing?: string;
95
+ }
96
+
97
+ /**
98
+ * Token props each component accepts in `components`. A component's defaults can only set
99
+ * props it actually has.
100
+ */
101
+ export interface ComponentTokenProps {
102
+ Button: 'size' | 'radius' | 'color' | 'variant';
103
+ IconButton: 'size' | 'radius' | 'color' | 'variant';
104
+ ToggleGroup: 'size' | 'radius' | 'color' | 'variant' | 'selectedVariant';
105
+ Input: 'size' | 'radius' | 'color';
106
+ Textarea: 'size' | 'radius' | 'color';
107
+ NumberInput: 'size' | 'radius' | 'color';
108
+ Select: 'size' | 'radius' | 'color';
109
+ Combobox: 'size' | 'radius' | 'color';
110
+ DatePicker: 'size' | 'radius' | 'color' | 'variant';
111
+ Checkbox: 'size' | 'color';
112
+ Radio: 'size' | 'color';
113
+ Switch: 'size' | 'color';
114
+ Slider: 'size' | 'radius' | 'color';
115
+ Badge: 'size' | 'radius' | 'color' | 'variant';
116
+ Alert: 'radius' | 'color' | 'variant';
117
+ Card: 'radius' | 'padding' | 'shadow';
118
+ Popover: 'radius' | 'padding';
119
+ HoverCard: 'radius' | 'padding';
120
+ Dialog: 'radius' | 'size';
121
+ Drawer: 'size';
122
+ CommandPalette: 'size' | 'radius' | 'color';
123
+ Menu: 'size';
124
+ Tabs: 'size' | 'color';
125
+ Pagination: 'size' | 'radius' | 'color' | 'variant' | 'selectedVariant';
126
+ Accordion: 'size' | 'radius' | 'color';
127
+ Table: 'density';
128
+ Stack: 'gap';
129
+ Inline: 'gap';
130
+ Text: 'textStyle' | 'color';
131
+ Label: 'textStyle' | 'color';
132
+ Link: 'color';
133
+ Breadcrumb: 'textStyle' | 'color';
134
+ Spinner: 'size' | 'color';
135
+ Skeleton: 'size' | 'radius';
136
+ Progress: 'size' | 'color' | 'radius';
137
+ Toast: 'color';
138
+ }
139
+
140
+ /** Names of components that accept defaults in `components`. */
141
+ export type ComponentName = keyof ComponentTokenProps;
142
+
143
+ /**
144
+ * The structure every yarcl config must satisfy.
145
+ *
146
+ * Open groups (`colors`, `sizes`, `radii`, `variants`, `spacing`, `shadows`, `density`, `modalSizes`, `typography`) take any keys;
147
+ * those keys become the valid prop values. Groups with required keys (`neutrals`, `zIndex`,
148
+ * `motion`, `timing`, `borders`) must include the keys the library depends on, and accept any extra
149
+ * keys, which are emitted as CSS variables for the consumer's own styles.
150
+ */
151
+ export interface YarclShape {
152
+ /** Semantic colors. Keys become the valid values of the `color` prop. */
153
+ colors: Record<string, ColorToken>;
154
+ /** Neutral colors for backgrounds, text and borders. Extra keys allowed. */
155
+ neutrals: Record<string, ColorPair> & {
156
+ /** Page background. */
157
+ bg: ColorPair;
158
+ /** Background of controls and raised surfaces. */
159
+ surface: ColorPair;
160
+ /** Default text. */
161
+ text: ColorPair;
162
+ /** Secondary text and placeholders. */
163
+ muted: ColorPair;
164
+ /** Default border. */
165
+ border: ColorPair;
166
+ };
167
+ /** Control size scale. Keys become the valid values of the `size` prop. */
168
+ sizes: Record<string, SizeToken>;
169
+ /**
170
+ * Border radii. Keys become the valid values of the `radius` prop. Name them after your
171
+ * sizes (`sm`, `md`, `lg` …) so controls can match their size, plus exceptions such as
172
+ * `square` and `rounded`. `size` is reserved.
173
+ */
174
+ radii: Record<string, string>;
175
+ /** Style recipes. Keys become the valid values of the `variant` prop. */
176
+ variants: Record<string, VariantToken>;
177
+ /** Spacing scale, e.g. for `gap` and padding. */
178
+ spacing: Record<string, string>;
179
+ /** Box shadows. */
180
+ shadows: Record<string, string>;
181
+ /** Table densities. Keys become the valid values of the `density` prop. */
182
+ density: Record<string, DensityToken>;
183
+ /**
184
+ * Widths of `Dialog` and `Drawer`, e.g. `{ sm: '24rem', md: '32rem', full: '100vw' }`.
185
+ * Keys become the valid values of their `size` prop. Separate from `sizes`, which sets control heights.
186
+ */
187
+ modalSizes: Record<string, string>;
188
+ /** Font files, font families, named text styles and heading levels. */
189
+ typography: {
190
+ /** Font files to load. Reference their `family` names in `families`. */
191
+ fontFaces?: readonly FontFaceToken[];
192
+ /** Font stacks, e.g. `{ sans: 'Inter, system-ui, sans-serif' }`. */
193
+ families: Record<string, string>;
194
+ /** Named text styles. Keys become the valid text style names. */
195
+ styles: Record<string, TextStyleToken>;
196
+ /** Text style for each heading level, used by `Heading`. Each must be a key of `styles`. */
197
+ headings: { h1: string; h2: string; h3: string; h4: string; h5: string; h6: string };
198
+ };
199
+ /** Stacking order of floating layers. Extra keys allowed. */
200
+ zIndex: Record<string, number> & { dropdown: number; tooltip: number; dialog: number; toast: number };
201
+ /** Transition timing. Extra keys allowed. */
202
+ motion: Record<string, string> & {
203
+ /** Short transitions, e.g. hover. */
204
+ fast: string;
205
+ /** Standard transitions, e.g. opening a popover. */
206
+ base: string;
207
+ /** Easing function. */
208
+ easing: string;
209
+ };
210
+ /** Interaction timing in milliseconds, read by components at render time. Extra keys allowed. */
211
+ timing: Record<string, number> & {
212
+ /** Delay before a `Tooltip` opens on hover. */
213
+ tooltipDelay: number;
214
+ /** Delay before a `HoverCard` opens on hover. */
215
+ hoverOpenDelay: number;
216
+ /** Delay before a `HoverCard` closes after the pointer leaves. */
217
+ hoverCloseDelay: number;
218
+ /** How long a toast stays before it dismisses itself. `0` keeps toasts until dismissed. */
219
+ toastDuration: number;
220
+ };
221
+ /** Border widths. Extra keys allowed. */
222
+ borders: Record<string, string> & { width: string };
223
+ /** Keyboard focus indicator, shared by every focusable component. */
224
+ focusRing: {
225
+ /** Outline width, e.g. `'2px'`. */
226
+ width: string;
227
+ /** Gap between the element and the outline, e.g. `'2px'`. Negative values draw it inside. */
228
+ offset: string;
229
+ /** A key of `colors`. */
230
+ color: string;
231
+ /**
232
+ * Outline style.
233
+ * @default 'solid'
234
+ */
235
+ style?: 'solid' | 'dashed' | 'dotted' | 'double';
236
+ };
237
+ /**
238
+ * Per-component defaults, e.g. `{ Button: { radius: 'square' } }`. Applied when a prop is omitted,
239
+ * before the global `defaults`. Each value must be a key of its group.
240
+ */
241
+ components?: { [C in ComponentName]?: { [P in ComponentTokenProps[C]]?: string } };
242
+ /** Values used when a component prop is omitted. Each must be a key of its group. */
243
+ defaults: {
244
+ size: string;
245
+ /**
246
+ * A key of `radii`, or `'size'` to use the radius named like the control's size
247
+ * (a `lg` button gets `radii.lg`). Components without a size use `defaults.size`.
248
+ */
249
+ radius: string;
250
+ color: string;
251
+ variant: string;
252
+ /** Color used for invalid fields. A key of `colors`. */
253
+ errorColor: string;
254
+ /** Text style for `Text`. A key of `typography.styles`. */
255
+ textStyle: string;
256
+ /** Text style for form labels and legends. A key of `typography.styles`. */
257
+ labelStyle: string;
258
+ /** Text style for helper and error text below form controls. A key of `typography.styles`. */
259
+ helperStyle: string;
260
+ /** Gap for `Stack` and `Inline`. A key of `spacing`. */
261
+ gap: string;
262
+ /** Padding for `Card`. A key of `spacing`. */
263
+ padding: string;
264
+ /** Elevation of popovers, menus and listboxes. A key of `shadows`. */
265
+ floatingShadow: string;
266
+ /** Density for `Table`. A key of `density`. */
267
+ density: string;
268
+ /** Variant for low-emphasis components such as `Badge` and `Alert`. A key of `variants`. */
269
+ softVariant: string;
270
+ /** Width of `Dialog` and `Drawer`. A key of `modalSizes`. */
271
+ modalSize: string;
272
+ };
273
+ }
274
+
275
+ type Whitespace = ' ' | '\n' | '\t';
276
+
277
+ type KeyCheck<G> = {
278
+ [K in keyof G as K extends `${string}${Whitespace}${string}` ? K : never]: {
279
+ error: `Key "${K & string}" must not contain whitespace`;
280
+ };
281
+ };
282
+
283
+ interface TokenKeys<T extends YarclShape> {
284
+ size: keyof T['sizes'];
285
+ radius: keyof T['radii'] | 'size';
286
+ color: keyof T['colors'];
287
+ variant: keyof T['variants'];
288
+ selectedVariant: keyof T['variants'];
289
+ gap: keyof T['spacing'];
290
+ padding: keyof T['spacing'];
291
+ shadow: keyof T['shadows'];
292
+ density: keyof T['density'];
293
+ textStyle: keyof T['typography']['styles'];
294
+ }
295
+
296
+ type ComponentChecks<T extends YarclShape> = {
297
+ [C in keyof T['components']]: C extends ComponentName
298
+ ? {
299
+ [P in keyof T['components'][C]]: P extends ComponentTokenProps[C]
300
+ ? C extends 'Dialog' | 'Drawer'
301
+ ? P extends 'size'
302
+ ? keyof T['modalSizes']
303
+ : TokenKeys<T>[P]
304
+ : TokenKeys<T>[P]
305
+ : never;
306
+ }
307
+ : { error: `Unknown component "${C & string}"` };
308
+ };
309
+
310
+ type Checks<T extends YarclShape> = {
311
+ components?: ComponentChecks<T>;
312
+ colors: KeyCheck<T['colors']>;
313
+ neutrals: KeyCheck<T['neutrals']>;
314
+ zIndex: KeyCheck<T['zIndex']>;
315
+ motion: KeyCheck<T['motion']>;
316
+ timing: KeyCheck<T['timing']>;
317
+ borders: KeyCheck<T['borders']>;
318
+ sizes: KeyCheck<T['sizes']>;
319
+ radii: KeyCheck<T['radii']> & { size?: { error: 'The radius key "size" is reserved' } };
320
+ variants: KeyCheck<T['variants']>;
321
+ spacing: KeyCheck<T['spacing']>;
322
+ shadows: KeyCheck<T['shadows']>;
323
+ density: KeyCheck<T['density']>;
324
+ modalSizes: KeyCheck<T['modalSizes']>;
325
+ typography: {
326
+ families: KeyCheck<T['typography']['families']>;
327
+ styles: KeyCheck<T['typography']['styles']> & {
328
+ [K in keyof T['typography']['styles']]: { family: keyof T['typography']['families'] };
329
+ };
330
+ headings: Record<'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6', keyof T['typography']['styles']>;
331
+ };
332
+ focusRing: { color: keyof T['colors'] };
333
+ defaults: {
334
+ size: keyof T['sizes'];
335
+ radius: keyof T['radii'] | 'size';
336
+ color: keyof T['colors'];
337
+ variant: keyof T['variants'];
338
+ errorColor: keyof T['colors'];
339
+ textStyle: keyof T['typography']['styles'];
340
+ labelStyle: keyof T['typography']['styles'];
341
+ helperStyle: keyof T['typography']['styles'];
342
+ gap: keyof T['spacing'];
343
+ padding: keyof T['spacing'];
344
+ floatingShadow: keyof T['shadows'];
345
+ density: keyof T['density'];
346
+ softVariant: keyof T['variants'];
347
+ modalSize: keyof T['modalSizes'];
348
+ };
349
+ };
350
+
351
+ /**
352
+ * Declares a yarcl design system config.
353
+ *
354
+ * Checks at compile time that:
355
+ * - every color has a `light` and `dark` value
356
+ * - `defaults`, `focusRing.color`, `typography.headings` and each text style's `family` reference existing keys
357
+ * - no key contains whitespace
358
+ * - `components` only names known components, only sets props they have, and only uses existing keys
359
+ *
360
+ * Returns the config unchanged with literal types preserved, so the library can derive
361
+ * its prop types from it. Spread `@yarcl/react/defaults` to extend the library defaults instead
362
+ * of replacing them.
363
+ *
364
+ * @example
365
+ * ```ts
366
+ * // src/yarcl.config.ts
367
+ * import { defineConfig } from '@yarcl/react/define';
368
+ * import defaults from '@yarcl/react/defaults';
369
+ *
370
+ * export default defineConfig({
371
+ * ...defaults,
372
+ * colors: { ...defaults.colors, brand: { light: '#2d4bb8', dark: '#8aa2ff' } },
373
+ * defaults: { ...defaults.defaults, color: 'brand' },
374
+ * });
375
+ * ```
376
+ */
377
+ export function defineConfig<const T extends YarclShape>(config: T & Checks<T>): T {
378
+ return config;
379
+ }
@@ -0,0 +1,31 @@
1
+ import { createContext, useContext } from 'react';
2
+ import { cx } from './classes';
3
+
4
+ export interface FieldContextValue {
5
+ id: string;
6
+ labelId: string;
7
+ describedBy: string | undefined;
8
+ invalid: boolean;
9
+ required: boolean | undefined;
10
+ }
11
+
12
+ export const FieldContext = createContext<FieldContextValue | null>(null);
13
+
14
+ interface FieldControlProps {
15
+ id?: string;
16
+ required?: boolean;
17
+ 'aria-describedby'?: string;
18
+ 'aria-invalid'?: boolean | 'true' | 'false' | 'grammar' | 'spelling';
19
+ }
20
+
21
+ export function useFieldProps<T extends FieldControlProps>(props: T): T {
22
+ const field = useContext(FieldContext);
23
+ if (!field) return props;
24
+ return {
25
+ ...props,
26
+ id: props.id ?? field.id,
27
+ required: props.required ?? field.required,
28
+ 'aria-describedby': cx(field.describedBy, props['aria-describedby']) || undefined,
29
+ 'aria-invalid': props['aria-invalid'] ?? (field.invalid || undefined),
30
+ };
31
+ }
@@ -0,0 +1,61 @@
1
+ import {
2
+ arrow,
3
+ flip,
4
+ offset,
5
+ shift,
6
+ size,
7
+ useMergeRefs,
8
+ type Middleware,
9
+ } from '@floating-ui/react';
10
+ import { cloneElement, isValidElement, type ReactElement, type Ref, type RefObject } from 'react';
11
+
12
+ interface MiddlewareOptions {
13
+ gap?: number;
14
+ matchWidth?: boolean;
15
+ arrowRef?: RefObject<SVGSVGElement | null>;
16
+ }
17
+
18
+ export function floatingMiddleware({ gap = 6, matchWidth = false, arrowRef }: MiddlewareOptions = {}): Middleware[] {
19
+ return [
20
+ offset(gap),
21
+ flip({ padding: 8 }),
22
+ shift({ padding: 8 }),
23
+ size({
24
+ padding: 8,
25
+ apply({ rects, availableHeight, elements }) {
26
+ elements.floating.style.maxHeight = `${Math.max(availableHeight, 120)}px`;
27
+ if (matchWidth) elements.floating.style.minWidth = `${rects.reference.width}px`;
28
+ },
29
+ }),
30
+ ...(arrowRef ? [arrow({ element: arrowRef })] : []),
31
+ ];
32
+ }
33
+
34
+ type ElementWithRef = ReactElement<{ ref?: Ref<Element> }>;
35
+
36
+ export function useTrigger(
37
+ child: ReactElement,
38
+ setReference: (node: Element | null) => void,
39
+ getReferenceProps: (props?: Record<string, unknown>) => Record<string, unknown>,
40
+ ): ReactElement {
41
+ if (!isValidElement(child)) throw new Error('yarcl: trigger must be a single React element');
42
+ const element = child as ElementWithRef;
43
+ const ref = useMergeRefs([setReference, element.props.ref]);
44
+ return cloneElement(element, getReferenceProps({ ...(element.props as Record<string, unknown>), ref }));
45
+ }
46
+
47
+ export function ChevronIcon() {
48
+ return (
49
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" aria-hidden="true">
50
+ <path d="m6 9 6 6 6-6" />
51
+ </svg>
52
+ );
53
+ }
54
+
55
+ export function CheckIcon() {
56
+ return (
57
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5" strokeLinecap="round" aria-hidden="true">
58
+ <path d="m5 12 5 5 9-10" />
59
+ </svg>
60
+ );
61
+ }
package/src/hooks.ts ADDED
@@ -0,0 +1,19 @@
1
+ import { useCallback, useState } from 'react';
2
+
3
+ export function useControllable<T>(
4
+ value: T | undefined,
5
+ defaultValue: T,
6
+ onChange?: (value: T) => void,
7
+ ): [T, (next: T) => void] {
8
+ const [internal, setInternal] = useState(defaultValue);
9
+ const controlled = value !== undefined;
10
+ const current = controlled ? value : internal;
11
+ const set = useCallback(
12
+ (next: T) => {
13
+ if (!controlled) setInternal(next);
14
+ onChange?.(next);
15
+ },
16
+ [controlled, onChange],
17
+ );
18
+ return [current, set];
19
+ }
package/src/index.ts ADDED
@@ -0,0 +1,119 @@
1
+ import 'virtual:yarcl.css';
2
+ import './styles.css';
3
+
4
+ export { Button } from './components/Button';
5
+ export type { ButtonProps } from './components/Button';
6
+ export { ButtonGroup } from './components/ButtonGroup';
7
+ export type { ButtonGroupProps } from './components/ButtonGroup';
8
+ export { ToggleGroup } from './components/ToggleGroup';
9
+ export type { ToggleGroupProps, ToggleGroupBaseProps, ToggleGroupItemProps } from './components/ToggleGroup';
10
+ export { IconButton } from './components/IconButton';
11
+ export type { IconButtonProps } from './components/IconButton';
12
+ export { Input } from './components/Input';
13
+ export type { InputProps } from './components/Input';
14
+ export { Textarea } from './components/Textarea';
15
+ export type { TextareaProps } from './components/Textarea';
16
+ export { NumberInput } from './components/NumberInput';
17
+ export type { NumberInputProps } from './components/NumberInput';
18
+ export { Checkbox } from './components/Checkbox';
19
+ export type { CheckboxProps } from './components/Checkbox';
20
+ export { Radio } from './components/Radio';
21
+ export type { RadioProps } from './components/Radio';
22
+ export { RadioGroup } from './components/RadioGroup';
23
+ export type { RadioGroupProps } from './components/RadioGroup';
24
+ export { Switch } from './components/Switch';
25
+ export type { SwitchProps } from './components/Switch';
26
+ export { Slider } from './components/Slider';
27
+ export type { SliderProps, SliderValue } from './components/Slider';
28
+ export { Field } from './components/Field';
29
+ export type { FieldProps } from './components/Field';
30
+ export { Label } from './components/Label';
31
+ export type { LabelProps } from './components/Label';
32
+ export { Text } from './components/Text';
33
+ export type { TextProps, TextElement } from './components/Text';
34
+ export { Heading } from './components/Heading';
35
+ export type { HeadingProps } from './components/Heading';
36
+ export { Link } from './components/Link';
37
+ export type { LinkProps } from './components/Link';
38
+ export { Breadcrumb } from './components/Breadcrumb';
39
+ export type { BreadcrumbProps, BreadcrumbItemProps } from './components/Breadcrumb';
40
+ export { Stack } from './components/Stack';
41
+ export type { StackProps, LayoutProps, LayoutElement } from './components/Stack';
42
+ export { Inline } from './components/Inline';
43
+ export type { InlineProps } from './components/Inline';
44
+ export { Card } from './components/Card';
45
+ export type { CardProps } from './components/Card';
46
+ export { Divider } from './components/Divider';
47
+ export type { DividerProps } from './components/Divider';
48
+ export { Popover } from './components/Popover';
49
+ export type { PopoverProps, PopoverTriggerProps, PopoverContentProps } from './components/Popover';
50
+ export { Tooltip } from './components/Tooltip';
51
+ export type { TooltipProps } from './components/Tooltip';
52
+ export { HoverCard } from './components/HoverCard';
53
+ export type { HoverCardProps } from './components/HoverCard';
54
+ export { Menu } from './components/Menu';
55
+ export type { MenuProps, MenuTriggerProps, MenuContentProps, MenuItemProps } from './components/Menu';
56
+ export { Select } from './components/Select';
57
+ export type { SelectProps, SelectOption } from './components/Select';
58
+ export { Combobox } from './components/Combobox';
59
+ export type { ComboboxBaseProps, ComboboxProps } from './components/Combobox';
60
+ export { DatePicker } from './components/DatePicker';
61
+ export type {
62
+ DatePickerProps,
63
+ DatePickerBaseProps,
64
+ DatePickerSingleProps,
65
+ DatePickerRangeProps,
66
+ DatePickerLabels,
67
+ DateRange,
68
+ } from './components/DatePicker';
69
+ export { Dialog } from './components/Dialog';
70
+ export type { DialogProps } from './components/Dialog';
71
+ export { Drawer } from './components/Drawer';
72
+ export type { DrawerProps } from './components/Drawer';
73
+ export type { ModalProps } from './components/Modal';
74
+ export { CommandPalette } from './components/CommandPalette';
75
+ export type { CommandPaletteProps, CommandPaletteCommand } from './components/CommandPalette';
76
+ export { Toaster, toast } from './components/Toast';
77
+ export type { ToasterProps, ToastOptions } from './components/Toast';
78
+ export { Accordion } from './components/Accordion';
79
+ export type {
80
+ AccordionProps,
81
+ AccordionBaseProps,
82
+ AccordionItemProps,
83
+ AccordionTriggerProps,
84
+ AccordionContentProps,
85
+ } from './components/Accordion';
86
+ export { Tabs } from './components/Tabs';
87
+ export type { TabsProps, TabsBaseProps, TabsListProps, TabsTriggerProps, TabsPanelProps } from './components/Tabs';
88
+ export { Pagination } from './components/Pagination';
89
+ export type { PaginationProps } from './components/Pagination';
90
+ export { Table } from './components/Table';
91
+ export type { TableProps, TableHeaderCellProps, TableCellProps, CellAlign } from './components/Table';
92
+ export { Badge } from './components/Badge';
93
+ export type { BadgeProps } from './components/Badge';
94
+ export { Alert } from './components/Alert';
95
+ export type { AlertProps } from './components/Alert';
96
+ export { Spinner } from './components/Spinner';
97
+ export type { SpinnerProps } from './components/Spinner';
98
+ export { Skeleton } from './components/Skeleton';
99
+ export type { SkeletonProps } from './components/Skeleton';
100
+ export { Progress } from './components/Progress';
101
+ export type { ProgressProps } from './components/Progress';
102
+ export type {
103
+ Size,
104
+ Radius,
105
+ Color,
106
+ Variant,
107
+ Spacing,
108
+ Shadow,
109
+ TextStyle,
110
+ Density,
111
+ ModalSize,
112
+ Align,
113
+ Justify,
114
+ TokenProps,
115
+ VariantProps,
116
+ } from './types';
117
+ /** The build-time design system config: the consumer's, or the library default. */
118
+ export { default as config } from '@yarcl/config';
119
+ export { useConfig } from './runtime';