@yarcl/react 0.1.0 → 0.2.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 (223) hide show
  1. package/README.md +14 -2
  2. package/{src/apply.ts → dist/apply.d.ts} +4 -23
  3. package/dist/apply.js +37 -0
  4. package/dist/classes.d.ts +13 -0
  5. package/dist/classes.js +22 -0
  6. package/dist/cli.d.ts +2 -0
  7. package/dist/cli.js +58 -0
  8. package/dist/color.js +49 -32
  9. package/dist/components/Accordion.d.ts +96 -0
  10. package/dist/components/Accordion.js +148 -0
  11. package/dist/components/Alert.d.ts +60 -0
  12. package/dist/components/Alert.js +61 -0
  13. package/dist/components/Avatar.d.ts +100 -0
  14. package/dist/components/Avatar.js +89 -0
  15. package/dist/components/Badge.d.ts +44 -0
  16. package/dist/components/Badge.js +43 -0
  17. package/dist/components/Breadcrumb.d.ts +77 -0
  18. package/dist/components/Breadcrumb.js +126 -0
  19. package/dist/components/Button.d.ts +18 -0
  20. package/dist/components/Button.js +33 -0
  21. package/dist/components/ButtonGroup.d.ts +29 -0
  22. package/dist/components/ButtonGroup.js +37 -0
  23. package/dist/components/Card.d.ts +36 -0
  24. package/dist/components/Card.js +26 -0
  25. package/dist/components/Checkbox.d.ts +28 -0
  26. package/dist/components/Checkbox.js +38 -0
  27. package/dist/components/Combobox.d.ts +75 -0
  28. package/dist/components/Combobox.js +362 -0
  29. package/dist/components/CommandPalette.d.ts +92 -0
  30. package/dist/components/CommandPalette.js +293 -0
  31. package/dist/components/DatePicker.d.ts +157 -0
  32. package/dist/components/DatePicker.js +230 -0
  33. package/dist/components/Dialog.d.ts +25 -0
  34. package/dist/components/Dialog.js +29 -0
  35. package/dist/components/Divider.d.ts +23 -0
  36. package/dist/components/Divider.js +25 -0
  37. package/dist/components/Drawer.d.ts +21 -0
  38. package/dist/components/Drawer.js +25 -0
  39. package/dist/components/EmptyState.d.ts +51 -0
  40. package/dist/components/EmptyState.js +47 -0
  41. package/dist/components/Field.d.ts +27 -0
  42. package/dist/components/Field.js +59 -0
  43. package/dist/components/Heading.d.ts +26 -0
  44. package/dist/components/Heading.js +25 -0
  45. package/dist/components/HoverCard.d.ts +47 -0
  46. package/dist/components/HoverCard.js +53 -0
  47. package/dist/components/IconButton.d.ts +19 -0
  48. package/dist/components/IconButton.js +32 -0
  49. package/dist/components/Inline.d.ts +21 -0
  50. package/dist/components/Inline.js +24 -0
  51. package/dist/components/Input.d.ts +19 -0
  52. package/dist/components/Input.js +25 -0
  53. package/dist/components/Label.d.ts +46 -0
  54. package/dist/components/Label.js +33 -0
  55. package/dist/components/Link.d.ts +27 -0
  56. package/dist/components/Link.js +26 -0
  57. package/dist/components/Menu.d.ts +73 -0
  58. package/dist/components/Menu.js +143 -0
  59. package/dist/components/Modal.d.ts +45 -0
  60. package/dist/components/Modal.js +110 -0
  61. package/dist/components/NumberInput.d.ts +49 -0
  62. package/dist/components/NumberInput.js +130 -0
  63. package/dist/components/Pagination.d.ts +86 -0
  64. package/dist/components/Pagination.js +119 -0
  65. package/dist/components/Popover.d.ts +72 -0
  66. package/dist/components/Popover.js +87 -0
  67. package/dist/components/Progress.d.ts +60 -0
  68. package/dist/components/Progress.js +59 -0
  69. package/dist/components/Radio.d.ts +32 -0
  70. package/dist/components/Radio.js +47 -0
  71. package/dist/components/RadioGroup.d.ts +57 -0
  72. package/dist/components/RadioGroup.js +68 -0
  73. package/dist/components/Select.d.ts +47 -0
  74. package/dist/components/Select.js +138 -0
  75. package/dist/components/Skeleton.d.ts +46 -0
  76. package/dist/components/Skeleton.js +40 -0
  77. package/dist/components/Slider.d.ts +126 -0
  78. package/dist/components/Slider.js +166 -0
  79. package/dist/components/Spinner.d.ts +23 -0
  80. package/dist/components/Spinner.js +23 -0
  81. package/dist/components/Stack.d.ts +35 -0
  82. package/dist/components/Stack.js +24 -0
  83. package/dist/components/Switch.d.ts +27 -0
  84. package/dist/components/Switch.js +33 -0
  85. package/dist/components/Table.d.ts +71 -0
  86. package/dist/components/Table.js +61 -0
  87. package/dist/components/Tabs.d.ts +66 -0
  88. package/dist/components/Tabs.js +109 -0
  89. package/dist/components/Text.d.ts +32 -0
  90. package/dist/components/Text.js +28 -0
  91. package/dist/components/Textarea.d.ts +15 -0
  92. package/dist/components/Textarea.js +24 -0
  93. package/dist/components/Toast.d.ts +90 -0
  94. package/dist/components/Toast.js +156 -0
  95. package/dist/components/ToggleGroup.d.ts +79 -0
  96. package/dist/components/ToggleGroup.js +101 -0
  97. package/dist/components/Tooltip.d.ts +46 -0
  98. package/dist/components/Tooltip.js +62 -0
  99. package/dist/components/VisuallyHidden.d.ts +18 -0
  100. package/dist/components/VisuallyHidden.js +22 -0
  101. package/dist/contrast.d.ts +32 -0
  102. package/dist/css.d.ts +2 -2
  103. package/dist/css.js +193 -157
  104. package/dist/define.d.ts +40 -15
  105. package/dist/define.js +30 -27
  106. package/dist/demo.d.ts +2 -0
  107. package/dist/demo.js +2 -0
  108. package/dist/esbuild.cjs +5 -0
  109. package/dist/esbuild.d.ts +4 -0
  110. package/dist/esbuild.js +6 -0
  111. package/dist/field-context.d.ts +16 -0
  112. package/dist/field-context.js +17 -0
  113. package/dist/floating.d.ts +12 -0
  114. package/dist/floating.js +52 -0
  115. package/dist/hooks.d.ts +1 -0
  116. package/dist/hooks.js +12 -0
  117. package/{src/index.ts → dist/index.d.ts} +11 -33
  118. package/dist/index.js +50 -0
  119. package/dist/init.d.ts +18 -0
  120. package/dist/init.js +224 -0
  121. package/dist/plugin.d.ts +10 -26
  122. package/dist/plugin.js +152 -78
  123. package/dist/reference/DemoYarcl.d.ts +12 -0
  124. package/dist/reference/DemoYarcl.js +312 -0
  125. package/dist/reference/DesignReference.d.ts +24 -0
  126. package/dist/reference/DesignReference.js +403 -0
  127. package/dist/reference/index.js +2 -0
  128. package/dist/rollup.cjs +5 -0
  129. package/dist/rollup.d.ts +4 -0
  130. package/dist/rollup.js +6 -0
  131. package/dist/rspack.cjs +5 -0
  132. package/dist/rspack.d.ts +4 -0
  133. package/dist/rspack.js +6 -0
  134. package/dist/runtime.d.ts +13 -0
  135. package/dist/runtime.js +30 -0
  136. package/dist/setup.d.ts +6 -0
  137. package/dist/setup.js +33 -0
  138. package/{src → dist}/styles.css +224 -106
  139. package/dist/themes/bloom.d.ts +295 -0
  140. package/dist/themes/bloom.js +202 -0
  141. package/dist/themes/brutalist.d.ts +277 -0
  142. package/dist/themes/brutalist.js +199 -0
  143. package/dist/themes/compact.d.ts +274 -0
  144. package/dist/themes/compact.js +200 -0
  145. package/dist/themes/contract.d.ts +23 -0
  146. package/dist/themes/editorial.d.ts +277 -0
  147. package/dist/themes/editorial.js +183 -0
  148. package/dist/themes/index.d.ts +1425 -0
  149. package/dist/themes/index.js +45 -0
  150. package/{src/types.ts → dist/types.d.ts} +40 -37
  151. package/dist/vite.cjs +5 -0
  152. package/dist/vite.d.ts +4 -0
  153. package/dist/vite.js +6 -0
  154. package/dist/webpack.cjs +5 -0
  155. package/dist/webpack.d.ts +4 -0
  156. package/dist/webpack.js +6 -0
  157. package/dist/yarcl.config.d.ts +276 -0
  158. package/dist/yarcl.config.js +273 -0
  159. package/package.json +69 -17
  160. package/src/classes.ts +0 -23
  161. package/src/color.ts +0 -48
  162. package/src/components/Accordion.tsx +0 -274
  163. package/src/components/Alert.tsx +0 -85
  164. package/src/components/Badge.tsx +0 -79
  165. package/src/components/Breadcrumb.tsx +0 -239
  166. package/src/components/Button.tsx +0 -58
  167. package/src/components/ButtonGroup.tsx +0 -61
  168. package/src/components/Card.tsx +0 -50
  169. package/src/components/Checkbox.tsx +0 -49
  170. package/src/components/Combobox.tsx +0 -522
  171. package/src/components/CommandPalette.tsx +0 -452
  172. package/src/components/DatePicker.tsx +0 -432
  173. package/src/components/Dialog.tsx +0 -39
  174. package/src/components/Divider.tsx +0 -34
  175. package/src/components/Drawer.tsx +0 -31
  176. package/src/components/Field.tsx +0 -61
  177. package/src/components/Heading.tsx +0 -40
  178. package/src/components/HoverCard.tsx +0 -108
  179. package/src/components/IconButton.tsx +0 -59
  180. package/src/components/Inline.tsx +0 -42
  181. package/src/components/Input.tsx +0 -28
  182. package/src/components/Label.tsx +0 -58
  183. package/src/components/Link.tsx +0 -41
  184. package/src/components/Menu.tsx +0 -207
  185. package/src/components/Modal.tsx +0 -164
  186. package/src/components/NumberInput.tsx +0 -208
  187. package/src/components/Pagination.tsx +0 -227
  188. package/src/components/Popover.tsx +0 -140
  189. package/src/components/Progress.tsx +0 -122
  190. package/src/components/Radio.tsx +0 -59
  191. package/src/components/RadioGroup.tsx +0 -114
  192. package/src/components/Select.tsx +0 -197
  193. package/src/components/Skeleton.tsx +0 -95
  194. package/src/components/Slider.tsx +0 -315
  195. package/src/components/Spinner.tsx +0 -38
  196. package/src/components/Stack.tsx +0 -57
  197. package/src/components/Switch.tsx +0 -42
  198. package/src/components/Table.tsx +0 -99
  199. package/src/components/Tabs.tsx +0 -159
  200. package/src/components/Text.tsx +0 -67
  201. package/src/components/Textarea.tsx +0 -26
  202. package/src/components/Toast.tsx +0 -190
  203. package/src/components/ToggleGroup.tsx +0 -227
  204. package/src/components/Tooltip.tsx +0 -78
  205. package/src/contrast.ts +0 -82
  206. package/src/css.ts +0 -228
  207. package/src/define.check.ts +0 -259
  208. package/src/define.ts +0 -379
  209. package/src/field-context.ts +0 -31
  210. package/src/floating.tsx +0 -61
  211. package/src/hooks.ts +0 -19
  212. package/src/plugin.ts +0 -94
  213. package/src/reference/DesignReference.tsx +0 -374
  214. package/src/runtime.ts +0 -38
  215. package/src/themes/bloom.ts +0 -72
  216. package/src/themes/brutalist.ts +0 -63
  217. package/src/themes/compact.ts +0 -63
  218. package/src/themes/contract.ts +0 -24
  219. package/src/themes/editorial.ts +0 -55
  220. package/src/themes/index.ts +0 -47
  221. package/src/yarcl.config.ts +0 -104
  222. /package/{src/reference/index.ts → dist/reference/index.d.ts} +0 -0
  223. /package/{src → dist}/reference/reference.css +0 -0
@@ -1,274 +0,0 @@
1
- import {
2
- createContext,
3
- useContext,
4
- useId,
5
- type ComponentProps,
6
- type KeyboardEvent,
7
- type ReactNode,
8
- } from 'react';
9
- import { colorClass, cx, radiusClass, sizeClass } from '../classes';
10
- import { ChevronIcon } from '../floating';
11
- import { useControllable } from '../hooks';
12
- import type { Color, Radius, Size } from '../types';
13
- import { useDefaults } from '../runtime';
14
-
15
- interface AccordionContextValue {
16
- open: string[];
17
- toggle: (value: string) => void;
18
- disabled?: boolean;
19
- idFor: (kind: 'trigger' | 'content', value: string) => string;
20
- }
21
-
22
- interface AccordionItemContextValue {
23
- value: string;
24
- open: boolean;
25
- disabled?: boolean;
26
- }
27
-
28
- const AccordionContext = createContext<AccordionContextValue | null>(null);
29
- const AccordionItemContext = createContext<AccordionItemContextValue | null>(null);
30
-
31
- function useAccordionContext(component: string) {
32
- const context = useContext(AccordionContext);
33
- if (!context) throw new Error(`yarcl: <${component}> must be inside <Accordion>`);
34
- return context;
35
- }
36
-
37
- function useItemContext(component: string) {
38
- const context = useContext(AccordionItemContext);
39
- if (!context) throw new Error(`yarcl: <${component}> must be inside <Accordion.Item>`);
40
- return context;
41
- }
42
-
43
- /** Props shared by both forms of {@link AccordionProps}. */
44
- export interface AccordionBaseProps extends Omit<ComponentProps<'div'>, 'defaultValue' | 'color'> {
45
- /**
46
- * Trigger height, padding and font size, from the `sizes` config.
47
- * @default config.defaults.size
48
- */
49
- size?: Size;
50
- /**
51
- * Corner radius of the outer frame, from the `radii` config, or `'size'` to match the size.
52
- * @default config.defaults.radius
53
- */
54
- radius?: Radius | 'size';
55
- /**
56
- * Color of the open item's indicator, from the `colors` config.
57
- * @default config.defaults.color
58
- */
59
- color?: Color;
60
- /** Disables every item. */
61
- disabled?: boolean;
62
- /** `Accordion.Item`s. */
63
- children?: ReactNode;
64
- }
65
-
66
- /** Props for {@link Accordion}. `type` decides whether one or many items can be open. */
67
- export type AccordionProps = AccordionBaseProps &
68
- (
69
- | {
70
- /** One item open at a time. */
71
- type: 'single';
72
- /** Open item (controlled), or `null` when all are closed. */
73
- value?: string | null;
74
- /** Initially open item (uncontrolled). */
75
- defaultValue?: string | null;
76
- /** Called with the open item, or `null` when it closes. */
77
- onValueChange?: (value: string | null) => void;
78
- /**
79
- * Lets the open item close, leaving all closed. When `false`, one item always stays open.
80
- * @default true
81
- */
82
- collapsible?: boolean;
83
- }
84
- | {
85
- /** Any number of items open. */
86
- type: 'multiple';
87
- /** Open items (controlled). */
88
- value?: string[];
89
- /** Initially open items (uncontrolled). */
90
- defaultValue?: string[];
91
- /** Called with all open items. */
92
- onValueChange?: (value: string[]) => void;
93
- collapsible?: never;
94
- }
95
- );
96
-
97
- const toArray = (value: string | string[] | null | undefined) => (value == null ? [] : Array.isArray(value) ? value : [value]);
98
-
99
- function AccordionRoot(props: AccordionProps) {
100
- const own = useDefaults('Accordion');
101
- const {
102
- type,
103
- value,
104
- defaultValue,
105
- onValueChange,
106
- collapsible = true,
107
- size,
108
- radius,
109
- color,
110
- disabled,
111
- className,
112
- onKeyDown,
113
- ...rest
114
- } = props;
115
-
116
- const [open, setOpen] = useControllable<string[]>(
117
- value === undefined ? undefined : toArray(value),
118
- toArray(defaultValue),
119
- (next) =>
120
- type === 'multiple'
121
- ? (onValueChange as (v: string[]) => void)?.(next)
122
- : (onValueChange as (v: string | null) => void)?.(next[0] ?? null),
123
- );
124
-
125
- const baseId = useId();
126
- const idFor = (kind: 'trigger' | 'content', v: string) => `${baseId}-${kind}-${v.replace(/[^\w-]/g, '_')}`;
127
-
128
- function toggle(item: string) {
129
- const on = open.includes(item);
130
- if (type === 'multiple') setOpen(on ? open.filter((v) => v !== item) : [...open, item]);
131
- else if (!on) setOpen([item]);
132
- else if (collapsible) setOpen([]);
133
- }
134
-
135
- function handleKeyDown(event: KeyboardEvent<HTMLDivElement>) {
136
- onKeyDown?.(event);
137
- const root = event.currentTarget;
138
- const triggers = [...root.querySelectorAll<HTMLButtonElement>('.yarcl-accordion-trigger:not(:disabled)')].filter(
139
- (trigger) => trigger.closest('.yarcl-accordion') === root,
140
- );
141
- const current = triggers.indexOf(document.activeElement as HTMLButtonElement);
142
- if (current === -1) return;
143
- const next = {
144
- ArrowDown: (current + 1) % triggers.length,
145
- ArrowUp: (current - 1 + triggers.length) % triggers.length,
146
- Home: 0,
147
- End: triggers.length - 1,
148
- }[event.key];
149
- if (next === undefined) return;
150
- event.preventDefault();
151
- triggers[next].focus();
152
- }
153
-
154
- const resolvedSize = size ?? own.size;
155
- return (
156
- <AccordionContext.Provider value={{ open, toggle, disabled, idFor }}>
157
- <div
158
- className={cx(
159
- 'yarcl-accordion',
160
- sizeClass(resolvedSize),
161
- radiusClass(radius ?? own.radius, resolvedSize),
162
- colorClass(color ?? own.color),
163
- className,
164
- )}
165
- onKeyDown={handleKeyDown}
166
- {...rest}
167
- />
168
- </AccordionContext.Provider>
169
- );
170
- }
171
-
172
- /** Props for `Accordion.Item`. */
173
- export interface AccordionItemProps extends Omit<ComponentProps<'div'>, 'value'> {
174
- /** Identifies the item in the accordion's value. */
175
- value: string;
176
- /** Prevents opening or closing this item. */
177
- disabled?: boolean;
178
- }
179
-
180
- function AccordionItem({ value, disabled, className, ...props }: AccordionItemProps) {
181
- const context = useAccordionContext('Accordion.Item');
182
- const open = context.open.includes(value);
183
- const itemDisabled = disabled || context.disabled;
184
- return (
185
- <AccordionItemContext.Provider value={{ value, open, disabled: itemDisabled }}>
186
- <div
187
- data-state={open ? 'open' : 'closed'}
188
- data-disabled={itemDisabled || undefined}
189
- className={cx('yarcl-accordion-item', className)}
190
- {...props}
191
- />
192
- </AccordionItemContext.Provider>
193
- );
194
- }
195
-
196
- /** Props for `Accordion.Trigger`. */
197
- export interface AccordionTriggerProps extends ComponentProps<'button'> {
198
- /**
199
- * Level of the heading that wraps the button, to fit the page outline.
200
- * @default 3
201
- */
202
- level?: 1 | 2 | 3 | 4 | 5 | 6;
203
- }
204
-
205
- function AccordionTrigger({ level = 3, className, onClick, children, ...props }: AccordionTriggerProps) {
206
- const context = useAccordionContext('Accordion.Trigger');
207
- const item = useItemContext('Accordion.Trigger');
208
- const Heading = `h${level}` as 'h3';
209
- return (
210
- <Heading className="yarcl-accordion-heading">
211
- <button
212
- type="button"
213
- id={context.idFor('trigger', item.value)}
214
- aria-controls={context.idFor('content', item.value)}
215
- aria-expanded={item.open}
216
- disabled={item.disabled}
217
- className={cx('yarcl-accordion-trigger', className)}
218
- onClick={(event) => {
219
- onClick?.(event);
220
- if (!event.defaultPrevented) context.toggle(item.value);
221
- }}
222
- {...props}
223
- >
224
- <span className="yarcl-accordion-label">{children}</span>
225
- <ChevronIcon />
226
- </button>
227
- </Heading>
228
- );
229
- }
230
-
231
- /** Props for `Accordion.Content`. */
232
- export type AccordionContentProps = ComponentProps<'div'>;
233
-
234
- function AccordionContent({ className, children, ...props }: AccordionContentProps) {
235
- const context = useAccordionContext('Accordion.Content');
236
- const item = useItemContext('Accordion.Content');
237
- return (
238
- <div
239
- role="region"
240
- id={context.idFor('content', item.value)}
241
- aria-labelledby={context.idFor('trigger', item.value)}
242
- data-state={item.open ? 'open' : 'closed'}
243
- className={cx('yarcl-accordion-content', className)}
244
- {...props}
245
- >
246
- <div className="yarcl-accordion-body">{children}</div>
247
- </div>
248
- );
249
- }
250
-
251
- /**
252
- * Stacked sections that expand and collapse. Each trigger is a button inside a heading;
253
- * Up and Down move between triggers, Home and End jump to the ends. The panel height animates
254
- * with the `motion` tokens, and snaps when reduced motion is preferred.
255
- *
256
- * @example
257
- * ```tsx
258
- * <Accordion type="single" defaultValue="shipping">
259
- * <Accordion.Item value="shipping">
260
- * <Accordion.Trigger>Shipping</Accordion.Trigger>
261
- * <Accordion.Content>Orders ship within two working days.</Accordion.Content>
262
- * </Accordion.Item>
263
- * <Accordion.Item value="returns">
264
- * <Accordion.Trigger>Returns</Accordion.Trigger>
265
- * <Accordion.Content>Free returns within 30 days.</Accordion.Content>
266
- * </Accordion.Item>
267
- * </Accordion>
268
- * ```
269
- */
270
- export const Accordion = Object.assign(AccordionRoot, {
271
- Item: AccordionItem,
272
- Trigger: AccordionTrigger,
273
- Content: AccordionContent,
274
- });
@@ -1,85 +0,0 @@
1
- import type { ComponentProps, ReactNode } from 'react';
2
- import { colorClass, cx, radiusClass, softVariantClass } from '../classes';
3
- import type { Color, Radius, Variant } from '../types';
4
- import { useDefaults } from '../runtime';
5
-
6
-
7
- /** Props for {@link Alert}. */
8
- export interface AlertProps extends Omit<ComponentProps<'div'>, 'color' | 'title'> {
9
- /** Bold first line. */
10
- title?: ReactNode;
11
- /** Icon shown before the text. */
12
- icon?: ReactNode;
13
- /** Actions shown after the text, e.g. a {@link Button} or {@link Link}. */
14
- action?: ReactNode;
15
- /**
16
- * Semantic color, from the `colors` config.
17
- * @default config.defaults.color
18
- */
19
- color?: Color;
20
- /**
21
- * Style recipe, from the `variants` config.
22
- * @default config.defaults.softVariant
23
- */
24
- variant?: Variant;
25
- /**
26
- * Corner radius, from the `radii` config.
27
- * @default config.defaults.radius
28
- */
29
- radius?: Radius;
30
- /** Shows a dismiss button. Called when it is pressed; hide the alert in response. */
31
- onDismiss?: () => void;
32
- /**
33
- * Announces the alert when it appears: `'polite'` (`role="status"`) or `'assertive'` (`role="alert"`).
34
- * Leave unset for messages present on page load.
35
- */
36
- live?: 'polite' | 'assertive';
37
- }
38
-
39
- /**
40
- * An inline message that stays on the page, e.g. a warning above a form.
41
- * For transient messages use {@link toast}.
42
- *
43
- * @example
44
- * ```tsx
45
- * <Alert color="warning" title="Trial ends in 3 days" action={<Button size="sm">Upgrade</Button>}>
46
- * Add a payment method to keep your projects.
47
- * </Alert>
48
- * ```
49
- */
50
- export function Alert({
51
- title,
52
- icon,
53
- action,
54
- color,
55
- variant,
56
- radius,
57
- onDismiss,
58
- live,
59
- className,
60
- children,
61
- ...props
62
- }: AlertProps) {
63
- const own = useDefaults('Alert');
64
- return (
65
- <div
66
- role={live === 'assertive' ? 'alert' : live === 'polite' ? 'status' : undefined}
67
- className={cx('yarcl-alert', colorClass(color ?? own.color), softVariantClass(variant ?? own.variant), radiusClass(radius ?? own.radius), className)}
68
- {...props}
69
- >
70
- {icon != null && <span className="yarcl-alert-icon">{icon}</span>}
71
- <div className="yarcl-alert-text">
72
- {title != null && <div className="yarcl-alert-title">{title}</div>}
73
- {children != null && <div className="yarcl-alert-body">{children}</div>}
74
- </div>
75
- {action != null && <div className="yarcl-alert-action">{action}</div>}
76
- {onDismiss && (
77
- <button type="button" className="yarcl-alert-dismiss" aria-label="Dismiss" onClick={onDismiss}>
78
- <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" aria-hidden="true">
79
- <path d="M6 6l12 12M18 6 6 18" />
80
- </svg>
81
- </button>
82
- )}
83
- </div>
84
- );
85
- }
@@ -1,79 +0,0 @@
1
- import type { ComponentProps } from 'react';
2
- import { colorClass, cx, radiusClass, sizeClass, softVariantClass } from '../classes';
3
- import type { Color, Radius, Size, Variant } from '../types';
4
- import { useDefaults } from '../runtime';
5
-
6
-
7
- /** Props for {@link Badge}. */
8
- export interface BadgeProps extends Omit<ComponentProps<'span'>, 'color'> {
9
- /**
10
- * Semantic color, from the `colors` config.
11
- * @default config.defaults.color
12
- */
13
- color?: Color;
14
- /**
15
- * Style recipe, from the `variants` config.
16
- * @default config.defaults.softVariant
17
- */
18
- variant?: Variant;
19
- /**
20
- * Scales with the size's font size, from the `sizes` config.
21
- * @default config.defaults.size
22
- */
23
- size?: Size;
24
- /**
25
- * Corner radius, from the `radii` config.
26
- * @default config.defaults.radius
27
- */
28
- radius?: Radius | 'size';
29
- /** Shows a remove button, making the badge a removable tag. Called when it is pressed. */
30
- onRemove?: () => void;
31
- /**
32
- * Accessible label of the remove button.
33
- * @default 'Remove'
34
- */
35
- removeLabel?: string;
36
- }
37
-
38
- /**
39
- * A small label for status, counts or categories. With `onRemove`, a removable tag.
40
- * Uses the same variant recipes as {@link Button}.
41
- *
42
- * @example
43
- * ```tsx
44
- * <Badge color="success">Active</Badge>
45
- * <Badge onRemove={() => removeTag('react')}>react</Badge>
46
- * ```
47
- */
48
- export function Badge({
49
- color,
50
- variant,
51
- size,
52
- radius,
53
- onRemove,
54
- removeLabel = 'Remove',
55
- className,
56
- children,
57
- ...props
58
- }: BadgeProps) {
59
- const own = useDefaults('Badge');
60
- return (
61
- <span
62
- className={cx('yarcl-badge', colorClass(color ?? own.color), softVariantClass(variant ?? own.variant), sizeClass(size ?? own.size), radiusClass(radius ?? own.radius, size ?? own.size), className)}
63
- {...props}
64
- >
65
- {children}
66
- {onRemove && <BadgeRemove aria-label={removeLabel} onClick={onRemove} />}
67
- </span>
68
- );
69
- }
70
-
71
- export function BadgeRemove(props: Omit<ComponentProps<'button'>, 'children'>) {
72
- return (
73
- <button type="button" className="yarcl-badge-remove" {...props}>
74
- <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5" strokeLinecap="round" aria-hidden="true">
75
- <path d="M7 7l10 10M17 7 7 17" />
76
- </svg>
77
- </button>
78
- );
79
- }
@@ -1,239 +0,0 @@
1
- import {
2
- Children,
3
- createContext,
4
- isValidElement,
5
- useContext,
6
- useRef,
7
- useState,
8
- type ComponentProps,
9
- type ReactNode,
10
- } from 'react';
11
- import { colorClass, cx, typeClass } from '../classes';
12
- import type { Color, TextStyle } from '../types';
13
- import { useConfig, useDefaults } from '../runtime';
14
- import type { LinkProps } from './Link';
15
-
16
- interface BreadcrumbItemContextValue {
17
- current: boolean;
18
- separator: ReactNode;
19
- color: Color;
20
- underline: NonNullable<LinkProps['underline']>;
21
- itemRef?: (node: HTMLElement | null) => void;
22
- }
23
-
24
- const BreadcrumbItemContext = createContext<BreadcrumbItemContextValue | null>(null);
25
-
26
- function ChevronIcon() {
27
- return (
28
- <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" aria-hidden="true">
29
- <path d="m9 6 6 6-6 6" />
30
- </svg>
31
- );
32
- }
33
-
34
- function Separator({ children }: { children: ReactNode }) {
35
- return (
36
- <span className="yarcl-breadcrumb-separator" aria-hidden="true">
37
- {children}
38
- </span>
39
- );
40
- }
41
-
42
- /** Props for {@link Breadcrumb}. Accepts all native `<nav>` attributes except `color`. */
43
- export interface BreadcrumbProps extends Omit<ComponentProps<'nav'>, 'color'> {
44
- /** `Breadcrumb.Item`s, from the root to the current page. */
45
- children?: ReactNode;
46
- /**
47
- * Content between items. Hidden from screen readers.
48
- * @default a chevron icon
49
- * @example
50
- * ```tsx
51
- * <Breadcrumb separator="/">…</Breadcrumb>
52
- * ```
53
- */
54
- separator?: ReactNode;
55
- /** Collapses the middle of the trail into an expandable ellipsis when there are more items than this. Without it, the trail never collapses. */
56
- maxItems?: number;
57
- /**
58
- * Items shown before the ellipsis when collapsed.
59
- * @default 1
60
- */
61
- itemsBeforeCollapse?: number;
62
- /**
63
- * Items shown after the ellipsis when collapsed.
64
- * @default 2
65
- */
66
- itemsAfterCollapse?: number;
67
- /**
68
- * Accessible label of the ellipsis button.
69
- * @default 'Show all breadcrumbs'
70
- */
71
- expandLabel?: string;
72
- /**
73
- * Text style, from the `typography.styles` config.
74
- * @default config.defaults.textStyle
75
- */
76
- textStyle?: TextStyle;
77
- /**
78
- * Link color, from the `colors` config.
79
- * @default config.defaults.color
80
- */
81
- color?: Color;
82
- /**
83
- * When to underline the links.
84
- * @default 'hover'
85
- */
86
- underline?: LinkProps['underline'];
87
- }
88
-
89
- function BreadcrumbRoot({
90
- children,
91
- separator = <ChevronIcon />,
92
- maxItems,
93
- itemsBeforeCollapse = 1,
94
- itemsAfterCollapse = 2,
95
- expandLabel = 'Show all breadcrumbs',
96
- textStyle,
97
- color,
98
- underline = 'hover',
99
- className,
100
- 'aria-label': ariaLabel = 'Breadcrumb',
101
- ...props
102
- }: BreadcrumbProps) {
103
- const config = useConfig();
104
- const own = useDefaults('Breadcrumb');
105
- const [expanded, setExpanded] = useState(false);
106
- const focusNext = useRef(false);
107
- const items = Children.toArray(children).filter(isValidElement);
108
- const resolvedColor = color ?? own.color ?? config.defaults.color;
109
- const before = Math.max(0, itemsBeforeCollapse);
110
- const after = Math.max(1, itemsAfterCollapse);
111
- const collapsible = maxItems !== undefined && items.length > maxItems && before + after < items.length;
112
- const collapsed = collapsible && !expanded;
113
- const hiddenEnd = items.length - after;
114
-
115
- const context = (index: number): BreadcrumbItemContextValue => ({
116
- current: index === items.length - 1,
117
- separator,
118
- color: resolvedColor,
119
- underline,
120
- itemRef:
121
- collapsible && index === before
122
- ? (node) => {
123
- if (node && focusNext.current) {
124
- focusNext.current = false;
125
- node.focus();
126
- }
127
- }
128
- : undefined,
129
- });
130
-
131
- const rendered: ReactNode[] = [];
132
- items.forEach((item, index) => {
133
- if (collapsed && index >= before && index < hiddenEnd) {
134
- if (index === before) {
135
- rendered.push(
136
- <li key="yarcl-breadcrumb-ellipsis" className="yarcl-breadcrumb-item">
137
- <button
138
- type="button"
139
- className="yarcl-breadcrumb-ellipsis"
140
- aria-label={expandLabel}
141
- onClick={() => {
142
- focusNext.current = true;
143
- setExpanded(true);
144
- }}
145
- >
146
- <span aria-hidden="true">…</span>
147
- </button>
148
- <Separator>{separator}</Separator>
149
- </li>,
150
- );
151
- }
152
- return;
153
- }
154
- rendered.push(
155
- <BreadcrumbItemContext.Provider key={item.key ?? index} value={context(index)}>
156
- {item}
157
- </BreadcrumbItemContext.Provider>,
158
- );
159
- });
160
-
161
- return (
162
- <nav
163
- aria-label={ariaLabel}
164
- className={cx(
165
- 'yarcl-breadcrumb',
166
- typeClass(textStyle ?? own.textStyle ?? config.defaults.textStyle),
167
- colorClass(resolvedColor),
168
- className,
169
- )}
170
- {...props}
171
- >
172
- <ol className="yarcl-breadcrumb-list">{rendered}</ol>
173
- </nav>
174
- );
175
- }
176
-
177
- /** Props for `Breadcrumb.Item`. Accepts all native `<a>` attributes except `color`. */
178
- export interface BreadcrumbItemProps extends Omit<ComponentProps<'a'>, 'color'> {
179
- /** The item's label. */
180
- children?: ReactNode;
181
- /** Where the item links to. Without it, the item renders as plain text. */
182
- href?: string;
183
- }
184
-
185
- function BreadcrumbItem({ href, className, children, ...props }: BreadcrumbItemProps) {
186
- const context = useContext(BreadcrumbItemContext);
187
- if (!context) throw new Error('yarcl: <Breadcrumb.Item> must be inside <Breadcrumb>');
188
- const { current, separator, color, underline, itemRef } = context;
189
- return (
190
- <li className="yarcl-breadcrumb-item">
191
- {href ? (
192
- <a
193
- ref={itemRef}
194
- href={href}
195
- aria-current={current ? 'page' : undefined}
196
- className={cx(
197
- 'yarcl-link',
198
- current ? 'yarcl-breadcrumb-current yarcl-link-underline-none' : `yarcl-link-underline-${underline}`,
199
- colorClass(color),
200
- className,
201
- )}
202
- {...props}
203
- >
204
- {children}
205
- </a>
206
- ) : (
207
- <span
208
- ref={itemRef}
209
- tabIndex={itemRef ? -1 : undefined}
210
- aria-current={current ? 'page' : undefined}
211
- className={cx('yarcl-breadcrumb-text', current && 'yarcl-breadcrumb-current', className)}
212
- {...(props as ComponentProps<'span'>)}
213
- >
214
- {children}
215
- </span>
216
- )}
217
- {!current && <Separator>{separator}</Separator>}
218
- </li>
219
- );
220
- }
221
-
222
- /**
223
- * Shows where the current page sits in a hierarchy. The last item is the current page
224
- * and gets `aria-current="page"`. Set `maxItems` to collapse long trails into an ellipsis
225
- * that expands the full trail.
226
- *
227
- * @example
228
- * ```tsx
229
- * <Breadcrumb maxItems={4}>
230
- * <Breadcrumb.Item href="/">Home</Breadcrumb.Item>
231
- * <Breadcrumb.Item href="/projects">Projects</Breadcrumb.Item>
232
- * <Breadcrumb.Item href="/projects/apollo">Apollo</Breadcrumb.Item>
233
- * <Breadcrumb.Item>Settings</Breadcrumb.Item>
234
- * </Breadcrumb>
235
- * ```
236
- */
237
- export const Breadcrumb = Object.assign(BreadcrumbRoot, {
238
- Item: BreadcrumbItem,
239
- });