@jirawatpyk/aura-react 4.4.2 → 4.5.1

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jirawatpyk/aura-react",
3
- "version": "4.4.2",
3
+ "version": "4.5.1",
4
4
  "description": "AURA Design System — React components (Enterprise Standard, Human Creative). Thai-first: Buddhist-era dates, Thai collation.",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -20,7 +20,6 @@
20
20
  "files": [
21
21
  "dist",
22
22
  "scripts/aura-theme.mjs",
23
- "src/theme.js",
24
23
  "README.md",
25
24
  "LICENSE"
26
25
  ],
@@ -30,27 +29,31 @@
30
29
  "scripts": {
31
30
  "build": "node scripts/build.mjs && node scripts/sync-bundle.mjs",
32
31
  "test:ssr": "node scripts/ssr-test.mjs",
33
- "typecheck": "tsc -p tsconfig.json",
32
+ "typecheck": "tsc -p tsconfig.src.json && tsc -p tsconfig.json",
34
33
  "examples": "node examples/build.mjs",
35
34
  "themes": "node scripts/test-themes.mjs",
36
35
  "test:pilots": "npm run examples && npm run themes && python3 tests/pilot_test.py && python3 tests/pilots_test.py",
37
36
  "theme": "node scripts/aura-theme.mjs",
38
37
  "prepack": "npm run build",
39
- "pretest:ssr": "node scripts/build.mjs"
38
+ "pretest:ssr": "node scripts/build.mjs",
39
+ "prethemes": "node scripts/build.mjs",
40
+ "test:hydrate": "node scripts/hydrate-test.mjs"
40
41
  },
41
42
  "peerDependencies": {
42
43
  "react": ">=18",
43
44
  "react-dom": ">=18"
44
45
  },
45
46
  "devDependencies": {
47
+ "@types/react": "^18.3.0",
48
+ "@types/react-dom": "^18.3.0",
49
+ "axe-core": "^4.10.0",
50
+ "dts-bundle-generator": "^9.5.1",
46
51
  "esbuild": "^0.24.0",
47
52
  "react": "^18.3.1",
48
53
  "react-dom": "^18.3.1",
49
- "@types/react": "^18.3.0",
50
- "@types/react-dom": "^18.3.0",
51
- "typescript": "^5.6.0",
52
54
  "react-hook-form": "^7.53.0",
53
- "axe-core": "^4.10.0"
55
+ "typescript": "^5.6.0",
56
+ "@playwright/test": "^1.45.0"
54
57
  },
55
58
  "bin": {
56
59
  "aura-theme": "scripts/aura-theme.mjs"
@@ -3,7 +3,7 @@
3
3
  * npx aura-theme --brand "#0ea5e9" [--signal "#facc15"] [--primary brand] [--name acme] [--selector .tenant-acme] [--out src/aura-theme.css]
4
4
  * Prints every contrast check; exits 1 if any fails. */
5
5
  import fs from 'node:fs';
6
- import { createTheme } from '../src/theme.js';
6
+ import { createTheme } from '../dist/esm/theme.js';
7
7
 
8
8
  const args = {};
9
9
  for (let i = 2; i < process.argv.length; i++) {
package/src/theme.js DELETED
@@ -1,147 +0,0 @@
1
- /* aura-lint: allow-colours — this file generates colours; its zinc values mirror the aura-zinc-* primitives. */
2
- /* createTheme — a brand layer over AURA's tokens for one project.
3
- * Give it the project's brand colour (and optionally a signal colour); it builds a 50–900 scale in OKLCH
4
- * (same hue and chroma family, AURA's lightness steps), maps it onto the semantic tokens that carry the
5
- * brand (links, focus ring, selection, info, progress, creative shadow, mesh…), then nudges any colour that
6
- * misses its WCAG target until it passes. Status (ready/blocked), success, warning and danger stay AURA's:
7
- * they are meanings, not brand. No React needed — works in Node (CLI) and the browser. */
8
-
9
- /* ---------- colour maths (sRGB ⇄ OKLab/OKLCH) ---------- */
10
- function hexToRgb(hex) {
11
- var h = String(hex).trim().replace('#', '');
12
- if (h.length === 3) h = h.split('').map(function (c) { return c + c; }).join('');
13
- if (!/^[0-9a-f]{6}$/i.test(h)) throw new Error('createTheme: "' + hex + '" is not a #rgb or #rrggbb colour');
14
- return [0, 2, 4].map(function (i) { return parseInt(h.slice(i, i + 2), 16) / 255; });
15
- }
16
- function rgbToHex(rgb) {
17
- return '#' + rgb.map(function (v) { var n = Math.round(Math.min(1, Math.max(0, v)) * 255); return (n < 16 ? '0' : '') + n.toString(16); }).join('');
18
- }
19
- function lin(c) { return c <= 0.04045 ? c / 12.92 : Math.pow((c + 0.055) / 1.055, 2.4); }
20
- function delin(c) { return c <= 0.0031308 ? 12.92 * c : 1.055 * Math.pow(c, 1 / 2.4) - 0.055; }
21
- function rgbToOklch(rgb) {
22
- var r = lin(rgb[0]), g = lin(rgb[1]), b = lin(rgb[2]);
23
- var l = Math.cbrt(0.4122214708 * r + 0.5363325363 * g + 0.0514459929 * b);
24
- var m = Math.cbrt(0.2119034982 * r + 0.6806995451 * g + 0.1073969566 * b);
25
- var s = Math.cbrt(0.0883024619 * r + 0.2817188376 * g + 0.6299787005 * b);
26
- var L = 0.2104542553 * l + 0.7936177850 * m - 0.0040720468 * s;
27
- var A = 1.9779984951 * l - 2.4285922050 * m + 0.4505937099 * s;
28
- var B = 0.0259040371 * l + 0.7827717662 * m - 0.8086757660 * s;
29
- return [L, Math.sqrt(A * A + B * B), (Math.atan2(B, A) * 180 / Math.PI + 360) % 360];
30
- }
31
- function oklchToRgbRaw(L, C, H) {
32
- var a = C * Math.cos(H * Math.PI / 180), b = C * Math.sin(H * Math.PI / 180);
33
- var l = Math.pow(L + 0.3963377774 * a + 0.2158037573 * b, 3);
34
- var m = Math.pow(L - 0.1055613458 * a - 0.0638541728 * b, 3);
35
- var s = Math.pow(L - 0.0894841775 * a - 1.2914855480 * b, 3);
36
- return [4.0767416621 * l - 3.3077115913 * m + 0.2309699292 * s,
37
- -1.2684380046 * l + 2.6097574011 * m - 0.3413193965 * s,
38
- -0.0041960863 * l - 0.7034186147 * m + 1.7076147010 * s].map(delin);
39
- }
40
- function inGamut(rgb) { return rgb.every(function (v) { return v >= -0.0005 && v <= 1.0005; }); }
41
- /* Keep hue and lightness, reduce chroma until the colour fits sRGB. */
42
- function oklchToHex(L, C, H) {
43
- var lo = 0, hi = C, rgb = oklchToRgbRaw(L, C, H);
44
- if (inGamut(rgb)) return rgbToHex(rgb);
45
- for (var i = 0; i < 24; i++) { var mid = (lo + hi) / 2; if (inGamut(oklchToRgbRaw(L, mid, H))) lo = mid; else hi = mid; }
46
- return rgbToHex(oklchToRgbRaw(L, lo, H));
47
- }
48
- function luminance(hex) { var c = hexToRgb(hex).map(lin); return 0.2126 * c[0] + 0.7152 * c[1] + 0.0722 * c[2]; }
49
- /** WCAG contrast ratio of two #hex colours. */
50
- export function contrast(a, b) { var x = luminance(a), y = luminance(b); return (Math.max(x, y) + 0.05) / (Math.min(x, y) + 0.05); }
51
- function mix(a, b, t) { var x = hexToRgb(a), y = hexToRgb(b); return rgbToHex(x.map(function (v, i) { return v + (y[i] - v) * t; })); }
52
-
53
- /* AURA's lightness steps (from the violet and lime scales), and relative chroma. */
54
- var STEPS = { 50: [0.975, 0.18], 100: [0.945, 0.3], 200: [0.895, 0.5], 300: [0.81, 0.72], 400: [0.715, 0.9], 500: [0.635, 1], 600: [0.555, 1], 700: [0.49, 0.95], 800: [0.43, 0.85], 900: [0.38, 0.72] };
55
- /** A 50–900 scale around one colour: same hue, AURA's lightness steps, chroma kept in gamut. */
56
- export function scale(hex) {
57
- var o = rgbToOklch(hexToRgb(hex)), C = Math.max(o[1], 0.02), out = {};
58
- Object.keys(STEPS).forEach(function (k) { out[k] = oklchToHex(STEPS[k][0], C * STEPS[k][1] / 0.95 * (o[1] < 0.03 ? 0.4 : 1), o[2]); });
59
- return out;
60
- }
61
- /* Darken (dir -1) or lighten (+1) in OKLCH until the ratio against every ground reaches the target. */
62
- function fit(hex, grounds, target, dir) {
63
- var o = rgbToOklch(hexToRgb(hex)), L = o[0], c = hex;
64
- for (var i = 0; i < 80; i++) {
65
- if (grounds.every(function (g) { return contrast(c, g) >= target; })) return c;
66
- L = Math.min(1, Math.max(0, L + dir * 0.01)); c = oklchToHex(L, o[1], o[2]);
67
- }
68
- return c;
69
- }
70
-
71
- var ZINC = { 0: '#ffffff', 50: '#fafafa', 100: '#f4f4f5', 800: '#27272a', 900: '#18181b', 950: '#09090b' };
72
- var INK = '#18181b';
73
-
74
- /**
75
- * createTheme({ brand, signal?, primary?: 'ink' | 'brand', name? })
76
- * → { name, brand: {50…900}, signal: {50…900}|null, light: {token: #hex}, dark: {…}, checks: [{pair, ratio, target, pass}], ok, css(selector?) }
77
- */
78
- export function createTheme(opts) {
79
- var o = opts || {};
80
- if (!o.brand) throw new Error('createTheme: pass { brand: "#rrggbb" }');
81
- var b = scale(o.brand), s = o.signal ? scale(o.signal) : null;
82
- var lightGrounds = [ZINC[0], ZINC[50]], darkGrounds = [ZINC[900], ZINC[950]];
83
- var L = {}, D = {};
84
-
85
- L['fg-accent'] = fit(b[700], lightGrounds, 4.5, -1);
86
- L['accent-violet'] = L['fg-accent'];
87
- L['focus-ring'] = fit(b[700], lightGrounds.concat([b[50]]), 3, -1);
88
- L['bg-selected'] = b[50];
89
- L['status-progress-bg'] = b[100];
90
- L['status-progress-fg'] = fit(b[800], [b[100]], 4.5, -1);
91
- L['alert-info-bg'] = b[50];
92
- L['alert-info-fg'] = fit(b[800], [b[50]], 4.5, -1);
93
- L['alert-info-border'] = b[200];
94
- L['mesh-from'] = b[400];
95
-
96
- D['fg-accent'] = fit(b[300], darkGrounds, 4.5, 1);
97
- D['accent-violet'] = fit(b[400], darkGrounds, 3, 1);
98
- D['focus-ring'] = fit(b[400], darkGrounds, 3, 1);
99
- D['bg-selected'] = mix(ZINC[900], b[500], 0.16);
100
- D['alert-info-bg'] = D['bg-selected'];
101
- D['alert-info-fg'] = fit(b[300], [D['alert-info-bg']], 4.5, 1);
102
- D['alert-info-border'] = mix(ZINC[900], b[400], 0.4);
103
- D['status-progress-bg'] = b[100];
104
- D['status-progress-fg'] = L['status-progress-fg'];
105
-
106
- if (s) {
107
- L['accent-dot'] = s[200]; L['accent-lime'] = s[200]; L['mesh-to'] = s[200];
108
- D['accent-dot'] = s[200]; D['accent-lime'] = s[200]; D['mesh-to'] = s[200];
109
- }
110
- var shadowLight = INK, shadowDark = D['accent-violet'];
111
- if (o.primary === 'brand') {
112
- L['button-primary-bg'] = fit(b[600], [ZINC[0]], 4.5, -1);
113
- L['button-primary-fg'] = ZINC[0];
114
- L['button-primary-bg-hover'] = fit(b[700], [ZINC[0]], 4.5, -1);
115
- D['button-primary-bg'] = fit(b[400], [ZINC[900]], 4.5, 1);
116
- D['button-primary-fg'] = ZINC[900];
117
- D['button-primary-bg-hover'] = fit(b[300], [ZINC[900]], 4.5, 1);
118
- }
119
- L['shadow-creative'] = '4px 4px 0px ' + shadowLight; L['shadow-creative-hover'] = '6px 6px 0px ' + shadowLight; L['card-shadow-creative'] = '8px 8px 0px ' + shadowLight;
120
- D['shadow-creative'] = '4px 4px 0px ' + shadowDark; D['shadow-creative-hover'] = '6px 6px 0px ' + shadowDark; D['card-shadow-creative'] = '8px 8px 0px ' + shadowDark;
121
-
122
- var checks = [];
123
- function check(theme, fg, bg, target, fgHex, bgHex) { var r = contrast(fgHex, bgHex); checks.push({ theme: theme, pair: fg + ' on ' + bg, ratio: Math.round(r * 100) / 100, target: target, pass: r >= target - 0.005 }); }
124
- [['bg-surface', ZINC[0]], ['bg-canvas', ZINC[50]], ['bg-selected', L['bg-selected']]].forEach(function (g) { check('light', 'fg-accent', g[0], 4.5, L['fg-accent'], g[1]); check('light', 'focus-ring', g[0], 3, L['focus-ring'], g[1]); });
125
- [['bg-surface', ZINC[900]], ['bg-canvas', ZINC[950]], ['bg-selected', D['bg-selected']]].forEach(function (g) { check('dark', 'fg-accent', g[0], 4.5, D['fg-accent'], g[1]); check('dark', 'focus-ring', g[0], 3, D['focus-ring'], g[1]); });
126
- check('light', 'fg-primary', 'bg-selected', 4.5, INK, L['bg-selected']);
127
- check('dark', 'fg-primary', 'bg-selected', 4.5, '#ffffff', D['bg-selected']);
128
- check('light', 'status-progress-fg', 'status-progress-bg', 4.5, L['status-progress-fg'], L['status-progress-bg']);
129
- check('light', 'alert-info-fg', 'alert-info-bg', 4.5, L['alert-info-fg'], L['alert-info-bg']);
130
- check('dark', 'alert-info-fg', 'alert-info-bg', 4.5, D['alert-info-fg'], D['alert-info-bg']);
131
- if (o.primary === 'brand') {
132
- check('light', 'button-primary-fg', 'button-primary-bg', 4.5, L['button-primary-fg'], L['button-primary-bg']);
133
- check('light', 'button-primary-fg', 'button-primary-bg-hover', 4.5, L['button-primary-fg'], L['button-primary-bg-hover']);
134
- check('dark', 'button-primary-fg', 'button-primary-bg', 4.5, D['button-primary-fg'], D['button-primary-bg']);
135
- check('dark', 'button-primary-fg', 'button-primary-bg-hover', 4.5, D['button-primary-fg'], D['button-primary-bg-hover']);
136
- }
137
- if (s) check('light', 'ink', 'accent-lime (signal)', 4.5, INK, s[200]);
138
-
139
- function css(selector) {
140
- var light = selector ? selector : ':root, [data-theme="light"]';
141
- var dark = selector ? selector + '.dark, .dark ' + selector + ', ' + selector + '[data-theme="dark"], [data-theme="dark"] ' + selector : '.dark, [data-theme="dark"]';
142
- function block(sel, m) { return sel + ' {\n' + Object.keys(m).map(function (k) { return ' --aura-' + k + ': ' + m[k] + ';'; }).join('\n') + '\n}'; }
143
- return '/* AURA theme' + (o.name ? ' "' + o.name + '"' : '') + ': brand ' + o.brand + (o.signal ? ', signal ' + o.signal : '') + (o.primary === 'brand' ? ', brand primary buttons' : '') + '. Load after aura.css. Generated by createTheme. */\n' +
144
- block(light, L) + '\n' + block(dark, D) + '\n';
145
- }
146
- return { name: o.name || null, brand: b, signal: s, light: L, dark: D, checks: checks, ok: checks.every(function (c) { return c.pass; }), css: css };
147
- }