@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
package/README.md CHANGED
@@ -2,6 +2,16 @@
2
2
 
3
3
  Yet another react component library. Your config file is the design system: every key becomes a typed prop and a rendered style.
4
4
 
5
+ From an existing React project using Vite, webpack, Rspack, Rollup or esbuild, run:
6
+
7
+ ```sh
8
+ npx @yarcl/react init
9
+ ```
10
+
11
+ This installs the package, adds the detected build plugin and TypeScript path mapping, and creates `src/yarcl.config.ts`. The equivalent commands are `pnpm dlx @yarcl/react init`, `yarn dlx @yarcl/react init` and `bunx @yarcl/react init`.
12
+
13
+ For manual setup:
14
+
5
15
  ```sh
6
16
  npm install @yarcl/react
7
17
  ```
@@ -10,17 +20,19 @@ npm install @yarcl/react
10
20
  // vite.config.ts
11
21
  import react from '@vitejs/plugin-react';
12
22
  import { defineConfig } from 'vite';
13
- import { yarcl } from '@yarcl/react/plugin';
23
+ import yarcl from '@yarcl/react/vite';
14
24
 
15
25
  export default defineConfig({ plugins: [react(), yarcl({ config: 'src/yarcl.config.ts' })] });
16
26
  ```
17
27
 
28
+ For webpack, Rspack, Rollup or esbuild, import the plugin from the matching `@yarcl/react/<build-tool>` entry point.
29
+
18
30
  ```jsonc
19
31
  // tsconfig.json
20
32
  {
21
33
  "compilerOptions": {
22
34
  "paths": {
23
- "@yarcl/config": ["./src/yarcl.config.ts", "./node_modules/@yarcl/react/src/yarcl.config.ts"]
35
+ "@yarcl/config": ["./src/yarcl.config.ts", "./node_modules/@yarcl/react/dist/yarcl.config.d.ts"]
24
36
  }
25
37
  }
26
38
  }
@@ -1,17 +1,11 @@
1
1
  import { generateCss } from './css';
2
2
  import type { YarclShape } from './define';
3
- import { setActiveConfig } from './runtime';
4
-
5
3
  export { generateCss };
6
-
7
- const STYLE_ID = 'yarcl-theme';
8
-
9
4
  /** Options for {@link applyTheme}. */
10
5
  export interface ApplyThemeOptions {
11
- /** Receives contrast warnings for the theme's colors. */
12
- onWarning?: (message: string) => void;
6
+ /** Receives contrast warnings for the theme's colors. */
7
+ onWarning?: (message: string) => void;
13
8
  }
14
-
15
9
  /**
16
10
  * Switches the whole app to another theme at runtime, without a rebuild.
17
11
  *
@@ -28,19 +22,6 @@ export interface ApplyThemeOptions {
28
22
  * applyTheme(themes.editorial);
29
23
  * ```
30
24
  */
31
- export function applyTheme(theme: YarclShape, { onWarning }: ApplyThemeOptions = {}) {
32
- let style = document.getElementById(STYLE_ID);
33
- if (!style) {
34
- style = document.createElement('style');
35
- style.id = STYLE_ID;
36
- }
37
- document.head.appendChild(style);
38
- style.textContent = generateCss(theme, onWarning);
39
- setActiveConfig(theme);
40
- }
41
-
25
+ export declare function applyTheme(theme: YarclShape, { onWarning }?: ApplyThemeOptions): void;
42
26
  /** Removes a theme applied with {@link applyTheme} and returns to the build-time config and styles. */
43
- export function resetTheme() {
44
- document.getElementById(STYLE_ID)?.remove();
45
- setActiveConfig(null);
46
- }
27
+ export declare function resetTheme(): void;
package/dist/apply.js ADDED
@@ -0,0 +1,37 @@
1
+ import { setActiveConfig } from "./runtime.js";
2
+ import { generateCss } from "./css.js";
3
+ //#region src/apply.ts
4
+ var STYLE_ID = "yarcl-theme";
5
+ /**
6
+ * Switches the whole app to another theme at runtime, without a rebuild.
7
+ *
8
+ * Injects the theme's generated CSS (replacing the build-time styles) and makes components read
9
+ * their defaults (`defaults`, `components`, heading levels) from the theme, re-rendering them.
10
+ * The theme must define the keys your app uses; bundled themes share the defaults' keys
11
+ * (`ThemeContract`), so any of them can replace another.
12
+ *
13
+ * @example
14
+ * ```ts
15
+ * import { applyTheme } from '@yarcl/react/css';
16
+ * import { themes } from '@yarcl/react/themes';
17
+ *
18
+ * applyTheme(themes.editorial);
19
+ * ```
20
+ */
21
+ function applyTheme(theme, { onWarning } = {}) {
22
+ let style = document.getElementById(STYLE_ID);
23
+ if (!style) {
24
+ style = document.createElement("style");
25
+ style.id = STYLE_ID;
26
+ }
27
+ document.head.appendChild(style);
28
+ style.textContent = generateCss(theme, onWarning);
29
+ setActiveConfig(theme);
30
+ }
31
+ /** Removes a theme applied with {@link applyTheme} and returns to the build-time config and styles. */
32
+ function resetTheme() {
33
+ document.getElementById(STYLE_ID)?.remove();
34
+ setActiveConfig(null);
35
+ }
36
+ //#endregion
37
+ export { applyTheme, generateCss, resetTheme };
@@ -0,0 +1,13 @@
1
+ import type { Color, Density, Radius, Shadow, Size, Spacing, TextStyle, Variant } from './types';
2
+ import type { ComponentName } from './define';
3
+ export declare function cx(...parts: (string | false | null | undefined)[]): string;
4
+ export declare const sizeClass: (size?: Size, component?: ComponentName) => string;
5
+ export declare function radiusClass(radius?: Radius | 'size', size?: Size): string | undefined;
6
+ export declare const colorClass: (color?: Color) => string;
7
+ export declare const variantClass: (variant?: Variant) => string;
8
+ export declare const gapClass: (gap?: Spacing) => string;
9
+ export declare const paddingClass: (padding?: Spacing) => string;
10
+ export declare const shadowClass: (shadow?: Shadow) => string | undefined;
11
+ export declare const typeClass: (style: TextStyle) => string;
12
+ export declare const densityClass: (density?: Density) => string;
13
+ export declare const softVariantClass: (variant?: Variant) => string;
@@ -0,0 +1,22 @@
1
+ import { activeConfig } from "./runtime.js";
2
+ //#region src/classes.ts
3
+ function cx(...parts) {
4
+ return parts.filter(Boolean).join(" ");
5
+ }
6
+ var sizeClass = (size = activeConfig().defaults.size, component) => `yarcl-size-${size}${component ? ` yarcl-sized-${component}` : ""}`;
7
+ function radiusClass(radius, size) {
8
+ const value = radius ?? activeConfig().defaults.radius;
9
+ if (value !== "size") return `yarcl-radius-${value}`;
10
+ const match = size ?? activeConfig().defaults.size;
11
+ return match in activeConfig().radii ? `yarcl-radius-${match}` : void 0;
12
+ }
13
+ var colorClass = (color = activeConfig().defaults.color) => `yarcl-color-${color}`;
14
+ var variantClass = (variant = activeConfig().defaults.variant) => `yarcl-variant-${variant}`;
15
+ var gapClass = (gap = activeConfig().defaults.gap) => `yarcl-gap-${gap}`;
16
+ var paddingClass = (padding = activeConfig().defaults.padding) => `yarcl-padding-${padding}`;
17
+ var shadowClass = (shadow) => shadow && `yarcl-shadow-${shadow}`;
18
+ var typeClass = (style) => `yarcl-type-${style}`;
19
+ var densityClass = (density = activeConfig().defaults.density) => `yarcl-density-${density}`;
20
+ var softVariantClass = (variant = activeConfig().defaults.softVariant) => `yarcl-variant-${variant}`;
21
+ //#endregion
22
+ export { colorClass, cx, densityClass, gapClass, paddingClass, radiusClass, shadowClass, sizeClass, softVariantClass, typeClass, variantClass };
package/dist/cli.d.ts ADDED
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};
package/dist/cli.js ADDED
@@ -0,0 +1,58 @@
1
+ #!/usr/bin/env node
2
+ import { initProject } from "./init.js";
3
+ import { readFile } from "node:fs/promises";
4
+ import { dirname, resolve } from "node:path";
5
+ import { error, log } from "node:console";
6
+ import process from "node:process";
7
+ import { fileURLToPath } from "node:url";
8
+ //#region src/cli.ts
9
+ var buildTools = /* @__PURE__ */ new Set([
10
+ "vite",
11
+ "webpack",
12
+ "rspack",
13
+ "rollup",
14
+ "esbuild"
15
+ ]);
16
+ function usage() {
17
+ log("Usage: yarcl init [--config <path>] [--root <path>] [--bundler <name>] [--skip-install]");
18
+ }
19
+ function option(args, name) {
20
+ const index = args.indexOf(name);
21
+ if (index < 0) return void 0;
22
+ const value = args[index + 1];
23
+ if (!value || value.startsWith("--")) throw new Error(`yarcl: ${name} requires a value.`);
24
+ return value;
25
+ }
26
+ async function main() {
27
+ const args = process.argv.slice(2);
28
+ if (args.includes("--help") || args.includes("-h")) {
29
+ usage();
30
+ return;
31
+ }
32
+ if (args[0] !== "init") {
33
+ usage();
34
+ process.exitCode = 1;
35
+ return;
36
+ }
37
+ const packageRoot = resolve(dirname(fileURLToPath(import.meta.url)), "..");
38
+ const manifest = JSON.parse(await readFile(resolve(packageRoot, "package.json"), "utf8"));
39
+ const configPath = option(args, "--config");
40
+ const requestedBuildTool = option(args, "--bundler");
41
+ if (requestedBuildTool && !buildTools.has(requestedBuildTool)) throw new Error(`yarcl: Unsupported bundler "${requestedBuildTool}". Use vite, webpack, rspack, rollup or esbuild.`);
42
+ const root = resolve(option(args, "--root") ?? process.cwd());
43
+ const result = await initProject({
44
+ root,
45
+ configPath,
46
+ configProvided: configPath !== void 0,
47
+ buildTool: requestedBuildTool,
48
+ install: !args.includes("--skip-install"),
49
+ version: manifest.version
50
+ });
51
+ log(`yarcl configured ${result.configPath}`);
52
+ log(`Updated ${result.buildConfig.slice(root.length + 1)} and ${result.tsconfig.slice(root.length + 1)}`);
53
+ }
54
+ main().catch((cause) => {
55
+ error(cause instanceof Error ? cause.message : cause);
56
+ process.exitCode = 1;
57
+ });
58
+ //#endregion
package/dist/color.js CHANGED
@@ -1,41 +1,58 @@
1
- export function parseHex(value) {
2
- const hex = value.trim().replace(/^#/, '');
3
- if (!/^([0-9a-f]{3}|[0-9a-f]{6})$/i.test(hex))
4
- return null;
5
- const full = hex.length === 3 ? [...hex].map((c) => c + c).join('') : hex;
6
- return [0, 2, 4].map((i) => parseInt(full.slice(i, i + 2), 16));
1
+ //#region src/color.ts
2
+ function parseHex(value) {
3
+ const hex = value.trim().replace(/^#/, "");
4
+ if (!/^([0-9a-f]{3}|[0-9a-f]{6})$/i.test(hex)) return null;
5
+ const full = hex.length === 3 ? [...hex].map((c) => c + c).join("") : hex;
6
+ return [
7
+ 0,
8
+ 2,
9
+ 4
10
+ ].map((i) => parseInt(full.slice(i, i + 2), 16));
7
11
  }
8
12
  function luminance([r, g, b]) {
9
- const [lr, lg, lb] = [r, g, b].map((c) => {
10
- const s = c / 255;
11
- return s <= 0.03928 ? s / 12.92 : ((s + 0.055) / 1.055) ** 2.4;
12
- });
13
- return 0.2126 * lr + 0.7152 * lg + 0.0722 * lb;
13
+ const [lr, lg, lb] = [
14
+ r,
15
+ g,
16
+ b
17
+ ].map((c) => {
18
+ const s = c / 255;
19
+ return s <= .03928 ? s / 12.92 : ((s + .055) / 1.055) ** 2.4;
20
+ });
21
+ return .2126 * lr + .7152 * lg + .0722 * lb;
14
22
  }
15
- export function contrast(a, b) {
16
- const [hi, lo] = [luminance(a), luminance(b)].sort((x, y) => y - x);
17
- return (hi + 0.05) / (lo + 0.05);
23
+ function contrast(a, b) {
24
+ const [hi, lo] = [luminance(a), luminance(b)].sort((x, y) => y - x);
25
+ return (hi + .05) / (lo + .05);
18
26
  }
19
- const WHITE = [255, 255, 255];
20
- const BLACK = [0, 0, 0];
21
- export function mix(a, b, amount) {
22
- return a.map((channel, i) => Math.round(channel + (b[i] - channel) * amount));
27
+ var WHITE = [
28
+ 255,
29
+ 255,
30
+ 255
31
+ ];
32
+ var BLACK = [
33
+ 0,
34
+ 0,
35
+ 0
36
+ ];
37
+ function mix(a, b, amount) {
38
+ return a.map((channel, i) => Math.round(channel + (b[i] - channel) * amount));
23
39
  }
24
- export function toHex(rgb) {
25
- return `#${rgb.map((c) => c.toString(16).padStart(2, '0')).join('')}`;
40
+ function toHex(rgb) {
41
+ return `#${rgb.map((c) => c.toString(16).padStart(2, "0")).join("")}`;
26
42
  }
27
43
  /**
28
- * The color, mixed toward `toward` in small steps until it reaches `min` contrast
29
- * against every background. Returns the color unchanged when it already passes.
30
- */
31
- export function readableText(color, backgrounds, toward, min) {
32
- for (let step = 0; step <= 20; step++) {
33
- const candidate = mix(color, toward, step / 20);
34
- if (backgrounds.every((bg) => contrast(candidate, bg) >= min))
35
- return candidate;
36
- }
37
- return toward;
44
+ * The color, mixed toward `toward` in small steps until it reaches `min` contrast
45
+ * against every background. Returns the color unchanged when it already passes.
46
+ */
47
+ function readableText(color, backgrounds, toward, min) {
48
+ for (let step = 0; step <= 20; step++) {
49
+ const candidate = mix(color, toward, step / 20);
50
+ if (backgrounds.every((bg) => contrast(candidate, bg) >= min)) return candidate;
51
+ }
52
+ return toward;
38
53
  }
39
- export function readableOn(background) {
40
- return contrast(background, WHITE) >= contrast(background, BLACK) ? '#ffffff' : '#000000';
54
+ function readableOn(background) {
55
+ return contrast(background, WHITE) >= contrast(background, BLACK) ? "#ffffff" : "#000000";
41
56
  }
57
+ //#endregion
58
+ export { contrast, mix, parseHex, readableOn, readableText, toHex };
@@ -0,0 +1,96 @@
1
+ import { type ComponentProps, type ReactNode } from 'react';
2
+ import type { Color, ComponentSize, Radius } from '../types';
3
+ /** Props shared by both forms of {@link AccordionProps}. */
4
+ export interface AccordionBaseProps extends Omit<ComponentProps<'div'>, 'defaultValue' | 'color'> {
5
+ /**
6
+ * Trigger height, padding and font size, from the `sizes` config.
7
+ * @default config.defaults.size
8
+ */
9
+ size?: ComponentSize<'Accordion'>;
10
+ /**
11
+ * Corner radius of the outer frame, from the `radii` config, or `'size'` to match the size.
12
+ * @default config.defaults.radius
13
+ */
14
+ radius?: Radius | 'size';
15
+ /**
16
+ * Color of the open item's indicator, from the `colors` config.
17
+ * @default config.defaults.color
18
+ */
19
+ color?: Color;
20
+ /** Disables every item. */
21
+ disabled?: boolean;
22
+ /** `Accordion.Item`s. */
23
+ children?: ReactNode;
24
+ }
25
+ /** Props for {@link Accordion}. `type` decides whether one or many items can be open. */
26
+ export type AccordionProps = AccordionBaseProps & ({
27
+ /** One item open at a time. */
28
+ type: 'single';
29
+ /** Open item (controlled), or `null` when all are closed. */
30
+ value?: string | null;
31
+ /** Initially open item (uncontrolled). */
32
+ defaultValue?: string | null;
33
+ /** Called with the open item, or `null` when it closes. */
34
+ onValueChange?: (value: string | null) => void;
35
+ /**
36
+ * Lets the open item close, leaving all closed. When `false`, one item always stays open.
37
+ * @default true
38
+ */
39
+ collapsible?: boolean;
40
+ } | {
41
+ /** Any number of items open. */
42
+ type: 'multiple';
43
+ /** Open items (controlled). */
44
+ value?: string[];
45
+ /** Initially open items (uncontrolled). */
46
+ defaultValue?: string[];
47
+ /** Called with all open items. */
48
+ onValueChange?: (value: string[]) => void;
49
+ collapsible?: never;
50
+ });
51
+ declare function AccordionRoot(props: AccordionProps): import("react").JSX.Element;
52
+ /** Props for `Accordion.Item`. */
53
+ export interface AccordionItemProps extends Omit<ComponentProps<'div'>, 'value'> {
54
+ /** Identifies the item in the accordion's value. */
55
+ value: string;
56
+ /** Prevents opening or closing this item. */
57
+ disabled?: boolean;
58
+ }
59
+ declare function AccordionItem({ value, disabled, className, ...props }: AccordionItemProps): import("react").JSX.Element;
60
+ /** Props for `Accordion.Trigger`. */
61
+ export interface AccordionTriggerProps extends ComponentProps<'button'> {
62
+ /**
63
+ * Level of the heading that wraps the button, to fit the page outline.
64
+ * @default 3
65
+ */
66
+ level?: 1 | 2 | 3 | 4 | 5 | 6;
67
+ }
68
+ declare function AccordionTrigger({ level, className, onClick, children, ...props }: AccordionTriggerProps): import("react").JSX.Element;
69
+ /** Props for `Accordion.Content`. */
70
+ export type AccordionContentProps = ComponentProps<'div'>;
71
+ declare function AccordionContent({ className, children, ...props }: AccordionContentProps): import("react").JSX.Element;
72
+ /**
73
+ * Stacked sections that expand and collapse. Each trigger is a button inside a heading;
74
+ * Up and Down move between triggers, Home and End jump to the ends. The panel height animates
75
+ * with the `motion` tokens, and snaps when reduced motion is preferred.
76
+ *
77
+ * @example
78
+ * ```tsx
79
+ * <Accordion type="single" defaultValue="shipping">
80
+ * <Accordion.Item value="shipping">
81
+ * <Accordion.Trigger>Shipping</Accordion.Trigger>
82
+ * <Accordion.Content>Orders ship within two working days.</Accordion.Content>
83
+ * </Accordion.Item>
84
+ * <Accordion.Item value="returns">
85
+ * <Accordion.Trigger>Returns</Accordion.Trigger>
86
+ * <Accordion.Content>Free returns within 30 days.</Accordion.Content>
87
+ * </Accordion.Item>
88
+ * </Accordion>
89
+ * ```
90
+ */
91
+ export declare const Accordion: typeof AccordionRoot & {
92
+ Item: typeof AccordionItem;
93
+ Trigger: typeof AccordionTrigger;
94
+ Content: typeof AccordionContent;
95
+ };
96
+ export {};
@@ -0,0 +1,148 @@
1
+ import { useDefaults } from "../runtime.js";
2
+ import { colorClass, cx, radiusClass, sizeClass } from "../classes.js";
3
+ import { useControllable } from "../hooks.js";
4
+ import { ChevronIcon } from "../floating.js";
5
+ import { createContext, useContext, useId } from "react";
6
+ import { jsx, jsxs } from "react/jsx-runtime";
7
+ //#region src/components/Accordion.tsx
8
+ var AccordionContext = createContext(null);
9
+ var AccordionItemContext = createContext(null);
10
+ function useAccordionContext(component) {
11
+ const context = useContext(AccordionContext);
12
+ if (!context) throw new Error(`yarcl: <${component}> must be inside <Accordion>`);
13
+ return context;
14
+ }
15
+ function useItemContext(component) {
16
+ const context = useContext(AccordionItemContext);
17
+ if (!context) throw new Error(`yarcl: <${component}> must be inside <Accordion.Item>`);
18
+ return context;
19
+ }
20
+ var toArray = (value) => value == null ? [] : Array.isArray(value) ? value : [value];
21
+ function AccordionRoot(props) {
22
+ const own = useDefaults("Accordion");
23
+ const { type, value, defaultValue, onValueChange, collapsible = true, size, radius, color, disabled, className, onKeyDown, ...rest } = props;
24
+ const [open, setOpen] = useControllable(value === void 0 ? void 0 : toArray(value), toArray(defaultValue), (next) => type === "multiple" ? onValueChange?.(next) : onValueChange?.(next[0] ?? null));
25
+ const baseId = useId();
26
+ const idFor = (kind, v) => `${baseId}-${kind}-${v.replace(/[^\w-]/g, "_")}`;
27
+ function toggle(item) {
28
+ const on = open.includes(item);
29
+ if (type === "multiple") setOpen(on ? open.filter((v) => v !== item) : [...open, item]);
30
+ else if (!on) setOpen([item]);
31
+ else if (collapsible) setOpen([]);
32
+ }
33
+ function handleKeyDown(event) {
34
+ onKeyDown?.(event);
35
+ const root = event.currentTarget;
36
+ const triggers = [...root.querySelectorAll(".yarcl-accordion-trigger:not(:disabled)")].filter((trigger) => trigger.closest(".yarcl-accordion") === root);
37
+ const current = triggers.indexOf(document.activeElement);
38
+ if (current === -1) return;
39
+ const next = {
40
+ ArrowDown: (current + 1) % triggers.length,
41
+ ArrowUp: (current - 1 + triggers.length) % triggers.length,
42
+ Home: 0,
43
+ End: triggers.length - 1
44
+ }[event.key];
45
+ if (next === void 0) return;
46
+ event.preventDefault();
47
+ triggers[next].focus();
48
+ }
49
+ const resolvedSize = size ?? own.size;
50
+ return /* @__PURE__ */ jsx(AccordionContext.Provider, {
51
+ value: {
52
+ open,
53
+ toggle,
54
+ disabled,
55
+ idFor
56
+ },
57
+ children: /* @__PURE__ */ jsx("div", {
58
+ className: cx("yarcl-accordion", sizeClass(resolvedSize, "Accordion"), radiusClass(radius ?? own.radius, resolvedSize), colorClass(color ?? own.color), className),
59
+ onKeyDown: handleKeyDown,
60
+ ...rest
61
+ })
62
+ });
63
+ }
64
+ function AccordionItem({ value, disabled, className, ...props }) {
65
+ const context = useAccordionContext("Accordion.Item");
66
+ const open = context.open.includes(value);
67
+ const itemDisabled = disabled || context.disabled;
68
+ return /* @__PURE__ */ jsx(AccordionItemContext.Provider, {
69
+ value: {
70
+ value,
71
+ open,
72
+ disabled: itemDisabled
73
+ },
74
+ children: /* @__PURE__ */ jsx("div", {
75
+ "data-state": open ? "open" : "closed",
76
+ "data-disabled": itemDisabled || void 0,
77
+ className: cx("yarcl-accordion-item", className),
78
+ ...props
79
+ })
80
+ });
81
+ }
82
+ function AccordionTrigger({ level = 3, className, onClick, children, ...props }) {
83
+ const context = useAccordionContext("Accordion.Trigger");
84
+ const item = useItemContext("Accordion.Trigger");
85
+ const Heading = `h${level}`;
86
+ return /* @__PURE__ */ jsx(Heading, {
87
+ className: "yarcl-accordion-heading",
88
+ children: /* @__PURE__ */ jsxs("button", {
89
+ type: "button",
90
+ id: context.idFor("trigger", item.value),
91
+ "aria-controls": context.idFor("content", item.value),
92
+ "aria-expanded": item.open,
93
+ disabled: item.disabled,
94
+ className: cx("yarcl-accordion-trigger", className),
95
+ onClick: (event) => {
96
+ onClick?.(event);
97
+ if (!event.defaultPrevented) context.toggle(item.value);
98
+ },
99
+ ...props,
100
+ children: [/* @__PURE__ */ jsx("span", {
101
+ className: "yarcl-accordion-label",
102
+ children
103
+ }), /* @__PURE__ */ jsx(ChevronIcon, {})]
104
+ })
105
+ });
106
+ }
107
+ function AccordionContent({ className, children, ...props }) {
108
+ const context = useAccordionContext("Accordion.Content");
109
+ const item = useItemContext("Accordion.Content");
110
+ return /* @__PURE__ */ jsx("div", {
111
+ role: "region",
112
+ id: context.idFor("content", item.value),
113
+ "aria-labelledby": context.idFor("trigger", item.value),
114
+ "data-state": item.open ? "open" : "closed",
115
+ className: cx("yarcl-accordion-content", className),
116
+ ...props,
117
+ children: /* @__PURE__ */ jsx("div", {
118
+ className: "yarcl-accordion-body",
119
+ children
120
+ })
121
+ });
122
+ }
123
+ /**
124
+ * Stacked sections that expand and collapse. Each trigger is a button inside a heading;
125
+ * Up and Down move between triggers, Home and End jump to the ends. The panel height animates
126
+ * with the `motion` tokens, and snaps when reduced motion is preferred.
127
+ *
128
+ * @example
129
+ * ```tsx
130
+ * <Accordion type="single" defaultValue="shipping">
131
+ * <Accordion.Item value="shipping">
132
+ * <Accordion.Trigger>Shipping</Accordion.Trigger>
133
+ * <Accordion.Content>Orders ship within two working days.</Accordion.Content>
134
+ * </Accordion.Item>
135
+ * <Accordion.Item value="returns">
136
+ * <Accordion.Trigger>Returns</Accordion.Trigger>
137
+ * <Accordion.Content>Free returns within 30 days.</Accordion.Content>
138
+ * </Accordion.Item>
139
+ * </Accordion>
140
+ * ```
141
+ */
142
+ var Accordion = Object.assign(AccordionRoot, {
143
+ Item: AccordionItem,
144
+ Trigger: AccordionTrigger,
145
+ Content: AccordionContent
146
+ });
147
+ //#endregion
148
+ export { Accordion };
@@ -0,0 +1,60 @@
1
+ import type { ComponentProps, ReactNode } from 'react';
2
+ import type { Color, Radius, Spacing, TextStyle, Variant } from '../types';
3
+ /** Props for {@link Alert}. */
4
+ export interface AlertProps extends Omit<ComponentProps<'div'>, 'color' | 'title'> {
5
+ /** Bold first line. */
6
+ title?: ReactNode;
7
+ /** Icon shown before the text. */
8
+ icon?: ReactNode;
9
+ /** Actions shown after the text, e.g. a {@link Button} or {@link Link}. */
10
+ action?: ReactNode;
11
+ /**
12
+ * Semantic color, from the `colors` config.
13
+ * @default config.defaults.color
14
+ */
15
+ color?: Color;
16
+ /**
17
+ * Style recipe, from the `variants` config.
18
+ * @default config.defaults.softVariant
19
+ */
20
+ variant?: Variant;
21
+ /**
22
+ * Corner radius, from the `radii` config.
23
+ * @default config.defaults.radius
24
+ */
25
+ radius?: Radius;
26
+ /**
27
+ * Space between the icon, text, action and dismiss button, from the `spacing` config.
28
+ * @default config.components.Alert.gap ?? config.defaults.gap
29
+ */
30
+ gap?: Spacing;
31
+ /**
32
+ * Inner spacing, from the `spacing` config.
33
+ * @default config.components.Alert.padding ?? config.defaults.padding
34
+ */
35
+ padding?: Spacing;
36
+ /**
37
+ * Typography style, from the `typography.styles` config.
38
+ * @default config.components.Alert.textStyle ?? config.defaults.labelStyle
39
+ */
40
+ textStyle?: TextStyle;
41
+ /** Shows a dismiss button. Called when it is pressed; hide the alert in response. */
42
+ onDismiss?: () => void;
43
+ /**
44
+ * Announces the alert when it appears: `'polite'` (`role="status"`) or `'assertive'` (`role="alert"`).
45
+ * Leave unset for messages present on page load.
46
+ */
47
+ live?: 'polite' | 'assertive';
48
+ }
49
+ /**
50
+ * An inline message that stays on the page, e.g. a warning above a form.
51
+ * For transient messages use {@link toast}.
52
+ *
53
+ * @example
54
+ * ```tsx
55
+ * <Alert color="warning" title="Trial ends in 3 days" action={<Button size="sm">Upgrade</Button>}>
56
+ * Add a payment method to keep your projects.
57
+ * </Alert>
58
+ * ```
59
+ */
60
+ export declare function Alert({ title, icon, action, color, variant, radius, gap, padding, textStyle, onDismiss, live, className, children, ...props }: AlertProps): import("react").JSX.Element;