@kupcad/ui 0.1.1 → 0.1.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/README.md +4 -0
- package/package.json +3 -3
- package/src/theme.js +19 -6
- package/src/tokens.css +28 -37
package/README.md
CHANGED
|
@@ -256,6 +256,10 @@ webview and the desktop app to the language server.
|
|
|
256
256
|
`--kc-focus` its focus ring, `--kc-accent-subtle` what is chosen in a list. `tokens.test.js`
|
|
257
257
|
holds every pair to WCAG's 4.5:1 for text and 3:1 for a control's edge, in both schemes, and
|
|
258
258
|
every colour token to a mapping in `vscode.css`.
|
|
259
|
+
Each colour is `light-dark()` of its two values, so the scheme decides: the system's
|
|
260
|
+
(`color-scheme: light dark`), until the page chooses one with `data-theme="light"` or
|
|
261
|
+
`"dark"` on its root (Starlight's convention, so a site's switch and the docs' agree) or a
|
|
262
|
+
`color-scheme` of its own. The viewer's own colours and the editor's follow the same scheme.
|
|
259
263
|
A host sets its own, as `vscode.css` maps VS Code's theme over them: the webview follows the
|
|
260
264
|
editor's theme, never the brand.
|
|
261
265
|
`--kc-viewer-*` theme the viewer (`themeFromTokens`, which reads each as the page draws it,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kupcad/ui",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.2",
|
|
4
4
|
"description": "KupCAD's UI: a three.js viewer of a model the core made, for any host (@kupcad/ui/viewer), and the Svelte panels around it (the viewer's pane, parameters, console, a language server's preview), styled by --kc-* tokens.",
|
|
5
5
|
"license": "AGPL-3.0-only",
|
|
6
6
|
"repository": {
|
|
@@ -36,11 +36,11 @@
|
|
|
36
36
|
"access": "public"
|
|
37
37
|
},
|
|
38
38
|
"dependencies": {
|
|
39
|
-
"@kupcad/protocol": "0.1.
|
|
39
|
+
"@kupcad/protocol": "0.1.2",
|
|
40
40
|
"three": "^0.186.1"
|
|
41
41
|
},
|
|
42
42
|
"devDependencies": {
|
|
43
|
-
"@kupcad/wasm": "0.1.
|
|
43
|
+
"@kupcad/wasm": "0.1.2",
|
|
44
44
|
"@playwright/test": "^1.64.1",
|
|
45
45
|
"@sveltejs/vite-plugin-svelte": "^7.3.1",
|
|
46
46
|
"@testing-library/svelte": "^5.4.2",
|
package/src/theme.js
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
// The viewer's theme from the --kc-viewer-* tokens of the page around it: a host themes the
|
|
2
2
|
// viewer as it themes the panels, and changes it while it shows (VS Code's theme switch). A
|
|
3
3
|
// token left unset, or set to no colour the page reads, takes the viewer's own colour, LIGHT or
|
|
4
|
-
// DARK as the page's colour scheme is.
|
|
4
|
+
// DARK as the page's colour scheme is: the one it chose (tokens.css's data-theme, a color-scheme
|
|
5
|
+
// of its own), else the system's.
|
|
5
6
|
|
|
6
7
|
import { DARK, LIGHT } from './viewer/index.js';
|
|
7
8
|
|
|
@@ -25,8 +26,9 @@ const HEX_WITH_ALPHA = /^(#[\da-f]{3})[\da-f]$|^(#[\da-f]{6})[\da-f]{2}$/i;
|
|
|
25
26
|
const RGBA = /^rgba\((\d+),\s*(\d+),\s*(\d+),\s*[\d.]+\)$/;
|
|
26
27
|
/** Two fills a colour the browser can't read leaves as they were: it reads as neither. */
|
|
27
28
|
const UNREAD = /** @type {const} */ (['#000000', '#ffffff']);
|
|
28
|
-
/** The attributes of the page's root and body a host themes it by (VS Code: a class, a style
|
|
29
|
-
|
|
29
|
+
/** The attributes of the page's root and body a host themes it by (VS Code: a class, a style; a
|
|
30
|
+
* site's switch: data-theme). */
|
|
31
|
+
const THEMED_BY = ['class', 'style', 'data-theme'];
|
|
30
32
|
|
|
31
33
|
/** colorReader's, once made (null where the page has no 2D context). @type {ColorReader | null | undefined} */
|
|
32
34
|
let reader;
|
|
@@ -43,8 +45,7 @@ let reader;
|
|
|
43
45
|
*/
|
|
44
46
|
export function themeFromTokens(element) {
|
|
45
47
|
const style = getComputedStyle(element);
|
|
46
|
-
const
|
|
47
|
-
const fallback = dark ? DARK : LIGHT;
|
|
48
|
+
const fallback = isDark(style) ? DARK : LIGHT;
|
|
48
49
|
/** @type {Theme} */
|
|
49
50
|
const theme = { ...fallback };
|
|
50
51
|
const context = colorReader();
|
|
@@ -54,6 +55,18 @@ export function themeFromTokens(element) {
|
|
|
54
55
|
return theme;
|
|
55
56
|
}
|
|
56
57
|
|
|
58
|
+
/**
|
|
59
|
+
* Whether an element is drawn dark: its colour scheme where the page chose one alone (`dark`,
|
|
60
|
+
* `only light`), else the system's (`light dark`, or none said).
|
|
61
|
+
* @param {CSSStyleDeclaration} style its computed style
|
|
62
|
+
*/
|
|
63
|
+
export function isDark(style) {
|
|
64
|
+
const scheme = (style.colorScheme ?? '').split(/\s+/);
|
|
65
|
+
const light = scheme.includes('light');
|
|
66
|
+
if (scheme.includes('dark') !== light) return !light;
|
|
67
|
+
return globalThis.matchMedia?.('(prefers-color-scheme: dark)').matches ?? false;
|
|
68
|
+
}
|
|
69
|
+
|
|
57
70
|
/**
|
|
58
71
|
* `color` as the viewer can draw it: #rrggbb, the sRGB of a pixel `context` draws in it, so any
|
|
59
72
|
* CSS colour the browser reads (three.js reads hex, rgb() and a name alone: a color-mix() or an
|
|
@@ -92,7 +105,7 @@ function colorReader() {
|
|
|
92
105
|
|
|
93
106
|
/**
|
|
94
107
|
* Gives `changed` the theme of `element`'s tokens now, and again whenever it changes: with the
|
|
95
|
-
*
|
|
108
|
+
* system's colour scheme, or a class, style or data-theme of the page's root or body.
|
|
96
109
|
* @param {Element} element
|
|
97
110
|
* @param {(theme: Theme) => void} changed
|
|
98
111
|
* @returns {() => void} stops watching
|
package/src/tokens.css
CHANGED
|
@@ -6,6 +6,11 @@
|
|
|
6
6
|
brand's too. A control of a host's own takes the panels' look by the class .kc-control
|
|
7
7
|
(controls.css); a range input by .kc-range, a checkbox by .kc-check.
|
|
8
8
|
|
|
9
|
+
Each colour is light-dark() of its light and its dark value, picked by the colour scheme, which
|
|
10
|
+
is the system's (`color-scheme: light dark`) until the page chooses: data-theme="light" or
|
|
11
|
+
"dark" on its root (the docs' convention, Starlight's), or a color-scheme of its own. The
|
|
12
|
+
viewer and the editor follow the same scheme.
|
|
13
|
+
|
|
9
14
|
The accent is a fill where there is one of a kind (the primary button, a slider, a checked
|
|
10
15
|
box); a toggle while on, or what is chosen in a list, is --kc-accent-subtle edged in it, as
|
|
11
16
|
several are on at once. The text on the fill is --kc-accent-fg, the brand black: white on the
|
|
@@ -16,55 +21,41 @@
|
|
|
16
21
|
@import './controls.css';
|
|
17
22
|
|
|
18
23
|
:root {
|
|
24
|
+
color-scheme: light dark;
|
|
19
25
|
--kc-font: system-ui, -apple-system, 'Segoe UI', sans-serif;
|
|
20
26
|
--kc-font-size: 13px;
|
|
21
|
-
--kc-bg: #ffffff;
|
|
22
|
-
--kc-fg: #1a1b1c;
|
|
23
|
-
--kc-muted: #5a5d65;
|
|
27
|
+
--kc-bg: light-dark(#ffffff, #1a1b1c);
|
|
28
|
+
--kc-fg: light-dark(#1a1b1c, #e3e7eb);
|
|
29
|
+
--kc-muted: light-dark(#5a5d65, #9a9da3);
|
|
24
30
|
/* A divider between panes and rows */
|
|
25
|
-
--kc-border: #d5dae0;
|
|
31
|
+
--kc-border: light-dark(#d5dae0, #333436);
|
|
26
32
|
/* The edge of a field, a select or a checkbox, which tells it from the background */
|
|
27
|
-
--kc-control-border: #8a9099;
|
|
28
|
-
--kc-input-bg: #ffffff;
|
|
33
|
+
--kc-control-border: light-dark(#8a9099, #73767c);
|
|
34
|
+
--kc-input-bg: light-dark(#ffffff, #282829);
|
|
29
35
|
/* A row or a button under the pointer */
|
|
30
|
-
--kc-hover: rgba(26, 27, 28, 0.06);
|
|
36
|
+
--kc-hover: light-dark(rgba(26, 27, 28, 0.06), rgba(227, 231, 235, 0.07));
|
|
31
37
|
--kc-accent: #ff5f14;
|
|
32
38
|
--kc-accent-fg: #1a1b1c;
|
|
33
|
-
--kc-accent-hover: #f0540c;
|
|
34
|
-
--kc-accent-text: #c5480d;
|
|
39
|
+
--kc-accent-hover: light-dark(#f0540c, #ff7a3d);
|
|
40
|
+
--kc-accent-text: light-dark(#c5480d, #ff6a24);
|
|
35
41
|
/* What is chosen in a list (the tree's open script), its text --kc-fg */
|
|
36
|
-
--kc-accent-subtle: #ffe9de;
|
|
37
|
-
--kc-focus: #c5480d;
|
|
42
|
+
--kc-accent-subtle: light-dark(#ffe9de, #43271b);
|
|
43
|
+
--kc-focus: light-dark(#c5480d, #ff6a24);
|
|
38
44
|
/* A slider's track beyond its thumb */
|
|
39
|
-
--kc-track: #d5dae0;
|
|
40
|
-
--kc-error: #c8102e;
|
|
41
|
-
--kc-warning: #8a5a00;
|
|
45
|
+
--kc-track: light-dark(#d5dae0, #3a3b3e);
|
|
46
|
+
--kc-error: light-dark(#c8102e, #ff6b81);
|
|
47
|
+
--kc-warning: light-dark(#8a5a00, #e3b341);
|
|
42
48
|
/* A section's header: a group of parameters' */
|
|
43
|
-
--kc-section-bg: #e3e7eb;
|
|
44
|
-
--kc-section-fg: #1a1b1c;
|
|
49
|
+
--kc-section-bg: light-dark(#e3e7eb, #282829);
|
|
50
|
+
--kc-section-fg: light-dark(#1a1b1c, #e3e7eb);
|
|
45
51
|
--kc-radius: 4px;
|
|
46
52
|
--kc-gap: 8px;
|
|
47
53
|
}
|
|
48
54
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
--kc-control-border: #73767c;
|
|
56
|
-
--kc-input-bg: #282829;
|
|
57
|
-
--kc-hover: rgba(227, 231, 235, 0.07);
|
|
58
|
-
--kc-accent: #ff5f14;
|
|
59
|
-
--kc-accent-fg: #1a1b1c;
|
|
60
|
-
--kc-accent-hover: #ff7a3d;
|
|
61
|
-
--kc-accent-text: #ff6a24;
|
|
62
|
-
--kc-accent-subtle: #43271b;
|
|
63
|
-
--kc-focus: #ff6a24;
|
|
64
|
-
--kc-track: #3a3b3e;
|
|
65
|
-
--kc-error: #ff6b81;
|
|
66
|
-
--kc-warning: #e3b341;
|
|
67
|
-
--kc-section-bg: #282829;
|
|
68
|
-
--kc-section-fg: #e3e7eb;
|
|
69
|
-
}
|
|
55
|
+
/* The scheme the page chose: the system's no longer decides */
|
|
56
|
+
:root[data-theme='light'] {
|
|
57
|
+
color-scheme: light;
|
|
58
|
+
}
|
|
59
|
+
:root[data-theme='dark'] {
|
|
60
|
+
color-scheme: dark;
|
|
70
61
|
}
|