orbital-ds 0.6.0 → 0.6.2
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/components.manifest.json +1 -1
- package/dist/styles.css +2 -0
- package/dist/themes/friendly.css +310 -310
- package/dist/themes/friendly.scoped.css +310 -310
- package/dist/themes/tactile.css +415 -399
- package/dist/themes/tactile.scoped.css +415 -399
- package/dist/themes/twitter.css +290 -290
- package/dist/themes/twitter.scoped.css +290 -290
- package/dist/themes/zyro.css +381 -381
- package/dist/themes/zyro.scoped.css +381 -381
- package/dist/ui/sidebar.js +2 -2
- package/docs/CONTRACT.md +2 -1
- package/package.json +142 -142
- package/scripts/doctor.mjs +64 -0
package/dist/ui/sidebar.js
CHANGED
|
@@ -26,7 +26,7 @@ const SIDEBAR_COOKIE_NAME = "sidebar_state";
|
|
|
26
26
|
const SIDEBAR_COOKIE_MAX_AGE = 60 * 60 * 24 * 7;
|
|
27
27
|
const SIDEBAR_WIDTH = "17.5rem";
|
|
28
28
|
const SIDEBAR_WIDTH_MOBILE = "18rem";
|
|
29
|
-
const SIDEBAR_WIDTH_ICON = "4rem";
|
|
29
|
+
const SIDEBAR_WIDTH_ICON = "var(--ds-sidebar-rail-w, 4rem)";
|
|
30
30
|
const SIDEBAR_KEYBOARD_SHORTCUT = "b";
|
|
31
31
|
const SidebarContext = React.createContext(null);
|
|
32
32
|
function useSidebar() {
|
|
@@ -180,7 +180,7 @@ function Sidebar({
|
|
|
180
180
|
"data-slot": "sidebar-container",
|
|
181
181
|
"data-side": side,
|
|
182
182
|
className: cn(
|
|
183
|
-
"fixed inset-y-0 z-(--ds-z-
|
|
183
|
+
"fixed inset-y-0 z-(--ds-z-sidebar) hidden h-svh w-(--sidebar-width) transition-[left,right,width] duration-(--ds-motion-base) ease-linear data-[side=left]:left-0 data-[side=left]:group-data-[collapsible=offcanvas]:left-[calc(var(--sidebar-width)*-1)] data-[side=right]:right-0 data-[side=right]:group-data-[collapsible=offcanvas]:right-[calc(var(--sidebar-width)*-1)] md:flex",
|
|
184
184
|
// Adjust the padding for floating and inset variants.
|
|
185
185
|
variant === "floating" || variant === "inset" ? "p-(--ds-sidebar-pad) group-data-[collapsible=icon]:w-[calc(var(--sidebar-width-icon)+(var(--ds-sidebar-pad)*2)+2px)]" : "group-data-[collapsible=icon]:w-(--sidebar-width-icon) group-data-[side=left]:border-r group-data-[side=right]:border-l",
|
|
186
186
|
className
|
package/docs/CONTRACT.md
CHANGED
|
@@ -74,9 +74,10 @@ Los define la estructura con un valor neutro; un tema los sobrescribe si quiere.
|
|
|
74
74
|
| Sombras | `--shadow-card`, `--shadow-card-hover`, `--shadow-control`, `--shadow-raised`, `--shadow-overlay`, `--shadow-popover` |
|
|
75
75
|
| Altura de controles | `--ds-control-h-sm`, `-md`, `-lg` |
|
|
76
76
|
| Espaciado interno | `--ds-card-spacing`, `--ds-card-spacing-sm`, `--ds-field-px`, `--ds-cell-p`, `--ds-overlay-p`, `--ds-overlay-gap`, `--ds-popover-p`, `--ds-menu-p`, `--ds-menu-item-px`, `--ds-menu-item-py`, `--ds-button-px-sm/md/lg`, `--ds-badge-px` |
|
|
77
|
-
| Capas | `--ds-z-raised`, `--ds-z-sticky`, `--ds-z-overlay` |
|
|
77
|
+
| Capas | `--ds-z-raised`, `--ds-z-sticky`, `--ds-z-sidebar` (sobre la cabecera sticky), `--ds-z-overlay` |
|
|
78
78
|
| Movimiento | `--ds-motion-fast`, `--ds-motion-base`, `--ds-motion-slow`, `--ds-motion-blink` |
|
|
79
79
|
| Foco | `--ds-ring-width` |
|
|
80
|
+
| Sidebar | `--ds-sidebar-rail-w` (ancho del lateral contraído; por defecto `4rem`) |
|
|
80
81
|
| Velo | `--color-scrim` |
|
|
81
82
|
| **Materiales** | `--ds-card-backdrop`, `--ds-overlay-backdrop`, `--ds-field-backdrop`, `--ds-sidebar-backdrop` (un `backdrop-filter` completo; por defecto `none`) y `--ds-page-backdrop` (un `background-image` para el fondo de la página; por defecto `none`) |
|
|
82
83
|
|
package/package.json
CHANGED
|
@@ -1,142 +1,142 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "orbital-ds",
|
|
3
|
-
"version": "0.6.
|
|
4
|
-
"description": "Sistema de diseño genérico: estructura común + temas con personalidad (qratia, zyro) + ~60 componentes sobre Base UI y Tailwind v4, con contrato verificable y legible por agentes.",
|
|
5
|
-
"keywords": [
|
|
6
|
-
"design-system",
|
|
7
|
-
"design-tokens",
|
|
8
|
-
"theme",
|
|
9
|
-
"tailwindcss",
|
|
10
|
-
"base-ui",
|
|
11
|
-
"shadcn",
|
|
12
|
-
"react"
|
|
13
|
-
],
|
|
14
|
-
"license": "MIT",
|
|
15
|
-
"type": "module",
|
|
16
|
-
"sideEffects": [
|
|
17
|
-
"*.css"
|
|
18
|
-
],
|
|
19
|
-
"files": [
|
|
20
|
-
"dist",
|
|
21
|
-
"scripts/doctor.mjs",
|
|
22
|
-
"contract.json",
|
|
23
|
-
"components.manifest.json",
|
|
24
|
-
"docs",
|
|
25
|
-
"AGENTS.md",
|
|
26
|
-
"README.md",
|
|
27
|
-
"LICENSE",
|
|
28
|
-
"scripts/init.mjs",
|
|
29
|
-
"scripts/manifest.mjs"
|
|
30
|
-
],
|
|
31
|
-
"exports": {
|
|
32
|
-
"./styles.css": "./dist/styles.css",
|
|
33
|
-
"./themes/*.css": "./dist/themes/*.css",
|
|
34
|
-
"./themes/*.md": "./dist/themes/*.md",
|
|
35
|
-
"./themes/*.meta.json": "./dist/themes/*.meta.json",
|
|
36
|
-
"./ui/*": {
|
|
37
|
-
"types": "./dist/ui/*.d.ts",
|
|
38
|
-
"import": "./dist/ui/*.js"
|
|
39
|
-
},
|
|
40
|
-
"./lib/*": {
|
|
41
|
-
"types": "./dist/lib/*.d.ts",
|
|
42
|
-
"import": "./dist/lib/*.js"
|
|
43
|
-
},
|
|
44
|
-
"./hooks/*": {
|
|
45
|
-
"types": "./dist/hooks/*.d.ts",
|
|
46
|
-
"import": "./dist/hooks/*.js"
|
|
47
|
-
},
|
|
48
|
-
"./package.json": "./package.json",
|
|
49
|
-
"./contract.json": "./contract.json",
|
|
50
|
-
"./components.manifest.json": "./components.manifest.json"
|
|
51
|
-
},
|
|
52
|
-
"scripts": {
|
|
53
|
-
"build": "tsup && node scripts/build-css.mjs",
|
|
54
|
-
"dev": "tsup --watch --onSuccess \"node scripts/copy-css.mjs\"",
|
|
55
|
-
"typecheck": "tsc --noEmit",
|
|
56
|
-
"verify": "pnpm check:ds && pnpm typecheck && pnpm build",
|
|
57
|
-
"manifest": "node scripts/manifest.mjs",
|
|
58
|
-
"check:ds": "node scripts/doctor.mjs"
|
|
59
|
-
},
|
|
60
|
-
"peerDependencies": {
|
|
61
|
-
"@base-ui/react": ">=1.9",
|
|
62
|
-
"class-variance-authority": ">=0.7",
|
|
63
|
-
"clsx": ">=2",
|
|
64
|
-
"lucide-react": ">=0.400",
|
|
65
|
-
"react": ">=19",
|
|
66
|
-
"react-dom": ">=19",
|
|
67
|
-
"tailwind-merge": ">=3",
|
|
68
|
-
"tailwindcss": ">=4.1",
|
|
69
|
-
"tw-animate-css": ">=1.3",
|
|
70
|
-
"next-themes": ">=0.4",
|
|
71
|
-
"recharts": ">=3",
|
|
72
|
-
"sonner": ">=2",
|
|
73
|
-
"@shadcn/react": ">=0.3",
|
|
74
|
-
"cmdk": ">=1.1",
|
|
75
|
-
"date-fns": ">=4",
|
|
76
|
-
"embla-carousel-react": ">=8.6",
|
|
77
|
-
"input-otp": ">=1.5",
|
|
78
|
-
"react-day-picker": ">=10",
|
|
79
|
-
"react-resizable-panels": ">=4"
|
|
80
|
-
},
|
|
81
|
-
"peerDependenciesMeta": {
|
|
82
|
-
"next-themes": {
|
|
83
|
-
"optional": true
|
|
84
|
-
},
|
|
85
|
-
"recharts": {
|
|
86
|
-
"optional": true
|
|
87
|
-
},
|
|
88
|
-
"sonner": {
|
|
89
|
-
"optional": true
|
|
90
|
-
},
|
|
91
|
-
"@shadcn/react": {
|
|
92
|
-
"optional": true
|
|
93
|
-
},
|
|
94
|
-
"cmdk": {
|
|
95
|
-
"optional": true
|
|
96
|
-
},
|
|
97
|
-
"date-fns": {
|
|
98
|
-
"optional": true
|
|
99
|
-
},
|
|
100
|
-
"embla-carousel-react": {
|
|
101
|
-
"optional": true
|
|
102
|
-
},
|
|
103
|
-
"input-otp": {
|
|
104
|
-
"optional": true
|
|
105
|
-
},
|
|
106
|
-
"react-day-picker": {
|
|
107
|
-
"optional": true
|
|
108
|
-
},
|
|
109
|
-
"react-resizable-panels": {
|
|
110
|
-
"optional": true
|
|
111
|
-
}
|
|
112
|
-
},
|
|
113
|
-
"devDependencies": {
|
|
114
|
-
"@base-ui/react": "^1.9.0",
|
|
115
|
-
"@types/react": "^19.2.0",
|
|
116
|
-
"@types/react-dom": "^19.2.0",
|
|
117
|
-
"class-variance-authority": "^0.7.1",
|
|
118
|
-
"clsx": "^2.1.1",
|
|
119
|
-
"lucide-react": "^0.577.0",
|
|
120
|
-
"next-themes": "^0.4.6",
|
|
121
|
-
"react": "^19.2.0",
|
|
122
|
-
"react-dom": "^19.2.0",
|
|
123
|
-
"recharts": "3.8.0",
|
|
124
|
-
"sonner": "^2.0.8",
|
|
125
|
-
"tailwind-merge": "^3.0.2",
|
|
126
|
-
"tailwindcss": "^4.1.18",
|
|
127
|
-
"tsup": "^8.5.0",
|
|
128
|
-
"tw-animate-css": "^1.3.6",
|
|
129
|
-
"typescript": "^5.9.0",
|
|
130
|
-
"@shadcn/react": "^0.3.1",
|
|
131
|
-
"cmdk": "^1.1.1",
|
|
132
|
-
"date-fns": "^4.4.0",
|
|
133
|
-
"embla-carousel-react": "^8.6.0",
|
|
134
|
-
"input-otp": "^1.5.0",
|
|
135
|
-
"react-day-picker": "^10.0.2",
|
|
136
|
-
"react-resizable-panels": "^4.14.4"
|
|
137
|
-
},
|
|
138
|
-
"bin": {
|
|
139
|
-
"orbital-ds-doctor": "./scripts/doctor.mjs",
|
|
140
|
-
"orbital-ds-init": "./scripts/init.mjs"
|
|
141
|
-
}
|
|
142
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "orbital-ds",
|
|
3
|
+
"version": "0.6.2",
|
|
4
|
+
"description": "Sistema de diseño genérico: estructura común + temas con personalidad (qratia, zyro) + ~60 componentes sobre Base UI y Tailwind v4, con contrato verificable y legible por agentes.",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"design-system",
|
|
7
|
+
"design-tokens",
|
|
8
|
+
"theme",
|
|
9
|
+
"tailwindcss",
|
|
10
|
+
"base-ui",
|
|
11
|
+
"shadcn",
|
|
12
|
+
"react"
|
|
13
|
+
],
|
|
14
|
+
"license": "MIT",
|
|
15
|
+
"type": "module",
|
|
16
|
+
"sideEffects": [
|
|
17
|
+
"*.css"
|
|
18
|
+
],
|
|
19
|
+
"files": [
|
|
20
|
+
"dist",
|
|
21
|
+
"scripts/doctor.mjs",
|
|
22
|
+
"contract.json",
|
|
23
|
+
"components.manifest.json",
|
|
24
|
+
"docs",
|
|
25
|
+
"AGENTS.md",
|
|
26
|
+
"README.md",
|
|
27
|
+
"LICENSE",
|
|
28
|
+
"scripts/init.mjs",
|
|
29
|
+
"scripts/manifest.mjs"
|
|
30
|
+
],
|
|
31
|
+
"exports": {
|
|
32
|
+
"./styles.css": "./dist/styles.css",
|
|
33
|
+
"./themes/*.css": "./dist/themes/*.css",
|
|
34
|
+
"./themes/*.md": "./dist/themes/*.md",
|
|
35
|
+
"./themes/*.meta.json": "./dist/themes/*.meta.json",
|
|
36
|
+
"./ui/*": {
|
|
37
|
+
"types": "./dist/ui/*.d.ts",
|
|
38
|
+
"import": "./dist/ui/*.js"
|
|
39
|
+
},
|
|
40
|
+
"./lib/*": {
|
|
41
|
+
"types": "./dist/lib/*.d.ts",
|
|
42
|
+
"import": "./dist/lib/*.js"
|
|
43
|
+
},
|
|
44
|
+
"./hooks/*": {
|
|
45
|
+
"types": "./dist/hooks/*.d.ts",
|
|
46
|
+
"import": "./dist/hooks/*.js"
|
|
47
|
+
},
|
|
48
|
+
"./package.json": "./package.json",
|
|
49
|
+
"./contract.json": "./contract.json",
|
|
50
|
+
"./components.manifest.json": "./components.manifest.json"
|
|
51
|
+
},
|
|
52
|
+
"scripts": {
|
|
53
|
+
"build": "tsup && node scripts/build-css.mjs",
|
|
54
|
+
"dev": "tsup --watch --onSuccess \"node scripts/copy-css.mjs\"",
|
|
55
|
+
"typecheck": "tsc --noEmit",
|
|
56
|
+
"verify": "pnpm check:ds && pnpm typecheck && pnpm build",
|
|
57
|
+
"manifest": "node scripts/manifest.mjs",
|
|
58
|
+
"check:ds": "node scripts/doctor.mjs"
|
|
59
|
+
},
|
|
60
|
+
"peerDependencies": {
|
|
61
|
+
"@base-ui/react": ">=1.9",
|
|
62
|
+
"class-variance-authority": ">=0.7",
|
|
63
|
+
"clsx": ">=2",
|
|
64
|
+
"lucide-react": ">=0.400",
|
|
65
|
+
"react": ">=19",
|
|
66
|
+
"react-dom": ">=19",
|
|
67
|
+
"tailwind-merge": ">=3",
|
|
68
|
+
"tailwindcss": ">=4.1",
|
|
69
|
+
"tw-animate-css": ">=1.3",
|
|
70
|
+
"next-themes": ">=0.4",
|
|
71
|
+
"recharts": ">=3",
|
|
72
|
+
"sonner": ">=2",
|
|
73
|
+
"@shadcn/react": ">=0.3",
|
|
74
|
+
"cmdk": ">=1.1",
|
|
75
|
+
"date-fns": ">=4",
|
|
76
|
+
"embla-carousel-react": ">=8.6",
|
|
77
|
+
"input-otp": ">=1.5",
|
|
78
|
+
"react-day-picker": ">=10",
|
|
79
|
+
"react-resizable-panels": ">=4"
|
|
80
|
+
},
|
|
81
|
+
"peerDependenciesMeta": {
|
|
82
|
+
"next-themes": {
|
|
83
|
+
"optional": true
|
|
84
|
+
},
|
|
85
|
+
"recharts": {
|
|
86
|
+
"optional": true
|
|
87
|
+
},
|
|
88
|
+
"sonner": {
|
|
89
|
+
"optional": true
|
|
90
|
+
},
|
|
91
|
+
"@shadcn/react": {
|
|
92
|
+
"optional": true
|
|
93
|
+
},
|
|
94
|
+
"cmdk": {
|
|
95
|
+
"optional": true
|
|
96
|
+
},
|
|
97
|
+
"date-fns": {
|
|
98
|
+
"optional": true
|
|
99
|
+
},
|
|
100
|
+
"embla-carousel-react": {
|
|
101
|
+
"optional": true
|
|
102
|
+
},
|
|
103
|
+
"input-otp": {
|
|
104
|
+
"optional": true
|
|
105
|
+
},
|
|
106
|
+
"react-day-picker": {
|
|
107
|
+
"optional": true
|
|
108
|
+
},
|
|
109
|
+
"react-resizable-panels": {
|
|
110
|
+
"optional": true
|
|
111
|
+
}
|
|
112
|
+
},
|
|
113
|
+
"devDependencies": {
|
|
114
|
+
"@base-ui/react": "^1.9.0",
|
|
115
|
+
"@types/react": "^19.2.0",
|
|
116
|
+
"@types/react-dom": "^19.2.0",
|
|
117
|
+
"class-variance-authority": "^0.7.1",
|
|
118
|
+
"clsx": "^2.1.1",
|
|
119
|
+
"lucide-react": "^0.577.0",
|
|
120
|
+
"next-themes": "^0.4.6",
|
|
121
|
+
"react": "^19.2.0",
|
|
122
|
+
"react-dom": "^19.2.0",
|
|
123
|
+
"recharts": "3.8.0",
|
|
124
|
+
"sonner": "^2.0.8",
|
|
125
|
+
"tailwind-merge": "^3.0.2",
|
|
126
|
+
"tailwindcss": "^4.1.18",
|
|
127
|
+
"tsup": "^8.5.0",
|
|
128
|
+
"tw-animate-css": "^1.3.6",
|
|
129
|
+
"typescript": "^5.9.0",
|
|
130
|
+
"@shadcn/react": "^0.3.1",
|
|
131
|
+
"cmdk": "^1.1.1",
|
|
132
|
+
"date-fns": "^4.4.0",
|
|
133
|
+
"embla-carousel-react": "^8.6.0",
|
|
134
|
+
"input-otp": "^1.5.0",
|
|
135
|
+
"react-day-picker": "^10.0.2",
|
|
136
|
+
"react-resizable-panels": "^4.14.4"
|
|
137
|
+
},
|
|
138
|
+
"bin": {
|
|
139
|
+
"orbital-ds-doctor": "./scripts/doctor.mjs",
|
|
140
|
+
"orbital-ds-init": "./scripts/init.mjs"
|
|
141
|
+
}
|
|
142
|
+
}
|
package/scripts/doctor.mjs
CHANGED
|
@@ -147,6 +147,70 @@ for (const f of themeFiles) {
|
|
|
147
147
|
if (meta.name !== t) errors.push(`tema ${t}: ${t}.meta.json tiene name «${meta.name}»`);
|
|
148
148
|
}
|
|
149
149
|
|
|
150
|
+
// 1c) CONTRASTE de los textos de estado: info, danger, warning, success y neutral
|
|
151
|
+
// sobre su fondo suave (compuesto sobre el lienzo), mínimo WCAG AA 4.5:1, en claro y oscuro.
|
|
152
|
+
// No incluye `link` ni `primary-foreground`: dependen de colores de marca fijados por la
|
|
153
|
+
// identidad (p. ej. el azul de Twitter), y se documentan como limitación en la guía del tema.
|
|
154
|
+
{
|
|
155
|
+
const parseColor = (raw) => {
|
|
156
|
+
const v = raw.replace(/\s+/g, ' ').trim();
|
|
157
|
+
let m = v.match(/^#([0-9a-f]{3,8})$/i);
|
|
158
|
+
if (m) {
|
|
159
|
+
let h = m[1];
|
|
160
|
+
if (h.length === 3) h = [...h].map((c) => c + c).join('');
|
|
161
|
+
return { r: parseInt(h.slice(0, 2), 16), g: parseInt(h.slice(2, 4), 16), b: parseInt(h.slice(4, 6), 16), a: h.length === 8 ? parseInt(h.slice(6, 8), 16) / 255 : 1 };
|
|
162
|
+
}
|
|
163
|
+
m = v.match(/^rgba?\(([^)]+)\)$/i);
|
|
164
|
+
if (m) { const p = m[1].split(/[ ,/]+/).filter(Boolean).map(Number); return { r: p[0], g: p[1], b: p[2], a: p[3] ?? 1 }; }
|
|
165
|
+
m = v.match(/^oklch\(\s*([\d.]+%?)\s+([\d.]+)\s+([\d.]+)(?:\s*\/\s*([\d.]+%?))?\s*\)$/i);
|
|
166
|
+
if (m) {
|
|
167
|
+
const L = m[1].endsWith('%') ? parseFloat(m[1]) / 100 : +m[1];
|
|
168
|
+
const C = +m[2], H = (+m[3] * Math.PI) / 180;
|
|
169
|
+
const a = C * Math.cos(H), b = C * Math.sin(H);
|
|
170
|
+
const l = (L + 0.3963377774 * a + 0.2158037573 * b) ** 3;
|
|
171
|
+
const mm = (L - 0.1055613458 * a - 0.0638541728 * b) ** 3;
|
|
172
|
+
const s = (L - 0.0894841775 * a - 1.291485548 * b) ** 3;
|
|
173
|
+
const lin = [4.0767416621 * l - 3.3077115913 * mm + 0.2309699292 * s, -1.2684380046 * l + 2.6097574011 * mm - 0.3413193965 * s, -0.0041960863 * l - 0.7034186147 * mm + 1.707614701 * s];
|
|
174
|
+
const g = (x) => Math.round(255 * Math.min(1, Math.max(0, x <= 0.0031308 ? 12.92 * x : 1.055 * x ** (1 / 2.4) - 0.055)));
|
|
175
|
+
const al = m[4] ? (m[4].endsWith('%') ? parseFloat(m[4]) / 100 : +m[4]) : 1;
|
|
176
|
+
return { r: g(lin[0]), g: g(lin[1]), b: g(lin[2]), a: al };
|
|
177
|
+
}
|
|
178
|
+
return null;
|
|
179
|
+
};
|
|
180
|
+
const lum = ({ r, g, b }) => {
|
|
181
|
+
const f = (c) => { c /= 255; return c <= 0.03928 ? c / 12.92 : ((c + 0.055) / 1.055) ** 2.4; };
|
|
182
|
+
return 0.2126 * f(r) + 0.7152 * f(g) + 0.0722 * f(b);
|
|
183
|
+
};
|
|
184
|
+
const over = (fg, bg) => ({ r: fg.r * fg.a + bg.r * (1 - fg.a), g: fg.g * fg.a + bg.g * (1 - fg.a), b: fg.b * fg.a + bg.b * (1 - fg.a), a: 1 });
|
|
185
|
+
const ratio = (x, y) => { const [p, q] = [lum(x), lum(y)].sort((u, w) => w - u); return (p + 0.05) / (q + 0.05); };
|
|
186
|
+
const varsDe = (css, selector) => {
|
|
187
|
+
const m = new RegExp(`(^|\\n)${selector}\\s*\\{`).exec(css);
|
|
188
|
+
if (!m) return {};
|
|
189
|
+
let i = m.index + m[0].length, d = 1, j = i;
|
|
190
|
+
while (d && j < css.length) { if (css[j] === '{') d++; else if (css[j] === '}') d--; j++; }
|
|
191
|
+
const out = {};
|
|
192
|
+
for (const mm of css.slice(i, j - 1).matchAll(/--([\w-]+):\s*([^;]+);/g)) out[mm[1]] = mm[2];
|
|
193
|
+
return out;
|
|
194
|
+
};
|
|
195
|
+
for (const f of themeFiles) {
|
|
196
|
+
const tema = f.replace(/\.css$/, '');
|
|
197
|
+
const css = stripComments(read(join(themesDir, f)));
|
|
198
|
+
const claro = varsDe(css, ':root');
|
|
199
|
+
for (const [piel, vars] of [['claro', claro], ['oscuro', { ...claro, ...varsDe(css, '\\.dark') }]]) {
|
|
200
|
+
const lienzo = parseColor(vars.background ?? '#fff');
|
|
201
|
+
if (!lienzo) continue;
|
|
202
|
+
for (const estado of ['info', 'danger', 'warning', 'success', 'neutral']) {
|
|
203
|
+
const fg = vars[estado] && parseColor(vars[estado]);
|
|
204
|
+
const suave = vars[`${estado}-soft`] && parseColor(vars[`${estado}-soft`]);
|
|
205
|
+
if (!fg || !suave) continue;
|
|
206
|
+
const fondo = over(suave, over(lienzo, { r: 255, g: 255, b: 255, a: 1 }));
|
|
207
|
+
const r = ratio(over(fg, fondo), fondo);
|
|
208
|
+
if (r < 4.5) errors.push(`tema ${tema} (${piel}): ${estado} sobre ${estado}-soft = ${r.toFixed(2)}:1 (mínimo 4.5:1)`);
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
|
|
150
214
|
// 4) fugas desde el tema base
|
|
151
215
|
const base = contract.baseTheme;
|
|
152
216
|
if (base && themeInfo[base]) {
|