@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.
- package/README.md +14 -2
- package/{src/apply.ts → dist/apply.d.ts} +4 -23
- package/dist/apply.js +37 -0
- package/dist/classes.d.ts +13 -0
- package/dist/classes.js +22 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +58 -0
- package/dist/color.js +49 -32
- package/dist/components/Accordion.d.ts +96 -0
- package/dist/components/Accordion.js +148 -0
- package/dist/components/Alert.d.ts +60 -0
- package/dist/components/Alert.js +61 -0
- package/dist/components/Avatar.d.ts +100 -0
- package/dist/components/Avatar.js +89 -0
- package/dist/components/Badge.d.ts +44 -0
- package/dist/components/Badge.js +43 -0
- package/dist/components/Breadcrumb.d.ts +77 -0
- package/dist/components/Breadcrumb.js +126 -0
- package/dist/components/Button.d.ts +18 -0
- package/dist/components/Button.js +33 -0
- package/dist/components/ButtonGroup.d.ts +29 -0
- package/dist/components/ButtonGroup.js +37 -0
- package/dist/components/Card.d.ts +36 -0
- package/dist/components/Card.js +26 -0
- package/dist/components/Checkbox.d.ts +28 -0
- package/dist/components/Checkbox.js +38 -0
- package/dist/components/Combobox.d.ts +75 -0
- package/dist/components/Combobox.js +362 -0
- package/dist/components/CommandPalette.d.ts +92 -0
- package/dist/components/CommandPalette.js +293 -0
- package/dist/components/DatePicker.d.ts +157 -0
- package/dist/components/DatePicker.js +230 -0
- package/dist/components/Dialog.d.ts +25 -0
- package/dist/components/Dialog.js +29 -0
- package/dist/components/Divider.d.ts +23 -0
- package/dist/components/Divider.js +25 -0
- package/dist/components/Drawer.d.ts +21 -0
- package/dist/components/Drawer.js +25 -0
- package/dist/components/EmptyState.d.ts +51 -0
- package/dist/components/EmptyState.js +47 -0
- package/dist/components/Field.d.ts +27 -0
- package/dist/components/Field.js +59 -0
- package/dist/components/Heading.d.ts +26 -0
- package/dist/components/Heading.js +25 -0
- package/dist/components/HoverCard.d.ts +47 -0
- package/dist/components/HoverCard.js +53 -0
- package/dist/components/IconButton.d.ts +19 -0
- package/dist/components/IconButton.js +32 -0
- package/dist/components/Inline.d.ts +21 -0
- package/dist/components/Inline.js +24 -0
- package/dist/components/Input.d.ts +19 -0
- package/dist/components/Input.js +25 -0
- package/dist/components/Label.d.ts +46 -0
- package/dist/components/Label.js +33 -0
- package/dist/components/Link.d.ts +27 -0
- package/dist/components/Link.js +26 -0
- package/dist/components/Menu.d.ts +73 -0
- package/dist/components/Menu.js +143 -0
- package/dist/components/Modal.d.ts +45 -0
- package/dist/components/Modal.js +110 -0
- package/dist/components/NumberInput.d.ts +49 -0
- package/dist/components/NumberInput.js +130 -0
- package/dist/components/Pagination.d.ts +86 -0
- package/dist/components/Pagination.js +119 -0
- package/dist/components/Popover.d.ts +72 -0
- package/dist/components/Popover.js +87 -0
- package/dist/components/Progress.d.ts +60 -0
- package/dist/components/Progress.js +59 -0
- package/dist/components/Radio.d.ts +32 -0
- package/dist/components/Radio.js +47 -0
- package/dist/components/RadioGroup.d.ts +57 -0
- package/dist/components/RadioGroup.js +68 -0
- package/dist/components/Select.d.ts +47 -0
- package/dist/components/Select.js +138 -0
- package/dist/components/Skeleton.d.ts +46 -0
- package/dist/components/Skeleton.js +40 -0
- package/dist/components/Slider.d.ts +126 -0
- package/dist/components/Slider.js +166 -0
- package/dist/components/Spinner.d.ts +23 -0
- package/dist/components/Spinner.js +23 -0
- package/dist/components/Stack.d.ts +35 -0
- package/dist/components/Stack.js +24 -0
- package/dist/components/Switch.d.ts +27 -0
- package/dist/components/Switch.js +33 -0
- package/dist/components/Table.d.ts +71 -0
- package/dist/components/Table.js +61 -0
- package/dist/components/Tabs.d.ts +66 -0
- package/dist/components/Tabs.js +109 -0
- package/dist/components/Text.d.ts +32 -0
- package/dist/components/Text.js +28 -0
- package/dist/components/Textarea.d.ts +15 -0
- package/dist/components/Textarea.js +24 -0
- package/dist/components/Toast.d.ts +90 -0
- package/dist/components/Toast.js +156 -0
- package/dist/components/ToggleGroup.d.ts +79 -0
- package/dist/components/ToggleGroup.js +101 -0
- package/dist/components/Tooltip.d.ts +46 -0
- package/dist/components/Tooltip.js +62 -0
- package/dist/components/VisuallyHidden.d.ts +18 -0
- package/dist/components/VisuallyHidden.js +22 -0
- package/dist/contrast.d.ts +32 -0
- package/dist/css.d.ts +2 -2
- package/dist/css.js +193 -157
- package/dist/define.d.ts +40 -15
- package/dist/define.js +30 -27
- package/dist/demo.d.ts +2 -0
- package/dist/demo.js +2 -0
- package/dist/esbuild.cjs +5 -0
- package/dist/esbuild.d.ts +4 -0
- package/dist/esbuild.js +6 -0
- package/dist/field-context.d.ts +16 -0
- package/dist/field-context.js +17 -0
- package/dist/floating.d.ts +12 -0
- package/dist/floating.js +52 -0
- package/dist/hooks.d.ts +1 -0
- package/dist/hooks.js +12 -0
- package/{src/index.ts → dist/index.d.ts} +11 -33
- package/dist/index.js +50 -0
- package/dist/init.d.ts +18 -0
- package/dist/init.js +224 -0
- package/dist/plugin.d.ts +10 -26
- package/dist/plugin.js +152 -78
- package/dist/reference/DemoYarcl.d.ts +12 -0
- package/dist/reference/DemoYarcl.js +312 -0
- package/dist/reference/DesignReference.d.ts +24 -0
- package/dist/reference/DesignReference.js +403 -0
- package/dist/reference/index.js +2 -0
- package/dist/rollup.cjs +5 -0
- package/dist/rollup.d.ts +4 -0
- package/dist/rollup.js +6 -0
- package/dist/rspack.cjs +5 -0
- package/dist/rspack.d.ts +4 -0
- package/dist/rspack.js +6 -0
- package/dist/runtime.d.ts +13 -0
- package/dist/runtime.js +30 -0
- package/dist/setup.d.ts +6 -0
- package/dist/setup.js +33 -0
- package/{src → dist}/styles.css +224 -106
- package/dist/themes/bloom.d.ts +295 -0
- package/dist/themes/bloom.js +202 -0
- package/dist/themes/brutalist.d.ts +277 -0
- package/dist/themes/brutalist.js +199 -0
- package/dist/themes/compact.d.ts +274 -0
- package/dist/themes/compact.js +200 -0
- package/dist/themes/contract.d.ts +23 -0
- package/dist/themes/editorial.d.ts +277 -0
- package/dist/themes/editorial.js +183 -0
- package/dist/themes/index.d.ts +1425 -0
- package/dist/themes/index.js +45 -0
- package/{src/types.ts → dist/types.d.ts} +40 -37
- package/dist/vite.cjs +5 -0
- package/dist/vite.d.ts +4 -0
- package/dist/vite.js +6 -0
- package/dist/webpack.cjs +5 -0
- package/dist/webpack.d.ts +4 -0
- package/dist/webpack.js +6 -0
- package/dist/yarcl.config.d.ts +276 -0
- package/dist/yarcl.config.js +273 -0
- package/package.json +69 -17
- package/src/classes.ts +0 -23
- package/src/color.ts +0 -48
- package/src/components/Accordion.tsx +0 -274
- package/src/components/Alert.tsx +0 -85
- package/src/components/Badge.tsx +0 -79
- package/src/components/Breadcrumb.tsx +0 -239
- package/src/components/Button.tsx +0 -58
- package/src/components/ButtonGroup.tsx +0 -61
- package/src/components/Card.tsx +0 -50
- package/src/components/Checkbox.tsx +0 -49
- package/src/components/Combobox.tsx +0 -522
- package/src/components/CommandPalette.tsx +0 -452
- package/src/components/DatePicker.tsx +0 -432
- package/src/components/Dialog.tsx +0 -39
- package/src/components/Divider.tsx +0 -34
- package/src/components/Drawer.tsx +0 -31
- package/src/components/Field.tsx +0 -61
- package/src/components/Heading.tsx +0 -40
- package/src/components/HoverCard.tsx +0 -108
- package/src/components/IconButton.tsx +0 -59
- package/src/components/Inline.tsx +0 -42
- package/src/components/Input.tsx +0 -28
- package/src/components/Label.tsx +0 -58
- package/src/components/Link.tsx +0 -41
- package/src/components/Menu.tsx +0 -207
- package/src/components/Modal.tsx +0 -164
- package/src/components/NumberInput.tsx +0 -208
- package/src/components/Pagination.tsx +0 -227
- package/src/components/Popover.tsx +0 -140
- package/src/components/Progress.tsx +0 -122
- package/src/components/Radio.tsx +0 -59
- package/src/components/RadioGroup.tsx +0 -114
- package/src/components/Select.tsx +0 -197
- package/src/components/Skeleton.tsx +0 -95
- package/src/components/Slider.tsx +0 -315
- package/src/components/Spinner.tsx +0 -38
- package/src/components/Stack.tsx +0 -57
- package/src/components/Switch.tsx +0 -42
- package/src/components/Table.tsx +0 -99
- package/src/components/Tabs.tsx +0 -159
- package/src/components/Text.tsx +0 -67
- package/src/components/Textarea.tsx +0 -26
- package/src/components/Toast.tsx +0 -190
- package/src/components/ToggleGroup.tsx +0 -227
- package/src/components/Tooltip.tsx +0 -78
- package/src/contrast.ts +0 -82
- package/src/css.ts +0 -228
- package/src/define.check.ts +0 -259
- package/src/define.ts +0 -379
- package/src/field-context.ts +0 -31
- package/src/floating.tsx +0 -61
- package/src/hooks.ts +0 -19
- package/src/plugin.ts +0 -94
- package/src/reference/DesignReference.tsx +0 -374
- package/src/runtime.ts +0 -38
- package/src/themes/bloom.ts +0 -72
- package/src/themes/brutalist.ts +0 -63
- package/src/themes/compact.ts +0 -63
- package/src/themes/contract.ts +0 -24
- package/src/themes/editorial.ts +0 -55
- package/src/themes/index.ts +0 -47
- package/src/yarcl.config.ts +0 -104
- /package/{src/reference/index.ts → dist/reference/index.d.ts} +0 -0
- /package/{src → dist}/reference/reference.css +0 -0
|
@@ -1,78 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
autoUpdate,
|
|
3
|
-
FloatingArrow,
|
|
4
|
-
FloatingPortal,
|
|
5
|
-
useDismiss,
|
|
6
|
-
useFloating,
|
|
7
|
-
useFocus,
|
|
8
|
-
useHover,
|
|
9
|
-
useInteractions,
|
|
10
|
-
useRole,
|
|
11
|
-
type Placement,
|
|
12
|
-
} from '@floating-ui/react';
|
|
13
|
-
import { useRef, useState, type ReactElement, type ReactNode } from 'react';
|
|
14
|
-
import { floatingMiddleware, useTrigger } from '../floating';
|
|
15
|
-
import { useConfig } from '../runtime';
|
|
16
|
-
|
|
17
|
-
/** Props for {@link Tooltip}. */
|
|
18
|
-
export interface TooltipProps {
|
|
19
|
-
/** Short text describing the trigger. Keep it plain; tooltips can't contain interactive content. */
|
|
20
|
-
content: ReactNode;
|
|
21
|
-
/** A single focusable element, e.g. an {@link IconButton}. */
|
|
22
|
-
children: ReactElement;
|
|
23
|
-
/**
|
|
24
|
-
* Preferred side. Flips when there isn't room.
|
|
25
|
-
* @default 'top'
|
|
26
|
-
*/
|
|
27
|
-
placement?: Placement;
|
|
28
|
-
/**
|
|
29
|
-
* Delay before opening on hover, in ms. Opens immediately on keyboard focus.
|
|
30
|
-
* @default config.timing.tooltipDelay
|
|
31
|
-
*/
|
|
32
|
-
delay?: number;
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
/**
|
|
36
|
-
* A short label shown on hover and keyboard focus.
|
|
37
|
-
*
|
|
38
|
-
* @example
|
|
39
|
-
* ```tsx
|
|
40
|
-
* <Tooltip content="Search">
|
|
41
|
-
* <IconButton aria-label="Search"><SearchIcon /></IconButton>
|
|
42
|
-
* </Tooltip>
|
|
43
|
-
* ```
|
|
44
|
-
*/
|
|
45
|
-
export function Tooltip({ content, children, placement = 'top', delay }: TooltipProps) {
|
|
46
|
-
const config = useConfig();
|
|
47
|
-
const [open, setOpen] = useState(false);
|
|
48
|
-
const arrowRef = useRef<SVGSVGElement>(null);
|
|
49
|
-
const { refs, floatingStyles, context } = useFloating({
|
|
50
|
-
open,
|
|
51
|
-
onOpenChange: setOpen,
|
|
52
|
-
placement,
|
|
53
|
-
transform: false,
|
|
54
|
-
whileElementsMounted: autoUpdate,
|
|
55
|
-
middleware: floatingMiddleware({ gap: 8, arrowRef }),
|
|
56
|
-
});
|
|
57
|
-
const { getReferenceProps, getFloatingProps } = useInteractions([
|
|
58
|
-
useHover(context, { move: false, delay: { open: delay ?? config.timing.tooltipDelay, close: 0 } }),
|
|
59
|
-
useFocus(context),
|
|
60
|
-
useDismiss(context),
|
|
61
|
-
useRole(context, { role: 'tooltip' }),
|
|
62
|
-
]);
|
|
63
|
-
const trigger = useTrigger(children, refs.setReference, getReferenceProps);
|
|
64
|
-
|
|
65
|
-
return (
|
|
66
|
-
<>
|
|
67
|
-
{trigger}
|
|
68
|
-
{open && (
|
|
69
|
-
<FloatingPortal>
|
|
70
|
-
<div ref={refs.setFloating} style={floatingStyles} className="yarcl-floating yarcl-tooltip" {...getFloatingProps()}>
|
|
71
|
-
{content}
|
|
72
|
-
<FloatingArrow ref={arrowRef} context={context} className="yarcl-tooltip-arrow" width={10} height={5} />
|
|
73
|
-
</div>
|
|
74
|
-
</FloatingPortal>
|
|
75
|
-
)}
|
|
76
|
-
</>
|
|
77
|
-
);
|
|
78
|
-
}
|
package/src/contrast.ts
DELETED
|
@@ -1,82 +0,0 @@
|
|
|
1
|
-
import { contrast, parseHex, readableOn } from './color.ts';
|
|
2
|
-
import type { ColorPair, YarclShape } from './define.ts';
|
|
3
|
-
|
|
4
|
-
/** A color combination in a config that falls below the required contrast. */
|
|
5
|
-
export interface ContrastIssue {
|
|
6
|
-
/** The config path of the text color, e.g. `colors.warning` or `neutrals.muted`. */
|
|
7
|
-
path: string;
|
|
8
|
-
/** The color scheme the issue occurs in. */
|
|
9
|
-
scheme: 'light' | 'dark';
|
|
10
|
-
/** The contrast ratio, or `null` when it can't be computed (non-hex values). */
|
|
11
|
-
ratio: number | null;
|
|
12
|
-
/** A readable description of the problem. */
|
|
13
|
-
message: string;
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
const schemes = ['light', 'dark'] as const;
|
|
17
|
-
|
|
18
|
-
function asPair(value: string | ColorPair): ColorPair {
|
|
19
|
-
return typeof value === 'string' ? { light: value, dark: value } : value;
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
/**
|
|
23
|
-
* Checks a config for text that doesn't reach a contrast ratio (WCAG AA, 4.5:1, by default)
|
|
24
|
-
* in light or dark mode. Returns the problems instead of printing them, so you can run it in a
|
|
25
|
-
* test, a CI step or a script.
|
|
26
|
-
*
|
|
27
|
-
* Checks the text drawn on each semantic color (its computed or configured `on`), and the
|
|
28
|
-
* neutral `text` and `muted` colors on the `bg` and `surface` backgrounds. Colors drawn as text
|
|
29
|
-
* need no check: their readable shade is computed automatically.
|
|
30
|
-
*
|
|
31
|
-
* @example
|
|
32
|
-
* ```ts
|
|
33
|
-
* import { checkContrast } from '@yarcl/react/contrast';
|
|
34
|
-
* import config from './src/yarcl.config';
|
|
35
|
-
*
|
|
36
|
-
* test('design system is readable', () => {
|
|
37
|
-
* expect(checkContrast(config)).toEqual([]);
|
|
38
|
-
* });
|
|
39
|
-
* ```
|
|
40
|
-
*/
|
|
41
|
-
export function checkContrast(config: YarclShape, min = 4.5): ContrastIssue[] {
|
|
42
|
-
const issues: ContrastIssue[] = [];
|
|
43
|
-
|
|
44
|
-
for (const [key, token] of Object.entries(config.colors)) {
|
|
45
|
-
const on = token.on ? asPair(token.on) : null;
|
|
46
|
-
for (const scheme of schemes) {
|
|
47
|
-
const bg = parseHex(token[scheme]);
|
|
48
|
-
const path = `colors.${key}`;
|
|
49
|
-
if (!bg || (on && !parseHex(on[scheme]))) {
|
|
50
|
-
issues.push({ path, scheme, ratio: null, message: `${path}: can't check ${scheme} contrast of non-hex values; set \`on\` to a hex value` });
|
|
51
|
-
continue;
|
|
52
|
-
}
|
|
53
|
-
const fg = on ? parseHex(on[scheme])! : parseHex(readableOn(bg))!;
|
|
54
|
-
const ratio = contrast(bg, fg);
|
|
55
|
-
if (ratio < min) {
|
|
56
|
-
issues.push({ path, scheme, ratio, message: `${path}: ${scheme} text on this color is ${ratio.toFixed(2)}:1, below ${min}:1` });
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
const { neutrals } = config;
|
|
62
|
-
for (const text of ['text', 'muted'] as const) {
|
|
63
|
-
for (const ground of ['bg', 'surface'] as const) {
|
|
64
|
-
for (const scheme of schemes) {
|
|
65
|
-
const fg = parseHex(neutrals[text][scheme]);
|
|
66
|
-
const bg = parseHex(neutrals[ground][scheme]);
|
|
67
|
-
if (!fg || !bg) continue;
|
|
68
|
-
const ratio = contrast(fg, bg);
|
|
69
|
-
if (ratio < min) {
|
|
70
|
-
issues.push({
|
|
71
|
-
path: `neutrals.${text}`,
|
|
72
|
-
scheme,
|
|
73
|
-
ratio,
|
|
74
|
-
message: `neutrals.${text} on neutrals.${ground}: ${scheme} contrast is ${ratio.toFixed(2)}:1, below ${min}:1`,
|
|
75
|
-
});
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
return issues;
|
|
82
|
-
}
|
package/src/css.ts
DELETED
|
@@ -1,228 +0,0 @@
|
|
|
1
|
-
import { contrast, mix, parseHex, readableOn, readableText, toHex } from './color.ts';
|
|
2
|
-
import type { ColorPair, ColorToken, FontFaceToken, VariantToken, YarclShape } from './define.ts';
|
|
3
|
-
|
|
4
|
-
const MIN_CONTRAST = 4.5;
|
|
5
|
-
|
|
6
|
-
function ident(key: string): string {
|
|
7
|
-
return key.replace(/[^a-zA-Z0-9_-]/g, (c) => `\\${c}`);
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
function pair({ light, dark }: ColorPair): string {
|
|
11
|
-
return light === dark ? light : `light-dark(${light}, ${dark})`;
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
function foreground(name: string, token: ColorToken, warn: (message: string) => void): string {
|
|
15
|
-
const modes = ['light', 'dark'] as const;
|
|
16
|
-
const on = typeof token.on === 'string' ? { light: token.on, dark: token.on } : token.on;
|
|
17
|
-
|
|
18
|
-
const resolved = modes.map((mode) => {
|
|
19
|
-
const bg = parseHex(token[mode]);
|
|
20
|
-
if (on) {
|
|
21
|
-
const fg = parseHex(on[mode]);
|
|
22
|
-
if (bg && fg && contrast(bg, fg) < MIN_CONTRAST) {
|
|
23
|
-
warn(`colors.${name}: ${mode} foreground contrast ${contrast(bg, fg).toFixed(2)}:1 is below ${MIN_CONTRAST}:1`);
|
|
24
|
-
}
|
|
25
|
-
return on[mode];
|
|
26
|
-
}
|
|
27
|
-
if (!bg) {
|
|
28
|
-
warn(`colors.${name}: cannot compute a ${mode} foreground from "${token[mode]}"; use a hex value or set \`on\``);
|
|
29
|
-
return '#ffffff';
|
|
30
|
-
}
|
|
31
|
-
const fg = readableOn(bg);
|
|
32
|
-
const ratio = contrast(bg, parseHex(fg)!);
|
|
33
|
-
if (ratio < MIN_CONTRAST) {
|
|
34
|
-
warn(`colors.${name}: best ${mode} foreground contrast is ${ratio.toFixed(2)}:1, below ${MIN_CONTRAST}:1`);
|
|
35
|
-
}
|
|
36
|
-
return fg;
|
|
37
|
-
});
|
|
38
|
-
|
|
39
|
-
return pair({ light: resolved[0], dark: resolved[1] });
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
const tint = (percent: number) => `color-mix(in oklab, var(--yarcl-c) ${percent}%, transparent)`;
|
|
43
|
-
const shade = (percent: number) => `color-mix(in oklab, var(--yarcl-c), var(--yarcl-c-on) ${percent}%)`;
|
|
44
|
-
|
|
45
|
-
const backgrounds: Record<VariantToken['background'], [string, string, string]> = {
|
|
46
|
-
fill: ['var(--yarcl-c)', shade(12), shade(20)],
|
|
47
|
-
tint: [tint(14), tint(22), tint(30)],
|
|
48
|
-
none: ['transparent', tint(10), tint(18)],
|
|
49
|
-
};
|
|
50
|
-
|
|
51
|
-
const borders: Record<VariantToken['border'], string> = {
|
|
52
|
-
color: 'var(--yarcl-c)',
|
|
53
|
-
neutral: 'var(--yarcl-neutral-border)',
|
|
54
|
-
none: 'transparent',
|
|
55
|
-
};
|
|
56
|
-
|
|
57
|
-
const texts: Record<VariantToken['text'], string> = {
|
|
58
|
-
on: 'var(--yarcl-c-on)',
|
|
59
|
-
color: 'var(--yarcl-c-text)',
|
|
60
|
-
neutral: 'var(--yarcl-neutral-text)',
|
|
61
|
-
};
|
|
62
|
-
|
|
63
|
-
const formats: Record<string, string> = { woff2: 'woff2', woff: 'woff', ttf: 'truetype', otf: 'opentype' };
|
|
64
|
-
|
|
65
|
-
function fontFace(face: FontFaceToken): string {
|
|
66
|
-
const sources = (Array.isArray(face.src) ? face.src : [face.src]).map((src) => {
|
|
67
|
-
if (src.startsWith('local(')) return src;
|
|
68
|
-
const format = formats[src.split(/[?#]/)[0].split('.').pop()?.toLowerCase() ?? ''];
|
|
69
|
-
return `url(${JSON.stringify(src)})${format ? ` format("${format}")` : ''}`;
|
|
70
|
-
});
|
|
71
|
-
return rule('@font-face', [
|
|
72
|
-
['font-family', JSON.stringify(face.family)],
|
|
73
|
-
['src', sources.join(', ')],
|
|
74
|
-
...(face.weight != null ? [['font-weight', face.weight] as [string, string | number]] : []),
|
|
75
|
-
...(face.style ? [['font-style', face.style] as [string, string]] : []),
|
|
76
|
-
['font-display', face.display ?? 'swap'],
|
|
77
|
-
]);
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
const TEXT_TINTS = [0, 0.14, 0.22];
|
|
81
|
-
|
|
82
|
-
function textShade(name: string, token: ColorToken, neutrals: YarclShape['neutrals']): string {
|
|
83
|
-
if (token.text) return pair(typeof token.text === 'string' ? { light: token.text, dark: token.text } : token.text);
|
|
84
|
-
const modes = ['light', 'dark'] as const;
|
|
85
|
-
const resolved = modes.map((mode) => {
|
|
86
|
-
const color = parseHex(token[mode]);
|
|
87
|
-
const text = parseHex(neutrals.text[mode]);
|
|
88
|
-
const grounds = [parseHex(neutrals.bg[mode]), parseHex(neutrals.surface[mode])];
|
|
89
|
-
if (!color || !text || grounds.some((g) => !g)) return token[mode];
|
|
90
|
-
const backgrounds = grounds.flatMap((ground) => TEXT_TINTS.map((alpha) => mix(ground!, color, alpha)));
|
|
91
|
-
return toHex(readableText(color, backgrounds, text, MIN_CONTRAST));
|
|
92
|
-
});
|
|
93
|
-
return pair({ light: resolved[0], dark: resolved[1] });
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
function rule(selector: string, declarations: [string, string | number][]): string {
|
|
97
|
-
return `${selector} {\n${declarations.map(([p, v]) => ` ${p}: ${v};`).join('\n')}\n}`;
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
/**
|
|
101
|
-
* Generates the stylesheet for a config: CSS variables on `:root`, one class per key and
|
|
102
|
-
* `@font-face` rules. The Vite plugin calls this at build time; call it yourself to preview
|
|
103
|
-
* or switch themes at runtime (inject the result into a `<style>` element).
|
|
104
|
-
*
|
|
105
|
-
* @param config A config from `defineConfig`, e.g. one of `@yarcl/react/themes`.
|
|
106
|
-
* @param warn Receives contrast warnings.
|
|
107
|
-
*/
|
|
108
|
-
export function generateCss(config: YarclShape, warn: (message: string) => void = () => {}): string {
|
|
109
|
-
const root: [string, string | number][] = [['color-scheme', 'light dark']];
|
|
110
|
-
const rules: string[] = [];
|
|
111
|
-
|
|
112
|
-
for (const [key, token] of Object.entries(config.colors)) {
|
|
113
|
-
const k = ident(key);
|
|
114
|
-
root.push(
|
|
115
|
-
[`--yarcl-color-${k}`, pair(token)],
|
|
116
|
-
[`--yarcl-color-${k}-on`, foreground(key, token, warn)],
|
|
117
|
-
[`--yarcl-color-${k}-text`, textShade(key, token, config.neutrals)],
|
|
118
|
-
);
|
|
119
|
-
rules.push(
|
|
120
|
-
rule(`.yarcl-color-${k}`, [
|
|
121
|
-
['--yarcl-c', `var(--yarcl-color-${k})`],
|
|
122
|
-
['--yarcl-c-on', `var(--yarcl-color-${k}-on)`],
|
|
123
|
-
['--yarcl-c-text', `var(--yarcl-color-${k}-text)`],
|
|
124
|
-
]),
|
|
125
|
-
);
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
for (const [key, value] of Object.entries(config.neutrals)) root.push([`--yarcl-neutral-${ident(key)}`, pair(value)]);
|
|
129
|
-
|
|
130
|
-
for (const [key, size] of Object.entries(config.sizes)) {
|
|
131
|
-
const k = ident(key);
|
|
132
|
-
root.push(
|
|
133
|
-
[`--yarcl-size-${k}-height`, size.height],
|
|
134
|
-
[`--yarcl-size-${k}-padding-x`, size.paddingX],
|
|
135
|
-
[`--yarcl-size-${k}-font-size`, size.fontSize],
|
|
136
|
-
[`--yarcl-size-${k}-icon-size`, size.iconSize],
|
|
137
|
-
);
|
|
138
|
-
rules.push(
|
|
139
|
-
rule(`.yarcl-size-${k}`, [
|
|
140
|
-
['--yarcl-h', `var(--yarcl-size-${k}-height)`],
|
|
141
|
-
['--yarcl-px', `var(--yarcl-size-${k}-padding-x)`],
|
|
142
|
-
['--yarcl-fs', `var(--yarcl-size-${k}-font-size)`],
|
|
143
|
-
['--yarcl-icon', `var(--yarcl-size-${k}-icon-size)`],
|
|
144
|
-
]),
|
|
145
|
-
);
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
for (const [key, value] of Object.entries(config.radii)) {
|
|
149
|
-
const k = ident(key);
|
|
150
|
-
root.push([`--yarcl-radius-${k}`, value]);
|
|
151
|
-
rules.push(rule(`.yarcl-radius-${k}`, [['--yarcl-r', `var(--yarcl-radius-${k})`]]));
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
for (const [key, variant] of Object.entries(config.variants)) {
|
|
155
|
-
const [bg, hover, active] = backgrounds[variant.background];
|
|
156
|
-
rules.push(
|
|
157
|
-
rule(`.yarcl-variant-${ident(key)}`, [
|
|
158
|
-
['--yarcl-v-bg', bg],
|
|
159
|
-
['--yarcl-v-bg-hover', hover],
|
|
160
|
-
['--yarcl-v-bg-active', active],
|
|
161
|
-
['--yarcl-v-border', borders[variant.border]],
|
|
162
|
-
['--yarcl-v-fg', texts[variant.text]],
|
|
163
|
-
]),
|
|
164
|
-
);
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
for (const [key, value] of Object.entries(config.spacing)) {
|
|
168
|
-
const k = ident(key);
|
|
169
|
-
root.push([`--yarcl-space-${k}`, value]);
|
|
170
|
-
rules.push(
|
|
171
|
-
rule(`.yarcl-gap-${k}`, [['gap', `var(--yarcl-space-${k})`]]),
|
|
172
|
-
rule(`.yarcl-padding-${k}`, [['padding', `var(--yarcl-space-${k})`]]),
|
|
173
|
-
);
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
for (const [key, value] of Object.entries(config.shadows)) {
|
|
177
|
-
const k = ident(key);
|
|
178
|
-
root.push([`--yarcl-shadow-${k}`, value]);
|
|
179
|
-
rules.push(rule(`.yarcl-shadow-${k}`, [['box-shadow', `var(--yarcl-shadow-${k})`]]));
|
|
180
|
-
}
|
|
181
|
-
for (const [key, value] of Object.entries(config.modalSizes)) {
|
|
182
|
-
const k = ident(key);
|
|
183
|
-
root.push([`--yarcl-modal-${k}`, value]);
|
|
184
|
-
rules.push(rule(`.yarcl-modal-size-${k}`, [['--yarcl-modal-width', `var(--yarcl-modal-${k})`]]));
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
for (const [key, density] of Object.entries(config.density)) {
|
|
188
|
-
rules.push(
|
|
189
|
-
rule(`.yarcl-density-${ident(key)}`, [
|
|
190
|
-
['--yarcl-cell-px', density.paddingX],
|
|
191
|
-
['--yarcl-cell-py', density.paddingY],
|
|
192
|
-
['--yarcl-cell-fs', density.fontSize],
|
|
193
|
-
]),
|
|
194
|
-
);
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
for (const [key, value] of Object.entries(config.typography.families)) root.push([`--yarcl-font-${ident(key)}`, value]);
|
|
198
|
-
|
|
199
|
-
for (const [key, style] of Object.entries(config.typography.styles)) {
|
|
200
|
-
rules.push(
|
|
201
|
-
rule(`.yarcl-type-${ident(key)}`, [
|
|
202
|
-
['font-family', `var(--yarcl-font-${ident(style.family)})`],
|
|
203
|
-
['font-size', style.size],
|
|
204
|
-
['font-weight', style.weight],
|
|
205
|
-
['line-height', style.lineHeight],
|
|
206
|
-
...(style.letterSpacing ? [['letter-spacing', style.letterSpacing] as [string, string]] : []),
|
|
207
|
-
]),
|
|
208
|
-
);
|
|
209
|
-
}
|
|
210
|
-
|
|
211
|
-
for (const [key, value] of Object.entries(config.zIndex)) root.push([`--yarcl-z-${ident(key)}`, value]);
|
|
212
|
-
for (const [key, value] of Object.entries(config.motion)) root.push([`--yarcl-motion-${ident(key)}`, value]);
|
|
213
|
-
for (const [key, value] of Object.entries(config.borders)) root.push([`--yarcl-border-${ident(key)}`, value]);
|
|
214
|
-
|
|
215
|
-
root.push(
|
|
216
|
-
['--yarcl-focus-width', config.focusRing.width],
|
|
217
|
-
['--yarcl-focus-offset', config.focusRing.offset],
|
|
218
|
-
['--yarcl-focus-style', config.focusRing.style ?? 'solid'],
|
|
219
|
-
['--yarcl-focus-color', `var(--yarcl-color-${ident(config.focusRing.color)})`],
|
|
220
|
-
['--yarcl-error', `var(--yarcl-color-${ident(config.defaults.errorColor)})`],
|
|
221
|
-
['--yarcl-floating-shadow', `var(--yarcl-shadow-${ident(config.defaults.floatingShadow)})`],
|
|
222
|
-
['--yarcl-padding', `var(--yarcl-space-${ident(config.defaults.padding)})`],
|
|
223
|
-
['--yarcl-gap', `var(--yarcl-space-${ident(config.defaults.gap)})`],
|
|
224
|
-
);
|
|
225
|
-
|
|
226
|
-
const faces = (config.typography.fontFaces ?? []).map(fontFace);
|
|
227
|
-
return [...faces, rule(':root', root), ...rules].join('\n\n') + '\n';
|
|
228
|
-
}
|
package/src/define.check.ts
DELETED
|
@@ -1,259 +0,0 @@
|
|
|
1
|
-
import { defineConfig } from './define';
|
|
2
|
-
import defaults from './yarcl.config';
|
|
3
|
-
|
|
4
|
-
defineConfig({ ...defaults, colors: { ...defaults.colors, brand: { light: '#000', dark: '#fff' } } });
|
|
5
|
-
|
|
6
|
-
defineConfig({
|
|
7
|
-
...defaults,
|
|
8
|
-
// @ts-expect-error
|
|
9
|
-
colors: { primary: { light: '#2d4bb8' } },
|
|
10
|
-
});
|
|
11
|
-
|
|
12
|
-
defineConfig({
|
|
13
|
-
...defaults,
|
|
14
|
-
// @ts-expect-error
|
|
15
|
-
defaults: { ...defaults.defaults, size: 'xxl' },
|
|
16
|
-
});
|
|
17
|
-
|
|
18
|
-
defineConfig({
|
|
19
|
-
...defaults,
|
|
20
|
-
// @ts-expect-error
|
|
21
|
-
focusRing: { ...defaults.focusRing, color: 'nope' },
|
|
22
|
-
});
|
|
23
|
-
|
|
24
|
-
defineConfig({
|
|
25
|
-
...defaults,
|
|
26
|
-
typography: {
|
|
27
|
-
...defaults.typography,
|
|
28
|
-
// @ts-expect-error
|
|
29
|
-
styles: { body: { family: 'serif', size: '1rem', weight: 400, lineHeight: 1.5 } },
|
|
30
|
-
},
|
|
31
|
-
});
|
|
32
|
-
|
|
33
|
-
defineConfig({
|
|
34
|
-
...defaults,
|
|
35
|
-
// @ts-expect-error
|
|
36
|
-
radii: { ...defaults.radii, 'extra round': '2rem' },
|
|
37
|
-
});
|
|
38
|
-
|
|
39
|
-
defineConfig({
|
|
40
|
-
...defaults,
|
|
41
|
-
zIndex: { ...defaults.zIndex, banner: 900 },
|
|
42
|
-
neutrals: { ...defaults.neutrals, raised: { light: '#fff', dark: '#222' } },
|
|
43
|
-
});
|
|
44
|
-
|
|
45
|
-
defineConfig({
|
|
46
|
-
...defaults,
|
|
47
|
-
// @ts-expect-error
|
|
48
|
-
zIndex: { dropdown: 1000, tooltip: 1100, dialog: 1200 },
|
|
49
|
-
});
|
|
50
|
-
|
|
51
|
-
defineConfig({
|
|
52
|
-
...defaults,
|
|
53
|
-
variants: { ...defaults.variants, link: { background: 'none', border: 'none', text: 'color' } },
|
|
54
|
-
});
|
|
55
|
-
|
|
56
|
-
defineConfig({
|
|
57
|
-
...defaults,
|
|
58
|
-
// @ts-expect-error
|
|
59
|
-
variants: { solid: { background: 'gradient', border: 'color', text: 'on' } },
|
|
60
|
-
});
|
|
61
|
-
|
|
62
|
-
defineConfig({
|
|
63
|
-
...defaults,
|
|
64
|
-
// @ts-expect-error
|
|
65
|
-
defaults: { ...defaults.defaults, errorColor: 'red' },
|
|
66
|
-
});
|
|
67
|
-
|
|
68
|
-
defineConfig({
|
|
69
|
-
...defaults,
|
|
70
|
-
// @ts-expect-error
|
|
71
|
-
defaults: { ...defaults.defaults, textStyle: 'huge' },
|
|
72
|
-
});
|
|
73
|
-
|
|
74
|
-
defineConfig({
|
|
75
|
-
...defaults,
|
|
76
|
-
// @ts-expect-error
|
|
77
|
-
defaults: { ...defaults.defaults, gap: 'tight' },
|
|
78
|
-
});
|
|
79
|
-
|
|
80
|
-
defineConfig({
|
|
81
|
-
...defaults,
|
|
82
|
-
// @ts-expect-error
|
|
83
|
-
defaults: { ...defaults.defaults, softVariant: 'subtle' },
|
|
84
|
-
});
|
|
85
|
-
|
|
86
|
-
defineConfig({
|
|
87
|
-
...defaults,
|
|
88
|
-
typography: {
|
|
89
|
-
...defaults.typography,
|
|
90
|
-
fontFaces: [{ family: 'Inter', src: ['/fonts/inter.woff2', 'local(Inter)'], weight: '100 900' }],
|
|
91
|
-
},
|
|
92
|
-
});
|
|
93
|
-
|
|
94
|
-
defineConfig({
|
|
95
|
-
...defaults,
|
|
96
|
-
typography: {
|
|
97
|
-
...defaults.typography,
|
|
98
|
-
// @ts-expect-error
|
|
99
|
-
headings: { ...defaults.typography.headings, h3: 'huge' },
|
|
100
|
-
},
|
|
101
|
-
});
|
|
102
|
-
|
|
103
|
-
defineConfig({
|
|
104
|
-
...defaults,
|
|
105
|
-
typography: {
|
|
106
|
-
...defaults.typography,
|
|
107
|
-
// @ts-expect-error
|
|
108
|
-
headings: { h1: 'display', h2: 'heading' },
|
|
109
|
-
},
|
|
110
|
-
});
|
|
111
|
-
|
|
112
|
-
defineConfig({
|
|
113
|
-
...defaults,
|
|
114
|
-
// @ts-expect-error
|
|
115
|
-
defaults: { ...defaults.defaults, labelStyle: 'tiny' },
|
|
116
|
-
});
|
|
117
|
-
|
|
118
|
-
defineConfig({
|
|
119
|
-
...defaults,
|
|
120
|
-
components: {
|
|
121
|
-
Button: { radius: 'square', variant: 'outline' },
|
|
122
|
-
IconButton: { radius: 'size' },
|
|
123
|
-
Card: { padding: 'xl', shadow: 'lg' },
|
|
124
|
-
Stack: { gap: 'sm' },
|
|
125
|
-
Pagination: { size: 'sm', variant: 'outline', selectedVariant: 'solid' },
|
|
126
|
-
Breadcrumb: { textStyle: 'caption', color: 'neutral' },
|
|
127
|
-
Accordion: { size: 'sm', radius: 'size', color: 'success' },
|
|
128
|
-
},
|
|
129
|
-
});
|
|
130
|
-
|
|
131
|
-
defineConfig({
|
|
132
|
-
...defaults,
|
|
133
|
-
components: {
|
|
134
|
-
// @ts-expect-error
|
|
135
|
-
Pagination: { selectedVariant: 'filled' },
|
|
136
|
-
},
|
|
137
|
-
});
|
|
138
|
-
|
|
139
|
-
defineConfig({
|
|
140
|
-
...defaults,
|
|
141
|
-
components: {
|
|
142
|
-
// @ts-expect-error
|
|
143
|
-
Breadcrumb: { size: 'sm' },
|
|
144
|
-
},
|
|
145
|
-
});
|
|
146
|
-
|
|
147
|
-
defineConfig({
|
|
148
|
-
...defaults,
|
|
149
|
-
components: {
|
|
150
|
-
// @ts-expect-error
|
|
151
|
-
Breadcrumb: { textStyle: 'huge' },
|
|
152
|
-
},
|
|
153
|
-
});
|
|
154
|
-
|
|
155
|
-
defineConfig({
|
|
156
|
-
...defaults,
|
|
157
|
-
components: {
|
|
158
|
-
// @ts-expect-error
|
|
159
|
-
Accordion: { variant: 'solid' },
|
|
160
|
-
},
|
|
161
|
-
});
|
|
162
|
-
|
|
163
|
-
defineConfig({
|
|
164
|
-
...defaults,
|
|
165
|
-
components: {
|
|
166
|
-
// @ts-expect-error
|
|
167
|
-
Buton: { radius: 'square' },
|
|
168
|
-
},
|
|
169
|
-
});
|
|
170
|
-
|
|
171
|
-
defineConfig({
|
|
172
|
-
...defaults,
|
|
173
|
-
components: {
|
|
174
|
-
// @ts-expect-error
|
|
175
|
-
Card: { variant: 'solid' },
|
|
176
|
-
},
|
|
177
|
-
});
|
|
178
|
-
|
|
179
|
-
defineConfig({
|
|
180
|
-
...defaults,
|
|
181
|
-
components: {
|
|
182
|
-
// @ts-expect-error
|
|
183
|
-
Button: { radius: 'pill' },
|
|
184
|
-
},
|
|
185
|
-
});
|
|
186
|
-
|
|
187
|
-
defineConfig({
|
|
188
|
-
...defaults,
|
|
189
|
-
// @ts-expect-error
|
|
190
|
-
radii: { ...defaults.radii, size: '1rem' },
|
|
191
|
-
});
|
|
192
|
-
|
|
193
|
-
defineConfig({ ...defaults, components: { CommandPalette: { size: 'lg', radius: 'size', color: 'danger' } } });
|
|
194
|
-
|
|
195
|
-
defineConfig({
|
|
196
|
-
...defaults,
|
|
197
|
-
components: {
|
|
198
|
-
// @ts-expect-error
|
|
199
|
-
CommandPalette: { variant: 'solid' },
|
|
200
|
-
},
|
|
201
|
-
});
|
|
202
|
-
|
|
203
|
-
defineConfig({ ...defaults, defaults: { ...defaults.defaults, radius: 'square' } });
|
|
204
|
-
|
|
205
|
-
defineConfig({
|
|
206
|
-
...defaults,
|
|
207
|
-
modalSizes: { ...defaults.modalSizes, huge: '80rem' },
|
|
208
|
-
components: { Dialog: { size: 'huge' }, Drawer: { size: 'sm' } },
|
|
209
|
-
});
|
|
210
|
-
|
|
211
|
-
defineConfig({
|
|
212
|
-
...defaults,
|
|
213
|
-
components: {
|
|
214
|
-
// @ts-expect-error
|
|
215
|
-
Dialog: { size: 'giant' },
|
|
216
|
-
},
|
|
217
|
-
});
|
|
218
|
-
|
|
219
|
-
defineConfig({ ...defaults, components: { Label: { textStyle: 'caption', color: 'neutral' } } });
|
|
220
|
-
|
|
221
|
-
defineConfig({
|
|
222
|
-
...defaults,
|
|
223
|
-
components: {
|
|
224
|
-
// @ts-expect-error
|
|
225
|
-
Label: { textStyle: 'tiny' },
|
|
226
|
-
},
|
|
227
|
-
});
|
|
228
|
-
|
|
229
|
-
defineConfig({
|
|
230
|
-
...defaults,
|
|
231
|
-
components: {
|
|
232
|
-
// @ts-expect-error
|
|
233
|
-
Label: { size: 'sm' },
|
|
234
|
-
},
|
|
235
|
-
});
|
|
236
|
-
|
|
237
|
-
defineConfig({
|
|
238
|
-
...defaults,
|
|
239
|
-
// @ts-expect-error
|
|
240
|
-
defaults: { ...defaults.defaults, modalSize: 'giant' },
|
|
241
|
-
});
|
|
242
|
-
|
|
243
|
-
defineConfig({
|
|
244
|
-
...defaults,
|
|
245
|
-
colors: { ...defaults.colors, primary: { light: '#2d4bb8', dark: '#8aa2ff', text: { light: '#1e3480', dark: '#c3cfff' } } },
|
|
246
|
-
});
|
|
247
|
-
|
|
248
|
-
defineConfig({
|
|
249
|
-
...defaults,
|
|
250
|
-
components: { Progress: { size: 'lg', color: 'success', radius: 'rounded' } },
|
|
251
|
-
});
|
|
252
|
-
|
|
253
|
-
defineConfig({
|
|
254
|
-
...defaults,
|
|
255
|
-
components: {
|
|
256
|
-
// @ts-expect-error
|
|
257
|
-
Progress: { variant: 'solid' },
|
|
258
|
-
},
|
|
259
|
-
});
|