@graview/core 0.1.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/LICENSE +96 -0
- package/README.md +35 -0
- package/dist/app.d.ts +294 -0
- package/dist/app.d.ts.map +1 -0
- package/dist/app.js +49 -0
- package/dist/app.js.map +1 -0
- package/dist/arrange.d.ts +185 -0
- package/dist/arrange.d.ts.map +1 -0
- package/dist/arrange.js +456 -0
- package/dist/arrange.js.map +1 -0
- package/dist/beginning.d.ts +65 -0
- package/dist/beginning.d.ts.map +1 -0
- package/dist/beginning.js +94 -0
- package/dist/beginning.js.map +1 -0
- package/dist/bind.d.ts +42 -0
- package/dist/bind.d.ts.map +1 -0
- package/dist/bind.js +26 -0
- package/dist/bind.js.map +1 -0
- package/dist/city.d.ts +93 -0
- package/dist/city.d.ts.map +1 -0
- package/dist/city.js +160 -0
- package/dist/city.js.map +1 -0
- package/dist/cli/check/arrangement.d.ts +13 -0
- package/dist/cli/check/arrangement.d.ts.map +1 -0
- package/dist/cli/check/arrangement.js +63 -0
- package/dist/cli/check/arrangement.js.map +1 -0
- package/dist/cli/check/beginnings.d.ts +16 -0
- package/dist/cli/check/beginnings.d.ts.map +1 -0
- package/dist/cli/check/beginnings.js +53 -0
- package/dist/cli/check/beginnings.js.map +1 -0
- package/dist/cli/check/brand.d.ts +17 -0
- package/dist/cli/check/brand.d.ts.map +1 -0
- package/dist/cli/check/brand.js +153 -0
- package/dist/cli/check/brand.js.map +1 -0
- package/dist/cli/check/city.d.ts +17 -0
- package/dist/cli/check/city.d.ts.map +1 -0
- package/dist/cli/check/city.js +58 -0
- package/dist/cli/check/city.js.map +1 -0
- package/dist/cli/check/context.d.ts +50 -0
- package/dist/cli/check/context.d.ts.map +1 -0
- package/dist/cli/check/context.js +37 -0
- package/dist/cli/check/context.js.map +1 -0
- package/dist/cli/check/fields.d.ts +16 -0
- package/dist/cli/check/fields.d.ts.map +1 -0
- package/dist/cli/check/fields.js +237 -0
- package/dist/cli/check/fields.js.map +1 -0
- package/dist/cli/check/index.d.ts +14 -0
- package/dist/cli/check/index.d.ts.map +1 -0
- package/dist/cli/check/index.js +14 -0
- package/dist/cli/check/index.js.map +1 -0
- package/dist/cli/check/intelligence.d.ts +17 -0
- package/dist/cli/check/intelligence.d.ts.map +1 -0
- package/dist/cli/check/intelligence.js +136 -0
- package/dist/cli/check/intelligence.js.map +1 -0
- package/dist/cli/check/lenses.d.ts +17 -0
- package/dist/cli/check/lenses.d.ts.map +1 -0
- package/dist/cli/check/lenses.js +239 -0
- package/dist/cli/check/lenses.js.map +1 -0
- package/dist/cli/check/migrations.d.ts +16 -0
- package/dist/cli/check/migrations.d.ts.map +1 -0
- package/dist/cli/check/migrations.js +43 -0
- package/dist/cli/check/migrations.js.map +1 -0
- package/dist/cli/check/modules.d.ts +16 -0
- package/dist/cli/check/modules.d.ts.map +1 -0
- package/dist/cli/check/modules.js +123 -0
- package/dist/cli/check/modules.js.map +1 -0
- package/dist/cli/check/policy.d.ts +16 -0
- package/dist/cli/check/policy.d.ts.map +1 -0
- package/dist/cli/check/policy.js +90 -0
- package/dist/cli/check/policy.js.map +1 -0
- package/dist/cli/check/relations.d.ts +29 -0
- package/dist/cli/check/relations.d.ts.map +1 -0
- package/dist/cli/check/relations.js +279 -0
- package/dist/cli/check/relations.js.map +1 -0
- package/dist/cli/check/routes.d.ts +16 -0
- package/dist/cli/check/routes.d.ts.map +1 -0
- package/dist/cli/check/routes.js +31 -0
- package/dist/cli/check/routes.js.map +1 -0
- package/dist/cli/check/settings.d.ts +16 -0
- package/dist/cli/check/settings.d.ts.map +1 -0
- package/dist/cli/check/settings.js +81 -0
- package/dist/cli/check/settings.js.map +1 -0
- package/dist/cli/check.d.ts +36 -0
- package/dist/cli/check.d.ts.map +1 -0
- package/dist/cli/check.js +76 -0
- package/dist/cli/check.js.map +1 -0
- package/dist/cli/create.d.ts +20 -0
- package/dist/cli/create.d.ts.map +1 -0
- package/dist/cli/create.js +251 -0
- package/dist/cli/create.js.map +1 -0
- package/dist/cli/describe.d.ts +35 -0
- package/dist/cli/describe.d.ts.map +1 -0
- package/dist/cli/describe.js +230 -0
- package/dist/cli/describe.js.map +1 -0
- package/dist/cli/docs.d.ts +11 -0
- package/dist/cli/docs.d.ts.map +1 -0
- package/dist/cli/docs.js +152 -0
- package/dist/cli/docs.js.map +1 -0
- package/dist/cli/index.d.ts +18 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +281 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/extend.d.ts +23 -0
- package/dist/extend.d.ts.map +1 -0
- package/dist/extend.js +53 -0
- package/dist/extend.js.map +1 -0
- package/dist/graph/diff.d.ts +31 -0
- package/dist/graph/diff.d.ts.map +1 -0
- package/dist/graph/diff.js +71 -0
- package/dist/graph/diff.js.map +1 -0
- package/dist/graph/graph.d.ts +69 -0
- package/dist/graph/graph.d.ts.map +1 -0
- package/dist/graph/graph.js +284 -0
- package/dist/graph/graph.js.map +1 -0
- package/dist/graph/primitives.d.ts +52 -0
- package/dist/graph/primitives.d.ts.map +1 -0
- package/dist/graph/primitives.js +62 -0
- package/dist/graph/primitives.js.map +1 -0
- package/dist/graph/tracked.d.ts +31 -0
- package/dist/graph/tracked.d.ts.map +1 -0
- package/dist/graph/tracked.js +69 -0
- package/dist/graph/tracked.js.map +1 -0
- package/dist/graph/types.d.ts +34 -0
- package/dist/graph/types.d.ts.map +1 -0
- package/dist/graph/types.js +0 -0
- package/dist/graph/types.js.map +1 -0
- package/dist/index.d.ts +100 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +90 -0
- package/dist/index.js.map +1 -0
- package/dist/installation.d.ts +112 -0
- package/dist/installation.d.ts.map +1 -0
- package/dist/installation.js +193 -0
- package/dist/installation.js.map +1 -0
- package/dist/intelligence-bridge.d.ts +73 -0
- package/dist/intelligence-bridge.d.ts.map +1 -0
- package/dist/intelligence-bridge.js +31 -0
- package/dist/intelligence-bridge.js.map +1 -0
- package/dist/invariants/engine.d.ts +36 -0
- package/dist/invariants/engine.d.ts.map +1 -0
- package/dist/invariants/engine.js +88 -0
- package/dist/invariants/engine.js.map +1 -0
- package/dist/invariants/types.d.ts +75 -0
- package/dist/invariants/types.d.ts.map +1 -0
- package/dist/invariants/types.js +2 -0
- package/dist/invariants/types.js.map +1 -0
- package/dist/modules.d.ts +75 -0
- package/dist/modules.d.ts.map +1 -0
- package/dist/modules.js +87 -0
- package/dist/modules.js.map +1 -0
- package/dist/mutations/decidable.d.ts +26 -0
- package/dist/mutations/decidable.d.ts.map +1 -0
- package/dist/mutations/decidable.js +39 -0
- package/dist/mutations/decidable.js.map +1 -0
- package/dist/mutations/define-mutation.d.ts +32 -0
- package/dist/mutations/define-mutation.d.ts.map +1 -0
- package/dist/mutations/define-mutation.js +181 -0
- package/dist/mutations/define-mutation.js.map +1 -0
- package/dist/mutations/derive-edits.d.ts +75 -0
- package/dist/mutations/derive-edits.d.ts.map +1 -0
- package/dist/mutations/derive-edits.js +240 -0
- package/dist/mutations/derive-edits.js.map +1 -0
- package/dist/mutations/form.d.ts +63 -0
- package/dist/mutations/form.d.ts.map +1 -0
- package/dist/mutations/form.js +113 -0
- package/dist/mutations/form.js.map +1 -0
- package/dist/mutations/node-ref.d.ts +83 -0
- package/dist/mutations/node-ref.d.ts.map +1 -0
- package/dist/mutations/node-ref.js +113 -0
- package/dist/mutations/node-ref.js.map +1 -0
- package/dist/mutations/types.d.ts +136 -0
- package/dist/mutations/types.d.ts.map +1 -0
- package/dist/mutations/types.js +2 -0
- package/dist/mutations/types.js.map +1 -0
- package/dist/ops/log.d.ts +35 -0
- package/dist/ops/log.d.ts.map +1 -0
- package/dist/ops/log.js +103 -0
- package/dist/ops/log.js.map +1 -0
- package/dist/ops/types.d.ts +52 -0
- package/dist/ops/types.d.ts.map +1 -0
- package/dist/ops/types.js +2 -0
- package/dist/ops/types.js.map +1 -0
- package/dist/ops/undo.d.ts +33 -0
- package/dist/ops/undo.d.ts.map +1 -0
- package/dist/ops/undo.js +65 -0
- package/dist/ops/undo.js.map +1 -0
- package/dist/permissions/policy.d.ts +68 -0
- package/dist/permissions/policy.d.ts.map +1 -0
- package/dist/permissions/policy.js +191 -0
- package/dist/permissions/policy.js.map +1 -0
- package/dist/permissions/types.d.ts +78 -0
- package/dist/permissions/types.d.ts.map +1 -0
- package/dist/permissions/types.js +17 -0
- package/dist/permissions/types.js.map +1 -0
- package/dist/persistence/memory.d.ts +6 -0
- package/dist/persistence/memory.d.ts.map +1 -0
- package/dist/persistence/memory.js +31 -0
- package/dist/persistence/memory.js.map +1 -0
- package/dist/persistence/sqlite.d.ts +59 -0
- package/dist/persistence/sqlite.d.ts.map +1 -0
- package/dist/persistence/sqlite.js +131 -0
- package/dist/persistence/sqlite.js.map +1 -0
- package/dist/persistence/types.d.ts +22 -0
- package/dist/persistence/types.d.ts.map +1 -0
- package/dist/persistence/types.js +2 -0
- package/dist/persistence/types.js.map +1 -0
- package/dist/presence.d.ts +38 -0
- package/dist/presence.d.ts.map +1 -0
- package/dist/presence.js +50 -0
- package/dist/presence.js.map +1 -0
- package/dist/scaffold/domain.d.ts +8 -0
- package/dist/scaffold/domain.d.ts.map +1 -0
- package/dist/scaffold/domain.js +331 -0
- package/dist/scaffold/domain.js.map +1 -0
- package/dist/scaffold/index.d.ts +66 -0
- package/dist/scaffold/index.d.ts.map +1 -0
- package/dist/scaffold/index.js +142 -0
- package/dist/scaffold/index.js.map +1 -0
- package/dist/scaffold/lens.d.ts +31 -0
- package/dist/scaffold/lens.d.ts.map +1 -0
- package/dist/scaffold/lens.js +176 -0
- package/dist/scaffold/lens.js.map +1 -0
- package/dist/scaffold/names.d.ts +44 -0
- package/dist/scaffold/names.d.ts.map +1 -0
- package/dist/scaffold/names.js +69 -0
- package/dist/scaffold/names.js.map +1 -0
- package/dist/scaffold/project.d.ts +41 -0
- package/dist/scaffold/project.d.ts.map +1 -0
- package/dist/scaffold/project.js +604 -0
- package/dist/scaffold/project.js.map +1 -0
- package/dist/scaffold/ui.d.ts +15 -0
- package/dist/scaffold/ui.d.ts.map +1 -0
- package/dist/scaffold/ui.js +536 -0
- package/dist/scaffold/ui.js.map +1 -0
- package/dist/schema/define-node.d.ts +132 -0
- package/dist/schema/define-node.d.ts.map +1 -0
- package/dist/schema/define-node.js +254 -0
- package/dist/schema/define-node.js.map +1 -0
- package/dist/schema/figures.d.ts +42 -0
- package/dist/schema/figures.d.ts.map +1 -0
- package/dist/schema/figures.js +220 -0
- package/dist/schema/figures.js.map +1 -0
- package/dist/schema/json-schema.d.ts +39 -0
- package/dist/schema/json-schema.d.ts.map +1 -0
- package/dist/schema/json-schema.js +74 -0
- package/dist/schema/json-schema.js.map +1 -0
- package/dist/schema/schema.d.ts +43 -0
- package/dist/schema/schema.d.ts.map +1 -0
- package/dist/schema/schema.js +102 -0
- package/dist/schema/schema.js.map +1 -0
- package/dist/schema/types.d.ts +201 -0
- package/dist/schema/types.d.ts.map +1 -0
- package/dist/schema/types.js +2 -0
- package/dist/schema/types.js.map +1 -0
- package/dist/search.d.ts +215 -0
- package/dist/search.d.ts.map +1 -0
- package/dist/search.js +449 -0
- package/dist/search.js.map +1 -0
- package/dist/settings.d.ts +30 -0
- package/dist/settings.d.ts.map +1 -0
- package/dist/settings.js +74 -0
- package/dist/settings.js.map +1 -0
- package/dist/store.d.ts +284 -0
- package/dist/store.d.ts.map +1 -0
- package/dist/store.js +660 -0
- package/dist/store.js.map +1 -0
- package/dist/studio-door.d.ts +187 -0
- package/dist/studio-door.d.ts.map +1 -0
- package/dist/studio-door.js +20 -0
- package/dist/studio-door.js.map +1 -0
- package/dist/sync/conflict.d.ts +37 -0
- package/dist/sync/conflict.d.ts.map +1 -0
- package/dist/sync/conflict.js +56 -0
- package/dist/sync/conflict.js.map +1 -0
- package/dist/sync/engine.d.ts +118 -0
- package/dist/sync/engine.d.ts.map +1 -0
- package/dist/sync/engine.js +341 -0
- package/dist/sync/engine.js.map +1 -0
- package/dist/sync/google-calendar.d.ts +54 -0
- package/dist/sync/google-calendar.d.ts.map +1 -0
- package/dist/sync/google-calendar.js +167 -0
- package/dist/sync/google-calendar.js.map +1 -0
- package/dist/sync/types.d.ts +125 -0
- package/dist/sync/types.d.ts.map +1 -0
- package/dist/sync/types.js +6 -0
- package/dist/sync/types.js.map +1 -0
- package/dist/temporal/effectivity.d.ts +75 -0
- package/dist/temporal/effectivity.d.ts.map +1 -0
- package/dist/temporal/effectivity.js +89 -0
- package/dist/temporal/effectivity.js.map +1 -0
- package/dist/testing.d.ts +63 -0
- package/dist/testing.d.ts.map +1 -0
- package/dist/testing.js +194 -0
- package/dist/testing.js.map +1 -0
- package/dist/theme/contrast.d.ts +47 -0
- package/dist/theme/contrast.d.ts.map +1 -0
- package/dist/theme/contrast.js +172 -0
- package/dist/theme/contrast.js.map +1 -0
- package/dist/theme/derive.d.ts +81 -0
- package/dist/theme/derive.d.ts.map +1 -0
- package/dist/theme/derive.js +171 -0
- package/dist/theme/derive.js.map +1 -0
- package/dist/theme/kit.d.ts +106 -0
- package/dist/theme/kit.d.ts.map +1 -0
- package/dist/theme/kit.js +84 -0
- package/dist/theme/kit.js.map +1 -0
- package/dist/theme/palettes.d.ts +32 -0
- package/dist/theme/palettes.d.ts.map +1 -0
- package/dist/theme/palettes.js +96 -0
- package/dist/theme/palettes.js.map +1 -0
- package/dist/theme/types.d.ts +131 -0
- package/dist/theme/types.d.ts.map +1 -0
- package/dist/theme/types.js +23 -0
- package/dist/theme/types.js.map +1 -0
- package/dist/views/types.d.ts +89 -0
- package/dist/views/types.d.ts.map +1 -0
- package/dist/views/types.js +88 -0
- package/dist/views/types.js.map +1 -0
- package/dist/watched.d.ts +33 -0
- package/dist/watched.d.ts.map +1 -0
- package/dist/watched.js +50 -0
- package/dist/watched.js.map +1 -0
- package/dist/who.d.ts +26 -0
- package/dist/who.d.ts.map +1 -0
- package/dist/who.js +20 -0
- package/dist/who.js.map +1 -0
- package/package.json +77 -0
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
import { TEXT_PAIRS } from "./types.js";
|
|
2
|
+
const HEX = /^#([0-9a-f]{3,8})$/i;
|
|
3
|
+
const FUNC = /(rgba?|hsla?)\(([^)]+)\)/gi;
|
|
4
|
+
function fromHex(hex) {
|
|
5
|
+
const match = HEX.exec(hex.trim());
|
|
6
|
+
if (!match)
|
|
7
|
+
return null;
|
|
8
|
+
let body = match[1];
|
|
9
|
+
if (body.length === 3 || body.length === 4) {
|
|
10
|
+
body = [...body].map((c) => c + c).join("");
|
|
11
|
+
}
|
|
12
|
+
if (body.length !== 6 && body.length !== 8)
|
|
13
|
+
return null;
|
|
14
|
+
const int = Number.parseInt(body.slice(0, 6), 16);
|
|
15
|
+
const alpha = body.length === 8 ? Number.parseInt(body.slice(6, 8), 16) / 255 : 1;
|
|
16
|
+
return { r: (int >> 16) & 255, g: (int >> 8) & 255, b: int & 255, a: alpha };
|
|
17
|
+
}
|
|
18
|
+
function fromFunction(text) {
|
|
19
|
+
const name = text.slice(0, text.indexOf("(")).toLowerCase();
|
|
20
|
+
const parts = text
|
|
21
|
+
.slice(text.indexOf("(") + 1, text.lastIndexOf(")"))
|
|
22
|
+
.split(/[,\s/]+/)
|
|
23
|
+
.filter(Boolean);
|
|
24
|
+
const numbers = parts.map((part) => part.endsWith("%") ? Number.parseFloat(part) / 100 : Number.parseFloat(part));
|
|
25
|
+
if (numbers.some(Number.isNaN))
|
|
26
|
+
return null;
|
|
27
|
+
if (name.startsWith("rgb")) {
|
|
28
|
+
const [r, g, b, a] = numbers;
|
|
29
|
+
if (r === undefined || g === undefined || b === undefined)
|
|
30
|
+
return null;
|
|
31
|
+
return { r, g, b, a: a ?? 1 };
|
|
32
|
+
}
|
|
33
|
+
const [h, s, l, a] = numbers;
|
|
34
|
+
if (h === undefined || s === undefined || l === undefined)
|
|
35
|
+
return null;
|
|
36
|
+
return { ...hslToRgb(h, s > 1 ? s / 100 : s, l > 1 ? l / 100 : l), a: a ?? 1 };
|
|
37
|
+
}
|
|
38
|
+
/** sRGB back to HSL, so a colour can be moved in lightness and stay itself. */
|
|
39
|
+
export function rgbToHsl(colour) {
|
|
40
|
+
const r = colour.r / 255;
|
|
41
|
+
const g = colour.g / 255;
|
|
42
|
+
const b = colour.b / 255;
|
|
43
|
+
const max = Math.max(r, g, b);
|
|
44
|
+
const min = Math.min(r, g, b);
|
|
45
|
+
const l = (max + min) / 2;
|
|
46
|
+
if (max === min)
|
|
47
|
+
return { h: 0, s: 0, l };
|
|
48
|
+
const d = max - min;
|
|
49
|
+
const s = d / (1 - Math.abs(2 * l - 1));
|
|
50
|
+
const h = max === r
|
|
51
|
+
? 60 * (((g - b) / d) % 6)
|
|
52
|
+
: max === g
|
|
53
|
+
? 60 * ((b - r) / d + 2)
|
|
54
|
+
: 60 * ((r - g) / d + 4);
|
|
55
|
+
return { h: (h + 360) % 360, s, l };
|
|
56
|
+
}
|
|
57
|
+
export function hsl(h, s, l) {
|
|
58
|
+
return { ...hslToRgb(h, s, l), a: 1 };
|
|
59
|
+
}
|
|
60
|
+
function hslToRgb(h, s, l) {
|
|
61
|
+
const c = (1 - Math.abs(2 * l - 1)) * s;
|
|
62
|
+
const hp = (((h % 360) + 360) % 360) / 60;
|
|
63
|
+
const x = c * (1 - Math.abs((hp % 2) - 1));
|
|
64
|
+
const [r, g, b] = hp < 1
|
|
65
|
+
? [c, x, 0]
|
|
66
|
+
: hp < 2
|
|
67
|
+
? [x, c, 0]
|
|
68
|
+
: hp < 3
|
|
69
|
+
? [0, c, x]
|
|
70
|
+
: hp < 4
|
|
71
|
+
? [0, x, c]
|
|
72
|
+
: hp < 5
|
|
73
|
+
? [x, 0, c]
|
|
74
|
+
: [c, 0, x];
|
|
75
|
+
const m = l - c / 2;
|
|
76
|
+
return {
|
|
77
|
+
r: Math.round((r + m) * 255),
|
|
78
|
+
g: Math.round((g + m) * 255),
|
|
79
|
+
b: Math.round((b + m) * 255),
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Every colour a token value mentions.
|
|
84
|
+
*
|
|
85
|
+
* A gradient is not one colour and pretending otherwise is how a check passes
|
|
86
|
+
* on a value it never looked at. `bar` and `float` are gradients in both
|
|
87
|
+
* built-in schemes; a pair drawn on one owes its contrast against the WORST
|
|
88
|
+
* stop, because that is where the text will be at some point along it.
|
|
89
|
+
*/
|
|
90
|
+
export function coloursIn(value) {
|
|
91
|
+
const found = [];
|
|
92
|
+
for (const token of value.matchAll(FUNC)) {
|
|
93
|
+
const parsed = fromFunction(token[0]);
|
|
94
|
+
if (parsed)
|
|
95
|
+
found.push(parsed);
|
|
96
|
+
}
|
|
97
|
+
for (const token of value.matchAll(/#[0-9a-fA-F]{3,8}\b/g)) {
|
|
98
|
+
const parsed = fromHex(token[0]);
|
|
99
|
+
if (parsed)
|
|
100
|
+
found.push(parsed);
|
|
101
|
+
}
|
|
102
|
+
return found;
|
|
103
|
+
}
|
|
104
|
+
/** One colour laid over another, straight alpha. */
|
|
105
|
+
export function composite(over, under) {
|
|
106
|
+
const a = over.a + under.a * (1 - over.a);
|
|
107
|
+
if (a === 0)
|
|
108
|
+
return { r: 0, g: 0, b: 0, a: 0 };
|
|
109
|
+
const mix = (x, y) => (x * over.a + y * under.a * (1 - over.a)) / a;
|
|
110
|
+
return { r: mix(over.r, under.r), g: mix(over.g, under.g), b: mix(over.b, under.b), a };
|
|
111
|
+
}
|
|
112
|
+
function channel(value) {
|
|
113
|
+
const c = value / 255;
|
|
114
|
+
return c <= 0.03928 ? c / 12.92 : ((c + 0.055) / 1.055) ** 2.4;
|
|
115
|
+
}
|
|
116
|
+
export function luminance(colour) {
|
|
117
|
+
return (0.2126 * channel(colour.r) + 0.7152 * channel(colour.g) + 0.0722 * channel(colour.b));
|
|
118
|
+
}
|
|
119
|
+
/** WCAG 2.1 contrast ratio, 1 to 21. */
|
|
120
|
+
export function contrast(a, b) {
|
|
121
|
+
const [x, y] = [luminance(a), luminance(b)].sort((m, n) => n - m);
|
|
122
|
+
return (x + 0.05) / (y + 0.05);
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* Every text pair in a palette, measured.
|
|
126
|
+
*
|
|
127
|
+
* Returns the failures AND the unreadable values. A token this cannot parse
|
|
128
|
+
* is reported rather than skipped: silently passing a value nobody looked at
|
|
129
|
+
* is exactly the failure mode a contrast check exists to prevent.
|
|
130
|
+
*/
|
|
131
|
+
export function checkContrast(tokens) {
|
|
132
|
+
const findings = [];
|
|
133
|
+
for (const pair of TEXT_PAIRS) {
|
|
134
|
+
const inkValue = String(tokens[pair.ink]);
|
|
135
|
+
const onValue = String(tokens[pair.on]);
|
|
136
|
+
const inks = coloursIn(inkValue);
|
|
137
|
+
const grounds = coloursIn(onValue);
|
|
138
|
+
if (inks.length === 0 || grounds.length === 0) {
|
|
139
|
+
findings.push({
|
|
140
|
+
ink: pair.ink,
|
|
141
|
+
on: pair.on,
|
|
142
|
+
where: pair.where,
|
|
143
|
+
ratio: 0,
|
|
144
|
+
requires: pair.requires,
|
|
145
|
+
unreadable: inks.length === 0 ? inkValue : onValue,
|
|
146
|
+
});
|
|
147
|
+
continue;
|
|
148
|
+
}
|
|
149
|
+
const backdrop = pair.over ? coloursIn(String(tokens[pair.over]))[0] : undefined;
|
|
150
|
+
const opaque = backdrop ?? { r: 255, g: 255, b: 255, a: 1 };
|
|
151
|
+
// The worst stop of a gradient and the worst ink of a multi-stop value:
|
|
152
|
+
// text has to be legible everywhere it lands, not on average.
|
|
153
|
+
let worst = Number.POSITIVE_INFINITY;
|
|
154
|
+
for (const ground of grounds) {
|
|
155
|
+
const solidGround = composite(ground, opaque);
|
|
156
|
+
for (const ink of inks) {
|
|
157
|
+
worst = Math.min(worst, contrast(composite(ink, solidGround), solidGround));
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
if (worst + 0.005 < pair.requires) {
|
|
161
|
+
findings.push({
|
|
162
|
+
ink: pair.ink,
|
|
163
|
+
on: pair.on,
|
|
164
|
+
where: pair.where,
|
|
165
|
+
ratio: Math.round(worst * 100) / 100,
|
|
166
|
+
requires: pair.requires,
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
return findings;
|
|
171
|
+
}
|
|
172
|
+
//# sourceMappingURL=contrast.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"contrast.js","sourceRoot":"","sources":["../../src/theme/contrast.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { checkContrast } from "./contrast.js";
|
|
2
|
+
import type { Scheme, ThemeTokens } from "./types.js";
|
|
3
|
+
/**
|
|
4
|
+
* A brand hands over one accent colour. What can be made of it, and what
|
|
5
|
+
* cannot.
|
|
6
|
+
*
|
|
7
|
+
* The two schemes here are not inversions of each other — dark loses
|
|
8
|
+
* luminance, light loses contrast and gains haze — so "derive the other one"
|
|
9
|
+
* is not a colour operation. What an accent CAN determine is everything
|
|
10
|
+
* keyed to it: its dim companion, its glow, the lit edge, the wash. What it
|
|
11
|
+
* cannot determine is the ground family (warm paper or cool slate is a
|
|
12
|
+
* decision, not a consequence), the ink that has to clear AA against that
|
|
13
|
+
* ground, and the warning colour, which must stay distinguishable from the
|
|
14
|
+
* accent rather than derived from it.
|
|
15
|
+
*
|
|
16
|
+
* So this derives what it can from a neutral base and REFUSES, naming what
|
|
17
|
+
* else is needed, when the accent cannot carry a role it is being asked to.
|
|
18
|
+
* A brand that gets a coherent pair of schemes and one that gets a clear
|
|
19
|
+
* refusal are both better served than one that gets a quietly unreadable
|
|
20
|
+
* interface.
|
|
21
|
+
*/
|
|
22
|
+
export interface AccentBrandOptions {
|
|
23
|
+
/** The one colour a brand always has. Hex, rgb() or hsl(). */
|
|
24
|
+
readonly accent: string;
|
|
25
|
+
/**
|
|
26
|
+
* Text drawn ON the accent — a filled button. Derived as black or white
|
|
27
|
+
* when absent, which works for most accents and is checked either way.
|
|
28
|
+
*/
|
|
29
|
+
readonly accentInk?: {
|
|
30
|
+
readonly dark?: string;
|
|
31
|
+
readonly light?: string;
|
|
32
|
+
};
|
|
33
|
+
/** The neutral pair to build on. Supply the framework's own when absent. */
|
|
34
|
+
readonly base: Readonly<Record<Scheme, ThemeTokens>>;
|
|
35
|
+
/** Kept away from the accent on purpose; derived only if it stays distinct. */
|
|
36
|
+
readonly warn?: {
|
|
37
|
+
readonly dark?: string;
|
|
38
|
+
readonly light?: string;
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
export interface DerivedBrand {
|
|
42
|
+
readonly ok: true;
|
|
43
|
+
readonly schemes: Readonly<Record<Scheme, ThemeTokens>>;
|
|
44
|
+
}
|
|
45
|
+
export interface RefusedBrand {
|
|
46
|
+
readonly ok: false;
|
|
47
|
+
/** What the brand has to supply, in the words of the thing that needs it. */
|
|
48
|
+
readonly missing: readonly string[];
|
|
49
|
+
readonly why: string;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Builds a coherent pair of schemes around one accent, or says what is
|
|
53
|
+
* missing.
|
|
54
|
+
*/
|
|
55
|
+
export declare function brandFromAccent(options: AccentBrandOptions): DerivedBrand | RefusedBrand;
|
|
56
|
+
/** Every contrast failure in a pair of schemes, named by scheme. */
|
|
57
|
+
export declare function checkBrandContrast(schemes: Readonly<Record<Scheme, ThemeTokens>>): readonly (ReturnType<typeof checkContrast>[number] & {
|
|
58
|
+
scheme: Scheme;
|
|
59
|
+
})[];
|
|
60
|
+
/**
|
|
61
|
+
* Stable hue per kind — THE thread of kind identity across every surface:
|
|
62
|
+
* chip dots, legend swatches, district roofs, the focus tag, a page's
|
|
63
|
+
* kind mark. A brand that declares a kind's hue (`accents`) wins over the
|
|
64
|
+
* hash. Lives beside the brand because the brand is what overrides it.
|
|
65
|
+
*
|
|
66
|
+
* IN DEGREES, 0–360, which is what a hue is in CSS, in every design tool,
|
|
67
|
+
* and in `brand.accents` itself — the checker already validates an accent as
|
|
68
|
+
* "a number 0–360". It used to divide by 360 on the way out, because every
|
|
69
|
+
* consumer in this repository wanted a fraction, and the name said nothing
|
|
70
|
+
* about that. So an app author read the name, wrote
|
|
71
|
+
* `hsl(${hueFor(kind)} 58% 50%)`, which is valid CSS that renders, and got a
|
|
72
|
+
* hue between 0 and 1 for every kind — which is red. A map with four
|
|
73
|
+
* surfaces came out four shades of the same pink. Nothing failed: not tsc,
|
|
74
|
+
* not graview check, not a test. It was only wrong to look at, and only if
|
|
75
|
+
* you knew what it should have looked like.
|
|
76
|
+
*
|
|
77
|
+
* The consumers divide now, where dividing is a local detail rather than a
|
|
78
|
+
* surprise in a public name.
|
|
79
|
+
*/
|
|
80
|
+
export declare function hueFor(kind: string, accents?: Readonly<Record<string, number>>): number;
|
|
81
|
+
//# sourceMappingURL=derive.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"derive.d.ts","sourceRoot":"","sources":["../../src/theme/derive.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,aAAa,EAOd,MAAM,eAAe,CAAC;AACvB,OAAO,KAAK,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAEtD;;;;;;;;;;;;;;;;;;GAkBG;AACH,MAAM,WAAW,kBAAkB;IACjC,8DAA8D;IAC9D,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB;;;OAGG;IACH,QAAQ,CAAC,SAAS,CAAC,EAAE;QAAE,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IACzE,4EAA4E;IAC5E,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC,CAAC;IACrD,+EAA+E;IAC/E,QAAQ,CAAC,IAAI,CAAC,EAAE;QAAE,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;CACrE;AAED,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,EAAE,EAAE,IAAI,CAAC;IAClB,QAAQ,CAAC,OAAO,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC,CAAC;CACzD;AAED,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,EAAE,EAAE,KAAK,CAAC;IACnB,6EAA6E;IAC7E,QAAQ,CAAC,OAAO,EAAE,SAAS,MAAM,EAAE,CAAC;IACpC,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;CACtB;AAQD;;;GAGG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,kBAAkB,GAAG,YAAY,GAAG,YAAY,CAmGxF;AAqDD,oEAAoE;AACpE,wBAAgB,kBAAkB,CAChC,OAAO,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC,GAC7C,SAAS,CAAC,UAAU,CAAC,OAAO,aAAa,CAAC,CAAC,MAAM,CAAC,GAAG;IAAE,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC,EAAE,CAI5E;AAGD;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,GAAG,MAAM,CASvF"}
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
import { checkContrast, coloursIn, composite, contrast, hsl, rgbToHsl, } from "./contrast.js";
|
|
2
|
+
const rgba = (colour, alpha) => `rgba(${Math.round(colour.r)}, ${Math.round(colour.g)}, ${Math.round(colour.b)}, ${alpha})`;
|
|
3
|
+
const BLACK = { r: 0, g: 0, b: 0, a: 1 };
|
|
4
|
+
const WHITE = { r: 255, g: 255, b: 255, a: 1 };
|
|
5
|
+
/**
|
|
6
|
+
* Builds a coherent pair of schemes around one accent, or says what is
|
|
7
|
+
* missing.
|
|
8
|
+
*/
|
|
9
|
+
export function brandFromAccent(options) {
|
|
10
|
+
const accent = coloursIn(options.accent)[0];
|
|
11
|
+
if (!accent) {
|
|
12
|
+
return {
|
|
13
|
+
ok: false,
|
|
14
|
+
missing: ["accent"],
|
|
15
|
+
why: `"${options.accent}" is not a colour this can read. Use a hex, rgb() or hsl() value.`,
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
const schemes = {};
|
|
19
|
+
const missing = new Set();
|
|
20
|
+
const reasons = [];
|
|
21
|
+
const base = rgbToHsl(accent);
|
|
22
|
+
for (const scheme of ["dark", "light"]) {
|
|
23
|
+
const neutral = options.base[scheme];
|
|
24
|
+
const ground = coloursIn(neutral.ground)[0] ?? (scheme === "dark" ? BLACK : WHITE);
|
|
25
|
+
const panel = composite(coloursIn(neutral.panel)[0] ?? WHITE, ground);
|
|
26
|
+
/*
|
|
27
|
+
* The accent is used as TEXT, and no single colour can be text in both
|
|
28
|
+
* schemes.
|
|
29
|
+
*
|
|
30
|
+
* 4.5:1 on white needs a lightness under about 0.18; 4.5:1 on a dark
|
|
31
|
+
* panel needs one over about 0.24. Those do not overlap, which is why
|
|
32
|
+
* "the brand's accent" is one hue with two lightnesses rather than one
|
|
33
|
+
* colour — and why a framework that simply took the hex would have
|
|
34
|
+
* shipped an unreadable label in one scheme or the other.
|
|
35
|
+
*
|
|
36
|
+
* So the hue and the saturation are the brand's; the lightness is moved
|
|
37
|
+
* as little as it takes. If it has to move further than this, the colour
|
|
38
|
+
* has stopped being recognisably theirs and the honest answer is to ask.
|
|
39
|
+
*/
|
|
40
|
+
const readable = nearestReadable(base, panel, scheme, 4.5);
|
|
41
|
+
if (!readable) {
|
|
42
|
+
missing.add(`accent (${scheme})`);
|
|
43
|
+
reasons.push(`no lightness of this hue clears 4.5:1 as text on the ${scheme} panel, so ${scheme} needs an accent of its own`);
|
|
44
|
+
}
|
|
45
|
+
else if (Math.abs(readable.l - base.l) > MAX_SHIFT) {
|
|
46
|
+
missing.add(`accent (${scheme})`);
|
|
47
|
+
reasons.push(`reaching 4.5:1 on the ${scheme} panel would move the accent's lightness by ${Math.round(Math.abs(readable.l - base.l) * 100)} points, which is far enough that it stops being the same colour — supply one for ${scheme}`);
|
|
48
|
+
}
|
|
49
|
+
const tone = readable ?? base;
|
|
50
|
+
const shown = hsl(tone.h, tone.s, tone.l);
|
|
51
|
+
const chosenInk = options.accentInk?.[scheme] ??
|
|
52
|
+
(contrast(WHITE, shown) >= contrast(BLACK, shown) ? "#ffffff" : "#000000");
|
|
53
|
+
const inkOnAccent = contrast(coloursIn(chosenInk)[0] ?? WHITE, shown);
|
|
54
|
+
if (inkOnAccent + 0.005 < 4.5) {
|
|
55
|
+
missing.add(`accentInk (${scheme})`);
|
|
56
|
+
reasons.push(`neither black nor white clears 4.5:1 on the accent (best ${inkOnAccent.toFixed(2)}:1), so text on a filled button has to be given`);
|
|
57
|
+
}
|
|
58
|
+
schemes[scheme] = {
|
|
59
|
+
...neutral,
|
|
60
|
+
accent: rgba(shown, 1),
|
|
61
|
+
accentDim: rgba(shown, scheme === "dark" ? 0.35 : 0.22),
|
|
62
|
+
accentInk: chosenInk,
|
|
63
|
+
glow: rgba(shown, scheme === "dark" ? 0.28 : 0.1),
|
|
64
|
+
/*
|
|
65
|
+
* A lit edge is not text, and it still owes 3:1: a panel outline nobody
|
|
66
|
+
* can see is a panel with no edge. The aesthetic alpha is a preference,
|
|
67
|
+
* so it gives way to the alpha that can actually be seen.
|
|
68
|
+
*/
|
|
69
|
+
edgeBright: rgba(shown, visibleAlpha(shown, panel, scheme === "dark" ? 0.55 : 0.42, 3)),
|
|
70
|
+
wash: scheme === "dark"
|
|
71
|
+
? `radial-gradient(120% 80% at 50% -10%, var(--graview-glow) 0%, transparent 60%), radial-gradient(90% 60% at 12% 108%, ${rgba(shown, 0.1)} 0%, transparent 62%)`
|
|
72
|
+
: `radial-gradient(120% 80% at 50% -20%, rgba(255,255,255,0.9) 0%, transparent 58%), radial-gradient(80% 60% at 92% 104%, ${rgba(shown, 0.06)} 0%, transparent 60%)`,
|
|
73
|
+
...(options.warn?.[scheme] ? { warn: options.warn[scheme] } : {}),
|
|
74
|
+
};
|
|
75
|
+
/*
|
|
76
|
+
* A warning colour must not be mistakable for the accent. Two roles that
|
|
77
|
+
* look alike is a worse failure than an ugly pair, because one of them
|
|
78
|
+
* means "something is broken".
|
|
79
|
+
*/
|
|
80
|
+
const warn = coloursIn(schemes[scheme].warn)[0];
|
|
81
|
+
if (warn && hueGap(rgbToHsl(warn).h, tone.h) < 25) {
|
|
82
|
+
missing.add(`warn (${scheme})`);
|
|
83
|
+
reasons.push(`the warning colour shares the accent's hue in ${scheme}, so "something is broken" looks like "this is selected"`);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
if (missing.size > 0) {
|
|
87
|
+
return { ok: false, missing: [...missing].sort(), why: reasons.join("; ") };
|
|
88
|
+
}
|
|
89
|
+
return { ok: true, schemes };
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* The smallest alpha at which a colour laid on a ground clears a ratio, or
|
|
93
|
+
* the preferred one if that is already enough.
|
|
94
|
+
*
|
|
95
|
+
* Searched rather than solved because compositing then luminance is not
|
|
96
|
+
* invertible in closed form, and a hundred steps is cheap for something that
|
|
97
|
+
* runs once per theme.
|
|
98
|
+
*/
|
|
99
|
+
function visibleAlpha(colour, ground, preferred, ratio) {
|
|
100
|
+
for (let step = Math.round(preferred * 100); step <= 100; step++) {
|
|
101
|
+
const alpha = step / 100;
|
|
102
|
+
if (contrast(composite({ ...colour, a: alpha }, ground), ground) >= ratio)
|
|
103
|
+
return alpha;
|
|
104
|
+
}
|
|
105
|
+
return 1;
|
|
106
|
+
}
|
|
107
|
+
/** How far apart two hues are on the wheel, 0–180. */
|
|
108
|
+
function hueGap(a, b) {
|
|
109
|
+
const gap = Math.abs(a - b) % 360;
|
|
110
|
+
return gap > 180 ? 360 - gap : gap;
|
|
111
|
+
}
|
|
112
|
+
/** As much lightness as a brand's colour may be moved and still be theirs. */
|
|
113
|
+
const MAX_SHIFT = 0.3;
|
|
114
|
+
/**
|
|
115
|
+
* The lightness nearest the brand's own that clears the ratio on this ground.
|
|
116
|
+
*
|
|
117
|
+
* Searched from the original outwards rather than from an end, so a colour
|
|
118
|
+
* that already works is left exactly alone and one that does not is moved the
|
|
119
|
+
* smallest distance that helps. Dark schemes are searched upward first and
|
|
120
|
+
* light ones downward, since that is the direction that will win.
|
|
121
|
+
*/
|
|
122
|
+
function nearestReadable(base, ground, scheme, ratio) {
|
|
123
|
+
const up = scheme === "dark";
|
|
124
|
+
for (let step = 0; step <= 100; step++) {
|
|
125
|
+
const first = up ? base.l + step / 100 : base.l - step / 100;
|
|
126
|
+
const second = up ? base.l - step / 100 : base.l + step / 100;
|
|
127
|
+
for (const l of [first, second]) {
|
|
128
|
+
if (l < 0 || l > 1)
|
|
129
|
+
continue;
|
|
130
|
+
if (contrast(hsl(base.h, base.s, l), ground) >= ratio)
|
|
131
|
+
return { ...base, l };
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
return null;
|
|
135
|
+
}
|
|
136
|
+
/** Every contrast failure in a pair of schemes, named by scheme. */
|
|
137
|
+
export function checkBrandContrast(schemes) {
|
|
138
|
+
return ["dark", "light"].flatMap((scheme) => checkContrast(schemes[scheme]).map((finding) => ({ ...finding, scheme })));
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* Stable hue per kind — THE thread of kind identity across every surface:
|
|
142
|
+
* chip dots, legend swatches, district roofs, the focus tag, a page's
|
|
143
|
+
* kind mark. A brand that declares a kind's hue (`accents`) wins over the
|
|
144
|
+
* hash. Lives beside the brand because the brand is what overrides it.
|
|
145
|
+
*
|
|
146
|
+
* IN DEGREES, 0–360, which is what a hue is in CSS, in every design tool,
|
|
147
|
+
* and in `brand.accents` itself — the checker already validates an accent as
|
|
148
|
+
* "a number 0–360". It used to divide by 360 on the way out, because every
|
|
149
|
+
* consumer in this repository wanted a fraction, and the name said nothing
|
|
150
|
+
* about that. So an app author read the name, wrote
|
|
151
|
+
* `hsl(${hueFor(kind)} 58% 50%)`, which is valid CSS that renders, and got a
|
|
152
|
+
* hue between 0 and 1 for every kind — which is red. A map with four
|
|
153
|
+
* surfaces came out four shades of the same pink. Nothing failed: not tsc,
|
|
154
|
+
* not graview check, not a test. It was only wrong to look at, and only if
|
|
155
|
+
* you knew what it should have looked like.
|
|
156
|
+
*
|
|
157
|
+
* The consumers divide now, where dividing is a local detail rather than a
|
|
158
|
+
* surprise in a public name.
|
|
159
|
+
*/
|
|
160
|
+
export function hueFor(kind, accents) {
|
|
161
|
+
const declared = accents?.[kind];
|
|
162
|
+
if (declared !== undefined)
|
|
163
|
+
return ((declared % 360) + 360) % 360;
|
|
164
|
+
let h = 2166136261;
|
|
165
|
+
for (let i = 0; i < kind.length; i++) {
|
|
166
|
+
h ^= kind.charCodeAt(i);
|
|
167
|
+
h = Math.imul(h, 16777619);
|
|
168
|
+
}
|
|
169
|
+
return (h >>> 0) % 360;
|
|
170
|
+
}
|
|
171
|
+
//# sourceMappingURL=derive.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"derive.js","sourceRoot":"","sources":["../../src/theme/derive.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import { type Rgba } from "./contrast.js";
|
|
2
|
+
import type { ThemeTokens } from "./types.js";
|
|
3
|
+
/** How a connector travels between its two ends. */
|
|
4
|
+
export type ConnectorRoute = "curve" | "straight" | "orthogonal";
|
|
5
|
+
export type KitStrokePattern = "solid" | "dashed" | "dotted" | "double" | "tapered";
|
|
6
|
+
export type KitEndCap = "none" | "arrow" | "dot" | "bar";
|
|
7
|
+
export interface ConnectorKit {
|
|
8
|
+
/** The path's shape. One strategy per name; adding one is one case. */
|
|
9
|
+
readonly route: ConnectorRoute;
|
|
10
|
+
/** Drawn at all. An edge kind a brand keeps quiet is still selectable from the inspector. */
|
|
11
|
+
readonly visible: boolean;
|
|
12
|
+
/** An explicit CSS colour; absent, the kind's own hue. */
|
|
13
|
+
readonly colour?: string;
|
|
14
|
+
readonly pattern?: KitStrokePattern;
|
|
15
|
+
readonly width?: number;
|
|
16
|
+
readonly cap?: KitEndCap;
|
|
17
|
+
readonly opacity?: number;
|
|
18
|
+
}
|
|
19
|
+
export interface Kit {
|
|
20
|
+
readonly connectors: {
|
|
21
|
+
/** Every edge kind, unless `byEdge` says otherwise. */
|
|
22
|
+
readonly all: ConnectorKit;
|
|
23
|
+
/** Per edge kind: colour, visibility, pattern — whatever this kind wants differently. */
|
|
24
|
+
readonly byEdge: Readonly<Record<string, Partial<ConnectorKit>>>;
|
|
25
|
+
};
|
|
26
|
+
/** The words over a neighbourhood: the edge's own reading. */
|
|
27
|
+
readonly captions: {
|
|
28
|
+
readonly visible: boolean;
|
|
29
|
+
};
|
|
30
|
+
/** The fine square measure under the scene on the ground. */
|
|
31
|
+
readonly grid: {
|
|
32
|
+
readonly visible: boolean;
|
|
33
|
+
readonly size: number;
|
|
34
|
+
};
|
|
35
|
+
/** The isometric lattice the ground becomes from altitude. */
|
|
36
|
+
readonly lattice: {
|
|
37
|
+
readonly visible: boolean;
|
|
38
|
+
readonly size: number;
|
|
39
|
+
};
|
|
40
|
+
/** The kind's name astride a focused card. */
|
|
41
|
+
readonly tags: {
|
|
42
|
+
readonly visible: boolean;
|
|
43
|
+
};
|
|
44
|
+
/**
|
|
45
|
+
* How loud a connector is when it is not the one being looked at.
|
|
46
|
+
*
|
|
47
|
+
* `rest` is what an unlit line keeps while NOTHING is lit — the quiet
|
|
48
|
+
* weight every relation in the picture carries at once. `dim` is what it
|
|
49
|
+
* keeps while something else IS lit: 0 vanishes, 1 does not recede. They
|
|
50
|
+
* are two different questions, and one number could not answer both —
|
|
51
|
+
* a resting opacity low enough to be calm made a selection's own lines
|
|
52
|
+
* barely brighter than the crowd, and one high enough to show the crowd
|
|
53
|
+
* left twenty lines shouting over the two a person had just chosen.
|
|
54
|
+
*/
|
|
55
|
+
readonly emphasis: {
|
|
56
|
+
readonly rest: number;
|
|
57
|
+
readonly dim: number;
|
|
58
|
+
};
|
|
59
|
+
/** The glyph a broken rule leaves on what it names. */
|
|
60
|
+
readonly marks: {
|
|
61
|
+
readonly flag: string;
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
/** A brand's say: any part of the kit, the rest as shipped. */
|
|
65
|
+
export interface KitOverrides {
|
|
66
|
+
readonly connectors?: {
|
|
67
|
+
readonly all?: Partial<ConnectorKit>;
|
|
68
|
+
readonly byEdge?: Readonly<Record<string, Partial<ConnectorKit>>>;
|
|
69
|
+
};
|
|
70
|
+
readonly captions?: Partial<Kit["captions"]>;
|
|
71
|
+
readonly grid?: Partial<Kit["grid"]>;
|
|
72
|
+
readonly lattice?: Partial<Kit["lattice"]>;
|
|
73
|
+
readonly tags?: Partial<Kit["tags"]>;
|
|
74
|
+
readonly emphasis?: Partial<Kit["emphasis"]>;
|
|
75
|
+
readonly marks?: Partial<Kit["marks"]>;
|
|
76
|
+
}
|
|
77
|
+
export declare const DEFAULT_KIT: Kit;
|
|
78
|
+
/** The kit as this brand wants it, every entry present. */
|
|
79
|
+
export declare function resolveKit(overrides?: KitOverrides): Kit;
|
|
80
|
+
/** One edge kind's connector, `all` under `byEdge`. */
|
|
81
|
+
export declare function connectorKitFor(kit: Kit, edgeKind: string): ConnectorKit;
|
|
82
|
+
/**
|
|
83
|
+
* The kit as custom properties, so the theme's rules read it and a host can
|
|
84
|
+
* override one entry without forking a component. Booleans become the CSS
|
|
85
|
+
* that carries them — a display, a multiplier — so no rule needs a script.
|
|
86
|
+
*/
|
|
87
|
+
export declare function kitVariables(kit: Kit): string;
|
|
88
|
+
export interface KitContrastFinding {
|
|
89
|
+
readonly edgeKind: string | "*";
|
|
90
|
+
readonly colour: string;
|
|
91
|
+
readonly ratio: number;
|
|
92
|
+
readonly requires: number;
|
|
93
|
+
readonly unreadable?: string;
|
|
94
|
+
/** Which ground it failed on: the scene's own, or the deeper one under a district. */
|
|
95
|
+
readonly ground?: "ground" | "deep ground";
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* A connector's colour must be told from the ground it crosses: 3:1, the
|
|
99
|
+
* floor for graphics, on both the ground and the deeper ground the
|
|
100
|
+
* altitude view uses. Only explicit colours are judged — a kind's own hue
|
|
101
|
+
* is the theme's to keep readable.
|
|
102
|
+
*/
|
|
103
|
+
export declare function checkKitContrast(kit: Kit, tokens: ThemeTokens): readonly KitContrastFinding[];
|
|
104
|
+
/** The kind's own hue (degrees) as the theme paints a connector, for callers that want the same colour elsewhere. */
|
|
105
|
+
export declare function connectorHueColour(hue: number): Rgba;
|
|
106
|
+
//# sourceMappingURL=kit.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"kit.d.ts","sourceRoot":"","sources":["../../src/theme/kit.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import { coloursIn, contrast, hsl } from "./contrast.js";
|
|
2
|
+
export const DEFAULT_KIT = {
|
|
3
|
+
connectors: { all: { route: "curve", visible: true }, byEdge: {} },
|
|
4
|
+
captions: { visible: true },
|
|
5
|
+
grid: { visible: true, size: 64 },
|
|
6
|
+
lattice: { visible: true, size: 46 },
|
|
7
|
+
tags: { visible: true },
|
|
8
|
+
emphasis: { rest: 0.34, dim: 0.12 },
|
|
9
|
+
marks: { flag: "⚠" },
|
|
10
|
+
};
|
|
11
|
+
/** The kit as this brand wants it, every entry present. */
|
|
12
|
+
export function resolveKit(overrides) {
|
|
13
|
+
if (!overrides)
|
|
14
|
+
return DEFAULT_KIT;
|
|
15
|
+
return {
|
|
16
|
+
connectors: {
|
|
17
|
+
all: { ...DEFAULT_KIT.connectors.all, ...(overrides.connectors?.all ?? {}) },
|
|
18
|
+
byEdge: { ...DEFAULT_KIT.connectors.byEdge, ...(overrides.connectors?.byEdge ?? {}) },
|
|
19
|
+
},
|
|
20
|
+
captions: { ...DEFAULT_KIT.captions, ...(overrides.captions ?? {}) },
|
|
21
|
+
grid: { ...DEFAULT_KIT.grid, ...(overrides.grid ?? {}) },
|
|
22
|
+
lattice: { ...DEFAULT_KIT.lattice, ...(overrides.lattice ?? {}) },
|
|
23
|
+
tags: { ...DEFAULT_KIT.tags, ...(overrides.tags ?? {}) },
|
|
24
|
+
emphasis: { ...DEFAULT_KIT.emphasis, ...(overrides.emphasis ?? {}) },
|
|
25
|
+
marks: { ...DEFAULT_KIT.marks, ...(overrides.marks ?? {}) },
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
/** One edge kind's connector, `all` under `byEdge`. */
|
|
29
|
+
export function connectorKitFor(kit, edgeKind) {
|
|
30
|
+
return { ...kit.connectors.all, ...(kit.connectors.byEdge[edgeKind] ?? {}) };
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* The kit as custom properties, so the theme's rules read it and a host can
|
|
34
|
+
* override one entry without forking a component. Booleans become the CSS
|
|
35
|
+
* that carries them — a display, a multiplier — so no rule needs a script.
|
|
36
|
+
*/
|
|
37
|
+
export function kitVariables(kit) {
|
|
38
|
+
return [
|
|
39
|
+
` --graview-kit-grid: ${kit.grid.visible ? 1 : 0};`,
|
|
40
|
+
` --graview-kit-grid-size: ${kit.grid.size}px;`,
|
|
41
|
+
` --graview-kit-lattice: ${kit.lattice.visible ? 1 : 0};`,
|
|
42
|
+
` --graview-kit-lattice-size: ${kit.lattice.size}px;`,
|
|
43
|
+
` --graview-kit-tags: ${kit.tags.visible ? "inline-flex" : "none"};`,
|
|
44
|
+
` --graview-kit-captions: ${kit.captions.visible ? "block" : "none"};`,
|
|
45
|
+
` --graview-kit-rest: ${kit.emphasis.rest};`,
|
|
46
|
+
` --graview-kit-dim: ${kit.emphasis.dim};`,
|
|
47
|
+
` --graview-kit-flag: "${kit.marks.flag.replace(/"/g, "'")}";`,
|
|
48
|
+
].join("\n");
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* A connector's colour must be told from the ground it crosses: 3:1, the
|
|
52
|
+
* floor for graphics, on both the ground and the deeper ground the
|
|
53
|
+
* altitude view uses. Only explicit colours are judged — a kind's own hue
|
|
54
|
+
* is the theme's to keep readable.
|
|
55
|
+
*/
|
|
56
|
+
export function checkKitContrast(kit, tokens) {
|
|
57
|
+
const findings = [];
|
|
58
|
+
const grounds = [["ground", tokens.ground], ["deep ground", tokens.groundDeep]]
|
|
59
|
+
.map(([name, value]) => ({ name, colour: coloursIn(value)[0] }))
|
|
60
|
+
.filter((one) => one.colour !== undefined);
|
|
61
|
+
const judge = (edgeKind, colour) => {
|
|
62
|
+
if (!colour)
|
|
63
|
+
return;
|
|
64
|
+
const ink = coloursIn(colour)[0];
|
|
65
|
+
if (!ink) {
|
|
66
|
+
findings.push({ edgeKind, colour, ratio: 0, requires: 3, unreadable: colour });
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
for (const ground of grounds) {
|
|
70
|
+
const ratio = Math.round(contrast(ink, ground.colour) * 100) / 100;
|
|
71
|
+
if (ratio < 3)
|
|
72
|
+
findings.push({ edgeKind, colour, ratio, requires: 3, ground: ground.name });
|
|
73
|
+
}
|
|
74
|
+
};
|
|
75
|
+
judge("*", kit.connectors.all.colour);
|
|
76
|
+
for (const [edgeKind, connector] of Object.entries(kit.connectors.byEdge))
|
|
77
|
+
judge(edgeKind, connector.colour);
|
|
78
|
+
return findings;
|
|
79
|
+
}
|
|
80
|
+
/** The kind's own hue (degrees) as the theme paints a connector, for callers that want the same colour elsewhere. */
|
|
81
|
+
export function connectorHueColour(hue) {
|
|
82
|
+
return hsl(hue, 55, 62);
|
|
83
|
+
}
|
|
84
|
+
//# sourceMappingURL=kit.js.map
|