bitwrench 2.0.31 → 2.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/README.md +210 -125
- package/dist/bitwrench-bccl.cjs.js +349 -188
- package/dist/bitwrench-bccl.cjs.min.js +2 -39
- package/dist/bitwrench-bccl.cjs.min.js.gz +0 -0
- package/dist/bitwrench-bccl.esm.js +349 -188
- package/dist/bitwrench-bccl.esm.min.js +2 -39
- package/dist/bitwrench-bccl.esm.min.js.gz +0 -0
- package/dist/bitwrench-bccl.umd.js +349 -188
- package/dist/bitwrench-bccl.umd.min.js +2 -39
- package/dist/bitwrench-bccl.umd.min.js.gz +0 -0
- package/dist/bitwrench-code-edit.cjs.js +17 -6
- package/dist/bitwrench-code-edit.cjs.min.js +2 -20
- package/dist/bitwrench-code-edit.es5.js +8 -3
- package/dist/bitwrench-code-edit.es5.min.js +2 -19
- package/dist/bitwrench-code-edit.esm.js +17 -6
- package/dist/bitwrench-code-edit.esm.min.js +2 -19
- package/dist/bitwrench-code-edit.umd.js +17 -6
- package/dist/bitwrench-code-edit.umd.min.js +2 -19
- package/dist/bitwrench-code-edit.umd.min.js.gz +0 -0
- package/dist/bitwrench-debug.js +1 -1
- package/dist/bitwrench-debug.min.js +1 -1
- package/dist/bitwrench-lean.cjs.js +2492 -1628
- package/dist/bitwrench-lean.cjs.min.js +2 -80
- package/dist/bitwrench-lean.cjs.min.js.gz +0 -0
- package/dist/bitwrench-lean.es5.js +2740 -1838
- package/dist/bitwrench-lean.es5.min.js +2 -49
- package/dist/bitwrench-lean.es5.min.js.gz +0 -0
- package/dist/bitwrench-lean.esm.js +2492 -1628
- package/dist/bitwrench-lean.esm.min.js +2 -80
- package/dist/bitwrench-lean.esm.min.js.gz +0 -0
- package/dist/bitwrench-lean.umd.js +2492 -1628
- package/dist/bitwrench-lean.umd.min.js +2 -80
- package/dist/bitwrench-lean.umd.min.js.gz +0 -0
- package/dist/bitwrench-util-color.cjs.js +251 -0
- package/dist/bitwrench-util-color.cjs.min.js +3 -0
- package/dist/bitwrench-util-color.es5.js +256 -0
- package/dist/bitwrench-util-color.es5.min.js +3 -0
- package/dist/bitwrench-util-color.esm.js +241 -0
- package/dist/bitwrench-util-color.esm.min.js +3 -0
- package/dist/bitwrench-util-color.umd.js +257 -0
- package/dist/bitwrench-util-color.umd.min.js +3 -0
- package/dist/bitwrench-util-css.cjs.js +2 -1
- package/dist/bitwrench-util-css.cjs.min.js +2 -21
- package/dist/bitwrench-util-css.es5.js +2 -1
- package/dist/bitwrench-util-css.es5.min.js +2 -20
- package/dist/bitwrench-util-css.esm.js +2 -1
- package/dist/bitwrench-util-css.esm.min.js +1 -19
- package/dist/bitwrench-util-css.umd.js +2 -1
- package/dist/bitwrench-util-css.umd.min.js +2 -20
- package/dist/bitwrench-util-css.umd.min.js.gz +0 -0
- package/dist/bitwrench.cjs.js +2826 -1801
- package/dist/bitwrench.cjs.min.js +2 -99
- package/dist/bitwrench.cjs.min.js.gz +0 -0
- package/dist/bitwrench.css +403 -479
- package/dist/bitwrench.d.ts +70 -73
- package/dist/bitwrench.es5.js +3106 -2020
- package/dist/bitwrench.es5.min.js +2 -67
- package/dist/bitwrench.es5.min.js.gz +0 -0
- package/dist/bitwrench.esm.js +2826 -1801
- package/dist/bitwrench.esm.min.js +2 -99
- package/dist/bitwrench.esm.min.js.gz +0 -0
- package/dist/bitwrench.min.css +1 -1
- package/dist/bitwrench.umd.js +2826 -1801
- package/dist/bitwrench.umd.min.js +2 -99
- package/dist/bitwrench.umd.min.js.gz +0 -0
- package/dist/builds.json +222 -134
- package/dist/bwserve.cjs.js +308 -298
- package/dist/bwserve.d.ts +157 -0
- package/dist/bwserve.esm.js +309 -299
- package/dist/sri.json +54 -46
- package/docs/README.md +6 -3
- package/docs/app-patterns.md +7 -6
- package/docs/bitwrench-for-wasm.md +53 -54
- package/docs/bitwrench-mcp.md +2 -2
- package/docs/bitwrench-northstar-principles.md +406 -0
- package/docs/bitwrench-taco-schema-discussion.md +2 -2
- package/docs/bitwrench_api.md +191 -106
- package/docs/bitwrench_typescript_usage.md +5 -5
- package/docs/bw-attach.md +29 -75
- package/docs/bwserve.md +200 -168
- package/docs/cli.md +36 -12
- package/docs/component-cheatsheet.md +2 -2
- package/docs/component-library.md +4 -4
- package/docs/component-lifecycle.md +234 -0
- package/docs/drift-lint.md +268 -0
- package/docs/framework-translation-table.md +4 -4
- package/docs/llm-bitwrench-guide.md +60 -50
- package/docs/routing.md +11 -13
- package/docs/state-management.md +110 -109
- package/docs/taco-format.md +13 -14
- package/docs/theming.md +13 -3
- package/docs/thinking-in-bitwrench.md +858 -983
- package/docs/tutorial-bwserve.md +37 -36
- package/docs/tutorial-embedded.md +10 -21
- package/docs/tutorial-website.md +2 -2
- package/package.json +38 -7
- package/readme.html +262 -160
- package/src/bitwrench-bccl-entry.js +2 -2
- package/src/bitwrench-bccl.js +346 -185
- package/src/bitwrench-code-edit.js +16 -5
- package/src/bitwrench-color-utils.js +117 -181
- package/src/bitwrench-file-ops.js +2 -2
- package/src/bitwrench-lean.js +4 -3
- package/src/bitwrench-router.js +5 -2
- package/src/bitwrench-styles.js +420 -504
- package/src/bitwrench-util-color.js +240 -0
- package/src/bitwrench-util-css.js +1 -0
- package/src/bitwrench-utils.js +4 -0
- package/src/bitwrench.d.ts +70 -73
- package/src/bitwrench.h +5 -0
- package/src/bitwrench.js +1939 -933
- package/src/bwserve/attach.js +0 -1
- package/src/bwserve/bwclient.js +172 -32
- package/src/bwserve/bwshell.js +0 -4
- package/src/bwserve/client.js +59 -220
- package/src/bwserve/index.js +78 -42
- package/src/bwserve.d.ts +157 -0
- package/src/bwserve.h +5 -0
- package/src/cli/attach.js +12 -75
- package/src/cli/convert.js +2 -2
- package/src/cli/serve.js +37 -35
- package/src/generate-css.js +1 -1
- package/src/mcp/knowledge.js +4 -4
- package/src/mcp/live.js +21 -13
- package/src/mcp/tools.js +0 -1
- package/src/version.js +3 -7
|
@@ -85,7 +85,10 @@ function tokenizeJS(code) {
|
|
|
85
85
|
var buf = '';
|
|
86
86
|
|
|
87
87
|
function flush(type) {
|
|
88
|
-
if (buf.length) {
|
|
88
|
+
if (buf.length) {
|
|
89
|
+
/* c8 ignore next -- flush() is always called with an explicit type argument */
|
|
90
|
+
tokens.push({ type: type || 'plain', text: buf }); buf = '';
|
|
91
|
+
}
|
|
89
92
|
}
|
|
90
93
|
|
|
91
94
|
while (i < len) {
|
|
@@ -279,7 +282,10 @@ function tokenizeCSS(code) {
|
|
|
279
282
|
var buf = '';
|
|
280
283
|
|
|
281
284
|
function flush(type) {
|
|
282
|
-
if (buf.length) {
|
|
285
|
+
if (buf.length) {
|
|
286
|
+
/* c8 ignore next -- flush() is always called with an explicit type argument */
|
|
287
|
+
tokens.push({ type: type || 'plain', text: buf }); buf = '';
|
|
288
|
+
}
|
|
283
289
|
}
|
|
284
290
|
|
|
285
291
|
while (i < len) {
|
|
@@ -316,7 +322,7 @@ function tokenizeCSS(code) {
|
|
|
316
322
|
flush('selector');
|
|
317
323
|
var aBuf = '@';
|
|
318
324
|
i++;
|
|
319
|
-
while (i < len && /[a-zA-Z
|
|
325
|
+
while (i < len && /[a-zA-Z-]/.test(code[i])) { aBuf += code[i]; i++; }
|
|
320
326
|
tokens.push({ type: 'at-rule', text: aBuf });
|
|
321
327
|
continue;
|
|
322
328
|
}
|
|
@@ -389,7 +395,10 @@ function tokenizeHTML(code) {
|
|
|
389
395
|
var buf = '';
|
|
390
396
|
|
|
391
397
|
function flush(type) {
|
|
392
|
-
if (buf.length) {
|
|
398
|
+
if (buf.length) {
|
|
399
|
+
/* c8 ignore next -- flush() is always called with an explicit type argument */
|
|
400
|
+
tokens.push({ type: type || 'plain', text: buf }); buf = '';
|
|
401
|
+
}
|
|
393
402
|
}
|
|
394
403
|
|
|
395
404
|
while (i < len) {
|
|
@@ -413,7 +422,7 @@ function tokenizeHTML(code) {
|
|
|
413
422
|
i++;
|
|
414
423
|
if (i < len && code[i] === '/') { tBuf += '/'; i++; }
|
|
415
424
|
// Tag name
|
|
416
|
-
while (i < len && /[a-zA-Z0-9
|
|
425
|
+
while (i < len && /[a-zA-Z0-9-]/.test(code[i])) { tBuf += code[i]; i++; }
|
|
417
426
|
tokens.push({ type: 'tag', text: tBuf });
|
|
418
427
|
|
|
419
428
|
// Attributes
|
|
@@ -614,6 +623,7 @@ function codeEditor(opts) {
|
|
|
614
623
|
|
|
615
624
|
// Scroll sync: keep gutter aligned with code
|
|
616
625
|
if (gutterEl) {
|
|
626
|
+
/* c8 ignore next -- codeEditor always wraps in .bw_ce; defensive fallback */
|
|
617
627
|
var scrollParent = codeEl.closest('.bw_ce') || el;
|
|
618
628
|
scrollParent.addEventListener('scroll', function() {
|
|
619
629
|
gutterEl.style.transform = 'translateY(' + (-scrollParent.scrollTop) + 'px)';
|
|
@@ -666,6 +676,7 @@ function install(bw) {
|
|
|
666
676
|
}
|
|
667
677
|
|
|
668
678
|
// Auto-install if bw is on window (script tag usage)
|
|
679
|
+
/* c8 ignore next 3 -- module-level auto-install; only runs at import time in browser with script tags */
|
|
669
680
|
if (typeof window !== 'undefined' && window.bw) {
|
|
670
681
|
install(window.bw);
|
|
671
682
|
}
|
|
@@ -1,189 +1,150 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Bitwrench Color Utilities
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
4
|
+
* Hex-only color math for the theme derivation pipeline, plus legacy
|
|
5
|
+
* tagged-array color functions (colorParse, colorRgbToHsl, colorHslToRgb,
|
|
6
|
+
* colorInterp) for the public API.
|
|
7
7
|
*
|
|
8
8
|
* @module bitwrench-color-utils
|
|
9
|
-
* @license BSD-2-Clause
|
|
9
|
+
* @license BSD-2-Clause
|
|
10
10
|
* @copy Manu Chatterjee @deftio
|
|
11
11
|
*/
|
|
12
12
|
|
|
13
13
|
function _xs (x) {
|
|
14
|
-
return ('0' + x.toString(16)).slice(-2)
|
|
14
|
+
return ('0' + x.toString(16)).slice(-2);
|
|
15
15
|
}
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
* @param {number} val
|
|
19
|
-
* @param {number} min
|
|
20
|
-
* @param {number} max
|
|
21
|
-
* @returns {number}
|
|
22
|
-
*/
|
|
23
|
-
export function clip(val, min, max) {
|
|
16
|
+
|
|
17
|
+
function clip(val, min, max) {
|
|
24
18
|
return Math.max(min, Math.min(max, val));
|
|
25
19
|
}
|
|
26
20
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
21
|
+
// Parse hex string to [r, g, b].
|
|
22
|
+
function _ph(hex) {
|
|
23
|
+
var h = hex.charAt(0) === '#' ? hex.slice(1) : hex;
|
|
24
|
+
if (h.length === 3) h = h[0]+h[0]+h[1]+h[1]+h[2]+h[2];
|
|
25
|
+
return [parseInt(h.slice(0,2),16), parseInt(h.slice(2,4),16), parseInt(h.slice(4,6),16)];
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// RGB [0-255] to HSL [h 0-360, s 0-100, l 0-100], float precision.
|
|
29
|
+
function _r2h(r, g, b) {
|
|
30
|
+
r /= 255; g /= 255; b /= 255;
|
|
31
|
+
var mx = Math.max(r, g, b), mn = Math.min(r, g, b);
|
|
32
|
+
var h, s, l = (mx + mn) / 2;
|
|
33
|
+
if (mx === mn) {
|
|
34
|
+
h = s = 0;
|
|
35
|
+
} else {
|
|
36
|
+
var d = mx - mn;
|
|
37
|
+
s = l > 0.5 ? d / (2 - mx - mn) : d / (mx + mn);
|
|
38
|
+
switch (mx) {
|
|
39
|
+
case r: h = ((g - b) / d + (g < b ? 6 : 0)) / 6; break;
|
|
40
|
+
case g: h = ((b - r) / d + 2) / 6; break;
|
|
41
|
+
case b: h = ((r - g) / d + 4) / 6; break;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
return [h * 360, s * 100, l * 100];
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// HSL [h 0-360, s 0-100, l 0-100] to RGB [0-255], rounded.
|
|
48
|
+
function _h2r(h, s, l) {
|
|
49
|
+
var hN = h / 360, sN = s / 100, lN = l / 100;
|
|
50
|
+
var r, g, b;
|
|
51
|
+
if (sN === 0) {
|
|
52
|
+
r = g = b = lN * 255;
|
|
53
|
+
} else {
|
|
54
|
+
var hue2rgb = function(p, q, t) {
|
|
55
|
+
if (t < 0) t += 1;
|
|
56
|
+
if (t > 1) t -= 1;
|
|
57
|
+
if (t < 1/6) return p + (q - p) * 6 * t;
|
|
58
|
+
if (t < 1/2) return q;
|
|
59
|
+
if (t < 2/3) return p + (q - p) * (2/3 - t) * 6;
|
|
60
|
+
return p;
|
|
61
|
+
};
|
|
62
|
+
var q = lN < 0.5 ? lN * (1 + sN) : lN + sN - lN * sN;
|
|
63
|
+
var p = 2 * lN - q;
|
|
64
|
+
r = hue2rgb(p, q, hN + 1/3) * 255;
|
|
65
|
+
g = hue2rgb(p, q, hN) * 255;
|
|
66
|
+
b = hue2rgb(p, q, hN - 1/3) * 255;
|
|
67
|
+
}
|
|
68
|
+
return [Math.round(r), Math.round(g), Math.round(b)];
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// =========================================================================
|
|
72
|
+
// Legacy color API — tagged 5-element arrays [r,g,b,a,"rgb"/"hsl"]
|
|
73
|
+
// =========================================================================
|
|
74
|
+
|
|
75
|
+
function _ms(x, i0, i1, o0, o1, opts) {
|
|
76
|
+
var n = (x - i0) / (i1 - i0);
|
|
77
|
+
if (opts && opts.expScale && opts.expScale !== 1) n = Math.pow(n, opts.expScale);
|
|
78
|
+
var r = n * (o1 - o0) + o0;
|
|
79
|
+
if (opts && opts.clip) r = clip(r, Math.min(o0, o1), Math.max(o0, o1));
|
|
80
|
+
return r;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
export function colorHslToRgb(h, s, l, a, rnd) {
|
|
84
|
+
if (a === undefined) a = 255;
|
|
85
|
+
if (rnd === undefined) rnd = true;
|
|
86
|
+
if (Array.isArray(h)) { s = h[1]; l = h[2]; a = h[3] !== undefined ? h[3] : 255; h = h[0]; }
|
|
87
|
+
var rgb = _h2r(h, s, l);
|
|
88
|
+
if (rnd) a = Math.round(a);
|
|
89
|
+
return [rgb[0], rgb[1], rgb[2], a, "rgb"];
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
export function colorRgbToHsl(r, g, b, a, rnd) {
|
|
93
|
+
if (a === undefined) a = 255;
|
|
94
|
+
if (rnd === undefined) rnd = true;
|
|
95
|
+
if (Array.isArray(r)) { g = r[1]; b = r[2]; a = r[3] !== undefined ? r[3] : 255; r = r[0]; }
|
|
96
|
+
var hsl = _r2h(r, g, b);
|
|
97
|
+
if (rnd) { hsl[0] = Math.round(hsl[0]); hsl[1] = Math.round(hsl[1]); hsl[2] = Math.round(hsl[2]); a = Math.round(a); }
|
|
98
|
+
return [hsl[0], hsl[1], hsl[2], a, "hsl"];
|
|
99
|
+
}
|
|
100
|
+
|
|
34
101
|
export function colorParse(s, defAlpha) {
|
|
35
102
|
if (defAlpha === undefined) defAlpha = 255;
|
|
36
103
|
var r = [0, 0, 0, defAlpha, "rgb"];
|
|
37
|
-
|
|
38
104
|
if (Array.isArray(s)) {
|
|
39
105
|
var df = [0, 0, 0, 255, "rgb"];
|
|
40
|
-
for (var p = 0; p < s.length && p < df.length; p++)
|
|
41
|
-
df[p] = s[p];
|
|
42
|
-
}
|
|
106
|
+
for (var p = 0; p < s.length && p < df.length; p++) df[p] = s[p];
|
|
43
107
|
return df;
|
|
44
108
|
}
|
|
45
|
-
|
|
46
109
|
s = String(s).replace(/\s/g, "");
|
|
47
|
-
|
|
48
110
|
if (s[0] === "#") {
|
|
49
111
|
var hex = s.slice(1);
|
|
50
112
|
if (hex.length === 3 || hex.length === 4) {
|
|
51
|
-
for (var i = 0; i < hex.length; i++)
|
|
52
|
-
r[i] = parseInt(hex[i] + hex[i], 16);
|
|
53
|
-
}
|
|
113
|
+
for (var i = 0; i < hex.length; i++) r[i] = parseInt(hex[i] + hex[i], 16);
|
|
54
114
|
} else if (hex.length === 6 || hex.length === 8) {
|
|
55
|
-
for (var j = 0; j < hex.length; j += 2)
|
|
56
|
-
r[j / 2] = parseInt(hex.substring(j, j + 2), 16);
|
|
57
|
-
}
|
|
115
|
+
for (var j = 0; j < hex.length; j += 2) r[j / 2] = parseInt(hex.substring(j, j + 2), 16);
|
|
58
116
|
}
|
|
59
117
|
} else {
|
|
60
118
|
var match = s.match(/^(rgb|hsl)a?\(([^)]+)\)$/i);
|
|
61
119
|
if (match) {
|
|
62
120
|
var type = match[1].toLowerCase();
|
|
63
121
|
var values = match[2].split(",").map(function(v) { return parseFloat(v); });
|
|
64
|
-
|
|
65
122
|
if (type === "rgb") {
|
|
66
|
-
r[0] = values[0] || 0;
|
|
67
|
-
r[1] = values[1] || 0;
|
|
68
|
-
r[2] = values[2] || 0;
|
|
123
|
+
r[0] = values[0] || 0; r[1] = values[1] || 0; r[2] = values[2] || 0;
|
|
69
124
|
r[3] = values[3] !== undefined ? values[3] * 255 : defAlpha;
|
|
70
|
-
r[4] = "rgb";
|
|
71
125
|
} else if (type === "hsl") {
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
return rgb;
|
|
126
|
+
return colorHslToRgb(values[0] || 0, values[1] || 0, values[2] || 0,
|
|
127
|
+
values[3] !== undefined ? values[3] * 255 : defAlpha);
|
|
75
128
|
}
|
|
76
129
|
}
|
|
77
130
|
}
|
|
78
|
-
|
|
79
131
|
return r;
|
|
80
132
|
}
|
|
81
133
|
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
if (a === undefined) a = 255;
|
|
93
|
-
if (rnd === undefined) rnd = true;
|
|
94
|
-
if (Array.isArray(r)) {
|
|
95
|
-
g = r[1]; b = r[2]; a = r[3] !== undefined ? r[3] : 255; r = r[0];
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
r /= 255;
|
|
99
|
-
g /= 255;
|
|
100
|
-
b /= 255;
|
|
101
|
-
|
|
102
|
-
var max = Math.max(r, g, b);
|
|
103
|
-
var min = Math.min(r, g, b);
|
|
104
|
-
var h, s, l = (max + min) / 2;
|
|
105
|
-
|
|
106
|
-
if (max === min) {
|
|
107
|
-
h = s = 0;
|
|
108
|
-
} else {
|
|
109
|
-
var d = max - min;
|
|
110
|
-
s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
|
|
111
|
-
|
|
112
|
-
switch (max) {
|
|
113
|
-
case r: h = ((g - b) / d + (g < b ? 6 : 0)) / 6; break;
|
|
114
|
-
case g: h = ((b - r) / d + 2) / 6; break;
|
|
115
|
-
case b: h = ((r - g) / d + 4) / 6; break;
|
|
116
|
-
}
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
h *= 360;
|
|
120
|
-
s *= 100;
|
|
121
|
-
l *= 100;
|
|
122
|
-
|
|
123
|
-
if (rnd) {
|
|
124
|
-
h = Math.round(h);
|
|
125
|
-
s = Math.round(s);
|
|
126
|
-
l = Math.round(l);
|
|
127
|
-
a = Math.round(a);
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
return [h, s, l, a, "hsl"];
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
/**
|
|
134
|
-
* Convert HSL to RGB.
|
|
135
|
-
* @param {number|Array} h - Hue 0-360, or [h,s,l,a] array
|
|
136
|
-
* @param {number} [s] - Saturation 0-100
|
|
137
|
-
* @param {number} [l] - Lightness 0-100
|
|
138
|
-
* @param {number} [a=255] - Alpha 0-255
|
|
139
|
-
* @param {boolean} [rnd=true] - Round results
|
|
140
|
-
* @returns {Array} [r, g, b, a, "rgb"]
|
|
141
|
-
*/
|
|
142
|
-
export function colorHslToRgb(h, s, l, a, rnd) {
|
|
143
|
-
if (a === undefined) a = 255;
|
|
144
|
-
if (rnd === undefined) rnd = true;
|
|
145
|
-
if (Array.isArray(h)) {
|
|
146
|
-
s = h[1]; l = h[2]; a = h[3] !== undefined ? h[3] : 255; h = h[0];
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
var hNorm = h / 360;
|
|
150
|
-
var sNorm = s / 100;
|
|
151
|
-
var lNorm = l / 100;
|
|
152
|
-
|
|
153
|
-
var r, g, b;
|
|
154
|
-
|
|
155
|
-
if (sNorm === 0) {
|
|
156
|
-
r = g = b = lNorm * 255;
|
|
157
|
-
} else {
|
|
158
|
-
var hue2rgb = function(p, q, t) {
|
|
159
|
-
if (t < 0) t += 1;
|
|
160
|
-
if (t > 1) t -= 1;
|
|
161
|
-
if (t < 1/6) return p + (q - p) * 6 * t;
|
|
162
|
-
if (t < 1/2) return q;
|
|
163
|
-
if (t < 2/3) return p + (q - p) * (2/3 - t) * 6;
|
|
164
|
-
return p;
|
|
165
|
-
};
|
|
166
|
-
|
|
167
|
-
var q = lNorm < 0.5 ? lNorm * (1 + sNorm) : lNorm + sNorm - lNorm * sNorm;
|
|
168
|
-
var p = 2 * lNorm - q;
|
|
169
|
-
|
|
170
|
-
r = hue2rgb(p, q, hNorm + 1/3) * 255;
|
|
171
|
-
g = hue2rgb(p, q, hNorm) * 255;
|
|
172
|
-
b = hue2rgb(p, q, hNorm - 1/3) * 255;
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
if (rnd) {
|
|
176
|
-
r = Math.round(r);
|
|
177
|
-
g = Math.round(g);
|
|
178
|
-
b = Math.round(b);
|
|
179
|
-
a = Math.round(a);
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
return [r, g, b, a, "rgb"];
|
|
134
|
+
export function colorInterp(x, in0, in1, colors, stretch) {
|
|
135
|
+
var c = Array.isArray(colors) ? colors : ["#000", "#fff"];
|
|
136
|
+
c = c.length === 0 ? ["#000", "#fff"] : c;
|
|
137
|
+
if (c.length === 1) return c[0];
|
|
138
|
+
c = c.map(function(col) { return colorParse(col); });
|
|
139
|
+
var a = _ms(x, in0, in1, 0, c.length - 1, { clip: true, expScale: stretch });
|
|
140
|
+
var i = clip(Math.floor(a), 0, c.length - 2);
|
|
141
|
+
var r = a - i;
|
|
142
|
+
var interp = function(idx) { return _ms(r, 0, 1, c[i][idx], c[i + 1][idx], { clip: true }); };
|
|
143
|
+
return [interp(0), interp(1), interp(2), interp(3), "rgb"];
|
|
183
144
|
}
|
|
184
145
|
|
|
185
146
|
// =========================================================================
|
|
186
|
-
//
|
|
147
|
+
// Public theme derivation helpers
|
|
187
148
|
// =========================================================================
|
|
188
149
|
|
|
189
150
|
/**
|
|
@@ -192,9 +153,8 @@ export function colorHslToRgb(h, s, l, a, rnd) {
|
|
|
192
153
|
* @returns {Array} [h, s, l] where h=0-360, s=0-100, l=0-100
|
|
193
154
|
*/
|
|
194
155
|
export function hexToHsl(hex) {
|
|
195
|
-
var rgb =
|
|
196
|
-
|
|
197
|
-
return [hsl[0], hsl[1], hsl[2]];
|
|
156
|
+
var rgb = _ph(hex);
|
|
157
|
+
return _r2h(rgb[0], rgb[1], rgb[2]);
|
|
198
158
|
}
|
|
199
159
|
|
|
200
160
|
/**
|
|
@@ -203,7 +163,7 @@ export function hexToHsl(hex) {
|
|
|
203
163
|
* @returns {string} Hex color e.g. '#006666'
|
|
204
164
|
*/
|
|
205
165
|
export function hslToHex(hsl) {
|
|
206
|
-
var rgb =
|
|
166
|
+
var rgb = _h2r(hsl[0], hsl[1], hsl[2]);
|
|
207
167
|
return '#' + _xs(rgb[0])+_xs(rgb[1])+_xs(rgb[2]);
|
|
208
168
|
}
|
|
209
169
|
|
|
@@ -228,8 +188,8 @@ export function adjustLightness(hex, amount) {
|
|
|
228
188
|
* @returns {string} Mixed hex color
|
|
229
189
|
*/
|
|
230
190
|
export function mixColor(hex1, hex2, ratio) {
|
|
231
|
-
var c1 =
|
|
232
|
-
var c2 =
|
|
191
|
+
var c1 = _ph(hex1);
|
|
192
|
+
var c2 = _ph(hex2);
|
|
233
193
|
var r = Math.round(c1[0] + (c2[0] - c1[0]) * ratio);
|
|
234
194
|
var g = Math.round(c1[1] + (c2[1] - c1[1]) * ratio);
|
|
235
195
|
var b = Math.round(c1[2] + (c2[2] - c1[2]) * ratio);
|
|
@@ -242,7 +202,7 @@ export function mixColor(hex1, hex2, ratio) {
|
|
|
242
202
|
* @returns {number} Relative luminance 0-1
|
|
243
203
|
*/
|
|
244
204
|
export function relativeLuminance(hex) {
|
|
245
|
-
var rgb =
|
|
205
|
+
var rgb = _ph(hex);
|
|
246
206
|
var vals = [rgb[0] / 255, rgb[1] / 255, rgb[2] / 255].map(function(v) {
|
|
247
207
|
return v <= 0.03928 ? v / 12.92 : Math.pow((v + 0.055) / 1.055, 2.4);
|
|
248
208
|
});
|
|
@@ -273,7 +233,6 @@ export function harmonize(sourceHex, targetHex, amount) {
|
|
|
273
233
|
var srcHsl = hexToHsl(sourceHex);
|
|
274
234
|
var tgtHsl = hexToHsl(targetHex);
|
|
275
235
|
|
|
276
|
-
// Shortest-arc hue interpolation
|
|
277
236
|
var diff = tgtHsl[0] - srcHsl[0];
|
|
278
237
|
if (diff > 180) diff -= 360;
|
|
279
238
|
if (diff < -180) diff += 360;
|
|
@@ -288,9 +247,7 @@ export function harmonize(sourceHex, targetHex, amount) {
|
|
|
288
247
|
* @returns {Object} { base, hover, active, light, darkText, border, focus, textOn }
|
|
289
248
|
*/
|
|
290
249
|
export function deriveShades(hex) {
|
|
291
|
-
var rgb =
|
|
292
|
-
// For light input colors (L > 75), mixing toward white produces invisible borders.
|
|
293
|
-
// Darken instead so borders remain visible against light backgrounds.
|
|
250
|
+
var rgb = _ph(hex);
|
|
294
251
|
var borderColor = hexToHsl(hex)[2] > 75
|
|
295
252
|
? adjustLightness(hex, -18)
|
|
296
253
|
: mixColor(hex, '#ffffff', 0.60);
|
|
@@ -318,14 +275,10 @@ export function deriveAlternateSeed(hex) {
|
|
|
318
275
|
var altL, altS;
|
|
319
276
|
|
|
320
277
|
if (l > 50) {
|
|
321
|
-
// Light color → make dark. Map 50-100 → 30-10 range
|
|
322
278
|
altL = clip(100 - l - 10, 8, 40);
|
|
323
|
-
// Reduce saturation slightly — vivid colors at low lightness look garish
|
|
324
279
|
altS = clip(s * 0.85, 0, 100);
|
|
325
280
|
} else {
|
|
326
|
-
// Dark color → make light. Map 0-50 → 65-92 range
|
|
327
281
|
altL = clip(100 - l + 10, 60, 92);
|
|
328
|
-
// Slightly increase saturation for light variant
|
|
329
282
|
altS = clip(s * 1.1, 0, 100);
|
|
330
283
|
}
|
|
331
284
|
|
|
@@ -354,35 +307,27 @@ export function isLightPalette(config) {
|
|
|
354
307
|
*/
|
|
355
308
|
export function deriveAlternateConfig(config) {
|
|
356
309
|
var alt = {};
|
|
357
|
-
// Invert the user's seed colors
|
|
358
310
|
alt.primary = deriveAlternateSeed(config.primary);
|
|
359
|
-
alt.secondary = deriveAlternateSeed(config.secondary);
|
|
311
|
+
alt.secondary = deriveAlternateSeed(config.secondary || config.primary);
|
|
360
312
|
alt.tertiary = config.tertiary ? deriveAlternateSeed(config.tertiary) : alt.primary;
|
|
361
313
|
|
|
362
|
-
// Derive alternate surface colors from primary hue.
|
|
363
|
-
// Check actual page surface brightness (not seed color brightness) to decide
|
|
364
|
-
// whether alternate should be dark or light. The page surface is what the
|
|
365
|
-
// user sees; seeds can be dark while the page is still light (default L=96).
|
|
366
314
|
var priHsl = hexToHsl(config.primary);
|
|
367
315
|
var h = priHsl[0];
|
|
368
316
|
var primarySurface = config.surface || hslToHex([h, 8, 96]);
|
|
369
317
|
var isLight = relativeLuminance(primarySurface) > 0.179;
|
|
370
318
|
|
|
371
319
|
if (isLight) {
|
|
372
|
-
// Page surface is light → alternate needs dark surfaces
|
|
373
320
|
alt.light = hslToHex([h, Math.min(priHsl[1], 15), 15]);
|
|
374
321
|
alt.dark = hslToHex([h, 5, 88]);
|
|
375
322
|
alt.surface = hslToHex([h, 12, 18]);
|
|
376
323
|
alt.background = hslToHex([h, 10, 14]);
|
|
377
324
|
} else {
|
|
378
|
-
// Page surface is dark → alternate needs light surfaces
|
|
379
325
|
alt.light = hslToHex([h, Math.min(priHsl[1], 10), 96]);
|
|
380
326
|
alt.dark = hslToHex([h, 10, 18]);
|
|
381
327
|
alt.surface = hslToHex([h, 8, 96]);
|
|
382
328
|
alt.background = hslToHex([h, 6, 98]);
|
|
383
329
|
}
|
|
384
330
|
|
|
385
|
-
// Semantic colors: harmonize toward primary, then invert for alternate
|
|
386
331
|
var amt = config.harmonize !== undefined ? config.harmonize : 0.20;
|
|
387
332
|
var semanticDefaults = {
|
|
388
333
|
success: '#198754', danger: '#dc3545',
|
|
@@ -396,7 +341,6 @@ export function deriveAlternateConfig(config) {
|
|
|
396
341
|
alt[key] = deriveAlternateSeed(harmonized);
|
|
397
342
|
}
|
|
398
343
|
|
|
399
|
-
// Semantic colors are already harmonized+inverted — don't re-harmonize in derivePalette
|
|
400
344
|
alt.harmonize = 0;
|
|
401
345
|
|
|
402
346
|
return alt;
|
|
@@ -404,8 +348,6 @@ export function deriveAlternateConfig(config) {
|
|
|
404
348
|
|
|
405
349
|
/**
|
|
406
350
|
* Derive complete palette from a theme config object.
|
|
407
|
-
* Semantic colors are harmonized toward the primary hue (configurable).
|
|
408
|
-
* Light/dark surface colors are tinted with the primary hue.
|
|
409
351
|
* @param {Object} config - Theme config with primary, secondary, tertiary, etc.
|
|
410
352
|
* @param {number} [config.harmonize=0.20] - Hue shift amount for semantic colors (0-1)
|
|
411
353
|
* @returns {Object} Full palette with shades for all 9 semantic colors
|
|
@@ -413,37 +355,31 @@ export function deriveAlternateConfig(config) {
|
|
|
413
355
|
export function derivePalette(config) {
|
|
414
356
|
var amt = config.harmonize !== undefined ? config.harmonize : 0.20;
|
|
415
357
|
var pri = config.primary;
|
|
358
|
+
var sec = config.secondary || pri;
|
|
359
|
+
var ter = config.tertiary || pri;
|
|
416
360
|
var priHsl = hexToHsl(pri);
|
|
417
361
|
var h = priHsl[0];
|
|
418
362
|
|
|
419
|
-
// Semantic defaults — harmonized toward primary hue
|
|
420
363
|
var successBase = harmonize(config.success || '#198754', pri, amt);
|
|
421
364
|
var dangerBase = harmonize(config.danger || '#dc3545', pri, amt);
|
|
422
365
|
var warningBase = harmonize(config.warning || '#f0ad4e', pri, amt);
|
|
423
366
|
var infoBase = harmonize(config.info || '#17a2b8', pri, amt);
|
|
424
367
|
|
|
425
|
-
// Light/dark: derive from primary hue with low saturation (if not user-supplied)
|
|
426
368
|
var lightBase = config.light || hslToHex([h, 8, 97]);
|
|
427
369
|
var darkBase = config.dark || hslToHex([h, 10, 13]);
|
|
428
370
|
|
|
429
|
-
// Background & surface tokens — tinted with primary hue for theme personality.
|
|
430
|
-
// Saturation high enough that the hue is visible (each theme feels distinct)
|
|
431
|
-
// but low enough to stay neutral and readable.
|
|
432
|
-
// User can override with config.background / config.surface.
|
|
433
371
|
var bgBase = config.background || hslToHex([h, 22, 96]);
|
|
434
372
|
var surfBase = config.surface || hslToHex([h, 25, 94]);
|
|
435
373
|
|
|
436
|
-
// surfaceAlt: subtle background variant for striped rows, hover states, headers.
|
|
437
|
-
// Slightly lighter than surface in dark mode, slightly darker in light mode.
|
|
438
374
|
var surfHsl = hexToHsl(surfBase);
|
|
439
375
|
var surfAlt = surfHsl[2] <= 50
|
|
440
376
|
? hslToHex([surfHsl[0], surfHsl[1], Math.min(surfHsl[2] + 8, 100)])
|
|
441
377
|
: hslToHex([surfHsl[0], surfHsl[1], Math.max(surfHsl[2] - 3, 0)]);
|
|
442
378
|
|
|
443
379
|
var palette = {
|
|
444
|
-
primary: deriveShades(
|
|
445
|
-
secondary: deriveShades(
|
|
446
|
-
tertiary: deriveShades(
|
|
380
|
+
primary: deriveShades(pri),
|
|
381
|
+
secondary: deriveShades(sec),
|
|
382
|
+
tertiary: deriveShades(ter),
|
|
447
383
|
success: deriveShades(successBase),
|
|
448
384
|
danger: deriveShades(dangerBase),
|
|
449
385
|
warning: deriveShades(warningBase),
|
|
@@ -40,7 +40,7 @@ export function bindFileOps(bw) {
|
|
|
40
40
|
} else {
|
|
41
41
|
var blob = new Blob([data], { type: "application/octet-stream" });
|
|
42
42
|
var url = window.URL.createObjectURL(blob);
|
|
43
|
-
var a = bw.
|
|
43
|
+
var a = bw.create({
|
|
44
44
|
t: 'a',
|
|
45
45
|
a: {
|
|
46
46
|
href: url,
|
|
@@ -144,7 +144,7 @@ export function bindFileOps(bw) {
|
|
|
144
144
|
return;
|
|
145
145
|
}
|
|
146
146
|
|
|
147
|
-
var input = bw.
|
|
147
|
+
var input = bw.create({
|
|
148
148
|
t: 'input',
|
|
149
149
|
a: {
|
|
150
150
|
type: 'file',
|
package/src/bitwrench-lean.js
CHANGED
|
@@ -7,8 +7,9 @@
|
|
|
7
7
|
*
|
|
8
8
|
* Includes: HTML/DOM generation, CSS generation, color utilities,
|
|
9
9
|
* state management, pub/sub, file I/O, random/lorem,
|
|
10
|
-
* cookies, URL params, logging, makeTable,
|
|
11
|
-
*
|
|
12
|
-
*
|
|
10
|
+
* cookies, URL params, logging, makeTable, makeTableFromArray,
|
|
11
|
+
* makeDataTable, makeBarChart.
|
|
12
|
+
* Excludes: BCCL component helpers from bitwrench-bccl.js
|
|
13
|
+
* (makeButton, makeCard, makeAlert, makeTabs, makeModal, etc.)
|
|
13
14
|
*/
|
|
14
15
|
export { default } from './bitwrench.js';
|
package/src/bitwrench-router.js
CHANGED
|
@@ -130,7 +130,8 @@ export function initRouter(bw) {
|
|
|
130
130
|
return p + s;
|
|
131
131
|
}
|
|
132
132
|
|
|
133
|
-
function handleRoute(toRaw,
|
|
133
|
+
function handleRoute(toRaw, _opts) {
|
|
134
|
+
/* c8 ignore next -- all callers (navigate, onHashChange, onPopState) check destroyed first */
|
|
134
135
|
if (destroyed) return;
|
|
135
136
|
var fromPath = currentPath;
|
|
136
137
|
var toPath = normalizePath(toRaw);
|
|
@@ -180,6 +181,7 @@ export function initRouter(bw) {
|
|
|
180
181
|
window.location.hash = path;
|
|
181
182
|
}
|
|
182
183
|
// hashchange listener will fire handleRoute; but if same hash, trigger manually
|
|
184
|
+
/* c8 ignore next -- fallback for bare '#' hash; navigate always sets a path */
|
|
183
185
|
var currentHash = window.location.hash.replace(/^#/, '') || '/';
|
|
184
186
|
if (normalizePath(currentHash) === normalizePath(path)) {
|
|
185
187
|
handleRoute(path, opts);
|
|
@@ -196,11 +198,13 @@ export function initRouter(bw) {
|
|
|
196
198
|
}
|
|
197
199
|
|
|
198
200
|
function onHashChange() {
|
|
201
|
+
/* c8 ignore next -- destroy() removes the hashchange listener; belt-and-suspenders guard */
|
|
199
202
|
if (destroyed) return;
|
|
200
203
|
handleRoute(getPath());
|
|
201
204
|
}
|
|
202
205
|
|
|
203
206
|
function onPopState() {
|
|
207
|
+
/* c8 ignore next -- destroy() removes the popstate listener; belt-and-suspenders guard */
|
|
204
208
|
if (destroyed) return;
|
|
205
209
|
handleRoute(getPath());
|
|
206
210
|
}
|
|
@@ -259,7 +263,6 @@ export function initRouter(bw) {
|
|
|
259
263
|
}
|
|
260
264
|
if (_activeRouter) {
|
|
261
265
|
// determine href based on mode -- check hash by looking at current location
|
|
262
|
-
var isHash = window.location.hash !== undefined; // always true, but we default hash
|
|
263
266
|
a.href = '#' + path;
|
|
264
267
|
} else {
|
|
265
268
|
a.href = path;
|