twiddle-panel 0.9.0 → 0.9.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -2
- package/dist/twiddle.js +74 -71
- package/dist/twiddle.mjs +671 -667
- package/package.json +1 -1
package/dist/twiddle.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
const Ct = /* @__PURE__ */ new Set();
|
|
2
|
-
let
|
|
2
|
+
let M = ya(), oe = [], Ee = [], Ze = null, gn = 0;
|
|
3
3
|
function ya() {
|
|
4
4
|
const e = new URLSearchParams(location.search).get("twd");
|
|
5
5
|
if (!e) return {};
|
|
@@ -11,15 +11,15 @@ function ya() {
|
|
|
11
11
|
}
|
|
12
12
|
function ka() {
|
|
13
13
|
const e = new URL(location.href);
|
|
14
|
-
Object.keys(
|
|
14
|
+
Object.keys(M).length ? e.searchParams.set("twd", JSON.stringify(M)) : e.searchParams.delete("twd"), history.replaceState(history.state, "", e);
|
|
15
15
|
}
|
|
16
16
|
function Rt() {
|
|
17
|
-
ka(), Ct.forEach((e) => e(
|
|
17
|
+
ka(), Ct.forEach((e) => e(M));
|
|
18
18
|
}
|
|
19
19
|
function re(e, t) {
|
|
20
|
-
if (JSON.stringify(e) === JSON.stringify(
|
|
20
|
+
if (JSON.stringify(e) === JSON.stringify(M)) return;
|
|
21
21
|
const n = Date.now();
|
|
22
|
-
t && t === Ze && n - gn < 400 || (oe.push(
|
|
22
|
+
t && t === Ze && n - gn < 400 || (oe.push(M), oe.length > 100 && oe.shift()), Ee = [], Ze = t, gn = n, M = e, Rt();
|
|
23
23
|
}
|
|
24
24
|
function Te(e, t) {
|
|
25
25
|
const n = { ...e, ...t };
|
|
@@ -32,51 +32,51 @@ function I(e, t, n) {
|
|
|
32
32
|
return n == null ? delete a[t] : a[t] = n, a;
|
|
33
33
|
}
|
|
34
34
|
function Mt() {
|
|
35
|
-
return JSON.parse(JSON.stringify(
|
|
35
|
+
return JSON.parse(JSON.stringify(M));
|
|
36
36
|
}
|
|
37
37
|
function Sa(e, t) {
|
|
38
|
-
re(I(
|
|
38
|
+
re(I(M, e, Te(M[e], t)), `${e}:${Object.keys(t)}`);
|
|
39
39
|
}
|
|
40
40
|
function $a(e, t = `multi:${Object.keys(e)}`) {
|
|
41
|
-
const n = Object.entries(e).reduce((a, [o, r]) => I(a, o, Te(a[o], r)),
|
|
41
|
+
const n = Object.entries(e).reduce((a, [o, r]) => I(a, o, Te(a[o], r)), M);
|
|
42
42
|
re(n, t);
|
|
43
43
|
}
|
|
44
|
-
function
|
|
45
|
-
const a = I(
|
|
46
|
-
re(I(
|
|
44
|
+
function In(e, t, n) {
|
|
45
|
+
const a = I(M.scopes?.[e], t, Te(M.scopes?.[e]?.[t], n)), o = I(M.scopes, e, Object.keys(a).length ? a : null);
|
|
46
|
+
re(I(M, "scopes", Object.keys(o).length ? o : null), `${e}|${t}:${Object.keys(n)}`);
|
|
47
47
|
}
|
|
48
48
|
function Ea(e, t, n = `multi:${Object.keys(t)}`) {
|
|
49
|
-
const a = Object.entries(t).reduce((r, [s, i]) => I(r, s, Te(r?.[s], i)),
|
|
50
|
-
re(I(
|
|
49
|
+
const a = Object.entries(t).reduce((r, [s, i]) => I(r, s, Te(r?.[s], i)), M.scopes?.[e]), o = I(M.scopes, e, Object.keys(a).length ? a : null);
|
|
50
|
+
re(I(M, "scopes", Object.keys(o).length ? o : null), `${e}|${n}`);
|
|
51
51
|
}
|
|
52
52
|
function Ca(e, t) {
|
|
53
|
-
if (t) return
|
|
54
|
-
Object.keys(
|
|
53
|
+
if (t) return In(e, t, Object.fromEntries(
|
|
54
|
+
Object.keys(M.scopes?.[e]?.[t] || {}).map((a) => [a, null])
|
|
55
55
|
));
|
|
56
|
-
const n = I(
|
|
57
|
-
re(I(
|
|
56
|
+
const n = I(M.scopes, e, null);
|
|
57
|
+
re(I(M, "scopes", Object.keys(n).length ? n : null));
|
|
58
58
|
}
|
|
59
59
|
function Ma(e, t) {
|
|
60
|
-
const n =
|
|
60
|
+
const n = M.scopes?.[e];
|
|
61
61
|
if (!n || e === t) return;
|
|
62
|
-
let a = { ...
|
|
62
|
+
let a = { ...M.scopes[t] };
|
|
63
63
|
Object.entries(n).forEach(([r, s]) => {
|
|
64
64
|
a = I(a, r, Te(a[r], s));
|
|
65
65
|
});
|
|
66
|
-
const o = I(I(
|
|
67
|
-
re(I(
|
|
66
|
+
const o = I(I(M.scopes, e, null), t, a);
|
|
67
|
+
re(I(M, "scopes", o));
|
|
68
68
|
}
|
|
69
|
-
function
|
|
69
|
+
function Dn() {
|
|
70
70
|
re({});
|
|
71
71
|
}
|
|
72
|
-
function
|
|
73
|
-
oe.length && (Ee.push(
|
|
72
|
+
function Bn() {
|
|
73
|
+
oe.length && (Ee.push(M), M = oe.pop(), Ze = null, Rt());
|
|
74
74
|
}
|
|
75
|
-
function
|
|
76
|
-
Ee.length && (oe.push(
|
|
75
|
+
function Un() {
|
|
76
|
+
Ee.length && (oe.push(M), M = Ee.pop(), Ze = null, Rt());
|
|
77
77
|
}
|
|
78
78
|
const Ta = () => oe.length > 0, La = () => Ee.length > 0;
|
|
79
|
-
function
|
|
79
|
+
function Vn(e) {
|
|
80
80
|
return Ct.add(e), () => Ct.delete(e);
|
|
81
81
|
}
|
|
82
82
|
const Aa = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
|
|
@@ -85,21 +85,21 @@ const Aa = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
|
|
|
85
85
|
canUndo: Ta,
|
|
86
86
|
getState: Mt,
|
|
87
87
|
moveScope: Ma,
|
|
88
|
-
onChange:
|
|
89
|
-
redo:
|
|
88
|
+
onChange: Vn,
|
|
89
|
+
redo: Un,
|
|
90
90
|
removeScope: Ca,
|
|
91
|
-
resetState:
|
|
92
|
-
setScope:
|
|
91
|
+
resetState: Dn,
|
|
92
|
+
setScope: In,
|
|
93
93
|
setScopeSections: Ea,
|
|
94
94
|
setSection: Sa,
|
|
95
95
|
setSections: $a,
|
|
96
|
-
undo:
|
|
97
|
-
}, Symbol.toStringTag, { value: "Module" })),
|
|
98
|
-
function
|
|
96
|
+
undo: Bn
|
|
97
|
+
}, Symbol.toStringTag, { value: "Module" })), qn = ':root{--twd-font-heading: ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;--twd-font-body: ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;--twd-text-xs: .694rem;--twd-text-sm: .833rem;--twd-text-base: 1rem;--twd-text-lg: 1.2rem;--twd-text-xl: 1.44rem;--twd-text-2xl: 1.728rem;--twd-text-3xl: 2.074rem;--twd-leading-tight: 1.2;--twd-leading-normal: 1.5;--twd-weight-heading: 600;--twd-weight-strong: 600;--twd-bg: #fafafa;--twd-surface: #ffffff;--twd-surface-raised: #ffffff;--twd-text: #18181b;--twd-text-muted: #71717a;--twd-border: #e4e4e7;--twd-primary: #4f46e5;--twd-primary-hover: #4338ca;--twd-on-primary: #ffffff;--twd-focus: #6366f1;--twd-success: #16a34a;--twd-warning: #d97706;--twd-danger: #dc2626;--twd-radius-control: 8px;--twd-radius-container: 12px;--twd-space-1: 4px;--twd-space-2: 8px;--twd-space-3: 12px;--twd-space-4: 16px;--twd-space-5: 24px;--twd-space-6: 32px;--twd-space-7: 48px;--twd-space-8: 64px;--twd-control-height: 40px;--twd-control-pad-x: 16px;--twd-page-pad: var(--twd-space-5);--twd-section-gap: var(--twd-space-6);--twd-card-pad: var(--twd-space-5);--twd-card-gap: var(--twd-space-2);--twd-control-gap: var(--twd-space-3);--twd-border-width: 1px;--twd-border-width-container: var(--twd-border-width);--twd-shadow-sm: 0 1px 2px rgb(0 0 0 / .06);--twd-shadow-md: 0 4px 12px rgb(0 0 0 / .08);--twd-shadow-lg: 0 12px 32px rgb(0 0 0 / .12);--twd-button-bg: var(--twd-primary);--twd-button-fg: var(--twd-on-primary);--twd-button-border: transparent;--twd-button-hover: var(--twd-primary-hover);--twd-card-bg: var(--twd-surface);--twd-card-border: var(--twd-border);--twd-card-shadow: var(--twd-shadow-sm)}', Pa = [...qn.matchAll(/(--twd-[\w-]+):\s*([^;]*var\(--twd-[^;]*);/g)].map((e) => [e[1], e[2].trim()]);
|
|
98
|
+
function Oa(e) {
|
|
99
99
|
const t = document.documentElement, n = document.createElement("div");
|
|
100
100
|
n.hidden = !0, t.appendChild(n);
|
|
101
101
|
const a = getComputedStyle(t), o = getComputedStyle(n), r = [];
|
|
102
|
-
return
|
|
102
|
+
return Pa.forEach(([s, i]) => {
|
|
103
103
|
const l = e[s];
|
|
104
104
|
if (l != null) {
|
|
105
105
|
String(l).includes("var(") && r.push([s, l]);
|
|
@@ -108,12 +108,12 @@ function Pa(e) {
|
|
|
108
108
|
n.style.setProperty("--twd-probe", i), o.getPropertyValue("--twd-probe").trim() === a.getPropertyValue(s).trim() && r.push([s, i]);
|
|
109
109
|
}), n.remove(), r;
|
|
110
110
|
}
|
|
111
|
-
const
|
|
112
|
-
let Tt = [], zt = {}, R = null, fe = !1,
|
|
113
|
-
function
|
|
114
|
-
typeof e == "function" &&
|
|
111
|
+
const Hn = [];
|
|
112
|
+
let Tt = [], zt = {}, R = null, fe = !1, _n = {};
|
|
113
|
+
function ja(e) {
|
|
114
|
+
typeof e == "function" && Hn.push(e);
|
|
115
115
|
}
|
|
116
|
-
const
|
|
116
|
+
const mn = (e) => Object.assign({}, ...Hn.map((t) => t(e) || {})), Lt = (e) => /^(\.[\w-]+|\[data-twd="[^"]+"\])$/.test(e), Fa = (e) => {
|
|
117
117
|
try {
|
|
118
118
|
return document.querySelector(e), !0;
|
|
119
119
|
} catch {
|
|
@@ -123,15 +123,15 @@ const bn = (e) => Object.assign({}, ..._n.map((t) => t(e) || {})), Lt = (e) => /
|
|
|
123
123
|
function Na() {
|
|
124
124
|
return (!R || !R.isConnected) && (R = document.createElement("style"), R.id = "twiddle-scoped", document.head.appendChild(R)), R;
|
|
125
125
|
}
|
|
126
|
-
function
|
|
126
|
+
function Kn() {
|
|
127
127
|
const e = document.documentElement;
|
|
128
128
|
Tt.forEach((t) => e.style.removeProperty(t)), Tt = [], zt = {};
|
|
129
129
|
}
|
|
130
130
|
function At(e) {
|
|
131
|
-
if (
|
|
131
|
+
if (_n = e, fe) return;
|
|
132
132
|
const t = document.documentElement;
|
|
133
|
-
|
|
134
|
-
const n =
|
|
133
|
+
Kn();
|
|
134
|
+
const n = mn(e), a = e.scopes ? Oa(n) : [], o = Object.entries(e.scopes || {}).filter(([s]) => Fa(s)).sort(([s], [i]) => Lt(i) - Lt(s)).map(([s, i]) => [s, mn(i)]);
|
|
135
135
|
Object.entries(n).forEach(([s, i]) => t.style.setProperty(s, i)), Tt = Object.keys(n), zt = n;
|
|
136
136
|
const r = o.filter(([, s]) => Object.keys(s).length).map(([s, i]) => `${s} {
|
|
137
137
|
${[
|
|
@@ -144,7 +144,7 @@ ${[
|
|
|
144
144
|
`);
|
|
145
145
|
(r || R) && (Na().textContent = r);
|
|
146
146
|
}
|
|
147
|
-
function
|
|
147
|
+
function Wn(e) {
|
|
148
148
|
const t = document.documentElement, n = fe, a = { ...zt };
|
|
149
149
|
Object.keys(a).forEach((o) => t.style.removeProperty(o)), R && (R.disabled = !0);
|
|
150
150
|
try {
|
|
@@ -154,16 +154,16 @@ function Gn(e) {
|
|
|
154
154
|
}
|
|
155
155
|
}
|
|
156
156
|
function Ra(e, t = document.documentElement) {
|
|
157
|
-
return
|
|
157
|
+
return Wn(() => {
|
|
158
158
|
const n = getComputedStyle(t);
|
|
159
159
|
return Object.fromEntries(e.map((a) => [a, n.getPropertyValue(a).trim()]));
|
|
160
160
|
});
|
|
161
161
|
}
|
|
162
162
|
function za() {
|
|
163
|
-
fe || (
|
|
163
|
+
fe || (Kn(), R && (R.disabled = !0), fe = !0);
|
|
164
164
|
}
|
|
165
165
|
function Ia() {
|
|
166
|
-
fe && (fe = !1, R && (R.disabled = !1), At(
|
|
166
|
+
fe && (fe = !1, R && (R.disabled = !1), At(_n));
|
|
167
167
|
}
|
|
168
168
|
const Da = `
|
|
169
169
|
:host { all: initial; } /* block fonts/colours inherited from the page */
|
|
@@ -909,32 +909,35 @@ const Da = `
|
|
|
909
909
|
.sketch i { height: 9px; border-radius: 2px; background: var(--p-line); }
|
|
910
910
|
.sketch i:first-child { background: var(--p-muted); }
|
|
911
911
|
.shape { display: block; }
|
|
912
|
-
|
|
913
|
-
.shape-button
|
|
914
|
-
.shape-button.size-
|
|
915
|
-
.shape-button.size-
|
|
912
|
+
/* Live previews: --pv-* come from the page (panel.js syncPreviews); fallbacks = defaults. */
|
|
913
|
+
.shape-button { width: 52px; height: 24px; background: var(--pv-primary, #4f46e5); }
|
|
914
|
+
.shape-button.size-small { width: 38px; height: 16px; border-radius: min(var(--pv-radius-control, 8px), 8px); }
|
|
915
|
+
.shape-button.size-medium { width: 52px; height: 22px; border-radius: min(var(--pv-radius-control, 8px), 11px); }
|
|
916
|
+
.shape-button.size-large { width: 66px; height: 28px; border-radius: min(var(--pv-radius-control, 8px), 14px); }
|
|
916
917
|
.shape-card { width: 52px; height: 38px; background: var(--p-bg); border: 1px solid var(--p-muted); }
|
|
917
|
-
.shape-card
|
|
918
|
-
.shape-card.border-
|
|
919
|
-
.shape-card.border-thick { border-width: 2px;
|
|
920
|
-
/*
|
|
921
|
-
.shape-button[class*="style-"] { width: 52px; height: 22px; border-radius:
|
|
922
|
-
.shape-button[class*="style-"]::after { content: ""; width: 22px; height: 3px; border-radius: 2px; background: #
|
|
923
|
-
.shape-button.style-solid::after { background: #fff; }
|
|
924
|
-
.shape-button.style-soft { background:
|
|
925
|
-
.shape-button.style-outline { background: transparent; border-color: #
|
|
918
|
+
.shape-card[class*="border-"] { border-radius: min(calc(var(--pv-radius-container, 12px) / 2), 10px); }
|
|
919
|
+
.shape-card.border-none { border-color: transparent; background: var(--p-hover); }
|
|
920
|
+
.shape-card.border-thick { border-width: 2px; }
|
|
921
|
+
/* Button style tiles (Figma 281:1158) */
|
|
922
|
+
.shape-button[class*="style-"] { width: 52px; height: 22px; border-radius: min(var(--pv-radius-control, 8px), 11px); display: grid; place-items: center; border: 1.5px solid transparent; }
|
|
923
|
+
.shape-button[class*="style-"]::after { content: ""; width: 22px; height: 3px; border-radius: 2px; background: color-mix(in srgb, var(--pv-primary, #4f46e5) 55%, white); }
|
|
924
|
+
.shape-button.style-solid::after { background: var(--pv-on-primary, #fff); }
|
|
925
|
+
.shape-button.style-soft { background: color-mix(in srgb, var(--pv-primary, #4f46e5) 32%, transparent); }
|
|
926
|
+
.shape-button.style-outline { background: transparent; border-color: color-mix(in srgb, var(--pv-primary, #4f46e5) 70%, white); }
|
|
926
927
|
.shape-button.style-ghost { background: transparent; }
|
|
927
|
-
|
|
928
|
-
.
|
|
929
|
-
.
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
.
|
|
935
|
-
.
|
|
936
|
-
.
|
|
937
|
-
.
|
|
928
|
+
/* Card style tiles: a mini card with content lines on a page backdrop (Figma 281:1421) */
|
|
929
|
+
.mini { display: grid; place-items: center; width: 60px; height: 42px; border-radius: 6px; background: var(--p-hover); }
|
|
930
|
+
.mini-card {
|
|
931
|
+
width: 44px; height: 28px; padding: 0 7px; box-sizing: border-box;
|
|
932
|
+
display: grid; align-content: center; gap: 4px;
|
|
933
|
+
border: 1px solid transparent; border-radius: min(calc(var(--pv-radius-container, 12px) / 2), 10px);
|
|
934
|
+
}
|
|
935
|
+
.mini-card i { display: block; width: 22px; height: 3px; border-radius: 2px; background: #a1a1aa; }
|
|
936
|
+
.mini-card i + i { width: 30px; background: #71717a; }
|
|
937
|
+
.mini-card.style-filled { background: #3f3f46; border-color: #52525b; }
|
|
938
|
+
.mini-card.style-outlined { background: transparent; border-color: #a1a1aa; }
|
|
939
|
+
.mini-card.style-elevated { background: #52525b; box-shadow: 0 4px 8px rgb(0 0 0 / 0.7); }
|
|
940
|
+
.mini-card.style-tinted { background: color-mix(in srgb, var(--pv-primary, #6366f1) 30%, transparent); border-color: color-mix(in srgb, var(--pv-primary, #6366f1) 70%, white); }
|
|
938
941
|
.shape-card[class*="shadow-"] { width: 44px; height: 32px; border-radius: 6px; border-color: var(--p-line); margin: 4px 0 6px; }
|
|
939
942
|
.shape-card.shadow-bold { border-color: var(--p-fg); }
|
|
940
943
|
|
|
@@ -985,91 +988,91 @@ const Da = `
|
|
|
985
988
|
.summary-swatch { width: 14px; height: 14px; border-radius: 4px; flex: none; }
|
|
986
989
|
.summary-swatch[hidden] { display: none; }
|
|
987
990
|
.summary-row .chev { display: grid; color: var(--p-muted); }
|
|
988
|
-
`,
|
|
989
|
-
dial:
|
|
990
|
-
link:
|
|
991
|
-
reset:
|
|
992
|
-
close:
|
|
993
|
-
chevron:
|
|
991
|
+
`, A = (e, t, n) => `<svg width="${e}" height="${e}" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="${t}" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">${n}</svg>`, P = {
|
|
992
|
+
dial: A(20, 1.8, '<circle cx="12" cy="12" r="8"/><path d="M12 12l4-4"/><path d="M12 2v2M12 20v2M2 12h2M20 12h2"/>'),
|
|
993
|
+
link: A(15, 2, '<path d="M10 13a5 5 0 0 0 7.07 0l3-3a5 5 0 0 0-7.07-7.07l-1 1"/><path d="M14 11a5 5 0 0 0-7.07 0l-3 3a5 5 0 0 0 7.07 7.07l1-1"/>'),
|
|
994
|
+
reset: A(15, 2, '<path d="M3 12a9 9 0 1 0 3-6.7"/><path d="M3 3v6h6"/>'),
|
|
995
|
+
close: A(15, 2, '<path d="M18 6L6 18M6 6l12 12"/>'),
|
|
996
|
+
chevron: A(12, 2.4, '<path d="M9 6l6 6-6 6"/>'),
|
|
994
997
|
// Proposals: not yet in the Figma Icon/* set.
|
|
995
998
|
// Figma: Icon/Cursor (39:313), the header's Pick button.
|
|
996
|
-
pick:
|
|
997
|
-
compare:
|
|
998
|
-
undo:
|
|
999
|
-
redo:
|
|
1000
|
-
back:
|
|
1001
|
-
down:
|
|
1002
|
-
minimise:
|
|
999
|
+
pick: A(15, 2, '<path d="M17.202 10.5576C17.6738 10.3035 17.9098 10.1765 17.9694 10.0236C18.0212 9.89097 18.0066 9.74158 17.9301 9.6215C17.8419 9.48312 17.5858 9.40424 17.0737 9.24647L7.05204 6.15943C6.63366 6.03055 6.42447 5.96611 6.28318 6.01796C6.16011 6.06312 6.06312 6.16011 6.01796 6.28317C5.96611 6.42446 6.03055 6.63365 6.15943 7.05204L9.24645 17.0737C9.40422 17.5858 9.4831 17.8419 9.62147 17.9301C9.74156 18.0066 9.89095 18.0212 10.0236 17.9694C10.1764 17.9098 10.3035 17.6738 10.5576 17.202L12.7816 13.0717C12.8193 13.0016 12.8382 12.9666 12.8625 12.9359C12.884 12.9086 12.9086 12.884 12.9359 12.8624C12.9666 12.8382 13.0016 12.8193 13.0717 12.7816L17.202 10.5576Z"/>'),
|
|
1000
|
+
compare: A(15, 2, '<circle cx="12" cy="12" r="9"/><path d="M12 3v18" /><path d="M12 3a9 9 0 0 0 0 18z" fill="currentColor" stroke="none"/>'),
|
|
1001
|
+
undo: A(15, 2, '<path d="M9 14L4 9l5-5"/><path d="M4 9h11a5 5 0 0 1 0 10h-3"/>'),
|
|
1002
|
+
redo: A(15, 2, '<path d="M15 14l5-5-5-5"/><path d="M20 9H9a5 5 0 0 0 0 10h3"/>'),
|
|
1003
|
+
back: A(15, 2, '<path d="M15 18l-6-6 6-6"/>'),
|
|
1004
|
+
down: A(12, 2.4, '<path d="M6 9l6 6 6-6"/>'),
|
|
1005
|
+
minimise: A(15, 2, '<path d="M6 9l6 6 6-6"/>'),
|
|
1003
1006
|
// chevron at the end of the tab bar; flips to ˄ when minimised (Ravi, 2026-10-16)
|
|
1004
|
-
changes:
|
|
1005
|
-
copy:
|
|
1006
|
-
warn:
|
|
1007
|
+
changes: A(15, 2, '<path d="M9 6h11M9 12h11M9 18h11"/><path d="M4.5 6h.01M4.5 12h.01M4.5 18h.01"/>'),
|
|
1008
|
+
copy: A(13, 2, '<rect x="9" y="9" width="11" height="11" rx="2"/><path d="M5 15V5a2 2 0 0 1 2-2h10"/>'),
|
|
1009
|
+
warn: A(13, 2, '<path d="M12 3l9.5 17h-19z"/><path d="M12 10v4M12 17.5v.01"/>'),
|
|
1007
1010
|
// Launcher: the Panel product mark (Twiddle brand; Figma Logo page › Panel mark; also site/favicon.svg).
|
|
1008
1011
|
// A switch knocked out of a disc; knob + two-dot trail. Classes let the Toggle animation move them.
|
|
1009
1012
|
panelMark: '<svg class="mark" width="44" height="44" viewBox="0 0 120 120" aria-hidden="true"><path class="mark-disc" fill-rule="evenodd" clip-rule="evenodd" d="M60 120C93.1371 120 120 93.1371 120 60C120 26.8629 93.1371 0 60 0C26.8629 0 0 26.8629 0 60C0 93.1371 26.8629 120 60 120ZM86 76C86 90.3594 74.3594 102 60 102C45.6406 102 34 90.3594 34 76V44C34 29.6406 45.6406 18 60 18C74.3594 18 86 29.6406 86 44V76ZM60 22C72.1503 22 82 31.8497 82 44V76C82 88.1503 72.1503 98 60 98C47.8497 98 38 88.1503 38 76V44C38 31.8497 47.8497 22 60 22Z"/><circle class="mark-t2" cx="60" cy="80.46" r="4.28"/><circle class="mark-t1" cx="60" cy="66.04" r="7.14"/><circle class="mark-knob" cx="60" cy="44" r="11.9"/></svg>',
|
|
1010
1013
|
// Tab bar (Figma: Panel — tabbed layout (proposal), Icon/Tab * components)
|
|
1011
|
-
tabOverview:
|
|
1012
|
-
tabColour:
|
|
1013
|
-
tabType:
|
|
1014
|
-
tabSpacing:
|
|
1015
|
-
tabShape:
|
|
1016
|
-
tabShadows:
|
|
1017
|
-
sliders:
|
|
1014
|
+
tabOverview: A(18, 1.8, '<circle cx="12" cy="12" r="8"/><path d="M12 12l4-4"/><path d="M12 2v2M12 20v2M2 12h2M20 12h2"/>'),
|
|
1015
|
+
tabColour: A(18, 2, '<path d="M12 3c-3.5 4.5-6 7.8-6 11a6 6 0 0 0 12 0c0-3.2-2.5-6.5-6-11z"/>'),
|
|
1016
|
+
tabType: A(18, 2, '<path d="M5 7V5h14v2"/><path d="M12 5v14"/><path d="M9 19h6"/>'),
|
|
1017
|
+
tabSpacing: A(18, 2, '<path d="M4 5v14M20 5v14"/><path d="M8 12h8"/><path d="M10 9l-3 3 3 3M14 9l3 3-3 3"/>'),
|
|
1018
|
+
tabShape: A(18, 2, '<path d="M20 4h-9a7 7 0 0 0-7 7v9"/><path d="M20 10h-5a5 5 0 0 0-5 5v5"/>'),
|
|
1019
|
+
tabShadows: A(18, 2, '<rect x="4" y="4" width="12" height="12" rx="2"/><path d="M20 8v10a2 2 0 0 1-2 2H8"/>'),
|
|
1020
|
+
sliders: A(15, 2, '<path d="M4 7h10M18 7h2M4 17h4M12 17h8"/><circle cx="16" cy="7" r="2"/><circle cx="10" cy="17" r="2"/>')
|
|
1018
1021
|
// Figma: Icon/Sliders (proposal)
|
|
1019
|
-
},
|
|
1022
|
+
}, Gn = "twiddle:";
|
|
1020
1023
|
function ne(e) {
|
|
1021
1024
|
try {
|
|
1022
|
-
return localStorage.getItem(
|
|
1025
|
+
return localStorage.getItem(Gn + e);
|
|
1023
1026
|
} catch {
|
|
1024
1027
|
return null;
|
|
1025
1028
|
}
|
|
1026
1029
|
}
|
|
1027
1030
|
function ce(e, t) {
|
|
1028
1031
|
try {
|
|
1029
|
-
localStorage.setItem(
|
|
1032
|
+
localStorage.setItem(Gn + e, t);
|
|
1030
1033
|
} catch {
|
|
1031
1034
|
}
|
|
1032
1035
|
}
|
|
1033
|
-
const pe = 44, de = 8, Ba = 4,
|
|
1036
|
+
const pe = 44, de = 8, Ba = 4, Yn = { corner: "br", x: 16, y: 16 };
|
|
1034
1037
|
function Ua() {
|
|
1035
1038
|
try {
|
|
1036
1039
|
const e = JSON.parse(ne("position"));
|
|
1037
1040
|
if (e && /^[tb][lr]$/.test(e.corner) && isFinite(e.x) && isFinite(e.y)) return e;
|
|
1038
1041
|
} catch {
|
|
1039
1042
|
}
|
|
1040
|
-
return { ...
|
|
1043
|
+
return { ...Yn };
|
|
1041
1044
|
}
|
|
1042
|
-
function
|
|
1045
|
+
function bn(e) {
|
|
1043
1046
|
const t = Math.max(de, innerWidth - pe - de), n = Math.max(de, innerHeight - pe - de);
|
|
1044
1047
|
return { corner: e.corner, x: Math.round(Math.min(Math.max(e.x, de), t)), y: Math.round(Math.min(Math.max(e.y, de), n)) };
|
|
1045
1048
|
}
|
|
1046
1049
|
function Va({ wrapEl: e, launcherEl: t }) {
|
|
1047
1050
|
let n = Ua();
|
|
1048
1051
|
function a() {
|
|
1049
|
-
const d =
|
|
1052
|
+
const d = bn(n), p = d.corner[1] === "l", f = d.corner[0] === "t";
|
|
1050
1053
|
Object.assign(e.style, {
|
|
1051
|
-
left:
|
|
1052
|
-
right:
|
|
1053
|
-
top:
|
|
1054
|
-
bottom:
|
|
1055
|
-
}), e.style.setProperty("--off-x", `${d.x}px`), e.style.setProperty("--off-y", `${d.y}px`), e.classList.toggle("at-left",
|
|
1054
|
+
left: p ? `${d.x}px` : "auto",
|
|
1055
|
+
right: p ? "auto" : `${d.x}px`,
|
|
1056
|
+
top: f ? `${d.y}px` : "auto",
|
|
1057
|
+
bottom: f ? "auto" : `${d.y}px`
|
|
1058
|
+
}), e.style.setProperty("--off-x", `${d.x}px`), e.style.setProperty("--off-y", `${d.y}px`), e.classList.toggle("at-left", p), e.classList.toggle("at-top", f);
|
|
1056
1059
|
}
|
|
1057
|
-
function o(d,
|
|
1058
|
-
n =
|
|
1060
|
+
function o(d, p = !0) {
|
|
1061
|
+
n = bn(d), a(), p && ce("position", JSON.stringify(n));
|
|
1059
1062
|
}
|
|
1060
|
-
function r(d,
|
|
1061
|
-
const
|
|
1063
|
+
function r(d, p) {
|
|
1064
|
+
const f = d + pe / 2 < innerWidth / 2, v = p + pe / 2 < innerHeight / 2, u = !v && e.classList.contains("is-open") ? 10 : 0;
|
|
1062
1065
|
return {
|
|
1063
|
-
corner: (
|
|
1064
|
-
x:
|
|
1065
|
-
y:
|
|
1066
|
+
corner: (v ? "t" : "b") + (f ? "l" : "r"),
|
|
1067
|
+
x: f ? d : innerWidth - d - pe,
|
|
1068
|
+
y: v ? p : innerHeight - p - pe - u
|
|
1066
1069
|
};
|
|
1067
1070
|
}
|
|
1068
1071
|
let s = null, i = !1;
|
|
1069
1072
|
t.addEventListener("pointerdown", (d) => {
|
|
1070
1073
|
if (d.button !== 0) return;
|
|
1071
|
-
const
|
|
1072
|
-
s = { id: d.pointerId, sx: d.clientX, sy: d.clientY, dx: d.clientX -
|
|
1074
|
+
const p = t.getBoundingClientRect();
|
|
1075
|
+
s = { id: d.pointerId, sx: d.clientX, sy: d.clientY, dx: d.clientX - p.left, dy: d.clientY - p.top, moving: !1 };
|
|
1073
1076
|
}), t.addEventListener("pointermove", (d) => {
|
|
1074
1077
|
if (!(!s || d.pointerId !== s.id)) {
|
|
1075
1078
|
if (!s.moving) {
|
|
@@ -1083,11 +1086,11 @@ function Va({ wrapEl: e, launcherEl: t }) {
|
|
|
1083
1086
|
!s || d.pointerId !== s.id || (s.moving && (i = !0, e.classList.remove("dragging"), o(n)), s = null);
|
|
1084
1087
|
};
|
|
1085
1088
|
return t.addEventListener("pointerup", l), t.addEventListener("pointercancel", l), t.addEventListener("keydown", (d) => {
|
|
1086
|
-
const
|
|
1087
|
-
if (!
|
|
1089
|
+
const p = { ArrowLeft: [-1, 0], ArrowRight: [1, 0], ArrowUp: [0, -1], ArrowDown: [0, 1] }[d.key];
|
|
1090
|
+
if (!p || d.altKey || d.metaKey || d.ctrlKey) return;
|
|
1088
1091
|
d.preventDefault();
|
|
1089
|
-
const
|
|
1090
|
-
o({ corner: n.corner, x: n.x +
|
|
1092
|
+
const f = d.shiftKey ? 10 : 1, v = n.corner[1] === "l" ? 1 : -1, u = n.corner[0] === "t" ? 1 : -1;
|
|
1093
|
+
o({ corner: n.corner, x: n.x + p[0] * f * v, y: n.y + p[1] * f * u });
|
|
1091
1094
|
}), window.addEventListener("resize", a), a(), {
|
|
1092
1095
|
/** Call from the launcher's click handler: true = ignore this click (it ended a drag). */
|
|
1093
1096
|
consumeClick() {
|
|
@@ -1095,7 +1098,7 @@ function Va({ wrapEl: e, launcherEl: t }) {
|
|
|
1095
1098
|
return i = !1, d;
|
|
1096
1099
|
},
|
|
1097
1100
|
reset() {
|
|
1098
|
-
o({ ...
|
|
1101
|
+
o({ ...Yn });
|
|
1099
1102
|
}
|
|
1100
1103
|
};
|
|
1101
1104
|
}
|
|
@@ -1109,28 +1112,28 @@ function ge({ label: e, options: t, onSelect: n }) {
|
|
|
1109
1112
|
a.append(...o);
|
|
1110
1113
|
let r = null;
|
|
1111
1114
|
function s(l) {
|
|
1112
|
-
r = l, o.forEach((
|
|
1113
|
-
const d = Math.max(0, o.findIndex((
|
|
1114
|
-
o.forEach((
|
|
1115
|
-
|
|
1115
|
+
r = l, o.forEach((p) => p.setAttribute("aria-checked", String(p.dataset.value === l)));
|
|
1116
|
+
const d = Math.max(0, o.findIndex((p) => p.dataset.value === l));
|
|
1117
|
+
o.forEach((p, f) => {
|
|
1118
|
+
p.tabIndex = f === d ? 0 : -1;
|
|
1116
1119
|
});
|
|
1117
1120
|
}
|
|
1118
1121
|
function i(l, d) {
|
|
1119
|
-
l !== r && (s(l), n(l)), d && o.find((
|
|
1122
|
+
l !== r && (s(l), n(l)), d && o.find((p) => p.dataset.value === l).focus();
|
|
1120
1123
|
}
|
|
1121
1124
|
return a.addEventListener("keydown", (l) => {
|
|
1122
1125
|
const d = o.indexOf(l.target);
|
|
1123
1126
|
if (d < 0) return;
|
|
1124
|
-
const
|
|
1125
|
-
let
|
|
1126
|
-
if (
|
|
1127
|
-
else if (l.key === "Home")
|
|
1128
|
-
else if (l.key === "End")
|
|
1127
|
+
const p = { ArrowRight: 1, ArrowDown: 1, ArrowLeft: -1, ArrowUp: -1 }[l.key];
|
|
1128
|
+
let f;
|
|
1129
|
+
if (p) f = (d + p + o.length) % o.length;
|
|
1130
|
+
else if (l.key === "Home") f = 0;
|
|
1131
|
+
else if (l.key === "End") f = o.length - 1;
|
|
1129
1132
|
else return;
|
|
1130
|
-
l.preventDefault(), i(o[
|
|
1133
|
+
l.preventDefault(), i(o[f].dataset.value, !0);
|
|
1131
1134
|
}), s(null), { el: a, setValue: s };
|
|
1132
1135
|
}
|
|
1133
|
-
const
|
|
1136
|
+
const Xn = /var\(\s*(--twd-[\w-]+)/g, qa = /::?[\w-]+(\([^)]*\))?/g;
|
|
1134
1137
|
function* Qe(e) {
|
|
1135
1138
|
for (const t of e)
|
|
1136
1139
|
t.selectorText != null && (yield t), t.cssRules && (yield* Qe(t.cssRules));
|
|
@@ -1146,7 +1149,7 @@ function Ha() {
|
|
|
1146
1149
|
continue;
|
|
1147
1150
|
}
|
|
1148
1151
|
for (const a of Qe(n)) {
|
|
1149
|
-
const o = [...a.style.cssText.matchAll(
|
|
1152
|
+
const o = [...a.style.cssText.matchAll(Xn)].map((r) => r[1]);
|
|
1150
1153
|
o.length && e.push({ selectors: a.selectorText.split(","), vars: o });
|
|
1151
1154
|
}
|
|
1152
1155
|
}
|
|
@@ -1160,33 +1163,33 @@ function _a(e, t) {
|
|
|
1160
1163
|
return !1;
|
|
1161
1164
|
}
|
|
1162
1165
|
}
|
|
1163
|
-
function
|
|
1166
|
+
function Zn(e) {
|
|
1164
1167
|
const t = /* @__PURE__ */ new Set(), n = [];
|
|
1165
1168
|
return Ha().forEach(({ selectors: a, vars: o }) => {
|
|
1166
1169
|
const r = a.find((s) => _a(e, s));
|
|
1167
1170
|
r && (o.forEach((s) => t.add(s)), n.push(r.trim()));
|
|
1168
|
-
}), [...(e.getAttribute("style") || "").matchAll(
|
|
1171
|
+
}), [...(e.getAttribute("style") || "").matchAll(Xn)].forEach((a) => t.add(a[1])), { names: t, selectors: n };
|
|
1169
1172
|
}
|
|
1170
|
-
const
|
|
1173
|
+
const Pt = (e) => window.CSS && CSS.escape ? CSS.escape(e) : e;
|
|
1171
1174
|
function Ka(e) {
|
|
1172
1175
|
const t = [];
|
|
1173
1176
|
let n = e;
|
|
1174
1177
|
for (; n && n.nodeType === 1 && n !== document.body && n !== document.documentElement; ) {
|
|
1175
|
-
if (n.id && document.querySelectorAll(`#${
|
|
1176
|
-
return t.unshift(`#${
|
|
1178
|
+
if (n.id && document.querySelectorAll(`#${Pt(n.id)}`).length === 1)
|
|
1179
|
+
return t.unshift(`#${Pt(n.id)}`), t.join(" > ");
|
|
1177
1180
|
const a = n.localName, o = [...n.parentElement.children].filter((r) => r.localName === a);
|
|
1178
1181
|
t.unshift(o.length > 1 ? `${a}:nth-of-type(${o.indexOf(n) + 1})` : a), n = n.parentElement;
|
|
1179
1182
|
}
|
|
1180
1183
|
return ["body", ...t].join(" > ");
|
|
1181
1184
|
}
|
|
1182
|
-
function Wa(e, t =
|
|
1185
|
+
function Wa(e, t = Zn(e).selectors) {
|
|
1183
1186
|
const n = e.getAttribute("data-twd");
|
|
1184
1187
|
if (n) return `[data-twd="${n.replace(/"/g, "")}"]`;
|
|
1185
1188
|
const a = [...e.classList], r = a.find((s) => t.some((i) => new RegExp(`\\.${s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}(?![\\w-])`).test(i))) || a[0];
|
|
1186
|
-
return r ? `.${
|
|
1189
|
+
return r ? `.${Pt(r)}` : null;
|
|
1187
1190
|
}
|
|
1188
1191
|
function Ga(e) {
|
|
1189
|
-
const t =
|
|
1192
|
+
const t = Zn(e), n = Wa(e, t.selectors), a = (e.getAttribute("aria-label") || e.placeholder || e.textContent || "").trim().replace(/\s+/g, " ");
|
|
1190
1193
|
return {
|
|
1191
1194
|
el: e,
|
|
1192
1195
|
tag: e.localName,
|
|
@@ -1198,9 +1201,9 @@ function Ga(e) {
|
|
|
1198
1201
|
classCount: n ? document.querySelectorAll(n).length : 0
|
|
1199
1202
|
};
|
|
1200
1203
|
}
|
|
1201
|
-
const
|
|
1204
|
+
const Ot = (e) => e.localName + [...e.classList].map((t) => `.${t}`).join(""), Ya = { radius: "px", intensity: "%", base: "px" }, Jn = (e) => e.charAt(0).toUpperCase() + e.slice(1), Xa = (e, t) => typeof t == "number" || /^\d+$/.test(t) ? `${t}${Ya[e] || ""}` : Jn(String(t));
|
|
1202
1205
|
function xn(e, t, n) {
|
|
1203
|
-
const a =
|
|
1206
|
+
const a = Wn(() => e.tokens({ [e.id]: t }) || {}), o = Object.keys(a);
|
|
1204
1207
|
let r = {};
|
|
1205
1208
|
if (o.length) {
|
|
1206
1209
|
const s = n.selector ? document.querySelector(n.selector) : void 0;
|
|
@@ -1210,7 +1213,7 @@ function xn(e, t, n) {
|
|
|
1210
1213
|
...n,
|
|
1211
1214
|
sectionId: e.id,
|
|
1212
1215
|
title: e.title,
|
|
1213
|
-
settings: Object.entries(t).map(([s, i]) => ({ key: s, label:
|
|
1216
|
+
settings: Object.entries(t).map(([s, i]) => ({ key: s, label: Jn(s), value: Xa(s, i), ...e.describe?.(s, i) || {} })),
|
|
1214
1217
|
tokens: o.map((s) => ({ name: s, from: r[s] || "", to: a[s] }))
|
|
1215
1218
|
};
|
|
1216
1219
|
}
|
|
@@ -1229,7 +1232,7 @@ function Za(e) {
|
|
|
1229
1232
|
const t = (o) => Object.values(o || {}).reduce((r, s) => r + Object.keys(s || {}).length, 0), { scopes: n, ...a } = e;
|
|
1230
1233
|
return t(a) + Object.values(n || {}).reduce((o, r) => o + t(r), 0);
|
|
1231
1234
|
}
|
|
1232
|
-
const ue = (e) => `\`${e}\``,
|
|
1235
|
+
const ue = (e) => `\`${e}\``, ct = (e) => e.map((t) => ` - ${ue(t.name)}: ${t.from ? `${ue(t.from)} → ` : ""}${ue(t.to)}`), pt = (e) => `${e.title} › ${e.settings.map((t) => `${t.label}: ${t.value}`).join(", ")}`;
|
|
1233
1236
|
function Ja(e) {
|
|
1234
1237
|
let t = null;
|
|
1235
1238
|
try {
|
|
@@ -1238,7 +1241,7 @@ function Ja(e) {
|
|
|
1238
1241
|
}
|
|
1239
1242
|
if (!t) return "not found on the current page";
|
|
1240
1243
|
const n = (t.getAttribute("aria-label") || t.placeholder || t.textContent || "").trim().replace(/\s+/g, " ").slice(0, 60);
|
|
1241
|
-
return `${ue(
|
|
1244
|
+
return `${ue(Ot(t))}${n ? ` with text “${n}”` : ""}`;
|
|
1242
1245
|
}
|
|
1243
1246
|
function vn(e, t) {
|
|
1244
1247
|
const n = /* @__PURE__ */ new Map();
|
|
@@ -1262,14 +1265,14 @@ function Qa(e, { link: t = location.href, warnings: n = [] } = {}) {
|
|
|
1262
1265
|
"",
|
|
1263
1266
|
"Update the default value of each token where it is defined (usually a `:root` rule or a `tokens.css` / `twiddle-tokens.css` file). Change the definition, not the places that use it.",
|
|
1264
1267
|
""
|
|
1265
|
-
), a.forEach((i) => s.push(`- **${
|
|
1268
|
+
), a.forEach((i) => s.push(`- **${pt(i)}**`, ...ct(i.tokens)))), o.length && (s.push(
|
|
1266
1269
|
"",
|
|
1267
1270
|
`## ${a.length ? 2 : 1}. Component-wide changes`,
|
|
1268
1271
|
"",
|
|
1269
1272
|
"These apply to every element matching the selector. In the CSS rule for that component, redeclare the token, e.g. `.input { --twd-radius-control: 999px; }`. Don't replace the `var(--twd-…)` usages with fixed values.",
|
|
1270
1273
|
""
|
|
1271
1274
|
), vn(o, "selector").forEach(([i, l]) => {
|
|
1272
|
-
s.push(`- ${ue(i)} (${document.querySelectorAll(i).length} on this page)`), l.forEach((d) => s.push(` - **${
|
|
1275
|
+
s.push(`- ${ue(i)} (${document.querySelectorAll(i).length} on this page)`), l.forEach((d) => s.push(` - **${pt(d)}**`, ...ct(d.tokens).map((p) => ` ${p}`)));
|
|
1273
1276
|
})), r.length) {
|
|
1274
1277
|
const i = 1 + (a.length ? 1 : 0) + (o.length ? 1 : 0);
|
|
1275
1278
|
s.push(
|
|
@@ -1279,7 +1282,7 @@ function Qa(e, { link: t = location.href, warnings: n = [] } = {}) {
|
|
|
1279
1282
|
"These apply to one element only. Add a modifier class to that element (e.g. `input--pill`) and redeclare the token in a rule for that class. The selectors below are runtime paths to help you find the element; don't copy them into the stylesheet.",
|
|
1280
1283
|
""
|
|
1281
1284
|
), vn(r, "selector").forEach(([l, d]) => {
|
|
1282
|
-
s.push(`- ${Ja(l)}, found at ${ue(l)}`), d.forEach((
|
|
1285
|
+
s.push(`- ${Ja(l)}, found at ${ue(l)}`), d.forEach((p) => s.push(` - **${pt(p)}**`, ...ct(p.tokens).map((f) => ` ${f}`)));
|
|
1283
1286
|
});
|
|
1284
1287
|
}
|
|
1285
1288
|
return n.length && s.push(
|
|
@@ -1322,19 +1325,19 @@ function yn(e) {
|
|
|
1322
1325
|
const kn = ([e, t, n]) => {
|
|
1323
1326
|
const a = (o) => (o /= 255, o <= 0.03928 ? o / 12.92 : ((o + 0.055) / 1.055) ** 2.4);
|
|
1324
1327
|
return 0.2126 * a(e) + 0.7152 * a(t) + 0.0722 * a(n);
|
|
1325
|
-
},
|
|
1326
|
-
function
|
|
1327
|
-
const n = kn(e[3] < 1 ?
|
|
1328
|
+
}, Qn = (e, t) => e.slice(0, 3).map((n, a) => n * e[3] + t[a] * (1 - e[3])).concat(1);
|
|
1329
|
+
function ea(e, t) {
|
|
1330
|
+
const n = kn(e[3] < 1 ? Qn(e, t) : e), a = kn(t);
|
|
1328
1331
|
return (Math.max(n, a) + 0.05) / (Math.min(n, a) + 0.05);
|
|
1329
1332
|
}
|
|
1330
|
-
const
|
|
1331
|
-
function
|
|
1333
|
+
const ta = (e) => `${e.toFixed(1)}:1`;
|
|
1334
|
+
function ut() {
|
|
1332
1335
|
const e = [];
|
|
1333
1336
|
return to.forEach(([t, n, a]) => {
|
|
1334
1337
|
const o = yn(t), r = yn(n);
|
|
1335
1338
|
if (!o || !r || r[3] === 0) return;
|
|
1336
|
-
const s =
|
|
1337
|
-
s < Ye && e.push({ label: a, ratio: s, needed: Ye, text: `${a}: ${
|
|
1339
|
+
const s = ea(o, r);
|
|
1340
|
+
s < Ye && e.push({ label: a, ratio: s, needed: Ye, text: `${a}: ${ta(s)} · AA needs ${Ye}` });
|
|
1338
1341
|
}), e;
|
|
1339
1342
|
}
|
|
1340
1343
|
function no(e) {
|
|
@@ -1344,16 +1347,16 @@ function no(e) {
|
|
|
1344
1347
|
if (a && a[3] > 0 && (t.push(a), a[3] >= 1))
|
|
1345
1348
|
break;
|
|
1346
1349
|
}
|
|
1347
|
-
return t.reduceRight((n, a) =>
|
|
1350
|
+
return t.reduceRight((n, a) => Qn(a, n), [255, 255, 255, 1]);
|
|
1348
1351
|
}
|
|
1349
1352
|
function ao(e) {
|
|
1350
1353
|
if (!e.textContent.trim() && !e.placeholder) return null;
|
|
1351
1354
|
const t = getComputedStyle(e), n = It(t.color);
|
|
1352
1355
|
if (!n) return null;
|
|
1353
|
-
const a = parseFloat(t.fontSize), r = a >= 24 || a >= 18.66 && parseInt(t.fontWeight, 10) >= 700 ? eo : Ye, s =
|
|
1354
|
-
return s < r ? { label: "This element", ratio: s, needed: r, text: `This element’s text: ${
|
|
1356
|
+
const a = parseFloat(t.fontSize), r = a >= 24 || a >= 18.66 && parseInt(t.fontWeight, 10) >= 700 ? eo : Ye, s = ea(n, no(e));
|
|
1357
|
+
return s < r ? { label: "This element", ratio: s, needed: r, text: `This element’s text: ${ta(s)} · AA needs ${r}` } : null;
|
|
1355
1358
|
}
|
|
1356
|
-
const Sn = "twiddle-panel", oo = "0.9.
|
|
1359
|
+
const Sn = "twiddle-panel", oo = "0.9.1", $n = "https://panel.twiddle.in", ro = "--twd-radius-control", so = /var\(\s*--twd-/;
|
|
1357
1360
|
function io(e) {
|
|
1358
1361
|
return e.style.cssText.split(";").some((t) => {
|
|
1359
1362
|
const n = t.slice(0, t.indexOf(":")).trim();
|
|
@@ -1439,107 +1442,106 @@ function D(e) {
|
|
|
1439
1442
|
function uo({ label: e, ends: t, cols: n = 9, rows: a = 5, onInput: o }) {
|
|
1440
1443
|
const r = document.createElement("div");
|
|
1441
1444
|
r.className = "pad", r.tabIndex = 0, r.setAttribute("role", "group"), r.setAttribute("aria-roledescription", "2D slider");
|
|
1442
|
-
const s = (
|
|
1443
|
-
const
|
|
1444
|
-
return
|
|
1445
|
+
const s = (b, h) => {
|
|
1446
|
+
const w = document.createElement("span");
|
|
1447
|
+
return w.className = `pad-edge ${b}`, w.textContent = h, w.setAttribute("aria-hidden", "true"), w;
|
|
1445
1448
|
};
|
|
1446
1449
|
r.append(s("top", t.top), s("bottom", t.bottom), s("left", t.left), s("right", t.right));
|
|
1447
1450
|
const i = document.createElement("div");
|
|
1448
1451
|
i.className = "pad-area";
|
|
1449
|
-
for (let
|
|
1450
|
-
for (let
|
|
1451
|
-
const
|
|
1452
|
-
|
|
1452
|
+
for (let b = 0; b < a; b++)
|
|
1453
|
+
for (let h = 0; h < n; h++) {
|
|
1454
|
+
const w = document.createElement("i");
|
|
1455
|
+
w.className = "pad-dot", w.style.left = `${h / (n - 1) * 100}%`, w.style.top = `${b / (a - 1) * 100}%`, i.append(w);
|
|
1453
1456
|
}
|
|
1454
1457
|
const l = document.createElement("span");
|
|
1455
1458
|
l.className = "pad-knob", i.append(l), r.append(i);
|
|
1456
|
-
let d = 0.5,
|
|
1457
|
-
const
|
|
1458
|
-
function
|
|
1459
|
-
l.style.left = `${d * 100}%`, l.style.top = `${
|
|
1459
|
+
let d = 0.5, p = 0.5;
|
|
1460
|
+
const f = (b, h) => Math.round(Math.min(1, Math.max(0, b)) * (h - 1)) / (h - 1);
|
|
1461
|
+
function v() {
|
|
1462
|
+
l.style.left = `${d * 100}%`, l.style.top = `${p * 100}%`;
|
|
1460
1463
|
}
|
|
1461
|
-
function
|
|
1462
|
-
|
|
1464
|
+
function u(b, h, w) {
|
|
1465
|
+
b = w === "x" ? d : f(b, n), h = w === "y" ? p : f(h, a), !(b === d && h === p) && (d = b, p = h, v(), o(d, p));
|
|
1463
1466
|
}
|
|
1464
|
-
const
|
|
1465
|
-
const
|
|
1466
|
-
|
|
1467
|
+
const m = (b) => {
|
|
1468
|
+
const h = i.getBoundingClientRect();
|
|
1469
|
+
u((b.clientX - h.left) / h.width, (b.clientY - h.top) / h.height);
|
|
1467
1470
|
};
|
|
1468
|
-
r.addEventListener("pointerdown", (
|
|
1469
|
-
r.setPointerCapture(
|
|
1470
|
-
}), r.addEventListener("pointermove", (
|
|
1471
|
-
r.hasPointerCapture(
|
|
1471
|
+
r.addEventListener("pointerdown", (b) => {
|
|
1472
|
+
r.setPointerCapture(b.pointerId), r.classList.add("dragging"), m(b);
|
|
1473
|
+
}), r.addEventListener("pointermove", (b) => {
|
|
1474
|
+
r.hasPointerCapture(b.pointerId) && m(b);
|
|
1472
1475
|
});
|
|
1473
|
-
const x = (
|
|
1474
|
-
r.hasPointerCapture(
|
|
1476
|
+
const x = (b) => {
|
|
1477
|
+
r.hasPointerCapture(b.pointerId) && r.releasePointerCapture(b.pointerId), r.classList.remove("dragging");
|
|
1475
1478
|
};
|
|
1476
|
-
return r.addEventListener("pointerup", x), r.addEventListener("pointercancel", x), r.addEventListener("keydown", (
|
|
1477
|
-
const
|
|
1478
|
-
|
|
1479
|
+
return r.addEventListener("pointerup", x), r.addEventListener("pointercancel", x), r.addEventListener("keydown", (b) => {
|
|
1480
|
+
const h = { ArrowLeft: [-1, 0], ArrowRight: [1, 0], ArrowUp: [0, -1], ArrowDown: [0, 1] }[b.key];
|
|
1481
|
+
h && (b.preventDefault(), h[0] ? u(f(d, n) + h[0] / (n - 1), p, "y") : u(d, f(p, a) + h[1] / (a - 1), "x"));
|
|
1479
1482
|
}), {
|
|
1480
1483
|
el: r,
|
|
1481
1484
|
/** Show a position without telling anyone (used to sync). Off-grid values are shown as they are. */
|
|
1482
|
-
setValue(
|
|
1483
|
-
d = Math.min(1, Math.max(0,
|
|
1485
|
+
setValue(b, h, w) {
|
|
1486
|
+
d = Math.min(1, Math.max(0, b)), p = Math.min(1, Math.max(0, h)), v(), r.setAttribute("aria-label", w ? `${e}: ${w}` : e);
|
|
1484
1487
|
}
|
|
1485
1488
|
};
|
|
1486
1489
|
}
|
|
1487
|
-
function
|
|
1490
|
+
function na({ label: e, min: t, max: n, step: a = 1, format: o = String, onInput: r }) {
|
|
1488
1491
|
const s = document.createElement("div");
|
|
1489
1492
|
s.className = "slider";
|
|
1490
1493
|
const i = document.createElement("input");
|
|
1491
1494
|
i.type = "range", i.min = String(t), i.max = String(n), i.step = String(a), i.setAttribute("aria-label", e);
|
|
1492
1495
|
const l = document.createElement("span");
|
|
1493
1496
|
l.className = "slider-value", l.setAttribute("aria-hidden", "true"), s.append(i, l);
|
|
1494
|
-
const d = (
|
|
1495
|
-
const
|
|
1496
|
-
i.style.setProperty("--fill", `${
|
|
1497
|
+
const d = (p) => {
|
|
1498
|
+
const f = (Number(i.value) - t) / (n - t) * 100;
|
|
1499
|
+
i.style.setProperty("--fill", `${f}%`), l.textContent = p ?? o(Number(i.value)), i.setAttribute("aria-valuetext", l.textContent);
|
|
1497
1500
|
};
|
|
1498
1501
|
return i.addEventListener("input", () => {
|
|
1499
1502
|
d(), r(Number(i.value));
|
|
1500
1503
|
}), {
|
|
1501
1504
|
el: s,
|
|
1502
1505
|
/** Show a value without reporting it (sync after reset / URL load). */
|
|
1503
|
-
setValue(
|
|
1504
|
-
i.value = String(
|
|
1506
|
+
setValue(p, f) {
|
|
1507
|
+
i.value = String(p), d(f);
|
|
1505
1508
|
}
|
|
1506
1509
|
};
|
|
1507
1510
|
}
|
|
1508
1511
|
function ho({ label: e, options: t, columns: n = 3, className: a = "", onSelect: o }) {
|
|
1509
1512
|
const r = document.createElement("div");
|
|
1510
1513
|
r.className = `tiles ${a}`.trim(), r.style.setProperty("--cols", n), r.setAttribute("role", "radiogroup"), r.setAttribute("aria-label", e);
|
|
1511
|
-
const s = t.map((
|
|
1512
|
-
const
|
|
1513
|
-
return
|
|
1514
|
+
const s = t.map((p) => {
|
|
1515
|
+
const f = document.createElement("button");
|
|
1516
|
+
return f.type = "button", f.className = "tile", p.wide && f.classList.add("wide"), f.setAttribute("role", "radio"), f.dataset.value = p.value, p.title && (f.title = p.title), f.innerHTML = `${p.preview ? `<span class="tile-preview" aria-hidden="true">${p.preview}</span>` : ""}<span class="tile-text"><span class="tile-label"></span>${p.sub ? '<span class="tile-sub"></span>' : ""}</span>`, f.querySelector(".tile-label").textContent = p.label, p.sub && (f.querySelector(".tile-sub").textContent = p.sub), f.addEventListener("click", () => l(p.value)), f;
|
|
1514
1517
|
});
|
|
1515
1518
|
r.append(...s);
|
|
1516
|
-
|
|
1517
|
-
|
|
1518
|
-
|
|
1519
|
-
|
|
1520
|
-
|
|
1521
|
-
p.tabIndex = g === w ? 0 : -1;
|
|
1519
|
+
function i(p) {
|
|
1520
|
+
s.forEach((v) => v.setAttribute("aria-checked", String(v.dataset.value === p)));
|
|
1521
|
+
const f = Math.max(0, s.findIndex((v) => v.dataset.value === p));
|
|
1522
|
+
s.forEach((v, u) => {
|
|
1523
|
+
v.tabIndex = u === f ? 0 : -1;
|
|
1522
1524
|
});
|
|
1523
1525
|
}
|
|
1524
|
-
function
|
|
1525
|
-
|
|
1526
|
+
function l(p, f) {
|
|
1527
|
+
i(p), o(p), f && s.find((v) => v.dataset.value === p).focus();
|
|
1526
1528
|
}
|
|
1527
|
-
function
|
|
1528
|
-
s.forEach((
|
|
1529
|
+
function d(p = []) {
|
|
1530
|
+
s.forEach((f) => f.classList.toggle("near", p.includes(f.dataset.value)));
|
|
1529
1531
|
}
|
|
1530
|
-
return r.addEventListener("keydown", (
|
|
1531
|
-
const
|
|
1532
|
-
if (
|
|
1533
|
-
const
|
|
1534
|
-
let
|
|
1535
|
-
if (
|
|
1536
|
-
else if (
|
|
1537
|
-
else if (
|
|
1532
|
+
return r.addEventListener("keydown", (p) => {
|
|
1533
|
+
const f = s.indexOf(p.target.closest(".tile"));
|
|
1534
|
+
if (f < 0) return;
|
|
1535
|
+
const v = { ArrowRight: 1, ArrowDown: 1, ArrowLeft: -1, ArrowUp: -1 }[p.key];
|
|
1536
|
+
let u;
|
|
1537
|
+
if (v) u = (f + v + s.length) % s.length;
|
|
1538
|
+
else if (p.key === "Home") u = 0;
|
|
1539
|
+
else if (p.key === "End") u = s.length - 1;
|
|
1538
1540
|
else return;
|
|
1539
|
-
|
|
1540
|
-
}),
|
|
1541
|
+
p.preventDefault(), l(s[u].dataset.value, !0);
|
|
1542
|
+
}), i(null), { el: r, setValue: i, setNear: d };
|
|
1541
1543
|
}
|
|
1542
|
-
const
|
|
1544
|
+
const L = (e) => getComputedStyle(document.documentElement).getPropertyValue(e).trim();
|
|
1543
1545
|
function Ce(e, t) {
|
|
1544
1546
|
const n = /^(-?\d*\.?\d+)([a-z%]*)$/i.exec(String(e).trim());
|
|
1545
1547
|
if (!n) return null;
|
|
@@ -1547,12 +1549,12 @@ function Ce(e, t) {
|
|
|
1547
1549
|
return o === "px" ? `${Math.round(a)}px` : `${+a.toFixed(3)}${o}`;
|
|
1548
1550
|
}
|
|
1549
1551
|
const fo = 999;
|
|
1550
|
-
function
|
|
1551
|
-
const
|
|
1552
|
-
if (typeof
|
|
1553
|
-
return { [a]: `${Math.min(Math.max(
|
|
1554
|
-
const
|
|
1555
|
-
return
|
|
1552
|
+
function aa({ id: e, title: t, hint: n, token: a, uses: o = [], presets: r, max: s, extra: i = [], extraTokens: l = () => ({}), shape: d = "card" }) {
|
|
1553
|
+
const p = (u) => r.find((m) => m.value === u), f = (u) => u >= fo ? "full" : `${u}px`, v = (u) => {
|
|
1554
|
+
if (typeof u.radius == "number" && isFinite(u.radius))
|
|
1555
|
+
return { [a]: `${Math.min(Math.max(u.radius, 0), s)}px` };
|
|
1556
|
+
const m = p(u.corners);
|
|
1557
|
+
return m ? { [a]: `${m.radius}px` } : {};
|
|
1556
1558
|
};
|
|
1557
1559
|
return {
|
|
1558
1560
|
id: e,
|
|
@@ -1560,86 +1562,86 @@ function oa({ id: e, title: t, hint: n, token: a, uses: o = [], presets: r, max:
|
|
|
1560
1562
|
hint: n,
|
|
1561
1563
|
presets: r,
|
|
1562
1564
|
uses: [a, ...o],
|
|
1563
|
-
tokens(
|
|
1564
|
-
const
|
|
1565
|
-
return { ...
|
|
1565
|
+
tokens(u) {
|
|
1566
|
+
const m = u[e] || {};
|
|
1567
|
+
return { ...v(m), ...l(m) };
|
|
1566
1568
|
},
|
|
1567
1569
|
// One render function per knob, so a layout can place them separately.
|
|
1568
1570
|
// Each takes an optional label (e.g. "Buttons" on the Corners page).
|
|
1569
1571
|
parts: {
|
|
1570
|
-
corners(
|
|
1571
|
-
const
|
|
1572
|
+
corners(u, m, { label: x = "Corners" } = {}) {
|
|
1573
|
+
const b = D(x), h = ge({
|
|
1572
1574
|
label: `${t} corners`,
|
|
1573
|
-
options: r.map(($) => ({ value: $.value, label: $.label, title:
|
|
1574
|
-
onSelect: ($) =>
|
|
1575
|
-
}),
|
|
1575
|
+
options: r.map(($) => ({ value: $.value, label: $.label, title: f($.radius) })),
|
|
1576
|
+
onSelect: ($) => m.setSection(e, { corners: $, radius: null })
|
|
1577
|
+
}), w = na({
|
|
1576
1578
|
label: `${t} corner radius`,
|
|
1577
1579
|
min: 0,
|
|
1578
1580
|
max: s,
|
|
1579
|
-
format:
|
|
1580
|
-
onInput: ($) =>
|
|
1581
|
+
format: f,
|
|
1582
|
+
onInput: ($) => m.setSection(e, { radius: $, corners: null })
|
|
1581
1583
|
});
|
|
1582
|
-
|
|
1584
|
+
b.append(h.el, w.el), u.append(b.el);
|
|
1583
1585
|
const S = () => {
|
|
1584
|
-
const $ = parseFloat((
|
|
1585
|
-
if (
|
|
1586
|
-
|
|
1586
|
+
const $ = parseFloat((m.readToken || L)(a)), K = m.getState()[e] || {}, Z = p(K.corners) || r.find((Le) => Le.radius === $);
|
|
1587
|
+
if (h.setValue(Z ? Z.value : null), isNaN($)) {
|
|
1588
|
+
w.setValue(0, "—"), b.setValue("");
|
|
1587
1589
|
return;
|
|
1588
1590
|
}
|
|
1589
|
-
|
|
1591
|
+
w.setValue(Math.min($, s), f($)), b.setValue(f($));
|
|
1590
1592
|
};
|
|
1591
|
-
S(),
|
|
1593
|
+
S(), m.onChange(S);
|
|
1592
1594
|
},
|
|
1593
|
-
...Object.fromEntries(i.map((
|
|
1595
|
+
...Object.fromEntries(i.map((u) => [u.key, (m, x, { label: b } = {}) => m.append(Me(x, { section: e, ...u, label: b || u.label }))])),
|
|
1594
1596
|
// Tabbed layout: presets as tiles showing the real rounding.
|
|
1595
|
-
cornerTiles(
|
|
1596
|
-
const
|
|
1597
|
-
|
|
1597
|
+
cornerTiles(u, m, { label: x = "Corners" } = {}) {
|
|
1598
|
+
const b = (h) => `<span class="shape shape-${d}" style="border-radius:${Math.min(h, d === "button" ? 12 : 16)}px"></span>`;
|
|
1599
|
+
u.append(_(m, {
|
|
1598
1600
|
section: e,
|
|
1599
1601
|
key: "corners",
|
|
1600
1602
|
label: x,
|
|
1601
1603
|
columns: r.length,
|
|
1602
|
-
options: r.map((
|
|
1603
|
-
current: (
|
|
1604
|
-
const
|
|
1605
|
-
if (
|
|
1606
|
-
if (
|
|
1607
|
-
if (he(
|
|
1608
|
-
const S = parseFloat((
|
|
1604
|
+
options: r.map((h) => ({ value: h.value, label: h.label, title: f(h.radius), preview: b(h.radius) })),
|
|
1605
|
+
current: (h) => {
|
|
1606
|
+
const w = h[e] || {};
|
|
1607
|
+
if (w.radius != null) return null;
|
|
1608
|
+
if (p(w.corners)) return w.corners;
|
|
1609
|
+
if (he(h, a)) return null;
|
|
1610
|
+
const S = parseFloat((m.readToken || L)(a));
|
|
1609
1611
|
return r.find(($) => $.radius === S)?.value || null;
|
|
1610
1612
|
},
|
|
1611
|
-
select: (
|
|
1612
|
-
valueText: (
|
|
1613
|
-
const S = parseFloat((
|
|
1613
|
+
select: (h) => m.setSection(e, { corners: h, radius: null }),
|
|
1614
|
+
valueText: (h, w) => {
|
|
1615
|
+
const S = parseFloat((m.readToken || L)(a));
|
|
1614
1616
|
if (isNaN(S)) return "";
|
|
1615
|
-
const $ =
|
|
1616
|
-
return
|
|
1617
|
+
const $ = w[e] || {};
|
|
1618
|
+
return f(S) + Cn(w, a, $.radius != null ? "custom" : p($.corners)?.label);
|
|
1617
1619
|
}
|
|
1618
1620
|
}));
|
|
1619
1621
|
},
|
|
1620
|
-
...Object.fromEntries(i.filter((
|
|
1622
|
+
...Object.fromEntries(i.filter((u) => u.preview).map((u) => [`${u.key}Tiles`, (m, x, { label: b } = {}) => m.append(_(x, {
|
|
1621
1623
|
section: e,
|
|
1622
|
-
key:
|
|
1623
|
-
label:
|
|
1624
|
-
fallback:
|
|
1625
|
-
columns:
|
|
1626
|
-
options:
|
|
1627
|
-
...
|
|
1628
|
-
current: (
|
|
1629
|
-
valueText: (
|
|
1630
|
-
if (!he(
|
|
1631
|
-
const S =
|
|
1632
|
-
return `${(x.readToken ||
|
|
1624
|
+
key: u.key,
|
|
1625
|
+
label: b || u.label,
|
|
1626
|
+
fallback: u.fallback,
|
|
1627
|
+
columns: u.columns || u.options.length,
|
|
1628
|
+
options: u.options.map((h) => ({ ...h, preview: u.preview(h.value) })),
|
|
1629
|
+
...u.token && {
|
|
1630
|
+
current: (h) => (h[e] || {})[u.key] || (he(h, u.token) ? null : u.fallback || null),
|
|
1631
|
+
valueText: (h, w) => {
|
|
1632
|
+
if (!he(w, u.token)) return "";
|
|
1633
|
+
const S = u.options.find(($) => $.value === (w[e] || {})[u.key]);
|
|
1634
|
+
return `${(x.readToken || L)(u.token)}${Cn(w, u.token, S && S.label)}`;
|
|
1633
1635
|
}
|
|
1634
1636
|
},
|
|
1635
1637
|
// A knob can bring its own rules (e.g. Cards › Fill reads "from Style").
|
|
1636
|
-
...
|
|
1637
|
-
...
|
|
1638
|
-
...
|
|
1638
|
+
...u.current && { current: (h) => u.current(h[e] || {}) },
|
|
1639
|
+
...u.valueText && { valueText: (h, w) => u.valueText(w[e] || {}, x.readToken || L) },
|
|
1640
|
+
...u.select && { select: (h) => x.setSection(e, u.select(h)) }
|
|
1639
1641
|
}))]))
|
|
1640
1642
|
},
|
|
1641
|
-
render(
|
|
1642
|
-
Object.entries(this.parts).filter(([x]) => !x.endsWith("Tiles")).forEach(([, x]) => x(
|
|
1643
|
+
render(u, m) {
|
|
1644
|
+
Object.entries(this.parts).filter(([x]) => !x.endsWith("Tiles")).forEach(([, x]) => x(u, m));
|
|
1643
1645
|
}
|
|
1644
1646
|
};
|
|
1645
1647
|
}
|
|
@@ -1647,44 +1649,44 @@ function Me(e, { section: t, key: n, label: a, options: o, fallback: r, valueTex
|
|
|
1647
1649
|
const i = D(a), l = ge({
|
|
1648
1650
|
label: a,
|
|
1649
1651
|
options: o,
|
|
1650
|
-
onSelect: (
|
|
1652
|
+
onSelect: (p) => e.setSection(t, { [n]: p })
|
|
1651
1653
|
});
|
|
1652
1654
|
i.append(l.el);
|
|
1653
1655
|
const d = () => {
|
|
1654
|
-
const
|
|
1655
|
-
l.setValue(
|
|
1656
|
+
const p = (e.getState()[t] || {})[n] || r;
|
|
1657
|
+
l.setValue(p), i.setValue(s ? s(p) : "");
|
|
1656
1658
|
};
|
|
1657
1659
|
return d(), e.onChange(d), i.el;
|
|
1658
1660
|
}
|
|
1659
1661
|
function go(e, { section: t, key: n, label: a, min: o, max: r, fallback: s, format: i, note: l, value: d }) {
|
|
1660
|
-
const
|
|
1661
|
-
|
|
1662
|
-
const
|
|
1663
|
-
const
|
|
1664
|
-
|
|
1662
|
+
const p = D(a), f = na({ label: a, min: o, max: r, format: i, onInput: (u) => e.setSection(t, { [n]: u }) });
|
|
1663
|
+
p.append(f.el);
|
|
1664
|
+
const v = () => {
|
|
1665
|
+
const u = e.getState(), m = d ? d(u) : (u[t] || {})[n];
|
|
1666
|
+
f.setValue(typeof m == "number" ? m : s), l && (p.el.querySelector(".field-label").textContent = `${a}${l(u) ? ` · ${l(u)}` : ""}`);
|
|
1665
1667
|
};
|
|
1666
|
-
return
|
|
1667
|
-
}
|
|
1668
|
-
let
|
|
1669
|
-
const
|
|
1670
|
-
|
|
1671
|
-
}, he = (e, t) => Object.prototype.hasOwnProperty.call(
|
|
1672
|
-
function _(e, { section: t, key: n, label: a, options: o, columns: r = 3, className: s = "", fallback: i, valueText: l, current: d, select:
|
|
1673
|
-
const
|
|
1668
|
+
return v(), e.onChange(v), p.el;
|
|
1669
|
+
}
|
|
1670
|
+
let oa = () => ({});
|
|
1671
|
+
const mo = (e) => {
|
|
1672
|
+
oa = e;
|
|
1673
|
+
}, he = (e, t) => Object.prototype.hasOwnProperty.call(oa(e), t), Cn = (e, t, n) => he(e, t) ? n ? ` · ${n}, adjusted by Character` : " · from Character" : "";
|
|
1674
|
+
function _(e, { section: t, key: n, label: a, options: o, columns: r = 3, className: s = "", fallback: i, valueText: l, current: d, select: p, near: f }) {
|
|
1675
|
+
const v = D(a), u = ho({
|
|
1674
1676
|
label: a,
|
|
1675
1677
|
options: o,
|
|
1676
1678
|
columns: r,
|
|
1677
1679
|
className: s,
|
|
1678
|
-
onSelect: (x) =>
|
|
1680
|
+
onSelect: (x) => p ? p(x) : e.setSection(t, { [n]: x })
|
|
1679
1681
|
});
|
|
1680
|
-
|
|
1681
|
-
const
|
|
1682
|
-
const x = e.getState(),
|
|
1683
|
-
|
|
1682
|
+
v.append(u.el);
|
|
1683
|
+
const m = () => {
|
|
1684
|
+
const x = e.getState(), b = d ? d(x) : (x[t] || {})[n] || i || null;
|
|
1685
|
+
u.setValue(b), u.setNear(f ? f(x) : []), v.setValue(l ? l(b, x) : "");
|
|
1684
1686
|
};
|
|
1685
|
-
return
|
|
1687
|
+
return m(), e.onChange(m), v.el;
|
|
1686
1688
|
}
|
|
1687
|
-
const Mn = (e, t) => t.map((n) => `${e}${n}`),
|
|
1689
|
+
const Mn = (e, t) => t.map((n) => `${e}${n}`), ra = {
|
|
1688
1690
|
fonts: { label: "Tokens", tokens: ["font-heading", "font-body"], kind: "text" },
|
|
1689
1691
|
type: { label: "Tokens", tokens: Mn("text-", ["xs", "sm", "base", "lg", "xl", "2xl", "3xl"]), kind: "length" },
|
|
1690
1692
|
leading: { label: "Line height", tokens: ["leading-tight", "leading-normal"], kind: "number" },
|
|
@@ -1698,8 +1700,8 @@ const Mn = (e, t) => t.map((n) => `${e}${n}`), sa = {
|
|
|
1698
1700
|
buttonStyle: { label: "Button", tokens: ["button-bg", "button-fg", "button-border", "button-hover"], kind: "colour" },
|
|
1699
1701
|
cardStyle: { label: "Card", tokens: ["card-bg", "card-border"], kind: "colour" },
|
|
1700
1702
|
cardShadow: { label: "Card shadow", tokens: ["card-shadow"], kind: "text" }
|
|
1701
|
-
}, Y = (e) => `--twd-${e}`,
|
|
1702
|
-
function
|
|
1703
|
+
}, Y = (e) => `--twd-${e}`, ht = (e, t) => Object.prototype.hasOwnProperty.call(e.getState().custom || {}, t), $e = (e, t) => ra[t].tokens.some((n) => (e.custom || {})[n] != null);
|
|
1704
|
+
function bo(e, t) {
|
|
1703
1705
|
const n = /^(-?\d*\.?\d+)(px|rem)?$/.exec(String(e).trim());
|
|
1704
1706
|
return !n || t === "text" || t === "colour" ? null : n[2] === "rem" ? { n: +(parseFloat(n[1]) * 16).toFixed(1), unit: "px" } : { n: +parseFloat(n[1]).toFixed(3), unit: n[2] || (t === "length" ? "px" : "") };
|
|
1705
1707
|
}
|
|
@@ -1718,29 +1720,29 @@ function wo(e, t, n, a) {
|
|
|
1718
1720
|
<input type="text" spellcheck="false" aria-label="${Y(t)}" ${n === "length" || n === "number" ? 'inputmode="decimal"' : ""}>
|
|
1719
1721
|
<span class="token-unit"></span>
|
|
1720
1722
|
</label>
|
|
1721
|
-
<button class="icon-btn token-reset" title="Back to the page’s value" aria-label="Reset ${Y(t)}" hidden>${
|
|
1723
|
+
<button class="icon-btn token-reset" title="Back to the page’s value" aria-label="Reset ${Y(t)}" hidden>${P.reset}</button>
|
|
1722
1724
|
`;
|
|
1723
|
-
const r = o.querySelector("input"), s = o.querySelector(".token-unit"), i = o.querySelector(".token-bar span"), l = o.querySelector(".token-swatch"), d = o.querySelector(".custom-tag"),
|
|
1724
|
-
let
|
|
1725
|
-
const
|
|
1726
|
-
let
|
|
1727
|
-
|
|
1728
|
-
const x = xo(
|
|
1725
|
+
const r = o.querySelector("input"), s = o.querySelector(".token-unit"), i = o.querySelector(".token-bar span"), l = o.querySelector(".token-swatch"), d = o.querySelector(".custom-tag"), p = o.querySelector(".token-reset");
|
|
1726
|
+
let f = "";
|
|
1727
|
+
const v = () => {
|
|
1728
|
+
let m = r.value;
|
|
1729
|
+
f && /^-?\d*\.?\d+$/.test(m.trim()) && (m = `${m.trim()}${f}`);
|
|
1730
|
+
const x = xo(m, n), b = L(Y(t));
|
|
1729
1731
|
if (x === null) {
|
|
1730
|
-
|
|
1732
|
+
ht(e, t) ? e.setSection("custom", { [t]: null }) : u();
|
|
1731
1733
|
return;
|
|
1732
1734
|
}
|
|
1733
|
-
if (x ===
|
|
1735
|
+
if (x === b && !ht(e, t)) return u();
|
|
1734
1736
|
e.setSection("custom", { [t]: x });
|
|
1735
1737
|
};
|
|
1736
|
-
r.addEventListener("change",
|
|
1737
|
-
|
|
1738
|
-
}),
|
|
1739
|
-
function
|
|
1740
|
-
const
|
|
1741
|
-
|
|
1738
|
+
r.addEventListener("change", v), r.addEventListener("blur", () => u()), r.addEventListener("keydown", (m) => {
|
|
1739
|
+
m.key === "Enter" && (m.preventDefault(), r.blur()), m.key === "Escape" && (m.stopPropagation(), u(), r.blur());
|
|
1740
|
+
}), p.addEventListener("click", () => e.setSection("custom", { [t]: null }));
|
|
1741
|
+
function u() {
|
|
1742
|
+
const m = L(Y(t)), x = ht(e, t), b = bo(m, n);
|
|
1743
|
+
f = b ? b.unit : "", document.activeElement !== r && o.getRootNode().activeElement !== r && (r.value = b ? String(b.n) : m), r.title = m, s.textContent = f, s.hidden = !f, i && (i.style.width = `${Math.max(2, Math.min(100, (b ? b.n : 0) / a * 100))}%`), l && (l.style.background = m), o.classList.toggle("edited", x), d.hidden = !x, p.hidden = !x;
|
|
1742
1744
|
}
|
|
1743
|
-
return
|
|
1745
|
+
return u(), e.onChange(u), o;
|
|
1744
1746
|
}
|
|
1745
1747
|
const vo = {
|
|
1746
1748
|
id: "custom",
|
|
@@ -1753,7 +1755,7 @@ const vo = {
|
|
|
1753
1755
|
},
|
|
1754
1756
|
describe: (e, t) => ({ label: Y(e), value: String(t) }),
|
|
1755
1757
|
// One part per Edit page group, e.g. parts.spacing → rows for --twd-space-1 … 8.
|
|
1756
|
-
parts: Object.fromEntries(Object.entries(
|
|
1758
|
+
parts: Object.fromEntries(Object.entries(ra).map(([e, t]) => [e, (n, a, { label: o = t.label } = {}) => {
|
|
1757
1759
|
const r = D(o);
|
|
1758
1760
|
r.el.classList.add("token-field");
|
|
1759
1761
|
const s = t.tokens[0], i = t.tokens[t.tokens.length - 1];
|
|
@@ -1761,24 +1763,24 @@ const vo = {
|
|
|
1761
1763
|
const l = document.createElement("div");
|
|
1762
1764
|
l.className = "token-rows", t.tokens.forEach((d) => l.append(wo(a, d, t.kind, t.bar))), r.append(l), n.append(r.el);
|
|
1763
1765
|
}]))
|
|
1764
|
-
}, X = { compact: 0.75, regular: 1, comfy: 1.25 },
|
|
1765
|
-
function
|
|
1766
|
+
}, X = { compact: 0.75, regular: 1, comfy: 1.25 }, jt = [0.75, 1.25], Tn = [1, 2, 3, 4, 5, 6, 7, 8].map((e) => `--twd-space-${e}`);
|
|
1767
|
+
function sa(e) {
|
|
1766
1768
|
const t = Object.entries(X).sort((a, o) => a[1] - o[1]);
|
|
1767
1769
|
if (t.some(([, a]) => a === e)) return [];
|
|
1768
1770
|
const n = t.findIndex(([, a]) => a > e);
|
|
1769
1771
|
return n > 0 ? [t[n - 1][0], t[n][0]] : [];
|
|
1770
1772
|
}
|
|
1771
|
-
const
|
|
1773
|
+
const ft = (e) => e[0].toUpperCase() + e.slice(1);
|
|
1772
1774
|
function Dt(e) {
|
|
1773
1775
|
const t = Object.keys(X).find((a) => X[a] === e);
|
|
1774
|
-
if (t) return
|
|
1775
|
-
const n =
|
|
1776
|
-
return n.length ? `Between ${
|
|
1776
|
+
if (t) return ft(t);
|
|
1777
|
+
const n = sa(e);
|
|
1778
|
+
return n.length ? `Between ${ft(n[0])} and ${ft(n[1])}` : e > 1 ? "Comfy" : "Compact";
|
|
1777
1779
|
}
|
|
1778
1780
|
function H(e = {}) {
|
|
1779
|
-
return typeof e.factor == "number" && isFinite(e.factor) ? Math.min(
|
|
1781
|
+
return typeof e.factor == "number" && isFinite(e.factor) ? Math.min(jt[1], Math.max(jt[0], e.factor)) : X[e.spacing] || 1;
|
|
1780
1782
|
}
|
|
1781
|
-
const
|
|
1783
|
+
const gt = (e) => `${Math.round(e * 100)}%`, yo = {
|
|
1782
1784
|
id: "density",
|
|
1783
1785
|
title: "Density",
|
|
1784
1786
|
hint: "Compact · regular · comfortable",
|
|
@@ -1788,12 +1790,12 @@ const ft = (e) => `${Math.round(e * 100)}%`, yo = {
|
|
|
1788
1790
|
if (t === 1) return {};
|
|
1789
1791
|
const n = {};
|
|
1790
1792
|
return Tn.forEach((a) => {
|
|
1791
|
-
const o = Ce(
|
|
1793
|
+
const o = Ce(L(a), t);
|
|
1792
1794
|
o && (n[a] = o);
|
|
1793
1795
|
}), n;
|
|
1794
1796
|
},
|
|
1795
1797
|
/** How the Changes list and prompt describe a setting. */
|
|
1796
|
-
describe: (e, t) => e === "factor" ? { label: "Spacing", value:
|
|
1798
|
+
describe: (e, t) => e === "factor" ? { label: "Spacing", value: gt(t) } : null,
|
|
1797
1799
|
parts: {
|
|
1798
1800
|
// Tabbed layout: presets as tiles with a tiny layout sketch.
|
|
1799
1801
|
spacingTiles(e, t, { label: n = "Density" } = {}) {
|
|
@@ -1808,8 +1810,8 @@ const ft = (e) => `${Math.round(e * 100)}%`, yo = {
|
|
|
1808
1810
|
return Object.keys(X).find((s) => X[s] === r) || null;
|
|
1809
1811
|
},
|
|
1810
1812
|
select: (o) => t.setSection("density", { spacing: o, factor: null }),
|
|
1811
|
-
near: (o) => $e(o, "spacing") ? [] :
|
|
1812
|
-
valueText: (o, r) => $e(r, "spacing") ? "Custom" : o ? "" : `${Dt(H(r.density))} · ${
|
|
1813
|
+
near: (o) => $e(o, "spacing") ? [] : sa(H(o.density)),
|
|
1814
|
+
valueText: (o, r) => $e(r, "spacing") ? "Custom" : o ? "" : `${Dt(H(r.density))} · ${gt(H(r.density))}`
|
|
1813
1815
|
}));
|
|
1814
1816
|
},
|
|
1815
1817
|
spacing(e, t, { label: n = "Spacing" } = {}) {
|
|
@@ -1821,7 +1823,7 @@ const ft = (e) => `${Math.round(e * 100)}%`, yo = {
|
|
|
1821
1823
|
a.append(o.el);
|
|
1822
1824
|
const r = () => {
|
|
1823
1825
|
const s = t.getState().density || {}, i = H(s), l = Object.keys(X).find((d) => X[d] === i);
|
|
1824
|
-
o.setValue(l || null), a.setValue($e(t.getState(), "spacing") ? "Custom" : l ? "" :
|
|
1826
|
+
o.setValue(l || null), a.setValue($e(t.getState(), "spacing") ? "Custom" : l ? "" : gt(i));
|
|
1825
1827
|
};
|
|
1826
1828
|
r(), t.onChange(r), e.append(a.el);
|
|
1827
1829
|
}
|
|
@@ -1841,7 +1843,7 @@ const ft = (e) => `${Math.round(e * 100)}%`, yo = {
|
|
|
1841
1843
|
[800, "black", 58],
|
|
1842
1844
|
[900, "black", 45],
|
|
1843
1845
|
[950, "black", 30]
|
|
1844
|
-
],
|
|
1846
|
+
], mt = (e) => {
|
|
1845
1847
|
let t = String(e).trim().replace(/^#/, "");
|
|
1846
1848
|
return /^[0-9a-f]{3}$/i.test(t) && (t = t.split("").map((n) => n + n).join("")), /^[0-9a-f]{6}$/i.test(t) ? `#${t.toUpperCase()}` : null;
|
|
1847
1849
|
};
|
|
@@ -1859,15 +1861,15 @@ function $o({ label: e, onInput: t }) {
|
|
|
1859
1861
|
const i = document.createElement("button");
|
|
1860
1862
|
i.type = "button", i.className = "colour-pipette", i.innerHTML = ko, i.title = "Pick a colour from the screen", i.setAttribute("aria-label", "Pick a colour from the screen"), a.append(o, r, s, i);
|
|
1861
1863
|
const l = document.createElement("div");
|
|
1862
|
-
l.className = "ramp", l.setAttribute("aria-hidden", "true"), l.innerHTML = So.map(([
|
|
1863
|
-
const
|
|
1864
|
-
return `<span title="${
|
|
1864
|
+
l.className = "ramp", l.setAttribute("aria-hidden", "true"), l.innerHTML = So.map(([u, m, x]) => {
|
|
1865
|
+
const b = m ? `color-mix(in oklch, var(--brand) ${x}%, ${m})` : "var(--brand)";
|
|
1866
|
+
return `<span title="${u}" style="background:${b}"></span>`;
|
|
1865
1867
|
}).join(""), n.append(a, l);
|
|
1866
1868
|
let d = "#000000";
|
|
1867
|
-
const
|
|
1868
|
-
d =
|
|
1869
|
-
},
|
|
1870
|
-
|
|
1869
|
+
const p = (u) => {
|
|
1870
|
+
d = u, o.value = u.toLowerCase(), r.style.background = u, n.getRootNode().activeElement !== s && (s.value = u), n.style.setProperty("--brand", u);
|
|
1871
|
+
}, f = (u) => {
|
|
1872
|
+
u !== d && (p(u), t(u));
|
|
1871
1873
|
};
|
|
1872
1874
|
r.addEventListener("click", () => {
|
|
1873
1875
|
if (o.showPicker)
|
|
@@ -1877,25 +1879,25 @@ function $o({ label: e, onInput: t }) {
|
|
|
1877
1879
|
} catch {
|
|
1878
1880
|
}
|
|
1879
1881
|
o.click();
|
|
1880
|
-
}), o.addEventListener("input", () =>
|
|
1881
|
-
const
|
|
1882
|
-
|
|
1882
|
+
}), o.addEventListener("input", () => f(o.value.toUpperCase())), s.addEventListener("input", () => {
|
|
1883
|
+
const u = mt(s.value);
|
|
1884
|
+
u && f(u);
|
|
1883
1885
|
});
|
|
1884
|
-
const
|
|
1886
|
+
const v = () => {
|
|
1885
1887
|
s.value = d;
|
|
1886
1888
|
};
|
|
1887
|
-
return s.addEventListener("blur",
|
|
1888
|
-
|
|
1889
|
+
return s.addEventListener("blur", v), s.addEventListener("keydown", (u) => {
|
|
1890
|
+
u.key === "Enter" && (v(), s.select());
|
|
1889
1891
|
}), i.addEventListener("click", async () => {
|
|
1890
1892
|
if ("EyeDropper" in window)
|
|
1891
1893
|
try {
|
|
1892
|
-
const { sRGBHex:
|
|
1893
|
-
|
|
1894
|
+
const { sRGBHex: u } = await new window.EyeDropper().open(), m = mt(u);
|
|
1895
|
+
m && f(m);
|
|
1894
1896
|
} catch {
|
|
1895
1897
|
}
|
|
1896
1898
|
else
|
|
1897
1899
|
r.click();
|
|
1898
|
-
}), { el: n, setValue: (
|
|
1900
|
+
}), { el: n, setValue: (u) => p(mt(u) || d) };
|
|
1899
1901
|
}
|
|
1900
1902
|
function Eo({ label: e, options: t, onSelect: n }) {
|
|
1901
1903
|
const a = document.createElement("div");
|
|
@@ -1907,25 +1909,25 @@ function Eo({ label: e, options: t, onSelect: n }) {
|
|
|
1907
1909
|
a.append(...o);
|
|
1908
1910
|
let r = null;
|
|
1909
1911
|
function s(l) {
|
|
1910
|
-
r = l, o.forEach((
|
|
1911
|
-
const d = Math.max(0, o.findIndex((
|
|
1912
|
-
o.forEach((
|
|
1913
|
-
|
|
1912
|
+
r = l, o.forEach((p) => p.setAttribute("aria-checked", String(p.dataset.value === l)));
|
|
1913
|
+
const d = Math.max(0, o.findIndex((p) => p.dataset.value === l));
|
|
1914
|
+
o.forEach((p, f) => {
|
|
1915
|
+
p.tabIndex = f === d ? 0 : -1;
|
|
1914
1916
|
});
|
|
1915
1917
|
}
|
|
1916
1918
|
function i(l, d) {
|
|
1917
|
-
l !== r && (s(l), n(l)), d && o.find((
|
|
1919
|
+
l !== r && (s(l), n(l)), d && o.find((p) => p.dataset.value === l).focus();
|
|
1918
1920
|
}
|
|
1919
1921
|
return a.addEventListener("keydown", (l) => {
|
|
1920
1922
|
const d = o.indexOf(l.target.closest(".swatch"));
|
|
1921
1923
|
if (d < 0) return;
|
|
1922
|
-
const
|
|
1923
|
-
let
|
|
1924
|
-
if (
|
|
1925
|
-
else if (l.key === "Home")
|
|
1926
|
-
else if (l.key === "End")
|
|
1924
|
+
const p = { ArrowRight: 1, ArrowDown: 1, ArrowLeft: -1, ArrowUp: -1 }[l.key];
|
|
1925
|
+
let f;
|
|
1926
|
+
if (p) f = (d + p + o.length) % o.length;
|
|
1927
|
+
else if (l.key === "Home") f = 0;
|
|
1928
|
+
else if (l.key === "End") f = o.length - 1;
|
|
1927
1929
|
else return;
|
|
1928
|
-
l.preventDefault(), i(o[
|
|
1930
|
+
l.preventDefault(), i(o[f].dataset.value, !0);
|
|
1929
1931
|
}), s(null), { el: a, setValue: s };
|
|
1930
1932
|
}
|
|
1931
1933
|
const Co = [50, 100, 200, 300, 400, 500, 600, 700, 800, 900, 950], ke = (e) => Object.fromEntries(e.split(" ").map((t, n) => [Co[n], `#${t}`])), bt = {
|
|
@@ -1934,7 +1936,7 @@ const Co = [50, 100, 200, 300, 400, 500, 600, 700, 800, 900, 950], ke = (e) => O
|
|
|
1934
1936
|
zinc: ke("fafafa f4f4f5 e4e4e7 d4d4d8 a1a1aa 71717a 52525b 3f3f46 27272a 18181b 09090b"),
|
|
1935
1937
|
neutral: ke("fafafa f5f5f5 e5e5e5 d4d4d4 a3a3a3 737373 525252 404040 262626 171717 0a0a0a"),
|
|
1936
1938
|
stone: ke("fafaf9 f5f5f4 e7e5e4 d6d3d1 a8a29e 78716c 57534e 44403c 292524 1c1917 0c0a09")
|
|
1937
|
-
}, N = (e) => Object.fromEntries(e.split(" ").map((t, n) => [400 + 100 * n, `#${t}`])),
|
|
1939
|
+
}, N = (e) => Object.fromEntries(e.split(" ").map((t, n) => [400 + 100 * n, `#${t}`])), xt = {
|
|
1938
1940
|
red: N("f87171 ef4444 dc2626 b91c1c 991b1b"),
|
|
1939
1941
|
orange: N("fb923c f97316 ea580c c2410c 9a3412"),
|
|
1940
1942
|
amber: N("fbbf24 f59e0b d97706 b45309 92400e"),
|
|
@@ -1970,8 +1972,8 @@ const Co = [50, 100, 200, 300, 400, 500, 600, 700, 800, 900, 950], ke = (e) => O
|
|
|
1970
1972
|
text: "#F4F4F5",
|
|
1971
1973
|
"text-muted": "#A1A1AA",
|
|
1972
1974
|
border: "#2E2E33"
|
|
1973
|
-
}, Ao = { bg: 4, surface: 2, "surface-raised": 2, text: 5, "text-muted": 12, border: 10 }, ee = (e) => /^#[0-9a-f]{6}$/i.test(e || ""),
|
|
1974
|
-
function
|
|
1975
|
+
}, Ao = { bg: 4, surface: 2, "surface-raised": 2, text: 5, "text-muted": 12, border: 10 }, ee = (e) => /^#[0-9a-f]{6}$/i.test(e || ""), wt = (e) => [500, 600, 700].includes(Number(e.shade)) ? Number(e.shade) : 600, vt = (e) => e[0].toUpperCase() + e.slice(1);
|
|
1976
|
+
function Pn(e) {
|
|
1975
1977
|
const t = (l) => (l /= 255, l <= 0.03928 ? l / 12.92 : ((l + 0.055) / 1.055) ** 2.4), [n, a, o] = [1, 3, 5].map((l) => t(parseInt(e.slice(l, l + 2), 16))), r = 0.2126 * n + 0.7152 * a + 0.0722 * o, s = 1.05 / (r + 0.05), i = (r + 0.05) / (98e-4 + 0.05);
|
|
1976
1978
|
return s >= i ? "#FFFFFF" : "#18181B";
|
|
1977
1979
|
}
|
|
@@ -1981,20 +1983,20 @@ const Je = {
|
|
|
1981
1983
|
hint: "Brand colour · neutral tint · mode",
|
|
1982
1984
|
uses: ["--twd-primary", "--twd-primary-hover", "--twd-on-primary", "--twd-focus", ...An.map((e) => `--twd-${e}`)],
|
|
1983
1985
|
tokens(e) {
|
|
1984
|
-
const t = e.colour || {}, n = {}, a = t.mode === "dark", o =
|
|
1986
|
+
const t = e.colour || {}, n = {}, a = t.mode === "dark", o = xt[t.primary];
|
|
1985
1987
|
if (!ee(t.brand) && o) {
|
|
1986
|
-
const i =
|
|
1987
|
-
n["--twd-primary"] = o[i], n["--twd-primary-hover"] = o[a ? i - 100 : i + 100], n["--twd-on-primary"] =
|
|
1988
|
+
const i = wt(t);
|
|
1989
|
+
n["--twd-primary"] = o[i], n["--twd-primary-hover"] = o[a ? i - 100 : i + 100], n["--twd-on-primary"] = Pn(o[i]), n["--twd-focus"] = o[500];
|
|
1988
1990
|
}
|
|
1989
|
-
ee(t.brand) && (n["--twd-primary"] = t.brand, n["--twd-primary-hover"] = a ? `color-mix(in oklch, ${t.brand} 85%, white)` : `color-mix(in oklch, ${t.brand} 86%, black)`, n["--twd-on-primary"] =
|
|
1990
|
-
const r = t.tint === "subtle" ? ee(t.brand) ? t.brand :
|
|
1991
|
+
ee(t.brand) && (n["--twd-primary"] = t.brand, n["--twd-primary-hover"] = a ? `color-mix(in oklch, ${t.brand} 85%, white)` : `color-mix(in oklch, ${t.brand} 86%, black)`, n["--twd-on-primary"] = Pn(t.brand), n["--twd-focus"] = t.brand);
|
|
1992
|
+
const r = t.tint === "subtle" ? ee(t.brand) ? t.brand : L("--twd-primary") || Ln : t.tint === "warm" ? Mo : null, s = bt[t.neutral];
|
|
1991
1993
|
if (s) {
|
|
1992
1994
|
const i = a ? { bg: s[950], surface: s[900], "surface-raised": s[800], text: s[100], "text-muted": s[400], border: s[800] } : { bg: s[50], surface: "#ffffff", "surface-raised": "#ffffff", text: s[900], "text-muted": s[500], border: s[200] };
|
|
1993
1995
|
Object.entries(i).forEach(([l, d]) => {
|
|
1994
1996
|
n[`--twd-${l}`] = d;
|
|
1995
1997
|
});
|
|
1996
1998
|
} else (a || r) && An.forEach((i) => {
|
|
1997
|
-
const l = a ? Lo[i] :
|
|
1999
|
+
const l = a ? Lo[i] : L(`--twd-${i}`);
|
|
1998
2000
|
l && (n[`--twd-${i}`] = r ? `color-mix(in oklch, ${l} ${100 - Ao[i]}%, ${r})` : l);
|
|
1999
2001
|
});
|
|
2000
2002
|
return n;
|
|
@@ -2003,7 +2005,7 @@ const Je = {
|
|
|
2003
2005
|
// ---- Tabbed layout (Colour tab): themes, then Tailwind fine-tuning ----
|
|
2004
2006
|
themeTiles(e, t, { label: n = "Theme" } = {}) {
|
|
2005
2007
|
const a = (o) => {
|
|
2006
|
-
const r = bt[o.neutral], s =
|
|
2008
|
+
const r = bt[o.neutral], s = xt[o.primary];
|
|
2007
2009
|
return `<span class="theme" style="--bg:${r[50]};--line:${r[200]};--ink:${r[900]};--soft:${r[500]};--pri:${s[600]}"><i><b></b><s></s><u></u></i></span><span class="palette">${[s[400], s[500], s[600], s[700], s[800], r[200], r[500], r[900]].map((i) => `<i style="background:${i}"></i>`).join("")}</span>`;
|
|
2008
2010
|
};
|
|
2009
2011
|
e.append(_(t, {
|
|
@@ -2034,7 +2036,7 @@ const Je = {
|
|
|
2034
2036
|
label: `${n} colour family`,
|
|
2035
2037
|
columns: 9,
|
|
2036
2038
|
className: "tiles-swatches",
|
|
2037
|
-
options: Object.entries(
|
|
2039
|
+
options: Object.entries(xt).map(([i, l]) => ({ value: i, label: vt(i), title: vt(i), preview: `<span class="dot" style="background:${l[500]}"></span>` })),
|
|
2038
2040
|
current: (i) => {
|
|
2039
2041
|
const l = i.colour || {};
|
|
2040
2042
|
return ee(l.brand) ? null : l.primary || null;
|
|
@@ -2046,7 +2048,7 @@ const Je = {
|
|
|
2046
2048
|
a.append(o, r.el);
|
|
2047
2049
|
const s = () => {
|
|
2048
2050
|
const i = t.getState().colour || {};
|
|
2049
|
-
r.setValue(String(
|
|
2051
|
+
r.setValue(String(wt(i))), a.setValue(ee(i.brand) ? i.brand.toLowerCase() : i.primary ? `${i.primary}-${wt(i)}` : "");
|
|
2050
2052
|
};
|
|
2051
2053
|
s(), t.onChange(s), e.append(a.el);
|
|
2052
2054
|
},
|
|
@@ -2057,7 +2059,7 @@ const Je = {
|
|
|
2057
2059
|
label: n,
|
|
2058
2060
|
columns: 5,
|
|
2059
2061
|
className: "tiles-greys",
|
|
2060
|
-
options: Object.entries(bt).map(([a, o]) => ({ value: a, label:
|
|
2062
|
+
options: Object.entries(bt).map(([a, o]) => ({ value: a, label: vt(a), preview: `<span class="greys">${[o[50], o[200], o[500], o[900]].map((r) => `<i style="background:${r}"></i>`).join("")}</span>` })),
|
|
2061
2063
|
select: (a) => t.setSection("colour", { neutral: a, tint: null }),
|
|
2062
2064
|
valueText: (a) => a || ""
|
|
2063
2065
|
}));
|
|
@@ -2071,7 +2073,7 @@ const Je = {
|
|
|
2071
2073
|
brand(e, t, { label: n = "Brand" } = {}) {
|
|
2072
2074
|
const a = D(n), o = $o({ label: "Brand colour", onInput: (s) => t.setSection("colour", { brand: s }) });
|
|
2073
2075
|
a.append(o.el);
|
|
2074
|
-
const r = () => o.setValue((t.getState().colour || {}).brand || (t.readToken ||
|
|
2076
|
+
const r = () => o.setValue((t.getState().colour || {}).brand || (t.readToken || L)("--twd-primary") || Ln);
|
|
2075
2077
|
r(), t.onChange(r), e.append(a.el);
|
|
2076
2078
|
},
|
|
2077
2079
|
neutral(e, t, { label: n = "Neutral" } = {}) {
|
|
@@ -2093,12 +2095,12 @@ const Je = {
|
|
|
2093
2095
|
render(e, t) {
|
|
2094
2096
|
["brand", "neutral", "mode"].forEach((n) => this.parts[n](e, t));
|
|
2095
2097
|
}
|
|
2096
|
-
}, Ve = (e, t = "var(--twd-surface)") => `color-mix(in oklch, var(--twd-primary) ${e}%, ${t})`,
|
|
2098
|
+
}, Ve = (e, t = "var(--twd-surface)") => `color-mix(in oklch, var(--twd-primary) ${e}%, ${t})`, Po = {
|
|
2097
2099
|
// proposal recipes; Solid leaves tokens.css defaults
|
|
2098
2100
|
soft: { bg: Ve(14), fg: "var(--twd-primary)", border: "transparent", hover: Ve(22) },
|
|
2099
2101
|
outline: { bg: "transparent", fg: "var(--twd-primary)", border: "var(--twd-primary)", hover: Ve(8, "transparent") },
|
|
2100
2102
|
ghost: { bg: "transparent", fg: "var(--twd-primary)", border: "transparent", hover: Ve(10, "transparent") }
|
|
2101
|
-
},
|
|
2103
|
+
}, Oo = { small: { height: 0.8, pad: 0.75 }, large: { height: 1.2, pad: 1.25 } }, ia = aa({
|
|
2102
2104
|
id: "buttons",
|
|
2103
2105
|
title: "Buttons",
|
|
2104
2106
|
hint: "Style · corners · size",
|
|
@@ -2118,13 +2120,13 @@ const Je = {
|
|
|
2118
2120
|
{ value: "pill", label: "Pill", radius: 999 }
|
|
2119
2121
|
],
|
|
2120
2122
|
extraTokens(e) {
|
|
2121
|
-
const t = {}, n =
|
|
2123
|
+
const t = {}, n = Po[e.style];
|
|
2122
2124
|
n && Object.entries(n).forEach(([s, i]) => {
|
|
2123
2125
|
t[`--twd-button-${s}`] = i;
|
|
2124
2126
|
});
|
|
2125
|
-
const a =
|
|
2127
|
+
const a = Oo[e.size];
|
|
2126
2128
|
if (!a) return t;
|
|
2127
|
-
const o = Ce(
|
|
2129
|
+
const o = Ce(L("--twd-control-height"), a.height), r = Ce(L("--twd-control-pad-x"), a.pad);
|
|
2128
2130
|
return o && (t["--twd-control-height"] = o), r && (t["--twd-control-pad-x"] = r), t;
|
|
2129
2131
|
},
|
|
2130
2132
|
extra: [
|
|
@@ -2140,25 +2142,21 @@ const Je = {
|
|
|
2140
2142
|
key: "size",
|
|
2141
2143
|
label: "Size",
|
|
2142
2144
|
fallback: "medium",
|
|
2145
|
+
valueText: (e, t) => t("--twd-control-height"),
|
|
2146
|
+
// the height in effect (Shape pass)
|
|
2143
2147
|
preview: (e) => `<span class="shape shape-button size-${e}"></span>`,
|
|
2144
2148
|
options: [{ value: "small", label: "Small" }, { value: "medium", label: "Medium" }, { value: "large", label: "Large" }]
|
|
2145
2149
|
}
|
|
2146
2150
|
]
|
|
2147
|
-
}),
|
|
2151
|
+
}), jo = {
|
|
2148
2152
|
// proposal recipes; Filled leaves tokens.css defaults
|
|
2149
2153
|
outlined: { bg: "transparent", border: "color-mix(in oklch, var(--twd-border) 60%, var(--twd-text))", shadow: "none" },
|
|
2150
2154
|
elevated: { bg: "var(--twd-surface-raised)", border: "transparent", shadow: "var(--twd-shadow-md)" },
|
|
2151
2155
|
tinted: { bg: "color-mix(in oklch, var(--twd-primary) 8%, var(--twd-surface))", border: "color-mix(in oklch, var(--twd-primary) 25%, var(--twd-surface))", shadow: "none" }
|
|
2152
|
-
},
|
|
2153
|
-
// proposal
|
|
2154
|
-
none: "transparent",
|
|
2155
|
-
surface: "var(--twd-surface)",
|
|
2156
|
-
raised: "var(--twd-surface-raised)",
|
|
2157
|
-
tinted: "color-mix(in oklch, var(--twd-primary) 8%, var(--twd-surface))"
|
|
2158
|
-
}, Fo = { outlined: "Outlined", elevated: "Elevated", tinted: "Tinted" }, jt = oa({
|
|
2156
|
+
}, Ft = aa({
|
|
2159
2157
|
id: "cards",
|
|
2160
2158
|
title: "Cards",
|
|
2161
|
-
hint: "Style · corners ·
|
|
2159
|
+
hint: "Style · corners · border",
|
|
2162
2160
|
token: "--twd-radius-container",
|
|
2163
2161
|
shape: "card",
|
|
2164
2162
|
// tile previews: an outlined card
|
|
@@ -2175,11 +2173,11 @@ const Je = {
|
|
|
2175
2173
|
// proposal (cards don't go fully pill)
|
|
2176
2174
|
],
|
|
2177
2175
|
extraTokens(e) {
|
|
2178
|
-
const t = {}, n =
|
|
2176
|
+
const t = {}, n = jo[e.style];
|
|
2179
2177
|
if (n && Object.entries(n).forEach(([a, o]) => {
|
|
2180
2178
|
t[`--twd-card-${a}`] = o;
|
|
2181
|
-
}),
|
|
2182
|
-
const a = Ce(
|
|
2179
|
+
}), e.border === "none" && (t["--twd-border-width-container"] = "0px"), e.border === "thick") {
|
|
2180
|
+
const a = Ce(L("--twd-border-width-container"), 2);
|
|
2183
2181
|
a && (t["--twd-border-width-container"] = a);
|
|
2184
2182
|
}
|
|
2185
2183
|
return t;
|
|
@@ -2190,19 +2188,9 @@ const Je = {
|
|
|
2190
2188
|
label: "Style",
|
|
2191
2189
|
fallback: "filled",
|
|
2192
2190
|
columns: 4,
|
|
2193
|
-
|
|
2194
|
-
|
|
2195
|
-
|
|
2196
|
-
},
|
|
2197
|
-
// a style is a whole recipe, its fill included
|
|
2198
|
-
{
|
|
2199
|
-
key: "fill",
|
|
2200
|
-
label: "Fill",
|
|
2201
|
-
columns: 4,
|
|
2202
|
-
preview: (e) => `<span class="shape shape-card fill-${e}"></span>`,
|
|
2203
|
-
options: [{ value: "none", label: "None" }, { value: "surface", label: "Surface" }, { value: "raised", label: "Raised" }, { value: "tinted", label: "Tinted" }],
|
|
2204
|
-
current: (e) => e.fill || (vt[e.style] ? null : "surface"),
|
|
2205
|
-
valueText: (e) => !e.fill && vt[e.style] ? `${Fo[e.style]} · from Style` : ""
|
|
2191
|
+
// A mini card with two content lines on a page backdrop (Figma 281:1421)
|
|
2192
|
+
preview: (e) => `<span class="mini"><span class="mini-card style-${e}"><i></i><i></i></span></span>`,
|
|
2193
|
+
options: [{ value: "filled", label: "Filled" }, { value: "outlined", label: "Outlined" }, { value: "elevated", label: "Elevated" }, { value: "tinted", label: "Tinted" }]
|
|
2206
2194
|
},
|
|
2207
2195
|
{
|
|
2208
2196
|
key: "border",
|
|
@@ -2214,7 +2202,7 @@ const Je = {
|
|
|
2214
2202
|
options: [{ value: "none", label: "None" }, { value: "thin", label: "Thin" }, { value: "thick", label: "Thick" }]
|
|
2215
2203
|
}
|
|
2216
2204
|
]
|
|
2217
|
-
}), qe = (e) => !(e.depth || {}).style && he(e, "--twd-shadow-md"),
|
|
2205
|
+
}), qe = (e) => !(e.depth || {}).style && he(e, "--twd-shadow-md"), Fo = (e) => ((e.character || {}).bold || 0.5) > 0.5, G = 60, yt = {
|
|
2218
2206
|
soft: { sm: [0, 1, 2, 0, 0.06], md: [0, 4, 12, 0, 0.08], lg: [0, 12, 32, 0, 0.12] },
|
|
2219
2207
|
// = tokens.css
|
|
2220
2208
|
crisp: { sm: [0, 1, 1, 0, 0.12], md: [0, 2, 4, 0, 0.14], lg: [0, 4, 8, 0, 0.16] },
|
|
@@ -2253,7 +2241,7 @@ const Je = {
|
|
|
2253
2241
|
columns: 4,
|
|
2254
2242
|
options: ["flat", "soft", "crisp", "bold"].map((o) => ({ value: o, label: o[0].toUpperCase() + o.slice(1), preview: a(o) })),
|
|
2255
2243
|
current: (o) => (o.depth || {}).style || (qe(o) ? null : "soft"),
|
|
2256
|
-
valueText: (o, r) => qe(r) ? `${
|
|
2244
|
+
valueText: (o, r) => qe(r) ? `${Fo(r) ? "Bold recipe" : "Soft, faded"} · from Character` : ""
|
|
2257
2245
|
}));
|
|
2258
2246
|
},
|
|
2259
2247
|
style(e, t, { label: n = "Style" } = {}) {
|
|
@@ -2287,11 +2275,11 @@ const Je = {
|
|
|
2287
2275
|
render(e, t) {
|
|
2288
2276
|
Object.entries(this.parts).filter(([n]) => !n.endsWith("Tiles")).forEach(([, n]) => n(e, t));
|
|
2289
2277
|
}
|
|
2290
|
-
}, No = (e) => Math.min(1, Math.max(0, e)),
|
|
2278
|
+
}, No = (e) => Math.min(1, Math.max(0, e)), On = (e) => Math.round(e / 50) * 50, kt = (e) => `${+e.toFixed(1)}%`;
|
|
2291
2279
|
function Bt(e = {}) {
|
|
2292
2280
|
return typeof e.bold == "number" && isFinite(e.bold) && e.bold !== 0.5 ? No(e.bold) : null;
|
|
2293
2281
|
}
|
|
2294
|
-
const _e = (e, t, n) => (e.tokens(t) || {})[n] ||
|
|
2282
|
+
const _e = (e, t, n) => (e.tokens(t) || {})[n] || L(n), la = {
|
|
2295
2283
|
id: "character",
|
|
2296
2284
|
title: "Character",
|
|
2297
2285
|
hint: "Subtle ↔ Bold",
|
|
@@ -2301,17 +2289,17 @@ const _e = (e, t, n) => (e.tokens(t) || {})[n] || O(n), da = {
|
|
|
2301
2289
|
const t = Bt(e.character);
|
|
2302
2290
|
if (t === null) return {};
|
|
2303
2291
|
const n = {}, a = 2 * t - 1, o = Math.max(0, a), r = Math.max(0, -a);
|
|
2304
|
-
n["--twd-weight-heading"] = String(
|
|
2292
|
+
n["--twd-weight-heading"] = String(On(600 + 200 * a)), n["--twd-weight-strong"] = String(On(600 + 100 * a));
|
|
2305
2293
|
const s = _e(Je, e, "--twd-border");
|
|
2306
2294
|
if (r && (n["--twd-border"] = `color-mix(in oklch, ${s} ${kt(100 - 50 * r)}, var(--twd-bg))`), o) {
|
|
2307
2295
|
n["--twd-border"] = `color-mix(in oklch, ${s} ${kt(100 - 90 * o)}, var(--twd-text))`;
|
|
2308
2296
|
const l = _e(Je, e, "--twd-text-muted");
|
|
2309
2297
|
n["--twd-text-muted"] = `color-mix(in oklch, ${l} ${kt(100 - 35 * o)}, var(--twd-text))`, ["--twd-border-width", "--twd-border-width-container"].forEach((d) => {
|
|
2310
|
-
const
|
|
2311
|
-
|
|
2312
|
-
}), [[
|
|
2313
|
-
const
|
|
2314
|
-
|
|
2298
|
+
const p = d === "--twd-border-width-container" ? _e(Ft, e, d) : L(d), f = parseFloat(p);
|
|
2299
|
+
f > 0 && (n[d] = `${Math.round(f * (1 + o))}px`);
|
|
2300
|
+
}), [[ia, "--twd-radius-control"], [Ft, "--twd-radius-container"]].forEach(([d, p]) => {
|
|
2301
|
+
const f = parseFloat(_e(d, e, p));
|
|
2302
|
+
f > 0 && f < 999 && (n[p] = Ce(`${f}px`, 1 - 0.5 * o));
|
|
2315
2303
|
});
|
|
2316
2304
|
}
|
|
2317
2305
|
const i = e.depth || {};
|
|
@@ -2323,7 +2311,7 @@ const _e = (e, t, n) => (e.tokens(t) || {})[n] || O(n), da = {
|
|
|
2323
2311
|
},
|
|
2324
2312
|
describe: (e, t) => e === "bold" ? { label: "Subtle ↔ Bold", value: `${Math.round(t * 100)}%` } : null
|
|
2325
2313
|
};
|
|
2326
|
-
|
|
2314
|
+
mo((e) => la.tokens(e));
|
|
2327
2315
|
const Ro = '<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M6 9l6 6 6-6"/></svg>', zo = '<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M5 12.5l4.5 4.5L19 7.5"/></svg>';
|
|
2328
2316
|
let Io = 0;
|
|
2329
2317
|
function Do({ label: e, options: t, onSelect: n, placeholder: a, onOpen: o }) {
|
|
@@ -2337,56 +2325,56 @@ function Do({ label: e, options: t, onSelect: n, placeholder: a, onOpen: o }) {
|
|
|
2337
2325
|
<span class="font-chevron">${Ro}</span>`;
|
|
2338
2326
|
const l = document.createElement("div");
|
|
2339
2327
|
l.className = "font-menu", l.id = r, l.setAttribute("role", "listbox"), l.setAttribute("aria-label", e), l.hidden = !0;
|
|
2340
|
-
const d = t.map((
|
|
2341
|
-
const
|
|
2342
|
-
return
|
|
2343
|
-
<span class="font-aa" style="font-family:${
|
|
2344
|
-
<span class="font-text"><span class="font-name">${
|
|
2345
|
-
<span class="font-check">${zo}</span>`,
|
|
2328
|
+
const d = t.map((h) => {
|
|
2329
|
+
const w = document.createElement("div");
|
|
2330
|
+
return w.className = "font-option", w.setAttribute("role", "option"), w.tabIndex = -1, w.dataset.value = h.value, w.innerHTML = `
|
|
2331
|
+
<span class="font-aa" style="font-family:${h.preview}" aria-hidden="true">Aa</span>
|
|
2332
|
+
<span class="font-text"><span class="font-name">${h.name}</span><span class="font-fonts">${h.fonts}</span></span>
|
|
2333
|
+
<span class="font-check">${zo}</span>`, w.addEventListener("click", () => b(h.value)), w;
|
|
2346
2334
|
});
|
|
2347
2335
|
l.append(...d), s.append(i, l);
|
|
2348
|
-
let
|
|
2349
|
-
function
|
|
2350
|
-
const
|
|
2351
|
-
|
|
2336
|
+
let p = null;
|
|
2337
|
+
function f(h) {
|
|
2338
|
+
const w = t.find(($) => $.value === h), S = w || a || t[0];
|
|
2339
|
+
p = w ? w.value : a ? null : t[0].value, i.querySelector(".font-name").textContent = S.name, i.querySelector(".font-fonts").textContent = S.fonts, i.querySelector(".font-aa").style.fontFamily = S.preview, i.setAttribute("aria-label", `${e}: ${S.name}, ${S.fonts}`), d.forEach(($) => $.setAttribute("aria-selected", String($.dataset.value === p)));
|
|
2352
2340
|
}
|
|
2353
|
-
function
|
|
2354
|
-
const
|
|
2355
|
-
l.style.top = `${$}px`, l.style.left = `${
|
|
2341
|
+
function v() {
|
|
2342
|
+
const h = i.getBoundingClientRect(), w = l.offsetHeight, $ = window.innerHeight - h.bottom - 8 >= w ? h.bottom + 4 : Math.max(8, h.top - 4 - w);
|
|
2343
|
+
l.style.top = `${$}px`, l.style.left = `${h.left}px`, l.style.width = `${h.width}px`;
|
|
2356
2344
|
}
|
|
2357
|
-
function
|
|
2358
|
-
l.hidden && (l.hidden = !1, i.setAttribute("aria-expanded", "true"), o && o(),
|
|
2345
|
+
function u() {
|
|
2346
|
+
l.hidden && (l.hidden = !1, i.setAttribute("aria-expanded", "true"), o && o(), v(), (d.find((h) => h.dataset.value === p) || d[0]).focus(), setTimeout(() => document.addEventListener("pointerdown", x, !0)), window.addEventListener("resize", m), s.closest(".body")?.addEventListener("scroll", m, { once: !0 }));
|
|
2359
2347
|
}
|
|
2360
|
-
function
|
|
2361
|
-
l.hidden || (l.hidden = !0, i.setAttribute("aria-expanded", "false"), document.removeEventListener("pointerdown", x, !0), window.removeEventListener("resize",
|
|
2348
|
+
function m(h) {
|
|
2349
|
+
l.hidden || (l.hidden = !0, i.setAttribute("aria-expanded", "false"), document.removeEventListener("pointerdown", x, !0), window.removeEventListener("resize", m), h === !0 && i.focus());
|
|
2362
2350
|
}
|
|
2363
|
-
function x(
|
|
2364
|
-
|
|
2351
|
+
function x(h) {
|
|
2352
|
+
h.composedPath().includes(s) || m();
|
|
2365
2353
|
}
|
|
2366
|
-
function
|
|
2367
|
-
|
|
2354
|
+
function b(h) {
|
|
2355
|
+
h !== p && (f(h), n(h)), m(!0);
|
|
2368
2356
|
}
|
|
2369
|
-
return i.addEventListener("click", () => l.hidden ?
|
|
2370
|
-
(
|
|
2371
|
-
}), l.addEventListener("keydown", (
|
|
2372
|
-
const
|
|
2357
|
+
return i.addEventListener("click", () => l.hidden ? u() : m(!0)), i.addEventListener("keydown", (h) => {
|
|
2358
|
+
(h.key === "ArrowDown" || h.key === "ArrowUp") && (h.preventDefault(), u());
|
|
2359
|
+
}), l.addEventListener("keydown", (h) => {
|
|
2360
|
+
const w = d.indexOf(h.target);
|
|
2373
2361
|
let S = null;
|
|
2374
|
-
if (
|
|
2375
|
-
else if (
|
|
2376
|
-
else if (
|
|
2377
|
-
else if (
|
|
2378
|
-
else if (
|
|
2379
|
-
|
|
2362
|
+
if (h.key === "ArrowDown") S = Math.min(d.length - 1, w + 1);
|
|
2363
|
+
else if (h.key === "ArrowUp") S = Math.max(0, w - 1);
|
|
2364
|
+
else if (h.key === "Home") S = 0;
|
|
2365
|
+
else if (h.key === "End") S = d.length - 1;
|
|
2366
|
+
else if (h.key === "Enter" || h.key === " ") {
|
|
2367
|
+
h.preventDefault(), b(h.target.dataset.value);
|
|
2380
2368
|
return;
|
|
2381
|
-
} else if (
|
|
2382
|
-
|
|
2369
|
+
} else if (h.key === "Escape") {
|
|
2370
|
+
h.preventDefault(), h.stopPropagation(), m(!0);
|
|
2383
2371
|
return;
|
|
2384
|
-
} else if (
|
|
2385
|
-
|
|
2372
|
+
} else if (h.key === "Tab") {
|
|
2373
|
+
m();
|
|
2386
2374
|
return;
|
|
2387
2375
|
}
|
|
2388
|
-
S !== null && (
|
|
2389
|
-
}),
|
|
2376
|
+
S !== null && (h.preventDefault(), d[S].focus());
|
|
2377
|
+
}), f(a ? null : t[0].value), { el: s, setValue: f };
|
|
2390
2378
|
}
|
|
2391
2379
|
const z = 'ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, sans-serif', Ke = 'Georgia, "Times New Roman", serif', ae = [
|
|
2392
2380
|
{ value: "neutral", name: "Neutral", fonts: "Inter · Inter", heading: `"Inter", ${z}`, body: `"Inter", ${z}`, load: ["Inter:wght@400;500;600;700"] },
|
|
@@ -2397,11 +2385,11 @@ const z = 'ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, sans-ser
|
|
|
2397
2385
|
{ value: "plex", name: "Plex", fonts: "Plex Serif · Plex Sans", heading: `"IBM Plex Serif", ${Ke}`, body: `"IBM Plex Sans", ${z}`, load: ["IBM+Plex+Serif:wght@500;600;700", "IBM+Plex+Sans:wght@400;500;600"] },
|
|
2398
2386
|
{ value: "elegant", name: "Elegant", fonts: "Instrument Serif · Inter", heading: `"Instrument Serif", ${Ke}`, body: `"Inter", ${z}`, load: ["Instrument+Serif", "Inter:wght@400;500;600;700"] },
|
|
2399
2387
|
{ value: "friendly", name: "Friendly", fonts: "Manrope · Manrope", heading: `"Manrope", ${z}`, body: `"Manrope", ${z}`, load: ["Manrope:wght@400;500;600;700"] }
|
|
2400
|
-
], Se = { compact: 1.125, balanced: 1.2, expressive: 1.333 }, jn = { xs: -2, sm: -1, base: 0, lg: 1, xl: 2, "2xl": 3, "3xl": 4 },
|
|
2388
|
+
], Se = { compact: 1.125, balanced: 1.2, expressive: 1.333 }, jn = { xs: -2, sm: -1, base: 0, lg: 1, xl: 2, "2xl": 3, "3xl": 4 }, Fn = /* @__PURE__ */ new Set();
|
|
2401
2389
|
function St(e) {
|
|
2402
|
-
const t = e.filter((a) => !
|
|
2390
|
+
const t = e.filter((a) => !Fn.has(a));
|
|
2403
2391
|
if (!t.length) return;
|
|
2404
|
-
t.forEach((a) =>
|
|
2392
|
+
t.forEach((a) => Fn.add(a));
|
|
2405
2393
|
const n = document.createElement("link");
|
|
2406
2394
|
n.rel = "stylesheet", n.href = `https://fonts.googleapis.com/css2?${t.map((a) => `family=${a}`).join("&")}&display=swap`, n.dataset.twiddle = "fonts", document.head.appendChild(n);
|
|
2407
2395
|
}
|
|
@@ -2468,7 +2456,7 @@ const Bo = {
|
|
|
2468
2456
|
// The weights in effect; Subtle ↔ Bold on the Character pad moves them (linked settings, rule 2).
|
|
2469
2457
|
weights(e, t, { label: n = "Weights" } = {}) {
|
|
2470
2458
|
const a = D(n), o = () => {
|
|
2471
|
-
const r = t.getState(), s =
|
|
2459
|
+
const r = t.getState(), s = L("--twd-weight-heading"), i = L("--twd-weight-strong");
|
|
2472
2460
|
a.setValue(s || i ? `Headings ${s || "—"} · strong ${i || "—"}${he(r, "--twd-weight-heading") ? " · from Character" : ""}` : "");
|
|
2473
2461
|
};
|
|
2474
2462
|
o(), t.onChange(o), e.append(a.el);
|
|
@@ -2498,17 +2486,17 @@ const Bo = {
|
|
|
2498
2486
|
render(e, t) {
|
|
2499
2487
|
Object.entries(this.parts).filter(([n]) => !n.endsWith("Tiles")).forEach(([, n]) => n(e, t));
|
|
2500
2488
|
}
|
|
2501
|
-
}, [
|
|
2489
|
+
}, [Nn, We] = jt;
|
|
2502
2490
|
function Uo(e) {
|
|
2503
2491
|
return e > 0.56 ? "Bold" : e < 0.44 ? "Subtle" : "Balanced";
|
|
2504
2492
|
}
|
|
2505
2493
|
function Vo(e) {
|
|
2506
2494
|
return $e(e, "spacing") ? "Custom spacing" : Dt(H(e.density));
|
|
2507
2495
|
}
|
|
2508
|
-
const Ge = (e) => e && e[0].toUpperCase() + e.slice(1),
|
|
2496
|
+
const Ge = (e) => e && e[0].toUpperCase() + e.slice(1), Rn = [
|
|
2509
2497
|
["colour", "Colour", (e) => {
|
|
2510
2498
|
const t = e.colour || {}, n = Xe.find((o) => o.primary === t.primary && o.neutral === t.neutral);
|
|
2511
|
-
return { text: `${t.brand ? t.brand.toUpperCase() : n && !t.shade ? n.label : t.primary ? `${Ge(t.primary)}${t.neutral ? ` · ${Ge(t.neutral)}` : ""}` : "Prototype colours"}${t.mode === "dark" ? " · Dark" : ""}`, swatch:
|
|
2499
|
+
return { text: `${t.brand ? t.brand.toUpperCase() : n && !t.shade ? n.label : t.primary ? `${Ge(t.primary)}${t.neutral ? ` · ${Ge(t.neutral)}` : ""}` : "Prototype colours"}${t.mode === "dark" ? " · Dark" : ""}`, swatch: L("--twd-primary") };
|
|
2512
2500
|
}],
|
|
2513
2501
|
["type", "Type", (e) => {
|
|
2514
2502
|
const t = e.typography || {};
|
|
@@ -2520,17 +2508,17 @@ const Ge = (e) => e && e[0].toUpperCase() + e.slice(1), zn = [
|
|
|
2520
2508
|
], qo = {
|
|
2521
2509
|
summary(e, t, { label: n = "Current look", goTab: a } = {}) {
|
|
2522
2510
|
const o = D(n), r = document.createElement("div");
|
|
2523
|
-
r.className = "summary",
|
|
2511
|
+
r.className = "summary", Rn.forEach(([i, l]) => {
|
|
2524
2512
|
const d = document.createElement("button");
|
|
2525
|
-
d.type = "button", d.className = "summary-row", d.dataset.summary = i, d.innerHTML = `<span class="summary-name"></span><span class="summary-swatch" hidden></span><span class="summary-value"></span><span class="chev" aria-hidden="true">${
|
|
2513
|
+
d.type = "button", d.className = "summary-row", d.dataset.summary = i, d.innerHTML = `<span class="summary-name"></span><span class="summary-swatch" hidden></span><span class="summary-value"></span><span class="chev" aria-hidden="true">${P.chevron}</span>`, d.querySelector(".summary-name").textContent = l, d.addEventListener("click", () => a && a(i)), r.append(d);
|
|
2526
2514
|
}), o.append(r);
|
|
2527
2515
|
const s = () => {
|
|
2528
2516
|
const i = t.getState();
|
|
2529
|
-
|
|
2530
|
-
const
|
|
2531
|
-
|
|
2532
|
-
const
|
|
2533
|
-
|
|
2517
|
+
Rn.forEach(([l, , d]) => {
|
|
2518
|
+
const p = r.querySelector(`[data-summary="${l}"]`), f = d(i);
|
|
2519
|
+
p.querySelector(".summary-value").textContent = f.text;
|
|
2520
|
+
const v = p.querySelector(".summary-swatch");
|
|
2521
|
+
v.hidden = !f.swatch, f.swatch && (v.style.background = f.swatch);
|
|
2534
2522
|
});
|
|
2535
2523
|
};
|
|
2536
2524
|
s(), t.onChange(s), e.append(o.el);
|
|
@@ -2540,7 +2528,7 @@ const Ge = (e) => e && e[0].toUpperCase() + e.slice(1), zn = [
|
|
|
2540
2528
|
label: n,
|
|
2541
2529
|
ends: { top: "Spacious", bottom: "Compact", left: "Subtle", right: "Bold" },
|
|
2542
2530
|
onInput: (s, i) => {
|
|
2543
|
-
const l = +(We - i * (We -
|
|
2531
|
+
const l = +(We - i * (We - Nn)).toFixed(3), d = +s.toFixed(3);
|
|
2544
2532
|
t.setSections({
|
|
2545
2533
|
density: { factor: l === 1 ? null : l, spacing: null },
|
|
2546
2534
|
character: { bold: d === 0.5 ? null : d }
|
|
@@ -2549,8 +2537,8 @@ const Ge = (e) => e && e[0].toUpperCase() + e.slice(1), zn = [
|
|
|
2549
2537
|
});
|
|
2550
2538
|
a.append(o.el);
|
|
2551
2539
|
const r = () => {
|
|
2552
|
-
const s = t.getState(), i = H(s.density), l = Bt(s.character), d = l === null ? 0.5 : l,
|
|
2553
|
-
o.setValue(d, (We - i) / (We -
|
|
2540
|
+
const s = t.getState(), i = H(s.density), l = Bt(s.character), d = l === null ? 0.5 : l, p = `${Vo(s)} · ${Uo(d)}`;
|
|
2541
|
+
o.setValue(d, (We - i) / (We - Nn), p), a.setValue(p);
|
|
2554
2542
|
};
|
|
2555
2543
|
r(), t.onChange(r), e.append(a.el);
|
|
2556
2544
|
}
|
|
@@ -2572,43 +2560,43 @@ function Ko(e, t, n) {
|
|
|
2572
2560
|
<label class="token-value role-fixed" hidden><input type="text" inputmode="decimal" spellcheck="false" aria-label="${t.label}, fixed value"><span class="token-unit">px</span></label>
|
|
2573
2561
|
<span class="step-select">
|
|
2574
2562
|
<select aria-label="${t.label}"></select>
|
|
2575
|
-
<span class="step-chevron" aria-hidden="true">${
|
|
2563
|
+
<span class="step-chevron" aria-hidden="true">${P.down}</span>
|
|
2576
2564
|
</span>
|
|
2577
|
-
<button class="icon-btn token-reset" title="Back to the default" aria-label="Reset ${t.label}" hidden>${
|
|
2565
|
+
<button class="icon-btn token-reset" title="Back to the default" aria-label="Reset ${t.label}" hidden>${P.reset}</button>
|
|
2578
2566
|
`;
|
|
2579
|
-
const r = o.querySelector("select"), s = o.querySelector(".role-fixed"), i = s.querySelector("input"), l = o.querySelector(".token-reset"), d = () => (e.getState().custom || {})[t.key],
|
|
2567
|
+
const r = o.querySelector("select"), s = o.querySelector(".role-fixed"), i = s.querySelector("input"), l = o.querySelector(".token-reset"), d = () => (e.getState().custom || {})[t.key], p = () => {
|
|
2580
2568
|
const x = d();
|
|
2581
|
-
if (x == null) return t.step ? { step: t.step } : { fixed:
|
|
2582
|
-
const
|
|
2583
|
-
return
|
|
2584
|
-
},
|
|
2569
|
+
if (x == null) return t.step ? { step: t.step } : { fixed: L(a) };
|
|
2570
|
+
const b = _o.exec(x);
|
|
2571
|
+
return b ? { step: +b[1] } : { fixed: x };
|
|
2572
|
+
}, f = (x) => e.setSection("custom", { [t.key]: x }), v = (x) => t.step ? x === `var(--twd-space-${t.step})` : !1;
|
|
2585
2573
|
r.addEventListener("change", () => {
|
|
2586
2574
|
if (r.value === "fixed") {
|
|
2587
|
-
const
|
|
2588
|
-
|
|
2575
|
+
const b = Et(L(a));
|
|
2576
|
+
f(b != null ? `${b}px` : L(a)), i.focus(), i.select();
|
|
2589
2577
|
return;
|
|
2590
2578
|
}
|
|
2591
2579
|
const x = `var(--twd-space-${r.value})`;
|
|
2592
|
-
|
|
2580
|
+
f(v(x) ? null : x);
|
|
2593
2581
|
});
|
|
2594
|
-
const
|
|
2582
|
+
const u = () => {
|
|
2595
2583
|
const x = i.value.trim();
|
|
2596
|
-
if (!x) return
|
|
2597
|
-
|
|
2584
|
+
if (!x) return f(null);
|
|
2585
|
+
f(/^-?\d*\.?\d+$/.test(x) ? `${x}px` : x);
|
|
2598
2586
|
};
|
|
2599
|
-
i.addEventListener("change",
|
|
2600
|
-
x.key === "Enter" && (x.preventDefault(), i.blur()), x.key === "Escape" && (x.stopPropagation(),
|
|
2601
|
-
}), l.addEventListener("click", () =>
|
|
2602
|
-
function
|
|
2603
|
-
const x =
|
|
2604
|
-
if (r.innerHTML = Ho.map((
|
|
2605
|
-
const
|
|
2606
|
-
i.value =
|
|
2587
|
+
i.addEventListener("change", u), i.addEventListener("blur", () => m()), i.addEventListener("keydown", (x) => {
|
|
2588
|
+
x.key === "Enter" && (x.preventDefault(), i.blur()), x.key === "Escape" && (x.stopPropagation(), m(), i.blur());
|
|
2589
|
+
}), l.addEventListener("click", () => f(null));
|
|
2590
|
+
function m() {
|
|
2591
|
+
const x = p();
|
|
2592
|
+
if (r.innerHTML = Ho.map((h) => `<option value="${h}">space-${h} · ${Et(L(`--twd-space-${h}`)) ?? "?"}</option>`).join("") + '<option value="fixed">Fixed</option>', r.value = x.step ? String(x.step) : "fixed", s.hidden = !x.fixed, o.classList.toggle("is-fixed", !!x.fixed), x.fixed && o.getRootNode().activeElement !== i) {
|
|
2593
|
+
const h = Et(x.fixed);
|
|
2594
|
+
i.value = h != null ? String(h) : x.fixed;
|
|
2607
2595
|
}
|
|
2608
|
-
const
|
|
2609
|
-
o.classList.toggle("edited",
|
|
2596
|
+
const b = d() != null;
|
|
2597
|
+
o.classList.toggle("edited", b), l.hidden = !b;
|
|
2610
2598
|
}
|
|
2611
|
-
return
|
|
2599
|
+
return m(), e.onChange(m), o;
|
|
2612
2600
|
}
|
|
2613
2601
|
const Wo = {
|
|
2614
2602
|
spacing(e, t, { label: n = "Roles" } = {}) {
|
|
@@ -2646,17 +2634,21 @@ const Wo = {
|
|
|
2646
2634
|
{ more: "Spacing tokens", parts: [["custom", "spacing"]] }
|
|
2647
2635
|
] },
|
|
2648
2636
|
{ id: "shape", title: "Shape", icon: "tabShape", parts: [
|
|
2649
|
-
//
|
|
2650
|
-
|
|
2651
|
-
|
|
2652
|
-
|
|
2653
|
-
|
|
2654
|
-
|
|
2655
|
-
|
|
2656
|
-
|
|
2657
|
-
|
|
2658
|
-
|
|
2659
|
-
|
|
2637
|
+
// Shape pass (Ravi, 2026-10-16; Figma 281:1158 / 281:1421): one group at a
|
|
2638
|
+
// time, so the tab fits without scrolling. Buttons & Inputs: corners and size
|
|
2639
|
+
// also change inputs and chips (shared control tokens).
|
|
2640
|
+
{ tabs: [
|
|
2641
|
+
{ label: "Buttons & Inputs", parts: [
|
|
2642
|
+
["buttons", "styleTiles", { label: "Style" }],
|
|
2643
|
+
["buttons", "cornerTiles", { label: "Corners" }],
|
|
2644
|
+
["buttons", "sizeTiles", { label: "Size" }]
|
|
2645
|
+
] },
|
|
2646
|
+
{ label: "Cards", parts: [
|
|
2647
|
+
["cards", "styleTiles", { label: "Style" }],
|
|
2648
|
+
["cards", "cornerTiles", { label: "Corners" }],
|
|
2649
|
+
["cards", "borderTiles", { label: "Borders" }]
|
|
2650
|
+
] }
|
|
2651
|
+
] },
|
|
2660
2652
|
{ more: "Shape tokens", parts: [["custom", "buttonStyle"], ["custom", "cardStyle"], ["custom", "cardShadow"], ["custom", "corners"], ["custom", "controls"], ["custom", "borders"]] }
|
|
2661
2653
|
] },
|
|
2662
2654
|
{ id: "shadows", title: "Shadows", icon: "tabShadows", parts: [
|
|
@@ -2664,7 +2656,7 @@ const Wo = {
|
|
|
2664
2656
|
["depth", "intensity"],
|
|
2665
2657
|
{ more: "Shadow tokens", parts: [["custom", "shadows"]] }
|
|
2666
2658
|
] }
|
|
2667
|
-
],
|
|
2659
|
+
], F = (e) => String(e).replace(/[&<>"]/g, (t) => ({ "&": "&", "<": "<", ">": ">", '"': """ })[t]);
|
|
2668
2660
|
function Go({ sections: e, store: t, view: n }) {
|
|
2669
2661
|
const a = document.createElement("div");
|
|
2670
2662
|
a.id = "twiddle-root", document.body.appendChild(a);
|
|
@@ -2675,13 +2667,13 @@ function Go({ sections: e, store: t, view: n }) {
|
|
|
2675
2667
|
<div class="wrap">
|
|
2676
2668
|
<div class="toast" role="status"></div>
|
|
2677
2669
|
<section class="side" aria-label="Changes" hidden>
|
|
2678
|
-
<div class="side-head"><span>Changes</span><button class="icon-btn" data-action="changes-close" title="Close Changes" aria-label="Close Changes">${
|
|
2670
|
+
<div class="side-head"><span>Changes</span><button class="icon-btn" data-action="changes-close" title="Close Changes" aria-label="Close Changes">${P.close}</button></div>
|
|
2679
2671
|
<div class="body" data-view="changes"></div>
|
|
2680
2672
|
</section>
|
|
2681
2673
|
<div class="panel" role="dialog" aria-label="Panel" hidden>
|
|
2682
2674
|
<nav class="tabbar" aria-label="Areas">
|
|
2683
|
-
${te.map((c) => `<button class="tab" data-tab="${c.id}" title="${c.title}" aria-pressed="false">${
|
|
2684
|
-
<button class="icon-btn tab-min" data-action="minimise" title="Minimise to the tabs" aria-label="Minimise to the tabs">${
|
|
2675
|
+
${te.map((c) => `<button class="tab" data-tab="${c.id}" title="${c.title}" aria-pressed="false">${P[c.icon]}<span>${c.title}</span></button>`).join("")}
|
|
2676
|
+
<button class="icon-btn tab-min" data-action="minimise" title="Minimise to the tabs" aria-label="Minimise to the tabs">${P.minimise}</button>
|
|
2685
2677
|
</nav>
|
|
2686
2678
|
<div class="original-pill" hidden>Showing original</div>
|
|
2687
2679
|
<div class="body" data-view="global"><div class="setup-hint" role="status" hidden></div>
|
|
@@ -2690,19 +2682,19 @@ function Go({ sections: e, store: t, view: n }) {
|
|
|
2690
2682
|
<div class="body" data-view="local" hidden></div>
|
|
2691
2683
|
<!-- One footer row with every action (Ravi, 2026-10-16); the launcher closes the panel. -->
|
|
2692
2684
|
<div class="actions">
|
|
2693
|
-
<button class="icon-btn" data-action="undo" title="Undo (⌘Z)" aria-label="Undo">${
|
|
2694
|
-
<button class="icon-btn" data-action="redo" title="Redo (⇧⌘Z)" aria-label="Redo">${
|
|
2685
|
+
<button class="icon-btn" data-action="undo" title="Undo (⌘Z)" aria-label="Undo">${P.undo}</button>
|
|
2686
|
+
<button class="icon-btn" data-action="redo" title="Redo (⇧⌘Z)" aria-label="Redo">${P.redo}</button>
|
|
2695
2687
|
<span class="sep" aria-hidden="true"></span>
|
|
2696
|
-
<button class="icon-btn" data-action="pick" title="Pick an element to tweak on its own" aria-label="Pick an element" aria-pressed="false">${
|
|
2697
|
-
<button class="icon-btn" data-action="compare" title="Hold to see the original (Alt+C toggles)" aria-label="Compare with original" aria-pressed="false">${
|
|
2698
|
-
<button class="icon-btn" data-action="copy" title="Copy link to this version" aria-label="Copy link">${
|
|
2699
|
-
<button class="icon-btn" data-action="reset" title="Reset to defaults" aria-label="Reset">${
|
|
2688
|
+
<button class="icon-btn" data-action="pick" title="Pick an element to tweak on its own" aria-label="Pick an element" aria-pressed="false">${P.pick}</button>
|
|
2689
|
+
<button class="icon-btn" data-action="compare" title="Hold to see the original (Alt+C toggles)" aria-label="Compare with original" aria-pressed="false">${P.compare}</button>
|
|
2690
|
+
<button class="icon-btn" data-action="copy" title="Copy link to this version" aria-label="Copy link">${P.link}</button>
|
|
2691
|
+
<button class="icon-btn" data-action="reset" title="Reset to defaults" aria-label="Reset">${P.reset}</button>
|
|
2700
2692
|
<span class="sep" aria-hidden="true"></span>
|
|
2701
2693
|
<button class="changes-btn" data-action="changes" title="Changes" aria-label="Changes" aria-pressed="false"><span class="badge">0</span></button>
|
|
2702
2694
|
<span class="spacer"></span>
|
|
2703
2695
|
<div class="apply">
|
|
2704
2696
|
<button class="apply-btn" data-action="apply" title="Copy these tweaks as a prompt for your coding agent">Copy<span class="wide"> prompt</span></button>
|
|
2705
|
-
<button class="apply-menu-btn" data-action="apply-menu" aria-label="Copy prompt options" aria-haspopup="true" aria-expanded="false">${
|
|
2697
|
+
<button class="apply-menu-btn" data-action="apply-menu" aria-label="Copy prompt options" aria-haspopup="true" aria-expanded="false">${P.down}</button>
|
|
2706
2698
|
<div class="menu apply-menu" role="menu" hidden>
|
|
2707
2699
|
<button role="menuitemradio" data-apply-mode="preview">Preview before copying</button>
|
|
2708
2700
|
<button role="menuitemradio" data-apply-mode="copy">Copy without preview</button>
|
|
@@ -2710,13 +2702,13 @@ function Go({ sections: e, store: t, view: n }) {
|
|
|
2710
2702
|
</div>
|
|
2711
2703
|
</div>
|
|
2712
2704
|
</div>
|
|
2713
|
-
<button class="launcher" aria-label="Open Panel" aria-expanded="false" title="Panel · drag to move, double-click to reset">${
|
|
2705
|
+
<button class="launcher" aria-label="Open Panel" aria-expanded="false" title="Panel · drag to move, double-click to reset">${P.panelMark}</button>
|
|
2714
2706
|
</div>
|
|
2715
2707
|
<div class="dialog-backdrop" hidden>
|
|
2716
2708
|
<div class="dialog" role="dialog" aria-modal="true" aria-labelledby="twd-dialog-title">
|
|
2717
2709
|
<div class="dialog-head">
|
|
2718
2710
|
<span id="twd-dialog-title">Prompt for your agent</span>
|
|
2719
|
-
<button class="icon-btn" data-action="dialog-close" aria-label="Close">${
|
|
2711
|
+
<button class="icon-btn" data-action="dialog-close" aria-label="Close">${P.close}</button>
|
|
2720
2712
|
</div>
|
|
2721
2713
|
<textarea class="prompt-text" readonly spellcheck="false" aria-label="Generated prompt"></textarea>
|
|
2722
2714
|
<div class="dialog-foot">
|
|
@@ -2726,142 +2718,142 @@ function Go({ sections: e, store: t, view: n }) {
|
|
|
2726
2718
|
</div>
|
|
2727
2719
|
</div>
|
|
2728
2720
|
`;
|
|
2729
|
-
const r = (c) => o.querySelector(c), s = r(".panel"), i = r(".launcher"), l = r(".toast"), d = { global: r('[data-view="global"]'), local: r('[data-view="local"]'), changes: r('[data-view="changes"]') },
|
|
2730
|
-
function
|
|
2731
|
-
const
|
|
2732
|
-
|
|
2721
|
+
const r = (c) => o.querySelector(c), s = r(".panel"), i = r(".launcher"), l = r(".toast"), d = { global: r('[data-view="global"]'), local: r('[data-view="local"]'), changes: r('[data-view="changes"]') }, p = r(".pick-box"), f = r(".pick-tag"), v = { getState: t.getState, setSection: t.setSection, setSections: t.setSections, onChange: t.onChange }, u = Object.fromEntries(e.map((c) => [c.id, c]));
|
|
2722
|
+
function m(c, g, y = v) {
|
|
2723
|
+
const C = y !== v;
|
|
2724
|
+
g.forEach((k) => {
|
|
2733
2725
|
if (k === "warnings") {
|
|
2734
|
-
if (
|
|
2735
|
-
const
|
|
2736
|
-
|
|
2726
|
+
if (C) return;
|
|
2727
|
+
const j = document.createElement("div");
|
|
2728
|
+
j.className = "warnings page-warnings", c.append(j);
|
|
2737
2729
|
return;
|
|
2738
2730
|
}
|
|
2739
2731
|
if (k.heading) {
|
|
2740
|
-
const
|
|
2741
|
-
|
|
2732
|
+
const j = document.createElement("div");
|
|
2733
|
+
j.className = "page-heading", j.innerHTML = `<span></span>${k.note ? '<span class="muted"></span>' : ""}`, j.firstChild.textContent = k.heading, k.note && (j.lastChild.textContent = k.note), c.append(j);
|
|
2742
2734
|
return;
|
|
2743
2735
|
}
|
|
2744
2736
|
if (k.more) {
|
|
2745
|
-
const
|
|
2746
|
-
|
|
2737
|
+
const j = document.createElement("details");
|
|
2738
|
+
j.className = "more", j.innerHTML = `<summary><span class="chev" aria-hidden="true">${P.chevron}</span><span></span></summary><div class="more-body"></div>`, j.querySelector("summary span:last-child").textContent = k.more, m(j.querySelector(".more-body"), k.parts, y), c.append(j);
|
|
2747
2739
|
return;
|
|
2748
2740
|
}
|
|
2749
2741
|
if (k.tabs) {
|
|
2750
|
-
const
|
|
2742
|
+
const j = k.tabs.map((W) => {
|
|
2751
2743
|
const q = document.createElement("div");
|
|
2752
|
-
return q.className = "tab-pane",
|
|
2753
|
-
}),
|
|
2744
|
+
return q.className = "tab-pane", m(q, W.parts, y), q;
|
|
2745
|
+
}), dt = ge({
|
|
2754
2746
|
label: "View",
|
|
2755
2747
|
options: k.tabs.map((W, q) => ({ value: String(q), label: W.label })),
|
|
2756
2748
|
onSelect: (W) => {
|
|
2757
|
-
|
|
2749
|
+
dt.setValue(W), j.forEach((q, va) => {
|
|
2758
2750
|
q.hidden = String(va) !== W;
|
|
2759
2751
|
});
|
|
2760
2752
|
}
|
|
2761
2753
|
});
|
|
2762
|
-
|
|
2754
|
+
dt.setValue("0"), j.forEach((W, q) => {
|
|
2763
2755
|
W.hidden = q !== 0;
|
|
2764
|
-
}), c.append(
|
|
2756
|
+
}), c.append(dt.el, ...j);
|
|
2765
2757
|
return;
|
|
2766
2758
|
}
|
|
2767
|
-
const [T, U,
|
|
2768
|
-
ye && ye(c, y, { ...
|
|
2769
|
-
Ae(Ut()),
|
|
2759
|
+
const [T, U, O = {}] = k, ye = T === "simple" ? qo[U] : T === "roles" ? Wo[U] : u[T]?.parts?.[U];
|
|
2760
|
+
ye && ye(c, y, { ...O, buttons: u.buttons, cards: u.cards, goTab: (j) => {
|
|
2761
|
+
Ae(Ut()), w(j);
|
|
2770
2762
|
} });
|
|
2771
2763
|
});
|
|
2772
2764
|
}
|
|
2773
|
-
te.forEach((c) =>
|
|
2765
|
+
te.forEach((c) => m(d.global.querySelector(`[data-page="${c.id}"]`), c.parts));
|
|
2774
2766
|
const x = [...o.querySelectorAll(".tab")];
|
|
2775
|
-
let
|
|
2776
|
-
function
|
|
2777
|
-
x.forEach((c) => c.setAttribute("aria-pressed", String(c.dataset.tab ===
|
|
2767
|
+
let b = te.some((c) => c.id === ne("tab")) ? ne("tab") : te[0].id;
|
|
2768
|
+
function h() {
|
|
2769
|
+
x.forEach((c) => c.setAttribute("aria-pressed", String(c.dataset.tab === b)));
|
|
2778
2770
|
}
|
|
2779
|
-
function
|
|
2780
|
-
|
|
2781
|
-
|
|
2771
|
+
function w(c) {
|
|
2772
|
+
b = c, ce("tab", c), [d.global, d.local].forEach((g) => {
|
|
2773
|
+
g.querySelectorAll(".page").forEach((y) => {
|
|
2782
2774
|
y.hidden = y.dataset.page !== c;
|
|
2783
|
-
}),
|
|
2784
|
-
}),
|
|
2775
|
+
}), g.scrollTop = 0;
|
|
2776
|
+
}), h();
|
|
2785
2777
|
}
|
|
2786
|
-
const S = (c) => c.map((
|
|
2778
|
+
const S = (c) => c.map((g) => `<div class="warning">${P.warn}<span>${F(g.text)}</span></div>`).join(""), $ = r(".side");
|
|
2787
2779
|
let K = !1;
|
|
2788
2780
|
function Z(c) {
|
|
2789
2781
|
K = c && !s.hidden, $.hidden = !K, r('[data-action="changes"]').setAttribute("aria-pressed", String(K)), K && rn();
|
|
2790
2782
|
}
|
|
2791
2783
|
let Le = "global";
|
|
2792
|
-
const Ut = () =>
|
|
2784
|
+
const Ut = () => E ? "local" : "global";
|
|
2793
2785
|
function Ae(c) {
|
|
2794
|
-
Le = c, Object.entries(d).forEach(([
|
|
2795
|
-
y.hidden =
|
|
2796
|
-
}),
|
|
2786
|
+
Le = c, Object.entries(d).forEach(([g, y]) => {
|
|
2787
|
+
y.hidden = g !== c;
|
|
2788
|
+
}), h();
|
|
2797
2789
|
}
|
|
2798
|
-
|
|
2799
|
-
const et = "cubic-bezier(0.3, 0.7, 0.2, 1)", tt = "cubic-bezier(0.2, 0.8, 0.2, 1)",
|
|
2790
|
+
w(b);
|
|
2791
|
+
const et = "cubic-bezier(0.3, 0.7, 0.2, 1)", tt = "cubic-bezier(0.2, 0.8, 0.2, 1)", Pe = 640, me = 100, nt = 50, da = () => i.querySelector(".mark-knob"), ca = () => [i.querySelector(".mark-t1"), i.querySelector(".mark-t2")];
|
|
2800
2792
|
function Vt(c) {
|
|
2801
2793
|
if (matchMedia("(prefers-reduced-motion: reduce)").matches || !i.animate) return;
|
|
2802
|
-
const
|
|
2794
|
+
const g = da(), [y, C] = ca(), k = (T) => `translateY(${T}px)`;
|
|
2803
2795
|
if (c) {
|
|
2804
|
-
|
|
2796
|
+
g.animate([{ transform: k(32) }, { transform: k(-6), offset: 0.78 }, { transform: k(0) }], { duration: Pe, easing: et });
|
|
2805
2797
|
const T = [{ transform: "scale(0.4)", opacity: 0 }, { transform: "scale(1)", opacity: 1 }];
|
|
2806
|
-
|
|
2798
|
+
C.animate(T, { duration: me * 2, delay: Pe * 0.12, easing: et, fill: "backwards" }), y.animate(T, { duration: me * 2, delay: Pe * 0.32 + nt, easing: et, fill: "backwards" });
|
|
2807
2799
|
} else {
|
|
2808
2800
|
const T = [{ opacity: 1 }, { opacity: 0 }];
|
|
2809
|
-
y.animate(T, { duration:
|
|
2801
|
+
y.animate(T, { duration: me, easing: tt }), C.animate(T, { duration: me, delay: nt / 2, easing: tt, fill: "backwards" }), g.animate([{ transform: k(0) }, { transform: k(34), offset: 0.8 }, { transform: k(32) }], { duration: Pe * 0.7, delay: me + nt / 2, easing: tt, fill: "backwards" });
|
|
2810
2802
|
}
|
|
2811
2803
|
}
|
|
2812
|
-
const
|
|
2804
|
+
const Oe = r(".wrap"), qt = Va({ wrapEl: Oe, launcherEl: i });
|
|
2813
2805
|
let at = !1;
|
|
2814
|
-
function
|
|
2815
|
-
at = c, s.classList.toggle("minimised", c), c && Z(!1),
|
|
2816
|
-
const
|
|
2817
|
-
|
|
2806
|
+
function be(c) {
|
|
2807
|
+
at = c, s.classList.toggle("minimised", c), c && Z(!1), Oe.classList.toggle("is-min", c);
|
|
2808
|
+
const g = r('[data-action="minimise"]');
|
|
2809
|
+
g.title = c ? "Expand the panel" : "Minimise to the tabs", g.setAttribute("aria-label", g.title), s.hidden || ce("panel", c ? "tabs" : "open");
|
|
2818
2810
|
}
|
|
2819
2811
|
function J({ animate: c = !0 } = {}) {
|
|
2820
|
-
s.hidden && c && Vt(!0), s.hidden = !1,
|
|
2812
|
+
s.hidden && c && Vt(!0), s.hidden = !1, Oe.classList.add("is-open"), i.setAttribute("aria-expanded", "true"), i.setAttribute("aria-label", "Close Panel"), be(!1);
|
|
2821
2813
|
}
|
|
2822
|
-
function
|
|
2823
|
-
s.hidden && J(),
|
|
2814
|
+
function pa() {
|
|
2815
|
+
s.hidden && J(), be(!0);
|
|
2824
2816
|
}
|
|
2825
2817
|
function ot() {
|
|
2826
|
-
s.hidden || Vt(!1), s.hidden = !0,
|
|
2818
|
+
s.hidden || Vt(!1), s.hidden = !0, Oe.classList.remove("is-open", "is-min"), Z(!1), i.setAttribute("aria-expanded", "false"), i.setAttribute("aria-label", "Open Panel"), ce("panel", "closed"), Re();
|
|
2827
2819
|
}
|
|
2828
|
-
function
|
|
2820
|
+
function je() {
|
|
2829
2821
|
s.hidden ? J() : ot();
|
|
2830
2822
|
}
|
|
2831
2823
|
let Ht;
|
|
2832
2824
|
function V(c) {
|
|
2833
2825
|
l.textContent = c, l.classList.add("show"), clearTimeout(Ht), Ht = setTimeout(() => l.classList.remove("show"), 1600);
|
|
2834
2826
|
}
|
|
2835
|
-
function xe(c,
|
|
2836
|
-
navigator.clipboard.writeText(c).then(() => V(
|
|
2827
|
+
function xe(c, g) {
|
|
2828
|
+
navigator.clipboard.writeText(c).then(() => V(g)).catch(() => V("Couldn’t copy — select the text and copy it instead"));
|
|
2837
2829
|
}
|
|
2838
2830
|
let rt = null;
|
|
2839
|
-
function se(c,
|
|
2831
|
+
function se(c, g) {
|
|
2840
2832
|
if (rt = c, !c) {
|
|
2841
|
-
|
|
2833
|
+
p.hidden = !0;
|
|
2842
2834
|
return;
|
|
2843
2835
|
}
|
|
2844
2836
|
const y = c.getBoundingClientRect();
|
|
2845
|
-
Object.assign(
|
|
2837
|
+
Object.assign(p.style, { top: `${y.top}px`, left: `${y.left}px`, width: `${y.width}px`, height: `${y.height}px` }), f.textContent = g || Ot(c), p.hidden = !1;
|
|
2846
2838
|
}
|
|
2847
2839
|
const _t = () => {
|
|
2848
|
-
rt && !
|
|
2840
|
+
rt && !p.hidden && se(rt, f.textContent);
|
|
2849
2841
|
};
|
|
2850
2842
|
window.addEventListener("scroll", _t, !0), window.addEventListener("resize", _t);
|
|
2851
2843
|
let ie = !1;
|
|
2852
|
-
const
|
|
2844
|
+
const Fe = r('[data-action="pick"]'), Kt = (c) => c.composedPath().includes(a);
|
|
2853
2845
|
function Wt(c) {
|
|
2854
2846
|
if (Kt(c)) return;
|
|
2855
|
-
const
|
|
2856
|
-
|
|
2847
|
+
const g = c.target;
|
|
2848
|
+
g && g.nodeType === 1 && g !== document.documentElement && g !== document.body && se(g);
|
|
2857
2849
|
}
|
|
2858
2850
|
function Gt(c) {
|
|
2859
2851
|
if (Kt(c) || (c.preventDefault(), c.stopPropagation(), c.type !== "click")) return;
|
|
2860
|
-
const
|
|
2861
|
-
!
|
|
2852
|
+
const g = c.target;
|
|
2853
|
+
!g || g === document.documentElement || g === document.body || (Re(), Jt(g));
|
|
2862
2854
|
}
|
|
2863
2855
|
function Yt(c) {
|
|
2864
|
-
c.key === "Escape" && (c.preventDefault(), Re(),
|
|
2856
|
+
c.key === "Escape" && (c.preventDefault(), Re(), E && se(E.el), Ne());
|
|
2865
2857
|
}
|
|
2866
2858
|
const Xt = ["pointerdown", "mousedown", "mouseup", "click"];
|
|
2867
2859
|
function Zt() {
|
|
@@ -2870,87 +2862,87 @@ function Go({ sections: e, store: t, view: n }) {
|
|
|
2870
2862
|
const c = document.createElement("style");
|
|
2871
2863
|
c.id = "twiddle-picking", c.textContent = "html.twd-picking, html.twd-picking * { cursor: crosshair !important; }", document.head.appendChild(c);
|
|
2872
2864
|
}
|
|
2873
|
-
J(),
|
|
2865
|
+
J(), Fe.setAttribute("aria-pressed", "true"), document.documentElement.classList.add("twd-picking"), document.addEventListener("pointermove", Wt, !0), Xt.forEach((c) => document.addEventListener(c, Gt, !0)), document.addEventListener("keydown", Yt, !0), V("Click an element · Esc to cancel");
|
|
2874
2866
|
}
|
|
2875
2867
|
}
|
|
2876
2868
|
function Ne() {
|
|
2877
|
-
const c = ie || !!
|
|
2878
|
-
|
|
2879
|
-
const
|
|
2880
|
-
|
|
2869
|
+
const c = ie || !!E;
|
|
2870
|
+
Fe.setAttribute("aria-pressed", String(c));
|
|
2871
|
+
const g = c ? "Leave selection mode" : "Pick an element to tweak on its own";
|
|
2872
|
+
Fe.title = g, Fe.setAttribute("aria-label", c ? "Leave selection mode" : "Pick an element");
|
|
2881
2873
|
}
|
|
2882
2874
|
function Re() {
|
|
2883
|
-
ie && (ie = !1, Ne(), document.documentElement.classList.remove("twd-picking"), document.removeEventListener("pointermove", Wt, !0), Xt.forEach((c) => document.removeEventListener(c, Gt, !0)), document.removeEventListener("keydown", Yt, !0), se(
|
|
2875
|
+
ie && (ie = !1, Ne(), document.documentElement.classList.remove("twd-picking"), document.removeEventListener("pointermove", Wt, !0), Xt.forEach((c) => document.removeEventListener(c, Gt, !0)), document.removeEventListener("keydown", Yt, !0), se(E ? E.el : null));
|
|
2884
2876
|
}
|
|
2885
|
-
let
|
|
2886
|
-
function
|
|
2877
|
+
let E = null;
|
|
2878
|
+
function ua(c, g) {
|
|
2887
2879
|
const y = [];
|
|
2888
2880
|
return {
|
|
2889
2881
|
ctx: {
|
|
2890
2882
|
getState: () => (t.getState().scopes || {})[c] || {},
|
|
2891
|
-
setSection: (
|
|
2892
|
-
setSections: (
|
|
2893
|
-
onChange: (
|
|
2894
|
-
const k = t.onChange(
|
|
2883
|
+
setSection: (C, k) => t.setScope(c, C, k),
|
|
2884
|
+
setSections: (C, k) => t.setScopeSections(c, C, k),
|
|
2885
|
+
onChange: (C) => {
|
|
2886
|
+
const k = t.onChange(C);
|
|
2895
2887
|
return y.push(k), k;
|
|
2896
2888
|
},
|
|
2897
|
-
readToken: (
|
|
2889
|
+
readToken: (C) => getComputedStyle(g).getPropertyValue(C).trim()
|
|
2898
2890
|
},
|
|
2899
|
-
dispose: () => y.forEach((
|
|
2891
|
+
dispose: () => y.forEach((C) => C())
|
|
2900
2892
|
};
|
|
2901
2893
|
}
|
|
2902
|
-
function Jt(c,
|
|
2903
|
-
const y = Ga(c),
|
|
2904
|
-
|
|
2905
|
-
} }, st(), Ae("local"), J(), se(c), Ne();
|
|
2894
|
+
function Jt(c, g) {
|
|
2895
|
+
const y = Ga(c), C = t.getState().scopes || {};
|
|
2896
|
+
g || (g = !C[y.elementSelector] && y.classSelector && C[y.classSelector] ? "class" : "element"), E && E.dispose(), E = { el: c, info: y, target: g, dispose: () => {
|
|
2897
|
+
} }, st(), Ae("local"), J(), se(c), Ne(), lt();
|
|
2906
2898
|
}
|
|
2907
|
-
const Qt = () =>
|
|
2899
|
+
const Qt = () => E.target === "class" ? E.info.classSelector : E.info.elementSelector;
|
|
2908
2900
|
function st() {
|
|
2909
|
-
|
|
2910
|
-
const { info: c } =
|
|
2911
|
-
if (
|
|
2901
|
+
E.dispose();
|
|
2902
|
+
const { info: c } = E, g = d.local;
|
|
2903
|
+
if (g.innerHTML = `
|
|
2912
2904
|
<div class="scope-bar">
|
|
2913
2905
|
<div class="scope-head">
|
|
2914
|
-
<button class="icon-btn" data-action="back" title="Leave selection mode" aria-label="Leave selection mode">${
|
|
2906
|
+
<button class="icon-btn" data-action="back" title="Leave selection mode" aria-label="Leave selection mode">${P.back}</button>
|
|
2915
2907
|
<div class="scope-name">
|
|
2916
|
-
<code>${
|
|
2917
|
-
${c.text ? `<span class="muted">“${
|
|
2908
|
+
<code>${F(Ot(c.el))}</code>
|
|
2909
|
+
${c.text ? `<span class="muted">“${F(c.text)}”</span>` : ""}
|
|
2918
2910
|
</div>
|
|
2919
2911
|
</div>
|
|
2920
2912
|
<div class="scope-target"></div>
|
|
2921
2913
|
${c.tokens.size ? "" : '<div class="scope-note">This element doesn’t use Panel tokens yet, so changes here won’t show. Style it with <code>var(--twd-…)</code> to make it tweakable.</div>'}
|
|
2922
2914
|
<div class="warnings"></div>
|
|
2923
2915
|
</div>
|
|
2924
|
-
${te.map((
|
|
2916
|
+
${te.map((O) => `<div class="page page-fields" data-page="${O.id}"${O.id === b ? "" : " hidden"}></div>`).join("")}
|
|
2925
2917
|
`, c.classSelector) {
|
|
2926
|
-
const
|
|
2918
|
+
const O = ge({
|
|
2927
2919
|
label: "Apply to",
|
|
2928
2920
|
options: [
|
|
2929
2921
|
{ value: "element", label: "This element" },
|
|
2930
2922
|
{ value: "class", label: `All ${c.classSelector} (${c.classCount})`, title: `Every element matching ${c.classSelector}` }
|
|
2931
2923
|
],
|
|
2932
2924
|
onSelect: (ye) => {
|
|
2933
|
-
ye === "class" && t.moveScope(c.elementSelector, c.classSelector),
|
|
2925
|
+
ye === "class" && t.moveScope(c.elementSelector, c.classSelector), E.target = ye, st();
|
|
2934
2926
|
}
|
|
2935
2927
|
});
|
|
2936
|
-
|
|
2928
|
+
O.setValue(E.target), g.querySelector(".scope-target").append(O.el);
|
|
2937
2929
|
}
|
|
2938
|
-
const { ctx: y, dispose:
|
|
2939
|
-
te.forEach((
|
|
2940
|
-
const k =
|
|
2941
|
-
const
|
|
2942
|
-
k.innerHTML =
|
|
2930
|
+
const { ctx: y, dispose: C } = ua(Qt(), c.el);
|
|
2931
|
+
te.forEach((O) => m(g.querySelector(`[data-page="${O.id}"]`), O.parts, y));
|
|
2932
|
+
const k = g.querySelector(".warnings"), T = () => {
|
|
2933
|
+
const O = c.tokens.size ? ao(c.el) : null;
|
|
2934
|
+
k.innerHTML = O ? S([O]) : "";
|
|
2943
2935
|
};
|
|
2944
2936
|
T();
|
|
2945
2937
|
const U = t.onChange(T);
|
|
2946
|
-
|
|
2947
|
-
|
|
2938
|
+
E.dispose = () => {
|
|
2939
|
+
C(), U();
|
|
2948
2940
|
};
|
|
2949
2941
|
}
|
|
2950
2942
|
function en() {
|
|
2951
|
-
if (!
|
|
2952
|
-
const c = t.getState().scopes || {},
|
|
2953
|
-
!c[Qt()] && c[y] && (
|
|
2943
|
+
if (!E || !E.info.classSelector) return;
|
|
2944
|
+
const c = t.getState().scopes || {}, g = E.target === "class" ? "element" : "class", y = g === "class" ? E.info.classSelector : E.info.elementSelector;
|
|
2945
|
+
!c[Qt()] && c[y] && (E.target = g, st());
|
|
2954
2946
|
}
|
|
2955
2947
|
const tn = () => {
|
|
2956
2948
|
t.undo(), en();
|
|
@@ -2958,51 +2950,51 @@ function Go({ sections: e, store: t, view: n }) {
|
|
|
2958
2950
|
t.redo(), en();
|
|
2959
2951
|
};
|
|
2960
2952
|
function an() {
|
|
2961
|
-
|
|
2953
|
+
E && (E.dispose(), E = null, d.local.innerHTML = "", se(null), Ne(), Le === "local" && Ae("global"));
|
|
2962
2954
|
}
|
|
2963
2955
|
const on = (c) => c.kind === "global" ? "Whole page" : c.kind === "class" ? `All ${c.selector}` : "One element";
|
|
2964
2956
|
function rn() {
|
|
2965
|
-
const c = wn(t.getState(), e),
|
|
2957
|
+
const c = wn(t.getState(), e), g = ut(), y = d.changes;
|
|
2966
2958
|
if (!c.length) {
|
|
2967
|
-
y.innerHTML = `<div class="empty">No changes yet. Tweak a section, or pick an element to change it on its own.</div>${S(
|
|
2959
|
+
y.innerHTML = `<div class="empty">No changes yet. Tweak a section, or pick an element to change it on its own.</div>${S(g)}`;
|
|
2968
2960
|
return;
|
|
2969
2961
|
}
|
|
2970
|
-
const
|
|
2962
|
+
const C = /* @__PURE__ */ new Map();
|
|
2971
2963
|
c.forEach((k) => {
|
|
2972
2964
|
const T = k.selector || "";
|
|
2973
|
-
|
|
2974
|
-
}), y.innerHTML = (
|
|
2965
|
+
C.has(T) || C.set(T, []), C.get(T).push(k);
|
|
2966
|
+
}), y.innerHTML = (g.length ? `<div class="warnings">${S(g)}</div>` : "") + [...C].map(([k, T]) => `
|
|
2975
2967
|
<div class="change-group">
|
|
2976
2968
|
<div class="change-scope">
|
|
2977
|
-
${k ? `<button class="link-btn" data-select="${
|
|
2969
|
+
${k ? `<button class="link-btn" data-select="${F(k)}" title="Select it on the page">${F(on(T[0]))}</button><code>${F(k)}</code>` : `<span>${on(T[0])}</span>`}
|
|
2978
2970
|
</div>
|
|
2979
2971
|
${T.map((U) => `
|
|
2980
2972
|
<div class="change-row">
|
|
2981
2973
|
<div class="change-main">
|
|
2982
|
-
<div class="change-title">${
|
|
2983
|
-
${U.tokens.map((
|
|
2974
|
+
<div class="change-title">${F(U.title)} <span class="muted">›</span> ${U.settings.map((O) => `${F(O.label)}: <b>${F(O.value)}</b>`).join(", ")}</div>
|
|
2975
|
+
${U.tokens.map((O) => `<div class="change-token"><code>${F(O.name)}</code> ${O.from ? `${F(O.from)} → ` : ""}${F(O.to)}</div>`).join("")}
|
|
2984
2976
|
</div>
|
|
2985
|
-
<button class="icon-btn" data-remove="${
|
|
2977
|
+
<button class="icon-btn" data-remove="${F(U.sectionId)}" data-remove-scope="${F(k)}" aria-label="Remove ${F(U.title)} change">${P.close}</button>
|
|
2986
2978
|
</div>`).join("")}
|
|
2987
2979
|
</div>`).join("");
|
|
2988
2980
|
}
|
|
2989
|
-
function
|
|
2990
|
-
if (
|
|
2981
|
+
function ha(c, g) {
|
|
2982
|
+
if (g) return t.removeScope(g, c);
|
|
2991
2983
|
const y = t.getState()[c] || {};
|
|
2992
|
-
t.setSection(c, Object.fromEntries(Object.keys(y).map((
|
|
2984
|
+
t.setSection(c, Object.fromEntries(Object.keys(y).map((C) => [C, null])));
|
|
2993
2985
|
}
|
|
2994
2986
|
const we = r(".apply-menu"), sn = r('[data-action="apply-menu"]'), ln = () => ne("apply-mode") === "copy" ? "copy" : "preview";
|
|
2995
|
-
function
|
|
2987
|
+
function fa() {
|
|
2996
2988
|
we.querySelectorAll("[data-apply-mode]").forEach((c) => c.setAttribute("aria-checked", String(c.dataset.applyMode === ln())));
|
|
2997
2989
|
}
|
|
2998
2990
|
function ze(c) {
|
|
2999
|
-
we.hidden = !c, sn.setAttribute("aria-expanded", String(c)), c &&
|
|
2991
|
+
we.hidden = !c, sn.setAttribute("aria-expanded", String(c)), c && fa();
|
|
3000
2992
|
}
|
|
3001
2993
|
function dn() {
|
|
3002
|
-
return Qa(wn(t.getState(), e), { warnings:
|
|
2994
|
+
return Qa(wn(t.getState(), e), { warnings: ut() });
|
|
3003
2995
|
}
|
|
3004
2996
|
const Ie = r(".dialog-backdrop"), cn = r(".prompt-text");
|
|
3005
|
-
function
|
|
2997
|
+
function ga() {
|
|
3006
2998
|
const c = dn();
|
|
3007
2999
|
if (!c) return V("No changes to copy yet");
|
|
3008
3000
|
if (ln() === "copy") return xe(c, "Prompt copied · paste it into your agent");
|
|
@@ -3025,7 +3017,7 @@ function Go({ sections: e, store: t, view: n }) {
|
|
|
3025
3017
|
clearTimeout(pn), ve && (De(!1), ve = !1);
|
|
3026
3018
|
};
|
|
3027
3019
|
le.addEventListener("pointerup", un), le.addEventListener("pointerleave", un);
|
|
3028
|
-
const Be = r(".setup-hint"), hn = `setup-hint-dismissed:${location.pathname}`,
|
|
3020
|
+
const Be = r(".setup-hint"), hn = `setup-hint-dismissed:${location.pathname}`, ba = {
|
|
3029
3021
|
"no-tokens": {
|
|
3030
3022
|
title: "The Panel tokens aren’t loaded",
|
|
3031
3023
|
text: "The knobs change the --twd-* variables, but this page doesn’t load them. Add the token stylesheet before your own CSS:",
|
|
@@ -3044,60 +3036,72 @@ function Go({ sections: e, store: t, view: n }) {
|
|
|
3044
3036
|
let B = null;
|
|
3045
3037
|
function Ue() {
|
|
3046
3038
|
const c = lo();
|
|
3047
|
-
B = ne(hn) === c ? null :
|
|
3048
|
-
<div class="setup-head">${
|
|
3049
|
-
<button class="icon-btn" data-action="setup-dismiss" title="Hide this message" aria-label="Hide this message">${
|
|
3039
|
+
B = ne(hn) === c ? null : ba[c] || null, i.toggleAttribute("data-hint", !!B), Be.hidden = !B, B && (Be.innerHTML = `
|
|
3040
|
+
<div class="setup-head">${P.warn}<b>${F(B.title)}</b>
|
|
3041
|
+
<button class="icon-btn" data-action="setup-dismiss" title="Hide this message" aria-label="Hide this message">${P.close}</button>
|
|
3050
3042
|
</div>
|
|
3051
|
-
<p>${
|
|
3052
|
-
${(B.snippets || []).map((
|
|
3043
|
+
<p>${F(B.text)}</p>
|
|
3044
|
+
${(B.snippets || []).map((g, y) => `
|
|
3053
3045
|
<div class="setup-snippet">
|
|
3054
|
-
<span>${
|
|
3055
|
-
<div class="setup-code"><code>${
|
|
3046
|
+
<span>${F(g.label)}</span>
|
|
3047
|
+
<div class="setup-code"><code>${F(g.code)}</code><button class="text-btn" data-setup-snippet="${y}">Copy</button></div>
|
|
3056
3048
|
</div>`).join("")}
|
|
3057
3049
|
<div class="setup-actions">
|
|
3058
|
-
${B.copy ? `<button class="apply-btn" data-action="setup-copy">${
|
|
3050
|
+
${B.copy ? `<button class="apply-btn" data-action="setup-copy">${F(B.copy)}</button>` : ""}
|
|
3059
3051
|
<a href="${B.link}" target="_blank" rel="noopener">Setup guide</a>
|
|
3060
3052
|
</div>`, Be.dataset.status = c);
|
|
3061
3053
|
}
|
|
3062
3054
|
Ue(), document.readyState !== "complete" && window.addEventListener("load", Ue, { once: !0 }), setTimeout(Ue, 1500);
|
|
3055
|
+
const xa = { "--pv-primary": "--twd-primary", "--pv-on-primary": "--twd-on-primary", "--pv-radius-control": "--twd-radius-control", "--pv-radius-container": "--twd-radius-container" };
|
|
3056
|
+
function lt() {
|
|
3057
|
+
[[d.global, document.documentElement], [d.local, E && E.info.el]].forEach(([c, g]) => {
|
|
3058
|
+
if (!g) return;
|
|
3059
|
+
const y = getComputedStyle(g);
|
|
3060
|
+
Object.entries(xa).forEach(([C, k]) => {
|
|
3061
|
+
const T = y.getPropertyValue(k).trim();
|
|
3062
|
+
T ? c.style.setProperty(C, T) : c.style.removeProperty(C);
|
|
3063
|
+
});
|
|
3064
|
+
});
|
|
3065
|
+
}
|
|
3066
|
+
t.onChange(() => requestAnimationFrame(lt)), lt();
|
|
3063
3067
|
const wa = r(".badge");
|
|
3064
3068
|
function fn() {
|
|
3065
3069
|
r('[data-action="undo"]').disabled = !t.canUndo(), r('[data-action="redo"]').disabled = !t.canRedo();
|
|
3066
3070
|
const c = Za(t.getState());
|
|
3067
3071
|
wa.textContent = c, r('[data-action="changes"]').classList.toggle("has-changes", c > 0), r('[data-action="changes"]').setAttribute("aria-label", `Changes (${c})`);
|
|
3068
|
-
const
|
|
3072
|
+
const g = S(ut());
|
|
3069
3073
|
d.global.querySelectorAll(".page-warnings").forEach((y) => {
|
|
3070
|
-
y.innerHTML =
|
|
3074
|
+
y.innerHTML = g;
|
|
3071
3075
|
}), K && rn();
|
|
3072
3076
|
}
|
|
3073
3077
|
return t.onChange(fn), fn(), o.addEventListener("click", (c) => {
|
|
3074
3078
|
if (c.target === Ie) return it();
|
|
3075
|
-
const
|
|
3076
|
-
if (
|
|
3077
|
-
if (
|
|
3078
|
-
return qt.consumeClick() ? void 0 : c.detail === 2 ? (
|
|
3079
|
-
if (
|
|
3080
|
-
const y = document.querySelector(
|
|
3079
|
+
const g = c.target.closest("button");
|
|
3080
|
+
if (g) {
|
|
3081
|
+
if (g !== sn && !we.contains(g) && ze(!1), g === i)
|
|
3082
|
+
return qt.consumeClick() ? void 0 : c.detail === 2 ? (je(), qt.reset(), V("Panel moved back to the corner")) : je();
|
|
3083
|
+
if (g.dataset.select) {
|
|
3084
|
+
const y = document.querySelector(g.dataset.select);
|
|
3081
3085
|
return y ? Jt(y) : V("That element isn’t on this page");
|
|
3082
3086
|
}
|
|
3083
|
-
if (
|
|
3084
|
-
if (
|
|
3085
|
-
return Ae(Ut()), at &&
|
|
3086
|
-
if (
|
|
3087
|
-
if (
|
|
3088
|
-
return ce("apply-mode",
|
|
3089
|
-
switch (
|
|
3087
|
+
if (g.dataset.setupSnippet) return xe(En[g.dataset.setupSnippet].code, "Copied");
|
|
3088
|
+
if (g.dataset.tab)
|
|
3089
|
+
return Ae(Ut()), at && be(!1), w(g.dataset.tab);
|
|
3090
|
+
if (g.dataset.remove) return ha(g.dataset.remove, g.dataset.removeScope);
|
|
3091
|
+
if (g.dataset.applyMode)
|
|
3092
|
+
return ce("apply-mode", g.dataset.applyMode), ze(!1), V(g.dataset.applyMode === "copy" ? "Copy prompt copies straight away" : "Copy prompt shows a preview first");
|
|
3093
|
+
switch (g.dataset.action) {
|
|
3090
3094
|
case "close":
|
|
3091
3095
|
return ot();
|
|
3092
3096
|
case "minimise":
|
|
3093
|
-
return at ?
|
|
3097
|
+
return at ? be(!1) : (pa(), (o.querySelector('.tab[aria-pressed="true"]') || x[0]).focus());
|
|
3094
3098
|
case "reset":
|
|
3095
3099
|
return t.resetState(), V("Reset to defaults · ⌘Z to undo");
|
|
3096
3100
|
case "copy":
|
|
3097
3101
|
return xe(location.href, "Link copied");
|
|
3098
3102
|
// Pressed again (picking, or an element selected): out of selection mode.
|
|
3099
3103
|
case "pick":
|
|
3100
|
-
return ie ||
|
|
3104
|
+
return ie || E ? (Re(), an()) : Zt();
|
|
3101
3105
|
case "compare":
|
|
3102
3106
|
ve || De(le.getAttribute("aria-pressed") !== "true");
|
|
3103
3107
|
return;
|
|
@@ -3112,7 +3116,7 @@ function Go({ sections: e, store: t, view: n }) {
|
|
|
3112
3116
|
case "changes-close":
|
|
3113
3117
|
return Z(!1);
|
|
3114
3118
|
case "apply":
|
|
3115
|
-
return
|
|
3119
|
+
return ga();
|
|
3116
3120
|
case "apply-menu":
|
|
3117
3121
|
return ze(we.hidden);
|
|
3118
3122
|
case "dialog-close":
|
|
@@ -3132,28 +3136,28 @@ function Go({ sections: e, store: t, view: n }) {
|
|
|
3132
3136
|
}
|
|
3133
3137
|
!(c.metaKey || c.ctrlKey) || c.key.toLowerCase() !== "z" || c.target.matches?.('input[type="text"], textarea') || (c.preventDefault(), c.shiftKey ? nn() : tn());
|
|
3134
3138
|
}), document.addEventListener("keydown", (c) => {
|
|
3135
|
-
c.altKey && (c.code === "KeyT" && (c.preventDefault(),
|
|
3136
|
-
}), ne("panel") === "open" ? J({ animate: !1 }) : ne("panel") === "tabs" && (J({ animate: !1 }),
|
|
3139
|
+
c.altKey && (c.code === "KeyT" && (c.preventDefault(), je()), c.code === "KeyC" && (c.preventDefault(), De(le.getAttribute("aria-pressed") !== "true")));
|
|
3140
|
+
}), ne("panel") === "open" ? J({ animate: !1 }) : ne("panel") === "tabs" && (J({ animate: !1 }), be(!0)), { open: J, close: ot, toggle: je, toast: V, pick: Zt, prompt: dn };
|
|
3137
3141
|
}
|
|
3138
|
-
const
|
|
3142
|
+
const zn = [Bo, Je, ia, Ft, yo, Nt, la, vo];
|
|
3139
3143
|
function Yo() {
|
|
3140
3144
|
if (getComputedStyle(document.documentElement).getPropertyValue("--twd-radius-control").trim() || document.getElementById("twiddle-tokens")) return;
|
|
3141
3145
|
const t = document.createElement("style");
|
|
3142
|
-
t.id = "twiddle-tokens", t.textContent =
|
|
3146
|
+
t.id = "twiddle-tokens", t.textContent = qn, document.head.prepend(t);
|
|
3143
3147
|
}
|
|
3144
3148
|
if (!window.Twiddle) {
|
|
3145
|
-
Yo(),
|
|
3149
|
+
Yo(), zn.forEach((n) => ja(n.tokens)), Vn(At);
|
|
3146
3150
|
let e;
|
|
3147
3151
|
const t = () => {
|
|
3148
|
-
At(Mt()), e = Go({ sections:
|
|
3152
|
+
At(Mt()), e = Go({ sections: zn, store: Aa, view: { suspend: za, resume: Ia } });
|
|
3149
3153
|
};
|
|
3150
3154
|
document.readyState === "loading" ? document.addEventListener("DOMContentLoaded", t) : t(), window.Twiddle = {
|
|
3151
3155
|
open: () => e && e.open(),
|
|
3152
3156
|
close: () => e && e.close(),
|
|
3153
3157
|
toggle: () => e && e.toggle(),
|
|
3154
|
-
reset: () =>
|
|
3155
|
-
undo: () =>
|
|
3156
|
-
redo: () =>
|
|
3158
|
+
reset: () => Dn(),
|
|
3159
|
+
undo: () => Bn(),
|
|
3160
|
+
redo: () => Un(),
|
|
3157
3161
|
pick: () => e && e.pick(),
|
|
3158
3162
|
prompt: () => e ? e.prompt() : "",
|
|
3159
3163
|
getState: Mt
|