twiddle-panel 0.6.1 → 0.7.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 +6 -2
- package/dist/twiddle-tokens.css +18 -1
- package/dist/twiddle.js +260 -138
- package/dist/twiddle.mjs +1757 -1242
- package/package.json +1 -1
package/dist/twiddle.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
var TwiddleBundle=(function(
|
|
2
|
-
${Object.entries(r).map(([
|
|
1
|
+
var TwiddleBundle=(function(Ve){"use strict";const He=new Set;let M=_n(),K=[],de=[],Se=null,Mt=0;function _n(){const t=new URLSearchParams(location.search).get("twd");if(!t)return{};try{return JSON.parse(t)}catch{return{}}}function Kn(){const t=new URL(location.href);Object.keys(M).length?t.searchParams.set("twd",JSON.stringify(M)):t.searchParams.delete("twd"),history.replaceState(history.state,"",t)}function _e(){Kn(),He.forEach(t=>t(M))}function Q(t,e){if(JSON.stringify(t)===JSON.stringify(M))return;const n=Date.now();e&&e===Se&&n-Mt<400||(K.push(M),K.length>100&&K.shift()),de=[],Se=e,Mt=n,M=t,_e()}function $e(t,e){const n={...t,...e};return Object.keys(n).forEach(a=>{n[a]==null&&delete n[a]}),Object.keys(n).length?n:null}function U(t,e,n){const a={...t};return n==null?delete a[e]:a[e]=n,a}function Ke(){return JSON.parse(JSON.stringify(M))}function Gn(t,e){Q(U(M,t,$e(M[t],e)),`${t}:${Object.keys(e)}`)}function Wn(t,e=`multi:${Object.keys(t)}`){const n=Object.entries(t).reduce((a,[o,s])=>U(a,o,$e(a[o],s)),M);Q(n,e)}function Tt(t,e,n){const a=U(M.scopes?.[t],e,$e(M.scopes?.[t]?.[e],n)),o=U(M.scopes,t,Object.keys(a).length?a:null);Q(U(M,"scopes",Object.keys(o).length?o:null),`${t}|${e}:${Object.keys(n)}`)}function Yn(t,e){if(e)return Tt(t,e,Object.fromEntries(Object.keys(M.scopes?.[t]?.[e]||{}).map(a=>[a,null])));const n=U(M.scopes,t,null);Q(U(M,"scopes",Object.keys(n).length?n:null))}function Zn(t,e){const n=M.scopes?.[t];if(!n||t===e)return;let a={...M.scopes[e]};Object.entries(n).forEach(([s,r])=>{a=U(a,s,$e(a[s],r))});const o=U(U(M.scopes,t,null),e,a);Q(U(M,"scopes",o))}function At(){Q({})}function Lt(){K.length&&(de.push(M),M=K.pop(),Se=null,_e())}function Ot(){de.length&&(K.push(M),M=de.pop(),Se=null,_e())}const Xn=()=>K.length>0,Jn=()=>de.length>0;function Pt(t){return He.add(t),()=>He.delete(t)}const Qn=Object.freeze(Object.defineProperty({__proto__:null,canRedo:Jn,canUndo:Xn,getState:Ke,moveScope:Zn,onChange:Pt,redo:Ot,removeScope:Yn,resetState:At,setScope:Tt,setSection:Gn,setSections:Wn,undo:Lt},Symbol.toStringTag,{value:"Module"})),Ft=[];let Ge=[],We={},R=null,ee=!1,Nt={};function ea(t){typeof t=="function"&&Ft.push(t)}const jt=t=>Object.assign({},...Ft.map(e=>e(t)||{})),Ye=t=>/^(\.[\w-]+|\[data-twd="[^"]+"\])$/.test(t),ta=t=>{try{return document.querySelector(t),!0}catch{return!1}};function na(){return(!R||!R.isConnected)&&(R=document.createElement("style"),R.id="twiddle-scoped",document.head.appendChild(R)),R}function Rt(){const t=document.documentElement;Ge.forEach(e=>t.style.removeProperty(e)),Ge=[],We={}}function Ze(t){if(Nt=t,ee)return;const e=document.documentElement;Rt();const n=jt(t),a=Object.entries(t.scopes||{}).filter(([s])=>ta(s)).sort(([s],[r])=>Ye(r)-Ye(s)).map(([s,r])=>[s,jt(r)]);Object.entries(n).forEach(([s,r])=>e.style.setProperty(s,r)),Ge=Object.keys(n),We=n;const o=a.filter(([,s])=>Object.keys(s).length).map(([s,r])=>`${s} {
|
|
2
|
+
${Object.entries(r).map(([i,l])=>` ${i}: ${l} !important;`).join(`
|
|
3
3
|
`)}
|
|
4
4
|
}`).join(`
|
|
5
|
-
`);(
|
|
5
|
+
`);(o||R)&&(na().textContent=o)}function zt(t){const e=document.documentElement,n=ee,a={...We};Object.keys(a).forEach(o=>e.style.removeProperty(o)),R&&(R.disabled=!0);try{return t()}finally{n||(Object.entries(a).forEach(([o,s])=>e.style.setProperty(o,s)),R&&(R.disabled=!1))}}function aa(t,e=document.documentElement){return zt(()=>{const n=getComputedStyle(e);return Object.fromEntries(t.map(a=>[a,n.getPropertyValue(a).trim()]))})}function oa(){ee||(Rt(),R&&(R.disabled=!0),ee=!0)}function ra(){ee&&(ee=!1,R&&(R.disabled=!1),Ze(Nt))}const sa=`
|
|
6
6
|
:host { all: initial; } /* block fonts/colours inherited from the page */
|
|
7
7
|
* { box-sizing: border-box; }
|
|
8
8
|
|
|
@@ -23,49 +23,68 @@ ${Object.entries(r).map(([d,l])=>` ${d}: ${l} !important;`).join(`
|
|
|
23
23
|
z-index: 2147483647;
|
|
24
24
|
font: 13px/1.4 ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
|
|
25
25
|
color: var(--p-fg);
|
|
26
|
+
/* The panel opens to the left of the launcher, bottoms aligned,
|
|
27
|
+
so it can use the full window height. */
|
|
26
28
|
display: flex;
|
|
27
|
-
flex-direction:
|
|
29
|
+
flex-direction: row;
|
|
28
30
|
align-items: flex-end;
|
|
29
31
|
gap: 10px;
|
|
30
32
|
}
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
33
|
+
/* Dark is the panel's default look (Ravi, 2026-10-15): these override the
|
|
34
|
+
light values above, whatever the page or system setting. */
|
|
35
|
+
.wrap {
|
|
36
|
+
--p-bg: #1c1c1f;
|
|
37
|
+
--p-fg: #f4f4f5;
|
|
38
|
+
--p-muted: #a1a1aa;
|
|
39
|
+
--p-line: #2e2e33;
|
|
40
|
+
--p-hover: #27272a;
|
|
41
|
+
--p-track: #27272a;
|
|
42
|
+
--p-selected: #3f3f46;
|
|
43
|
+
--p-accent: #f4f4f5;
|
|
44
|
+
--p-on-accent: #18181b;
|
|
45
|
+
--p-shadow: 0 12px 40px rgb(0 0 0 / 0.5), 0 2px 6px rgb(0 0 0 / 0.3);
|
|
44
46
|
}
|
|
45
47
|
|
|
46
48
|
/* Launcher */
|
|
49
|
+
/* Launcher = the Panel product mark (Twiddle brand): ink disc, indigo knob,
|
|
50
|
+
solid-tint trail. Closed = knob at "off" (bottom), no trail; open = "on".
|
|
51
|
+
The Toggle animation (panel.js) moves between them; these are the rest states. */
|
|
47
52
|
.launcher {
|
|
48
53
|
width: 44px; height: 44px;
|
|
49
|
-
border-radius: 50%;
|
|
50
|
-
|
|
51
|
-
background: var(--p-bg);
|
|
52
|
-
color: var(--p-fg);
|
|
54
|
+
border-radius: 50%; border: 0;
|
|
55
|
+
background: transparent;
|
|
53
56
|
box-shadow: var(--p-shadow);
|
|
54
57
|
display: grid; place-items: center;
|
|
55
58
|
cursor: pointer;
|
|
56
59
|
padding: 0;
|
|
57
60
|
}
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
.launcher
|
|
61
|
+
/* Open or minimised: centred on the tabs. 10px = panel border 1 + tab bar
|
|
62
|
+
padding 6 + half a tab (~49px) − half the launcher (22). */
|
|
63
|
+
.launcher { transition: margin-bottom .2s cubic-bezier(0.2, 0.8, 0.2, 1); }
|
|
64
|
+
.wrap.is-open .launcher { margin-bottom: 10px; }
|
|
65
|
+
@media (prefers-reduced-motion: reduce) { .launcher { transition: none; } }
|
|
66
|
+
.mark { display: block; overflow: visible; }
|
|
67
|
+
.mark-disc { fill: #16161a; }
|
|
68
|
+
.mark-knob { fill: #4f46e5; }
|
|
69
|
+
.mark-t1 { fill: #443cbc; }
|
|
70
|
+
.mark-t2 { fill: #3b359e; }
|
|
71
|
+
.mark circle { transform-box: fill-box; transform-origin: center; }
|
|
72
|
+
.launcher[aria-expanded="false"] .mark-knob { transform: translateY(32px); }
|
|
73
|
+
.launcher[aria-expanded="false"] .mark-t1, .launcher[aria-expanded="false"] .mark-t2 { opacity: 0; }
|
|
74
|
+
.launcher:hover .mark-knob { fill: #6366f1; }
|
|
61
75
|
.launcher:focus-visible, button:focus-visible, summary:focus-visible {
|
|
62
76
|
outline: 2px solid var(--p-accent); outline-offset: 2px;
|
|
63
77
|
}
|
|
64
78
|
|
|
65
79
|
/* Panel */
|
|
66
80
|
.panel {
|
|
67
|
-
width:
|
|
68
|
-
|
|
81
|
+
width: 360px; /* tabbed layout (Figma 254:323); was 300 */
|
|
82
|
+
/* 86px = 16 + 16 margins + 44 launcher + 10 gap */
|
|
83
|
+
max-width: calc(100vw - 86px);
|
|
84
|
+
/* As tall as its content; scrolls only when the window is shorter.
|
|
85
|
+
32px = 16 margin below + 16 room at the top. */
|
|
86
|
+
max-height: calc(100vh - 32px);
|
|
87
|
+
max-height: calc(100dvh - 32px);
|
|
69
88
|
background: var(--p-bg);
|
|
70
89
|
border: 1px solid var(--p-line);
|
|
71
90
|
border-radius: 14px;
|
|
@@ -77,8 +96,7 @@ ${Object.entries(r).map(([d,l])=>` ${d}: ${l} !important;`).join(`
|
|
|
77
96
|
|
|
78
97
|
.head {
|
|
79
98
|
display: flex; align-items: center; gap: 4px;
|
|
80
|
-
padding: 10px 10px
|
|
81
|
-
border-bottom: 1px solid var(--p-line);
|
|
99
|
+
padding: 10px 10px 6px 14px; /* the actions row below carries the divider */
|
|
82
100
|
}
|
|
83
101
|
.brand { font-weight: 600; font-size: 14px; letter-spacing: -0.01em; flex: 1; }
|
|
84
102
|
.icon-btn {
|
|
@@ -275,16 +293,17 @@ ${Object.entries(r).map(([d,l])=>` ${d}: ${l} !important;`).join(`
|
|
|
275
293
|
.swatch-label { font-size: 12px; color: var(--p-muted); }
|
|
276
294
|
.swatch[aria-checked="true"] .swatch-label { color: var(--p-fg); }
|
|
277
295
|
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
296
|
+
/* Second header row: the global actions that used to be the footer */
|
|
297
|
+
.actions {
|
|
298
|
+
border-bottom: 1px solid var(--p-line);
|
|
299
|
+
padding: 2px 10px 10px;
|
|
281
300
|
display: flex; align-items: center; gap: 2px;
|
|
282
301
|
color: var(--p-muted); font-size: 12px;
|
|
283
302
|
}
|
|
284
303
|
.spacer { flex: 1; }
|
|
285
304
|
.icon-btn:disabled { opacity: .35; cursor: default; background: transparent; }
|
|
286
|
-
.
|
|
287
|
-
.
|
|
305
|
+
.actions .icon-btn, .actions .apply { flex: none; } /* Undo / Redo / Copy prompt keep their size; Changes gives way if space runs out */
|
|
306
|
+
.actions .text-btn { min-width: 0; overflow: hidden; }
|
|
288
307
|
.icon-btn[aria-pressed="true"] { background: var(--p-accent); color: var(--p-on-accent); }
|
|
289
308
|
kbd {
|
|
290
309
|
font: 11px ui-monospace, "SF Mono", Menlo, monospace;
|
|
@@ -292,8 +311,9 @@ ${Object.entries(r).map(([d,l])=>` ${d}: ${l} !important;`).join(`
|
|
|
292
311
|
padding: 1px 4px;
|
|
293
312
|
}
|
|
294
313
|
|
|
295
|
-
/*
|
|
296
|
-
|
|
314
|
+
/* Closed: beside the launcher (left of it, centred on it). Open or minimised:
|
|
315
|
+
the panel takes that spot, so the toast floats just above the tab bar
|
|
316
|
+
(63px tall), inside the panel's right edge. */
|
|
297
317
|
.toast {
|
|
298
318
|
position: absolute; bottom: 22px; right: 54px; transform: translateY(50%);
|
|
299
319
|
background: var(--p-accent); color: var(--p-on-accent);
|
|
@@ -302,6 +322,7 @@ ${Object.entries(r).map(([d,l])=>` ${d}: ${l} !important;`).join(`
|
|
|
302
322
|
opacity: 0; transition: opacity .15s ease; pointer-events: none;
|
|
303
323
|
}
|
|
304
324
|
.toast.show { opacity: 1; }
|
|
325
|
+
.wrap.is-open .toast { bottom: 72px; right: 62px; transform: none; z-index: 3; }
|
|
305
326
|
|
|
306
327
|
/* ---------- Proposals below: not yet designed in Figma ---------- */
|
|
307
328
|
|
|
@@ -340,7 +361,7 @@ ${Object.entries(r).map(([d,l])=>` ${d}: ${l} !important;`).join(`
|
|
|
340
361
|
background: var(--p-accent); color: var(--p-on-accent); cursor: pointer;
|
|
341
362
|
}
|
|
342
363
|
.menu {
|
|
343
|
-
position: absolute; right: 0;
|
|
364
|
+
position: absolute; right: 0; top: calc(100% + 6px); z-index: 2; /* opens downwards from the header */
|
|
344
365
|
min-width: 180px; padding: 4px; display: grid; gap: 2px;
|
|
345
366
|
background: var(--p-bg); border: 1px solid var(--p-line); border-radius: 8px;
|
|
346
367
|
box-shadow: var(--p-shadow);
|
|
@@ -410,7 +431,7 @@ ${Object.entries(r).map(([d,l])=>` ${d}: ${l} !important;`).join(`
|
|
|
410
431
|
font-size: 12px; line-height: 1.4;
|
|
411
432
|
}
|
|
412
433
|
.warning svg { flex: none; width: 16px; height: 16px; margin-top: 0.5px; }
|
|
413
|
-
|
|
434
|
+
.warning { color: #fbbf24; } /* amber text that reads on the dark panel */
|
|
414
435
|
|
|
415
436
|
/* Changes list */
|
|
416
437
|
.change-group { padding: 10px 14px; border-bottom: 1px solid var(--p-line); display: grid; gap: 6px; }
|
|
@@ -438,11 +459,9 @@ ${Object.entries(r).map(([d,l])=>` ${d}: ${l} !important;`).join(`
|
|
|
438
459
|
--p-accent: #18181b; --p-on-accent: #ffffff;
|
|
439
460
|
--p-shadow: 0 12px 40px rgb(0 0 0 / 0.14), 0 2px 6px rgb(0 0 0 / 0.06);
|
|
440
461
|
}
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
--p-accent: #f4f4f5; --p-on-accent: #18181b;
|
|
445
|
-
}
|
|
462
|
+
.dialog-backdrop { /* dark by default, like the panel */
|
|
463
|
+
--p-bg: #1c1c1f; --p-fg: #f4f4f5; --p-muted: #a1a1aa; --p-line: #2e2e33; --p-hover: #27272a;
|
|
464
|
+
--p-accent: #f4f4f5; --p-on-accent: #18181b;
|
|
446
465
|
}
|
|
447
466
|
.dialog-backdrop[hidden] { display: none; }
|
|
448
467
|
.dialog {
|
|
@@ -504,35 +523,13 @@ ${Object.entries(r).map(([d,l])=>` ${d}: ${l} !important;`).join(`
|
|
|
504
523
|
width: 10px; height: 10px; border-radius: 50%;
|
|
505
524
|
background: #d97706; box-shadow: 0 0 0 2px var(--p-bg);
|
|
506
525
|
}
|
|
507
|
-
|
|
526
|
+
.setup-head svg { color: #fbbf24; }
|
|
508
527
|
|
|
509
528
|
/* ---------- Layout direction A (Figma 80:245 › A1b, A2) ---------- */
|
|
510
|
-
.
|
|
511
|
-
.subhead { padding-left: 8px; }
|
|
529
|
+
.page[hidden] { display: none; }
|
|
512
530
|
.page-fields { padding: 14px 14px 16px; display: grid; gap: 14px; color: var(--p-muted); }
|
|
513
531
|
.page-warnings:empty { display: none; }
|
|
514
532
|
|
|
515
|
-
/* Edit list rows look like the Figma Section row (6:134) */
|
|
516
|
-
.nav-row {
|
|
517
|
-
width: 100%; display: flex; align-items: center; gap: 8px;
|
|
518
|
-
padding: 11px 14px; border: 0; border-bottom: 1px solid var(--p-line);
|
|
519
|
-
background: transparent; color: var(--p-fg);
|
|
520
|
-
font: inherit; font-weight: 500; text-align: left; cursor: pointer;
|
|
521
|
-
}
|
|
522
|
-
.nav-row:last-child { border-bottom: 0; }
|
|
523
|
-
.nav-row:hover { background: var(--p-hover); }
|
|
524
|
-
.nav-row .chev { margin-left: auto; color: var(--p-muted); display: grid; }
|
|
525
|
-
|
|
526
|
-
/* "Edit every token" row above the footer (Figma: Edit row (proposal)) */
|
|
527
|
-
.edit-row {
|
|
528
|
-
display: flex; align-items: center; gap: 8px;
|
|
529
|
-
padding: 11px 14px; border: 0; border-top: 1px solid var(--p-line);
|
|
530
|
-
background: transparent; color: var(--p-fg);
|
|
531
|
-
font: inherit; font-weight: 500; text-align: left; cursor: pointer;
|
|
532
|
-
}
|
|
533
|
-
.edit-row:hover { background: var(--p-hover); }
|
|
534
|
-
.edit-row .chev { margin-left: auto; color: var(--p-muted); display: grid; }
|
|
535
|
-
|
|
536
533
|
/* Character pad (Figma: Character pad (proposal)): 170px tall, 9 × 5 dots */
|
|
537
534
|
.pad {
|
|
538
535
|
position: relative; height: 170px; border-radius: 10px;
|
|
@@ -620,97 +617,229 @@ ${Object.entries(r).map(([d,l])=>` ${d}: ${l} !important;`).join(`
|
|
|
620
617
|
.role-row.edited .step-select select, .step-select select:focus-visible { border-color: var(--p-accent); outline: none; }
|
|
621
618
|
.step-chevron { position: absolute; right: 7px; top: 50%; transform: translateY(-50%); display: grid; color: var(--p-muted); pointer-events: none; }
|
|
622
619
|
.role-note { margin: 0; font-size: 11px; line-height: 1.45; color: var(--p-muted); }
|
|
623
|
-
|
|
624
|
-
|
|
620
|
+
|
|
621
|
+
/* ---------- Tabbed layout (Figma: Panel — tabbed layout (proposal), 254:323) ---------- */
|
|
622
|
+
.tabbar {
|
|
623
|
+
display: flex; gap: 2px; padding: 6px;
|
|
624
|
+
border-top: 1px solid var(--p-line);
|
|
625
|
+
}
|
|
626
|
+
.tab {
|
|
627
|
+
flex: 1 1 0; min-width: 0;
|
|
628
|
+
display: grid; justify-items: center; gap: 3px;
|
|
629
|
+
padding: 7px 2px 6px; border: 0; border-radius: 8px;
|
|
630
|
+
background: transparent; color: var(--p-muted);
|
|
631
|
+
font: inherit; font-size: 11px; cursor: pointer;
|
|
632
|
+
}
|
|
633
|
+
.tab:hover { background: var(--p-hover); color: var(--p-fg); }
|
|
634
|
+
.tab[aria-pressed="true"] { background: var(--p-hover); color: var(--p-fg); font-weight: 600; }
|
|
635
|
+
.tab span { max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
636
|
+
|
|
637
|
+
/* Minimised (proposal, not yet in Figma): only the tab bar (and the Compare
|
|
638
|
+
strip while it shows); clicking a tab opens the panel on that tab. */
|
|
639
|
+
.panel.minimised > :not(.tabbar):not(.original-pill) { display: none; }
|
|
640
|
+
.panel.minimised .tabbar { border-top: 0; }
|
|
641
|
+
.page-fields { gap: 16px; }
|
|
642
|
+
.page-heading { display: flex; align-items: baseline; justify-content: space-between; font-size: 13px; font-weight: 500; color: var(--p-fg); margin-bottom: -6px; }
|
|
643
|
+
.page-heading .muted { font-size: 12px; font-weight: 400; }
|
|
644
|
+
|
|
645
|
+
/* Tiles (Figma: Tile (proposal)) */
|
|
646
|
+
.tiles { display: grid; grid-template-columns: repeat(var(--cols, 3), minmax(0, 1fr)); gap: 8px; }
|
|
647
|
+
.tile {
|
|
648
|
+
display: grid; justify-items: center; align-content: start; gap: 6px; min-width: 0;
|
|
649
|
+
padding: 8px; border: 1px solid var(--p-line); border-radius: 10px;
|
|
650
|
+
background: var(--p-bg); color: var(--p-muted);
|
|
651
|
+
font: inherit; font-size: 11px; text-align: center; cursor: pointer;
|
|
652
|
+
}
|
|
653
|
+
.tile:hover { border-color: var(--p-muted); }
|
|
654
|
+
.tile[aria-checked="true"] { border-color: var(--p-accent); box-shadow: inset 0 0 0 1px var(--p-accent); color: var(--p-fg); font-weight: 600; }
|
|
655
|
+
.tile:focus-visible { outline: 2px solid var(--p-accent); outline-offset: 2px; }
|
|
656
|
+
.tile.wide { grid-column: 1 / -1; }
|
|
657
|
+
.tile-text { display: grid; gap: 1px; min-width: 0; max-width: 100%; }
|
|
658
|
+
.tile-label { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
659
|
+
.tile-sub { font-size: 11px; font-weight: 400; color: var(--p-muted); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
660
|
+
.tile-preview { display: grid; place-items: center; }
|
|
661
|
+
|
|
662
|
+
/* Font tiles: left-aligned, big "Aa" in the pairing's heading font */
|
|
663
|
+
.tiles-fonts .tile { justify-items: start; text-align: left; padding: 10px 12px; gap: 2px; }
|
|
664
|
+
.tiles-fonts .tile-label { font-size: 13px; font-weight: 500; color: var(--p-fg); }
|
|
665
|
+
.tiles-fonts .tile[aria-checked="true"] .tile-label { font-weight: 600; }
|
|
666
|
+
.tile-aa { font-size: 26px; line-height: 32px; font-weight: 600; color: var(--p-fg); }
|
|
667
|
+
.tiles-fonts .tile.wide { grid-template-columns: auto 1fr; align-items: center; column-gap: 10px; }
|
|
668
|
+
.tiles-fonts .tile.wide .tile-aa { font-size: 18px; line-height: 24px; }
|
|
669
|
+
.tiles-fonts .tile.wide .tile-text { display: flex; justify-content: space-between; align-items: center; gap: 8px; width: 100%; }
|
|
670
|
+
.tiles-fonts .tile.wide { justify-items: stretch; }
|
|
671
|
+
|
|
672
|
+
/* Previews drawn in CSS */
|
|
673
|
+
.ladder { display: flex; align-items: baseline; gap: 3px; height: 32px; color: var(--p-fg); }
|
|
674
|
+
.ladder b { font-weight: 600; line-height: 1; }
|
|
675
|
+
.sketch { display: grid; align-content: start; width: 84px; height: 56px; border: 1px solid var(--p-line); border-radius: 6px; background: var(--p-hover); }
|
|
676
|
+
.sketch i { height: 9px; border-radius: 2px; background: var(--p-line); }
|
|
677
|
+
.sketch i:first-child { background: var(--p-muted); }
|
|
678
|
+
.shape { display: block; }
|
|
679
|
+
.shape-button { width: 52px; height: 24px; background: #4f46e5; }
|
|
680
|
+
.shape-button.size-small { width: 38px; height: 16px; border-radius: 4px; }
|
|
681
|
+
.shape-button.size-medium { width: 52px; height: 22px; border-radius: 5px; }
|
|
682
|
+
.shape-button.size-large { width: 66px; height: 28px; border-radius: 6px; }
|
|
683
|
+
.shape-card { width: 52px; height: 38px; background: var(--p-bg); border: 1px solid var(--p-muted); }
|
|
684
|
+
.shape-card.border-none { border-color: transparent; background: var(--p-hover); border-radius: 6px; }
|
|
685
|
+
.shape-card.border-thin { border-radius: 6px; }
|
|
686
|
+
.shape-card.border-thick { border-width: 2px; border-radius: 6px; }
|
|
687
|
+
/* Style tiles (v0.4): Figma "Shape — with styles" 257:711 */
|
|
688
|
+
.shape-button[class*="style-"] { width: 52px; height: 22px; border-radius: 5px; display: grid; place-items: center; border: 1.5px solid transparent; }
|
|
689
|
+
.shape-button[class*="style-"]::after { content: ""; width: 22px; height: 3px; border-radius: 2px; background: #a5b4fc; }
|
|
690
|
+
.shape-button.style-solid::after { background: #fff; }
|
|
691
|
+
.shape-button.style-soft { background: rgb(79 70 229 / 0.32); }
|
|
692
|
+
.shape-button.style-outline { background: transparent; border-color: #818cf8; }
|
|
693
|
+
.shape-button.style-ghost { background: transparent; }
|
|
694
|
+
.shape-card[class*="style-"] { border-radius: 6px; }
|
|
695
|
+
.shape-card.style-filled { background: var(--p-hover); border-color: var(--p-line); }
|
|
696
|
+
.shape-card.style-outlined { background: transparent; border-color: var(--p-muted); }
|
|
697
|
+
.shape-card.style-elevated { background: color-mix(in oklch, var(--p-hover) 88%, white); border-color: transparent; box-shadow: 0 5px 12px rgb(0 0 0 / 0.55); }
|
|
698
|
+
.shape-card.style-tinted { background: rgb(79 70 229 / 0.2); border-color: rgb(129 140 248 / 0.5); }
|
|
699
|
+
.shape-card[class*="shadow-"] { width: 44px; height: 32px; border-radius: 6px; border-color: var(--p-line); margin: 4px 0 6px; }
|
|
700
|
+
.shape-card.shadow-bold { border-color: var(--p-fg); }
|
|
701
|
+
|
|
702
|
+
/* Colour tab */
|
|
703
|
+
.tiles-themes .tile { justify-items: stretch; }
|
|
704
|
+
.tiles-themes .tile-preview { display: block; width: 100%; place-items: normal; } /* stretch the palette (block centring is supported now) */
|
|
705
|
+
.theme { width: 100%; }
|
|
706
|
+
.theme { display: block; height: 58px; border-radius: 6px; background: var(--bg); border: 1px solid var(--line); position: relative; }
|
|
707
|
+
.theme i { position: absolute; left: 10px; right: 30px; top: 9px; bottom: 9px; background: #fff; border: 1px solid var(--line); border-radius: 5px; }
|
|
708
|
+
.theme b, .theme s, .theme u { position: absolute; left: 7px; height: 4px; border-radius: 2px; text-decoration: none; }
|
|
709
|
+
.theme b { top: 7px; width: 40%; background: var(--ink); }
|
|
710
|
+
.theme s { top: 15px; width: 60%; height: 3px; background: var(--soft); }
|
|
711
|
+
.theme u { top: 24px; width: 26px; height: 9px; border-radius: 3px; background: var(--pri); }
|
|
712
|
+
.palette { display: flex; gap: 2px; margin-top: 6px; }
|
|
713
|
+
.palette i { flex: 1; height: 10px; border-radius: 2px; }
|
|
714
|
+
.tiles-swatches { gap: 6px; }
|
|
715
|
+
.tiles-swatches .tile { padding: 0; width: 30px; height: 30px; border-radius: 50%; border: 0; display: grid; place-items: center; align-content: center; gap: 0; justify-self: center; } /* dot centred in its ring */
|
|
716
|
+
.tiles-swatches .tile .tile-text { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); }
|
|
717
|
+
.tiles-swatches .tile[aria-checked="true"] { box-shadow: inset 0 0 0 2px var(--p-accent); }
|
|
718
|
+
.tiles-swatches .dot { width: 22px; height: 22px; border-radius: 50%; display: block; }
|
|
719
|
+
.tiles-greys .tile { padding: 6px 4px; font-size: 10px; }
|
|
720
|
+
.greys { display: flex; border-radius: 4px; overflow: hidden; }
|
|
721
|
+
.greys i { width: 10px; height: 18px; }
|
|
722
|
+
.rainbow { width: 16px; height: 16px; border-radius: 50%; background: conic-gradient(#ef4444, #eab308, #22c55e, #06b6d4, #6366f1, #d946ef, #ef4444); flex: none; }
|
|
723
|
+
|
|
724
|
+
/* Fold-out rows ("Colour tokens"…, "Custom colour…") */
|
|
725
|
+
.more { border: 1px solid var(--p-line); border-radius: 8px; }
|
|
726
|
+
.more summary { display: flex; align-items: center; gap: 6px; padding: 9px 10px; font-weight: 500; font-size: 12px; color: var(--p-fg); cursor: pointer; border-radius: 8px; }
|
|
727
|
+
.more summary::-webkit-details-marker { display: none; }
|
|
728
|
+
.more summary:hover { background: var(--p-hover); }
|
|
729
|
+
.more summary .chev { display: grid; color: var(--p-muted); transition: transform .15s ease; }
|
|
730
|
+
.more[open] summary .chev { transform: rotate(90deg); }
|
|
731
|
+
.more summary .muted { margin-left: auto; font-weight: 400; }
|
|
732
|
+
.more summary > span:nth-child(2) { flex: 1; }
|
|
733
|
+
.more-body { display: grid; gap: 14px; padding: 4px 10px 12px; }
|
|
734
|
+
|
|
735
|
+
/* Overview: "Current look" rows */
|
|
736
|
+
.summary { border: 1px solid var(--p-line); border-radius: 10px; overflow: hidden; }
|
|
737
|
+
.summary-row {
|
|
738
|
+
width: 100%; display: flex; align-items: center; gap: 8px;
|
|
739
|
+
padding: 9px 10px 9px 12px; border: 0; border-bottom: 1px solid var(--p-line);
|
|
740
|
+
background: transparent; color: var(--p-fg); font: inherit; text-align: left; cursor: pointer;
|
|
741
|
+
}
|
|
742
|
+
.summary-row:last-child { border-bottom: 0; }
|
|
743
|
+
.summary-row:hover { background: var(--p-hover); }
|
|
744
|
+
.summary-name { flex: 1; font-weight: 500; }
|
|
745
|
+
.summary-value { font-size: 12px; color: var(--p-muted); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; max-width: 180px; }
|
|
746
|
+
.summary-swatch { width: 14px; height: 14px; border-radius: 4px; flex: none; }
|
|
747
|
+
.summary-swatch[hidden] { display: none; }
|
|
748
|
+
.summary-row .chev { display: grid; color: var(--p-muted); }
|
|
749
|
+
`,L=(t,e,n)=>`<svg width="${t}" height="${t}" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="${e}" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">${n}</svg>`,A={dial:L(20,1.8,'<circle cx="12" cy="12" r="8"/><path d="M12 12l4-4"/><path d="M12 2v2M12 20v2M2 12h2M20 12h2"/>'),link:L(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"/>'),reset:L(15,2,'<path d="M3 12a9 9 0 1 0 3-6.7"/><path d="M3 3v6h6"/>'),close:L(15,2,'<path d="M18 6L6 18M6 6l12 12"/>'),chevron:L(12,2.4,'<path d="M9 6l6 6-6 6"/>'),pick:L(15,2,'<circle cx="12" cy="12" r="7"/><path d="M12 2v4M12 18v4M2 12h4M18 12h4"/>'),compare:L(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"/>'),undo:L(15,2,'<path d="M9 14L4 9l5-5"/><path d="M4 9h11a5 5 0 0 1 0 10h-3"/>'),redo:L(15,2,'<path d="M15 14l5-5-5-5"/><path d="M20 9H9a5 5 0 0 0 0 10h3"/>'),back:L(15,2,'<path d="M15 18l-6-6 6-6"/>'),down:L(12,2.4,'<path d="M6 9l6 6 6-6"/>'),minimise:L(15,2,'<path d="M5 12h14"/>'),copy:L(13,2,'<rect x="9" y="9" width="11" height="11" rx="2"/><path d="M5 15V5a2 2 0 0 1 2-2h10"/>'),warn:L(13,2,'<path d="M12 3l9.5 17h-19z"/><path d="M12 10v4M12 17.5v.01"/>'),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>',tabOverview:L(18,1.8,'<circle cx="12" cy="12" r="8"/><path d="M12 12l4-4"/><path d="M12 2v2M12 20v2M2 12h2M20 12h2"/>'),tabColour:L(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"/>'),tabType:L(18,2,'<path d="M5 7V5h14v2"/><path d="M12 5v14"/><path d="M9 19h6"/>'),tabSpacing:L(18,2,'<path d="M4 5v14M20 5v14"/><path d="M8 12h8"/><path d="M10 9l-3 3 3 3M14 9l3 3-3 3"/>'),tabShape:L(18,2,'<path d="M20 4h-9a7 7 0 0 0-7 7v9"/><path d="M20 10h-5a5 5 0 0 0-5 5v5"/>'),tabShadows:L(18,2,'<rect x="4" y="4" width="12" height="12" rx="2"/><path d="M20 8v10a2 2 0 0 1-2 2H8"/>'),sliders:L(15,2,'<path d="M4 7h10M18 7h2M4 17h4M12 17h8"/><circle cx="16" cy="7" r="2"/><circle cx="10" cy="17" r="2"/>')},It="twiddle:";function te(t){try{return localStorage.getItem(It+t)}catch{return null}}function ce(t,e){try{localStorage.setItem(It+t,e)}catch{}}function ne({label:t,options:e,onSelect:n}){const a=document.createElement("div");a.className="seg",a.setAttribute("role","radiogroup"),a.setAttribute("aria-label",t);const o=e.map(l=>{const p=document.createElement("button");return p.type="button",p.setAttribute("role","radio"),p.dataset.value=l.value,p.textContent=l.label,l.title&&(p.title=l.title),p.addEventListener("click",()=>i(l.value)),p});a.append(...o);let s=null;function r(l){s=l,o.forEach(c=>c.setAttribute("aria-checked",String(c.dataset.value===l)));const p=Math.max(0,o.findIndex(c=>c.dataset.value===l));o.forEach((c,h)=>{c.tabIndex=h===p?0:-1})}function i(l,p){l!==s&&(r(l),n(l)),p&&o.find(c=>c.dataset.value===l).focus()}return a.addEventListener("keydown",l=>{const p=o.indexOf(l.target);if(p<0)return;const c={ArrowRight:1,ArrowDown:1,ArrowLeft:-1,ArrowUp:-1}[l.key];let h;if(c)h=(p+c+o.length)%o.length;else if(l.key==="Home")h=0;else if(l.key==="End")h=o.length-1;else return;l.preventDefault(),i(o[h].dataset.value,!0)}),r(null),{el:a,setValue:r}}const Dt=/var\(\s*(--twd-[\w-]+)/g,ia=/::?[\w-]+(\([^)]*\))?/g;function*Ee(t){for(const e of t)e.selectorText!=null&&(yield e),e.cssRules&&(yield*Ee(e.cssRules))}function la(){const t=[];for(const e of document.styleSheets){if(e.ownerNode?.id==="twiddle-scoped")continue;let n;try{n=e.cssRules}catch{continue}for(const a of Ee(n)){const o=[...a.style.cssText.matchAll(Dt)].map(s=>s[1]);o.length&&t.push({selectors:a.selectorText.split(","),vars:o})}}return t}function da(t,e){const n=e.replace(ia,"").trim()||"*";try{return t.matches(n)}catch{return!1}}function Bt(t){const e=new Set,n=[];return la().forEach(({selectors:a,vars:o})=>{const s=a.find(r=>da(t,r));s&&(o.forEach(r=>e.add(r)),n.push(s.trim()))}),[...(t.getAttribute("style")||"").matchAll(Dt)].forEach(a=>e.add(a[1])),{names:e,selectors:n}}const Xe=t=>window.CSS&&CSS.escape?CSS.escape(t):t;function ca(t){const e=[];let n=t;for(;n&&n.nodeType===1&&n!==document.body&&n!==document.documentElement;){if(n.id&&document.querySelectorAll(`#${Xe(n.id)}`).length===1)return e.unshift(`#${Xe(n.id)}`),e.join(" > ");const a=n.localName,o=[...n.parentElement.children].filter(s=>s.localName===a);e.unshift(o.length>1?`${a}:nth-of-type(${o.indexOf(n)+1})`:a),n=n.parentElement}return["body",...e].join(" > ")}function pa(t,e=Bt(t).selectors){const n=t.getAttribute("data-twd");if(n)return`[data-twd="${n.replace(/"/g,"")}"]`;const a=[...t.classList],s=a.find(r=>e.some(i=>new RegExp(`\\.${r.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}(?![\\w-])`).test(i)))||a[0];return s?`.${Xe(s)}`:null}function ua(t){const e=Bt(t),n=pa(t,e.selectors),a=(t.getAttribute("aria-label")||t.placeholder||t.textContent||"").trim().replace(/\s+/g," ");return{el:t,tag:t.localName,classes:[...t.classList],text:a.length>40?`${a.slice(0,40)}…`:a,tokens:e.names,elementSelector:ca(t),classSelector:n,classCount:n?document.querySelectorAll(n).length:0}}const Je=t=>t.localName+[...t.classList].map(e=>`.${e}`).join(""),ha={radius:"px",intensity:"%",base:"px"},Ut=t=>t.charAt(0).toUpperCase()+t.slice(1),fa=(t,e)=>typeof e=="number"||/^\d+$/.test(e)?`${e}${ha[t]||""}`:Ut(String(e));function qt(t,e,n){const a=zt(()=>t.tokens({[t.id]:e})||{}),o=Object.keys(a);let s={};if(o.length){const r=n.selector?document.querySelector(n.selector):void 0;s=aa(o,r||void 0)}return{...n,sectionId:t.id,title:t.title,settings:Object.entries(e).map(([r,i])=>({key:r,label:Ut(r),value:fa(r,i),...t.describe?.(r,i)||{}})),tokens:o.map(r=>({name:r,from:s[r]||"",to:a[r]}))}}function Vt(t,e){const n=[];return e.forEach(a=>{t[a.id]&&n.push(qt(a,t[a.id],{kind:"global",selector:null}))}),Object.entries(t.scopes||{}).forEach(([a,o])=>{const s=Ye(a)?"class":"element";e.forEach(r=>{o[r.id]&&n.push(qt(r,o[r.id],{kind:s,selector:a}))})}),n}function ga(t){const e=o=>Object.values(o||{}).reduce((s,r)=>s+Object.keys(r||{}).length,0),{scopes:n,...a}=t;return e(a)+Object.values(n||{}).reduce((o,s)=>o+e(s),0)}const ae=t=>`\`${t}\``,Qe=t=>t.map(e=>` - ${ae(e.name)}: ${e.from?`${ae(e.from)} → `:""}${ae(e.to)}`),et=t=>`${t.title} › ${t.settings.map(e=>`${e.label}: ${e.value}`).join(", ")}`;function ma(t){let e=null;try{e=document.querySelector(t)}catch{}if(!e)return"not found on the current page";const n=(e.getAttribute("aria-label")||e.placeholder||e.textContent||"").trim().replace(/\s+/g," ").slice(0,60);return`${ae(Je(e))}${n?` with text “${n}”`:""}`}function Ht(t,e){const n=new Map;return t.forEach(a=>{const o=a[e];n.has(o)||n.set(o,[]),n.get(o).push(a)}),[...n]}function ba(t,{link:e=location.href,warnings:n=[]}={}){if(!t.length)return"";const a=t.filter(i=>i.kind==="global"),o=t.filter(i=>i.kind==="class"),s=t.filter(i=>i.kind==="element"),r=[];if(r.push("# Apply design tweaks from Panel","","I explored design changes to this prototype with Panel (by Twiddle), a tweak panel that overrides the prototype's `--twd-*` CSS custom properties (design tokens) at runtime. Make these changes permanent in the source code.","",`Preview of the tweaked version: ${e}`),a.length&&(r.push("","## 1. Global token changes","","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.",""),a.forEach(i=>r.push(`- **${et(i)}**`,...Qe(i.tokens)))),o.length&&(r.push("",`## ${a.length?2:1}. Component-wide changes`,"","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.",""),Ht(o,"selector").forEach(([i,l])=>{r.push(`- ${ae(i)} (${document.querySelectorAll(i).length} on this page)`),l.forEach(p=>r.push(` - **${et(p)}**`,...Qe(p.tokens).map(c=>` ${c}`)))})),s.length){const i=1+(a.length?1:0)+(o.length?1:0);r.push("",`## ${i}. Single-element changes`,"","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.",""),Ht(s,"selector").forEach(([l,p])=>{r.push(`- ${ma(l)}, found at ${ae(l)}`),p.forEach(c=>r.push(` - **${et(c)}**`,...Qe(c.tokens).map(h=>` ${h}`)))})}return n.length&&r.push("","## Contrast to check","","Panel flagged these colour pairs as below WCAG AA with the new values:","",...n.map(i=>`- ${i.text}`)),r.push("","## Constraints","","- Keep styling through the `--twd-*` tokens; don't hard-code the new values in component rules.","- Change only what is listed above.","- If a value uses `color-mix()` and the project targets older browsers, ask before converting it.","- When done, list the files you changed."),r.join(`
|
|
750
|
+
`)}const Ce=4.5,xa=3,wa=[["--twd-text","--twd-bg","Text on background"],["--twd-text","--twd-surface","Text on surface"],["--twd-text-muted","--twd-surface","Muted text on surface"],["--twd-on-primary","--twd-primary","Text on brand"]];let G;function tt(t){if(!t||(G||=Object.assign(document.createElement("canvas"),{width:1,height:1}).getContext("2d",{willReadFrequently:!0}),!G))return null;G.clearRect(0,0,1,1),G.fillStyle="#000",G.fillStyle=t,G.fillRect(0,0,1,1);const[e,n,a,o]=G.getImageData(0,0,1,1).data;return[e,n,a,o/255]}function _t(t){const e=document.createElement("i");e.style.cssText=`position:absolute;visibility:hidden;color:var(${t})`,document.documentElement.appendChild(e);const n=getComputedStyle(e).color;return e.remove(),tt(n)}const Kt=([t,e,n])=>{const a=o=>(o/=255,o<=.03928?o/12.92:((o+.055)/1.055)**2.4);return .2126*a(t)+.7152*a(e)+.0722*a(n)},Gt=(t,e)=>t.slice(0,3).map((n,a)=>n*t[3]+e[a]*(1-t[3])).concat(1);function Wt(t,e){const n=Kt(t[3]<1?Gt(t,e):t),a=Kt(e);return(Math.max(n,a)+.05)/(Math.min(n,a)+.05)}const Yt=t=>`${t.toFixed(1)}:1`;function nt(){const t=[];return wa.forEach(([e,n,a])=>{const o=_t(e),s=_t(n);if(!o||!s||s[3]===0)return;const r=Wt(o,s);r<Ce&&t.push({label:a,ratio:r,needed:Ce,text:`${a}: ${Yt(r)} · AA needs ${Ce}`})}),t}function va(t){const e=[];for(let n=t;n&&n.nodeType===1;n=n.parentElement){const a=tt(getComputedStyle(n).backgroundColor);if(a&&a[3]>0&&(e.push(a),a[3]>=1))break}return e.reduceRight((n,a)=>Gt(a,n),[255,255,255,1])}function ya(t){if(!t.textContent.trim()&&!t.placeholder)return null;const e=getComputedStyle(t),n=tt(e.color);if(!n)return null;const a=parseFloat(e.fontSize),s=a>=24||a>=18.66&&parseInt(e.fontWeight,10)>=700?xa:Ce,r=Wt(n,va(t));return r<s?{label:"This element",ratio:r,needed:s,text:`This element’s text: ${Yt(r)} · AA needs ${s}`}:null}const Zt="twiddle-panel",ka="0.7.1",Xt="https://panel.twiddle.in",Sa="--twd-radius-control",$a=/var\(\s*--twd-/;function Ea(t){return t.style.cssText.split(";").some(e=>{const n=e.slice(0,e.indexOf(":")).trim();return n&&!n.startsWith("--")&&$a.test(e)})}function Ca(){if(!getComputedStyle(document.documentElement).getPropertyValue(Sa).trim())return"no-tokens";let t=!1;for(const e of document.styleSheets){if(e.ownerNode?.id==="twiddle-scoped")continue;let n;try{n=e.cssRules}catch{t=!0;continue}for(const a of Ee(n))if(Ea(a))return"ok"}return document.querySelector('[style*="var(--twd-"]')?"ok":t?"unknown":"unused"}function Ma(){const t=new Set,e=n=>{for(const a of n.matchAll(/var\(\s*(--twd-[\w-]+)/g))t.add(a[1])};for(const n of document.styleSheets){if(n.ownerNode?.id==="twiddle-scoped")continue;let a;try{a=n.cssRules}catch{continue}for(const o of Ee(a))o.style.cssText.split(";").forEach(s=>{const r=s.slice(0,s.indexOf(":")).trim();r&&!r.startsWith("--")&&e(s)})}return document.querySelectorAll('[style*="var(--twd-"]').forEach(n=>e(n.getAttribute("style"))),t}const Jt=[{label:"With a build tool, in your entry file",code:`import '${Zt}/tokens.css';`},{label:"Plain HTML, in <head>",code:`<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/${Zt}@${ka}/dist/twiddle-tokens.css">`}],Ta=`Convert this prototype's styles to use the Panel design tokens (the --twd-* CSS custom properties from twiddle-panel), so the panel can tweak them live.
|
|
625
751
|
|
|
626
752
|
1. Keep the current look. In a :root rule loaded after twiddle-tokens.css, set each token below to the value this project already uses (for example, if buttons use #0f766e, set --twd-primary: #0f766e). Only set the tokens the project actually needs.
|
|
627
753
|
2. Replace fixed values in component styles with var(--twd-…). Map each value to the closest token by role:
|
|
628
754
|
- Fonts: --twd-font-heading, --twd-font-body
|
|
629
755
|
- Text sizes: --twd-text-xs, -sm, -base, -lg, -xl, -2xl, -3xl; line height: --twd-leading-tight, --twd-leading-normal
|
|
756
|
+
- Font weights: --twd-weight-heading (headings, big numbers), --twd-weight-strong (buttons, labels, emphasis)
|
|
630
757
|
- Colours: --twd-bg (page), --twd-surface (cards, inputs), --twd-surface-raised (menus, popovers), --twd-text, --twd-text-muted, --twd-border, --twd-primary, --twd-primary-hover, --twd-on-primary (text on primary), --twd-focus, --twd-success, --twd-warning, --twd-danger
|
|
631
758
|
- Buttons, inputs, chips: --twd-radius-control, --twd-control-height, --twd-control-pad-x
|
|
632
759
|
- Cards, menus, modals: --twd-radius-container, --twd-border-width-container
|
|
760
|
+
- Main button and default card, preferred where they fit: --twd-button-bg, --twd-button-fg, --twd-button-border, --twd-button-hover (hover background); --twd-card-bg, --twd-card-border, --twd-card-shadow
|
|
633
761
|
- Borders: --twd-border-width
|
|
634
762
|
- Spacing (padding, margin, gap): --twd-space-1 to --twd-space-8 (4, 8, 12, 16, 24, 32, 48, 64px)
|
|
635
763
|
- Layout roles, preferred where they fit: --twd-page-pad (side padding of the page), --twd-section-gap (between page sections), --twd-card-pad (inside cards, menus, modals), --twd-card-gap (between items in a card), --twd-control-gap (between buttons, chips, inputs in a row)
|
|
636
764
|
- Shadows: --twd-shadow-sm, --twd-shadow-md, --twd-shadow-lg
|
|
637
765
|
3. Leave values that don't match a role as they are (layout widths, one-off illustrations, icon sizes). Don't invent new --twd-* tokens.
|
|
638
766
|
4. Don't change the layout or how the page looks; after the change it should look the same until someone uses the panel.
|
|
639
|
-
5. When done, list the files you changed and any values you left fixed, with the reason.`;function
|
|
640
|
-
<code class="token-name" title="${
|
|
641
|
-
${
|
|
767
|
+
5. When done, list the files you changed and any values you left fixed, with the reason.`;function D(t){const e=document.createElement("div");e.className="field";const n=document.createElement("div");n.className="field-head";const a=document.createElement("span");a.className="field-label",a.textContent=t;const o=document.createElement("span");return o.className="field-value",o.hidden=!0,n.append(a,o),e.append(n),{el:e,setValue(s){o.textContent=s||"",o.hidden=!s},append(...s){e.append(...s)}}}function Aa({label:t,ends:e,cols:n=9,rows:a=5,onInput:o}){const s=document.createElement("div");s.className="pad",s.tabIndex=0,s.setAttribute("role","group"),s.setAttribute("aria-roledescription","2D slider");const r=(b,u)=>{const v=document.createElement("span");return v.className=`pad-edge ${b}`,v.textContent=u,v.setAttribute("aria-hidden","true"),v};s.append(r("top",e.top),r("bottom",e.bottom),r("left",e.left),r("right",e.right));const i=document.createElement("div");i.className="pad-area";for(let b=0;b<a;b++)for(let u=0;u<n;u++){const v=document.createElement("i");v.className="pad-dot",v.style.left=`${u/(n-1)*100}%`,v.style.top=`${b/(a-1)*100}%`,i.append(v)}const l=document.createElement("span");l.className="pad-knob",i.append(l),s.append(i);let p=.5,c=.5;const h=(b,u)=>Math.round(Math.min(1,Math.max(0,b))*(u-1))/(u-1);function y(){l.style.left=`${p*100}%`,l.style.top=`${c*100}%`}function f(b,u,v){b=v==="x"?p:h(b,n),u=v==="y"?c:h(u,a),!(b===p&&u===c)&&(p=b,c=u,y(),o(p,c))}const m=b=>{const u=i.getBoundingClientRect();f((b.clientX-u.left)/u.width,(b.clientY-u.top)/u.height)};s.addEventListener("pointerdown",b=>{s.setPointerCapture(b.pointerId),s.classList.add("dragging"),m(b)}),s.addEventListener("pointermove",b=>{s.hasPointerCapture(b.pointerId)&&m(b)});const x=b=>{s.hasPointerCapture(b.pointerId)&&s.releasePointerCapture(b.pointerId),s.classList.remove("dragging")};return s.addEventListener("pointerup",x),s.addEventListener("pointercancel",x),s.addEventListener("keydown",b=>{const u={ArrowLeft:[-1,0],ArrowRight:[1,0],ArrowUp:[0,-1],ArrowDown:[0,1]}[b.key];u&&(b.preventDefault(),u[0]?f(h(p,n)+u[0]/(n-1),c,"y"):f(p,h(c,a)+u[1]/(a-1),"x"))}),{el:s,setValue(b,u,v){p=Math.min(1,Math.max(0,b)),c=Math.min(1,Math.max(0,u)),y(),s.setAttribute("aria-label",v?`${t}: ${v}`:t)}}}function Qt({label:t,min:e,max:n,step:a=1,format:o=String,onInput:s}){const r=document.createElement("div");r.className="slider";const i=document.createElement("input");i.type="range",i.min=String(e),i.max=String(n),i.step=String(a),i.setAttribute("aria-label",t);const l=document.createElement("span");l.className="slider-value",l.setAttribute("aria-hidden","true"),r.append(i,l);const p=c=>{const h=(Number(i.value)-e)/(n-e)*100;i.style.setProperty("--fill",`${h}%`),l.textContent=c??o(Number(i.value)),i.setAttribute("aria-valuetext",l.textContent)};return i.addEventListener("input",()=>{p(),s(Number(i.value))}),{el:r,setValue(c,h){i.value=String(c),p(h)}}}function La({label:t,options:e,columns:n=3,className:a="",onSelect:o}){const s=document.createElement("div");s.className=`tiles ${a}`.trim(),s.style.setProperty("--cols",n),s.setAttribute("role","radiogroup"),s.setAttribute("aria-label",t);const r=e.map(c=>{const h=document.createElement("button");return h.type="button",h.className="tile",c.wide&&h.classList.add("wide"),h.setAttribute("role","radio"),h.dataset.value=c.value,c.title&&(h.title=c.title),h.innerHTML=`${c.preview?`<span class="tile-preview" aria-hidden="true">${c.preview}</span>`:""}<span class="tile-text"><span class="tile-label"></span>${c.sub?'<span class="tile-sub"></span>':""}</span>`,h.querySelector(".tile-label").textContent=c.label,c.sub&&(h.querySelector(".tile-sub").textContent=c.sub),h.addEventListener("click",()=>p(c.value)),h});s.append(...r);let i=null;function l(c){i=c,r.forEach(y=>y.setAttribute("aria-checked",String(y.dataset.value===c)));const h=Math.max(0,r.findIndex(y=>y.dataset.value===c));r.forEach((y,f)=>{y.tabIndex=f===h?0:-1})}function p(c,h){c!==i&&(l(c),o(c)),h&&r.find(y=>y.dataset.value===c).focus()}return s.addEventListener("keydown",c=>{const h=r.indexOf(c.target.closest(".tile"));if(h<0)return;const y={ArrowRight:1,ArrowDown:1,ArrowLeft:-1,ArrowUp:-1}[c.key];let f;if(y)f=(h+y+r.length)%r.length;else if(c.key==="Home")f=0;else if(c.key==="End")f=r.length-1;else return;c.preventDefault(),p(r[f].dataset.value,!0)}),l(null),{el:s,setValue:l}}const F=t=>getComputedStyle(document.documentElement).getPropertyValue(t).trim();function pe(t,e){const n=/^(-?\d*\.?\d+)([a-z%]*)$/i.exec(String(t).trim());if(!n)return null;const a=parseFloat(n[1])*e,o=n[2]||"px";return o==="px"?`${Math.round(a)}px`:`${+a.toFixed(3)}${o}`}const Oa=999;function en({id:t,title:e,hint:n,token:a,uses:o=[],presets:s,max:r,extra:i=[],extraTokens:l=()=>({}),shape:p="card"}){const c=f=>s.find(m=>m.value===f),h=f=>f>=Oa?"full":`${f}px`,y=f=>{if(typeof f.radius=="number"&&isFinite(f.radius))return{[a]:`${Math.min(Math.max(f.radius,0),r)}px`};const m=c(f.corners);return m?{[a]:`${m.radius}px`}:{}};return{id:t,title:e,hint:n,presets:s,uses:[a,...o],tokens(f){const m=f[t]||{};return{...y(m),...l(m)}},parts:{corners(f,m,{label:x="Corners"}={}){const b=D(x),u=ne({label:`${e} corners`,options:s.map(E=>({value:E.value,label:E.label,title:h(E.radius)})),onSelect:E=>m.setSection(t,{corners:E,radius:null})}),v=Qt({label:`${e} corner radius`,min:0,max:r,format:h,onInput:E=>m.setSection(t,{radius:E,corners:null})});b.append(u.el,v.el),f.append(b.el);const O=()=>{const E=parseFloat((m.readToken||F)(a)),se=m.getState()[t]||{},Z=c(se.corners)||s.find(X=>X.radius===E);if(u.setValue(Z?Z.value:null),isNaN(E)){v.setValue(0,"—"),b.setValue("");return}v.setValue(Math.min(E,r),h(E)),b.setValue(h(E))};O(),m.onChange(O)},...Object.fromEntries(i.map(f=>[f.key,(m,x,{label:b}={})=>m.append(ue(x,{section:t,...f,label:b||f.label}))])),cornerTiles(f,m,{label:x="Corners"}={}){const b=u=>`<span class="shape shape-${p}" style="border-radius:${Math.min(u,p==="button"?12:16)}px"></span>`;f.append(V(m,{section:t,key:"corners",label:x,columns:s.length,options:s.map(u=>({value:u.value,label:u.label,title:h(u.radius),preview:b(u.radius)})),current:u=>{const v=u[t]||{};if(v.radius!=null)return null;const O=parseFloat((m.readToken||F)(a));return(c(v.corners)||s.find(E=>E.radius===O))?.value||null},select:u=>m.setSection(t,{corners:u,radius:null}),valueText:()=>{const u=parseFloat((m.readToken||F)(a));return isNaN(u)?"":h(u)}}))},...Object.fromEntries(i.filter(f=>f.preview).map(f=>[`${f.key}Tiles`,(m,x,{label:b}={})=>m.append(V(x,{section:t,key:f.key,label:b||f.label,fallback:f.fallback,columns:f.columns||f.options.length,options:f.options.map(u=>({...u,preview:f.preview(u.value)}))}))]))},render(f,m){Object.entries(this.parts).filter(([x])=>!x.endsWith("Tiles")).forEach(([,x])=>x(f,m))}}}function ue(t,{section:e,key:n,label:a,options:o,fallback:s,valueText:r}){const i=D(a),l=ne({label:a,options:o,onSelect:c=>t.setSection(e,{[n]:c})});i.append(l.el);const p=()=>{const c=(t.getState()[e]||{})[n]||s;l.setValue(c),i.setValue(r?r(c):"")};return p(),t.onChange(p),i.el}function Pa(t,{section:e,key:n,label:a,min:o,max:s,fallback:r,format:i}){const l=D(a),p=Qt({label:a,min:o,max:s,format:i,onInput:h=>t.setSection(e,{[n]:h})});l.append(p.el);const c=()=>{const h=(t.getState()[e]||{})[n];p.setValue(typeof h=="number"?h:r)};return c(),t.onChange(c),l.el}function V(t,{section:e,key:n,label:a,options:o,columns:s=3,className:r="",fallback:i,valueText:l,current:p,select:c}){const h=D(a),y=La({label:a,options:o,columns:s,className:r,onSelect:m=>c?c(m):t.setSection(e,{[n]:m})});h.append(y.el);const f=()=>{const m=t.getState(),x=p?p(m):(m[e]||{})[n]||i||null;y.setValue(x),h.setValue(l?l(x,m):"")};return f(),t.onChange(f),h.el}const tn=(t,e)=>e.map(n=>`${t}${n}`),nn={fonts:{label:"Tokens",tokens:["font-heading","font-body"],kind:"text"},type:{label:"Tokens",tokens:tn("text-",["xs","sm","base","lg","xl","2xl","3xl"]),kind:"length"},leading:{label:"Line height",tokens:["leading-tight","leading-normal"],kind:"number"},weights:{label:"Weights",tokens:["weight-heading","weight-strong"],kind:"number"},colours:{label:"Tokens",tokens:["bg","surface","surface-raised","text","text-muted","border","primary","primary-hover","on-primary","focus","success","warning","danger"],kind:"colour"},spacing:{label:"Steps",tokens:tn("space-",[1,2,3,4,5,6,7,8]),kind:"length",bar:64},controls:{label:"Controls",tokens:["control-height","control-pad-x"],kind:"length"},corners:{label:"Tokens",tokens:["radius-control","radius-container"],kind:"length"},borders:{label:"Tokens",tokens:["border-width","border-width-container"],kind:"length"},shadows:{label:"Tokens",tokens:["shadow-sm","shadow-md","shadow-lg"],kind:"text"},buttonStyle:{label:"Button",tokens:["button-bg","button-fg","button-border","button-hover"],kind:"colour"},cardStyle:{label:"Card",tokens:["card-bg","card-border"],kind:"colour"},cardShadow:{label:"Card shadow",tokens:["card-shadow"],kind:"text"}},H=t=>`--twd-${t}`,at=(t,e)=>Object.prototype.hasOwnProperty.call(t.getState().custom||{},e),an=(t,e)=>nn[e].tokens.some(n=>(t.custom||{})[n]!=null);function Fa(t,e){const n=/^(-?\d*\.?\d+)(px|rem)?$/.exec(String(t).trim());return!n||e==="text"||e==="colour"?null:n[2]==="rem"?{n:+(parseFloat(n[1])*16).toFixed(1),unit:"px"}:{n:+parseFloat(n[1]).toFixed(3),unit:n[2]||(e==="length"?"px":"")}}function Na(t,e){const n=t.trim();return n?e==="length"&&/^-?\d*\.?\d+$/.test(n)?`${n}px`:n:null}function ja(t,e,n,a){const o=document.createElement("div");o.className=`token-row kind-${n}`,o.innerHTML=`
|
|
768
|
+
<code class="token-name" title="${H(e)}">${e}</code>
|
|
769
|
+
${a?'<span class="token-bar"><span></span></span>':'<span class="token-gap"></span>'}
|
|
642
770
|
<span class="custom-tag" hidden>Custom</span>
|
|
643
771
|
<label class="token-value">
|
|
644
772
|
${n==="colour"?'<span class="token-swatch"></span>':""}
|
|
645
|
-
<input type="text" spellcheck="false" aria-label="${
|
|
773
|
+
<input type="text" spellcheck="false" aria-label="${H(e)}" ${n==="length"||n==="number"?'inputmode="decimal"':""}>
|
|
646
774
|
<span class="token-unit"></span>
|
|
647
775
|
</label>
|
|
648
|
-
<button class="icon-btn token-reset" title="Back to the page’s value" aria-label="Reset ${
|
|
649
|
-
`;const s=a.querySelector("input"),r=a.querySelector(".token-unit"),d=a.querySelector(".token-bar span"),l=a.querySelector(".token-swatch"),c=a.querySelector(".custom-tag"),p=a.querySelector(".token-reset");let m="";const v=()=>{let x=s.value;m&&/^-?\d*\.?\d+$/.test(x.trim())&&(x=`${x.trim()}${m}`);const b=ro(x,n),g=P(V(e));if(b===null){Ue(t,e)?t.setSection("custom",{[e]:null}):f();return}if(b===g&&!Ue(t,e))return f();t.setSection("custom",{[e]:b})};s.addEventListener("change",v),s.addEventListener("blur",()=>f()),s.addEventListener("keydown",x=>{x.key==="Enter"&&(x.preventDefault(),s.blur()),x.key==="Escape"&&(x.stopPropagation(),f(),s.blur())}),p.addEventListener("click",()=>t.setSection("custom",{[e]:null}));function f(){const x=P(V(e)),b=Ue(t,e),g=ao(x,n);m=g?g.unit:"",document.activeElement!==s&&a.getRootNode().activeElement!==s&&(s.value=g?String(g.n):x),s.title=x,r.textContent=m,r.hidden=!m,d&&(d.style.width=`${Math.max(2,Math.min(100,(g?g.n:0)/o*100))}%`),l&&(l.style.background=x),a.classList.toggle("edited",b),c.hidden=!b,p.hidden=!b}return f(),t.onChange(f),a}const io={id:"custom",title:"Custom tokens",hint:"Any token, set to a fixed value",uses:[],tokens(t){return Object.fromEntries(Object.entries(t.custom||{}).map(([e,n])=>[V(e),n]))},describe:(t,e)=>({label:V(t),value:String(e)}),parts:Object.fromEntries(Object.entries(Ft).map(([t,e])=>[t,(n,o,{label:a=e.label}={})=>{const s=B(a);s.el.classList.add("token-field");const r=e.tokens[0],d=e.tokens[e.tokens.length-1];s.setValue(e.tokens.length>2&&/-\w+$/.test(r)?`${V(r)} … ${d.split("-").pop()}`:"");const l=document.createElement("div");l.className="token-rows",e.tokens.forEach(c=>l.append(so(o,c,e.kind,e.bar))),s.append(l),n.append(s.el)}]))},Ve={compact:.75,regular:1,comfy:1.25},qe=[.75,1.25],Ot=[1,2,3,4,5,6,7,8].map(t=>`--twd-space-${t}`);function He(t={}){return typeof t.factor=="number"&&isFinite(t.factor)?Math.min(qe[1],Math.max(qe[0],t.factor)):Ve[t.spacing]||1}const Rt=t=>`${Math.round(t*100)}%`,lo={id:"density",title:"Density",hint:"Compact · regular · comfortable",uses:Ot,tokens(t){const e=He(t.density);if(e===1)return{};const n={};return Ot.forEach(o=>{const a=fe(P(o),e);a&&(n[o]=a)}),n},describe:(t,e)=>t==="factor"?{label:"Spacing",value:Rt(e)}:null,parts:{spacing(t,e,{label:n="Spacing"}={}){const o=B(n),a=W({label:n,options:[{value:"compact",label:"Compact"},{value:"regular",label:"Regular"},{value:"comfy",label:"Comfy"}],onSelect:r=>e.setSection("density",{spacing:r,factor:null})});o.append(a.el);const s=()=>{const r=e.getState().density||{},d=He(r),l=Object.keys(Ve).find(c=>Ve[c]===d);a.setValue(l||null),o.setValue(oo(e.getState(),"spacing")?"Custom":l?"":Rt(d))};s(),e.onChange(s),t.append(o.el)}},render(t,e){Object.values(this.parts).forEach(n=>n(t,e))}},ee=60,co={soft:{sm:[0,1,2,0,.06],md:[0,4,12,0,.08],lg:[0,12,32,0,.12]},crisp:{sm:[0,1,1,0,.12],md:[0,2,4,0,.14],lg:[0,4,8,0,.16]},bold:{sm:[2,2,0,0,.85],md:[3,3,0,0,.85],lg:[5,5,0,0,.85]}},_e=([t,e,n,o,a],s)=>{const r=Math.min(1,+(a*s).toFixed(3));return r<=0?"none":`${t}px ${e}px ${n}px ${o}px rgb(0 0 0 / ${r})`},po={id:"depth",title:"Depth",hint:"Flat · soft · crisp · bold",uses:["--twd-shadow-sm","--twd-shadow-md","--twd-shadow-lg"],tokens(t){const e=t.depth||{},n=e.style||"soft",o=typeof e.intensity=="number"?Math.min(100,Math.max(0,e.intensity)):ee;if(n==="flat")return{"--twd-shadow-sm":"none","--twd-shadow-md":"none","--twd-shadow-lg":"none"};const a=co[n];if(!a)return{};if(n==="soft"&&o===ee)return{};const s=o/ee;return{"--twd-shadow-sm":_e(a.sm,s),"--twd-shadow-md":_e(a.md,s),"--twd-shadow-lg":_e(a.lg,s)}},parts:{style(t,e,{label:n="Style"}={}){t.append(Q(e,{section:"depth",key:"style",label:n,fallback:"soft",options:[{value:"flat",label:"Flat"},{value:"soft",label:"Soft"},{value:"crisp",label:"Crisp"},{value:"bold",label:"Bold"}]}))},intensity(t,e,{label:n="Intensity"}={}){t.append(no(e,{section:"depth",key:"intensity",label:n,min:0,max:100,fallback:ee,format:o=>`${o}%`}))}},render(t,e){Object.values(this.parts).forEach(n=>n(t,e))}},[Nt,ge]=qe,jt={square:"square",soft:"soft",rounded:"rounded",pill:"large"};function uo(t){return t>1.06?"Comfy":t<.94?"Compact":"Regular"}const ho={character(t,e,{label:n="Character"}={}){const o=B(n),a=eo({label:n,ends:{top:"Spacious",bottom:"Compact",left:"Subtle",right:"Bold"},onInput:(r,d)=>{const l=+(ge-d*(ge-Nt)).toFixed(3),c={intensity:Math.round(r*100)};(e.getState().depth||{}).style==="flat"&&(c.style=null),e.setSections({density:{factor:l===1?null:l,spacing:null},depth:c},"character")}});o.append(a.el);const s=()=>{const r=e.getState(),d=He(r.density),l=r.depth||{},c=l.style==="flat"?0:typeof l.intensity=="number"?l.intensity:ee,p=`${uo(d)} · ${c}%`;a.setValue(c/100,(ge-d)/(ge-Nt),p),o.setValue(p)};s(),e.onChange(s),t.append(o.el)},corners(t,e,{label:n="Corners",buttons:o,cards:a}){const s=B(n),r=W({label:n,options:o.presets.map(c=>({value:c.value,label:c.label})),onSelect:c=>e.setSections({buttons:{corners:c,radius:null},cards:{corners:jt[c],radius:null}})});s.append(r.el);const d=(c,p,m)=>{if(p.radius!=null)return null;if(p.corners)return p.corners;const v=parseFloat(P(m));return c.presets.find(f=>f.radius===v)?.value||null},l=()=>{const c=e.getState(),p=d(o,c.buttons||{},"--twd-radius-control"),m=d(a,c.cards||{},"--twd-radius-container");r.setValue(p&&jt[p]===m?p:null);const v=b=>{const g=parseFloat(P(b));return isNaN(g)?"":g>=999?"full":`${g}px`},f=v("--twd-radius-control"),x=v("--twd-radius-container");s.setValue(f&&x?`${f} · ${x}`:"")};l(),e.onChange(l),t.append(s.el)}},Ge=[{key:"page-pad",label:"Page padding",step:5},{key:"section-gap",label:"Section gap",step:6},{key:"card-pad",label:"Card padding",step:5},{key:"card-gap",label:"Card gap",step:2},{key:"control-gap",label:"Control gap",step:3},{key:"control-pad-x",label:"Control padding",step:null}],fo=[1,2,3,4,5,6,7,8],go=/^var\(\s*--twd-space-(\d)\s*\)$/,Ke=t=>{const e=/^(-?\d*\.?\d+)(px|rem)?$/.exec(String(t).trim());return e?+(parseFloat(e[1])*(e[2]==="rem"?16:1)).toFixed(1):null};function mo(t,e,n){const o=`--twd-${e.key}`,a=document.createElement("div");a.className="role-row",n||a.classList.add("unused"),a.innerHTML=`
|
|
650
|
-
<span class="
|
|
776
|
+
<button class="icon-btn token-reset" title="Back to the page’s value" aria-label="Reset ${H(e)}" hidden>${A.reset}</button>
|
|
777
|
+
`;const s=o.querySelector("input"),r=o.querySelector(".token-unit"),i=o.querySelector(".token-bar span"),l=o.querySelector(".token-swatch"),p=o.querySelector(".custom-tag"),c=o.querySelector(".token-reset");let h="";const y=()=>{let m=s.value;h&&/^-?\d*\.?\d+$/.test(m.trim())&&(m=`${m.trim()}${h}`);const x=Na(m,n),b=F(H(e));if(x===null){at(t,e)?t.setSection("custom",{[e]:null}):f();return}if(x===b&&!at(t,e))return f();t.setSection("custom",{[e]:x})};s.addEventListener("change",y),s.addEventListener("blur",()=>f()),s.addEventListener("keydown",m=>{m.key==="Enter"&&(m.preventDefault(),s.blur()),m.key==="Escape"&&(m.stopPropagation(),f(),s.blur())}),c.addEventListener("click",()=>t.setSection("custom",{[e]:null}));function f(){const m=F(H(e)),x=at(t,e),b=Fa(m,n);h=b?b.unit:"",document.activeElement!==s&&o.getRootNode().activeElement!==s&&(s.value=b?String(b.n):m),s.title=m,r.textContent=h,r.hidden=!h,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),p.hidden=!x,c.hidden=!x}return f(),t.onChange(f),o}const Ra={id:"custom",title:"Custom tokens",hint:"Any token, set to a fixed value",uses:[],tokens(t){return Object.fromEntries(Object.entries(t.custom||{}).map(([e,n])=>[H(e),n]))},describe:(t,e)=>({label:H(t),value:String(e)}),parts:Object.fromEntries(Object.entries(nn).map(([t,e])=>[t,(n,a,{label:o=e.label}={})=>{const s=D(o);s.el.classList.add("token-field");const r=e.tokens[0],i=e.tokens[e.tokens.length-1];s.setValue(e.tokens.length>2&&/-\w+$/.test(r)?`${H(r)} … ${i.split("-").pop()}`:"");const l=document.createElement("div");l.className="token-rows",e.tokens.forEach(p=>l.append(ja(a,p,e.kind,e.bar))),s.append(l),n.append(s.el)}]))},he={compact:.75,regular:1,comfy:1.25},ot=[.75,1.25],on=[1,2,3,4,5,6,7,8].map(t=>`--twd-space-${t}`);function oe(t={}){return typeof t.factor=="number"&&isFinite(t.factor)?Math.min(ot[1],Math.max(ot[0],t.factor)):he[t.spacing]||1}const rt=t=>`${Math.round(t*100)}%`,za={id:"density",title:"Density",hint:"Compact · regular · comfortable",uses:on,tokens(t){const e=oe(t.density);if(e===1)return{};const n={};return on.forEach(a=>{const o=pe(F(a),e);o&&(n[a]=o)}),n},describe:(t,e)=>t==="factor"?{label:"Spacing",value:rt(e)}:null,parts:{spacingTiles(t,e,{label:n="Density"}={}){const a=(o,s)=>`<span class="sketch" style="padding:${s}px;gap:${o}px"><i></i><i></i><i></i></span>`;t.append(V(e,{section:"density",key:"spacing",label:n,options:[{value:"compact",label:"Compact",preview:a(2,5)},{value:"regular",label:"Regular",preview:a(4,8)},{value:"comfy",label:"Comfy",preview:a(6,11)}],current:o=>{const s=oe(o.density);return Object.keys(he).find(r=>he[r]===s)||null},select:o=>e.setSection("density",{spacing:o,factor:null}),valueText:(o,s)=>an(s,"spacing")?"Custom":o?"":rt(oe(s.density))}))},spacing(t,e,{label:n="Spacing"}={}){const a=D(n),o=ne({label:n,options:[{value:"compact",label:"Compact"},{value:"regular",label:"Regular"},{value:"comfy",label:"Comfy"}],onSelect:r=>e.setSection("density",{spacing:r,factor:null})});a.append(o.el);const s=()=>{const r=e.getState().density||{},i=oe(r),l=Object.keys(he).find(p=>he[p]===i);o.setValue(l||null),a.setValue(an(e.getState(),"spacing")?"Custom":l?"":rt(i))};s(),e.onChange(s),t.append(a.el)}},render(t,e){Object.entries(this.parts).filter(([n])=>!n.endsWith("Tiles")).forEach(([,n])=>n(t,e))}},Ia='<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.9" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M14 6l4 4M4 20l1-4 9.5-9.5a2.1 2.1 0 013 3L8 19l-4 1z"/></svg>',Da=[[50,"white",10],[100,"white",20],[200,"white",36],[300,"white",56],[400,"white",78],[500,null,100],[600,"black",86],[700,"black",72],[800,"black",58],[900,"black",45],[950,"black",30]],st=t=>{let e=String(t).trim().replace(/^#/,"");return/^[0-9a-f]{3}$/i.test(e)&&(e=e.split("").map(n=>n+n).join("")),/^[0-9a-f]{6}$/i.test(e)?`#${e.toUpperCase()}`:null};function Ba({label:t,onInput:e}){const n=document.createElement("div");n.className="colour";const a=document.createElement("div");a.className="colour-field";const o=document.createElement("input");o.type="color",o.className="colour-picker",o.tabIndex=-1,o.setAttribute("aria-hidden","true");const s=document.createElement("button");s.type="button",s.className="colour-swatch",s.setAttribute("aria-label",`${t}: open colour picker`);const r=document.createElement("input");r.type="text",r.className="colour-hex",r.spellcheck=!1,r.maxLength=7,r.setAttribute("aria-label",`${t} hex value`);const i=document.createElement("button");i.type="button",i.className="colour-pipette",i.innerHTML=Ia,i.title="Pick a colour from the screen",i.setAttribute("aria-label","Pick a colour from the screen"),a.append(o,s,r,i);const l=document.createElement("div");l.className="ramp",l.setAttribute("aria-hidden","true"),l.innerHTML=Da.map(([f,m,x])=>{const b=m?`color-mix(in oklch, var(--brand) ${x}%, ${m})`:"var(--brand)";return`<span title="${f}" style="background:${b}"></span>`}).join(""),n.append(a,l);let p="#000000";const c=f=>{p=f,o.value=f.toLowerCase(),s.style.background=f,n.getRootNode().activeElement!==r&&(r.value=f),n.style.setProperty("--brand",f)},h=f=>{f!==p&&(c(f),e(f))};s.addEventListener("click",()=>{if(o.showPicker)try{o.showPicker();return}catch{}o.click()}),o.addEventListener("input",()=>h(o.value.toUpperCase())),r.addEventListener("input",()=>{const f=st(r.value);f&&h(f)});const y=()=>{r.value=p};return r.addEventListener("blur",y),r.addEventListener("keydown",f=>{f.key==="Enter"&&(y(),r.select())}),i.addEventListener("click",async()=>{if("EyeDropper"in window)try{const{sRGBHex:f}=await new window.EyeDropper().open(),m=st(f);m&&h(m)}catch{}else s.click()}),{el:n,setValue:f=>c(st(f)||p)}}function Ua({label:t,options:e,onSelect:n}){const a=document.createElement("div");a.className="swatches",a.setAttribute("role","radiogroup"),a.setAttribute("aria-label",t);const o=e.map(l=>{const p=document.createElement("button");return p.type="button",p.className="swatch",p.setAttribute("role","radio"),p.dataset.value=l.value,p.innerHTML=`<span class="swatch-ring"><span class="swatch-dot" style="background:${l.colour}"></span></span><span class="swatch-label">${l.label}</span>`,p.addEventListener("click",()=>i(l.value)),p});a.append(...o);let s=null;function r(l){s=l,o.forEach(c=>c.setAttribute("aria-checked",String(c.dataset.value===l)));const p=Math.max(0,o.findIndex(c=>c.dataset.value===l));o.forEach((c,h)=>{c.tabIndex=h===p?0:-1})}function i(l,p){l!==s&&(r(l),n(l)),p&&o.find(c=>c.dataset.value===l).focus()}return a.addEventListener("keydown",l=>{const p=o.indexOf(l.target.closest(".swatch"));if(p<0)return;const c={ArrowRight:1,ArrowDown:1,ArrowLeft:-1,ArrowUp:-1}[l.key];let h;if(c)h=(p+c+o.length)%o.length;else if(l.key==="Home")h=0;else if(l.key==="End")h=o.length-1;else return;l.preventDefault(),i(o[h].dataset.value,!0)}),r(null),{el:a,setValue:r}}const qa=[50,100,200,300,400,500,600,700,800,900,950],fe=t=>Object.fromEntries(t.split(" ").map((e,n)=>[qa[n],`#${e}`])),it={slate:fe("f8fafc f1f5f9 e2e8f0 cbd5e1 94a3b8 64748b 475569 334155 1e293b 0f172a 020617"),gray:fe("f9fafb f3f4f6 e5e7eb d1d5db 9ca3af 6b7280 4b5563 374151 1f2937 111827 030712"),zinc:fe("fafafa f4f4f5 e4e4e7 d4d4d8 a1a1aa 71717a 52525b 3f3f46 27272a 18181b 09090b"),neutral:fe("fafafa f5f5f5 e5e5e5 d4d4d4 a3a3a3 737373 525252 404040 262626 171717 0a0a0a"),stone:fe("fafaf9 f5f5f4 e7e5e4 d6d3d1 a8a29e 78716c 57534e 44403c 292524 1c1917 0c0a09")},N=t=>Object.fromEntries(t.split(" ").map((e,n)=>[400+100*n,`#${e}`])),lt={red:N("f87171 ef4444 dc2626 b91c1c 991b1b"),orange:N("fb923c f97316 ea580c c2410c 9a3412"),amber:N("fbbf24 f59e0b d97706 b45309 92400e"),yellow:N("facc15 eab308 ca8a04 a16207 854d0e"),lime:N("a3e635 84cc16 65a30d 4d7c0f 3f6212"),green:N("4ade80 22c55e 16a34a 15803d 166534"),emerald:N("34d399 10b981 059669 047857 065f46"),teal:N("2dd4bf 14b8a6 0d9488 0f766e 115e59"),cyan:N("22d3ee 06b6d4 0891b2 0e7490 155e75"),sky:N("38bdf8 0ea5e9 0284c7 0369a1 075985"),blue:N("60a5fa 3b82f6 2563eb 1d4ed8 1e40af"),indigo:N("818cf8 6366f1 4f46e5 4338ca 3730a3"),violet:N("a78bfa 8b5cf6 7c3aed 6d28d9 5b21b6"),purple:N("c084fc a855f7 9333ea 7e22ce 6b21a8"),fuchsia:N("e879f9 d946ef c026d3 a21caf 86198f"),pink:N("f472b6 ec4899 db2777 be185d 9d174d"),rose:N("fb7185 f43f5e e11d48 be123c 9f1239")},Me=[{value:"indigo-zinc",label:"Indigo · Zinc",primary:"indigo",neutral:"zinc"},{value:"emerald-stone",label:"Emerald · Stone",primary:"emerald",neutral:"stone"},{value:"rose-slate",label:"Rose · Slate",primary:"rose",neutral:"slate"},{value:"amber-neutral",label:"Amber · Neutral",primary:"amber",neutral:"neutral"}],rn="#4F46E5",Va="#A0743C",Ha=[{value:"pure",label:"Pure",colour:"#8E8E93"},{value:"subtle",label:"Subtle",colour:"#8A89A6"},{value:"warm",label:"Warm",colour:"#9C9389"}],sn=["bg","surface","surface-raised","text","text-muted","border"],_a={bg:"#0F0F11",surface:"#18181B","surface-raised":"#1F1F23",text:"#F4F4F5","text-muted":"#A1A1AA",border:"#2E2E33"},Ka={bg:4,surface:2,"surface-raised":2,text:5,"text-muted":12,border:10},W=t=>/^#[0-9a-f]{6}$/i.test(t||""),dt=t=>[500,600,700].includes(Number(t.shade))?Number(t.shade):600,ct=t=>t[0].toUpperCase()+t.slice(1);function ln(t){const e=l=>(l/=255,l<=.03928?l/12.92:((l+.055)/1.055)**2.4),[n,a,o]=[1,3,5].map(l=>e(parseInt(t.slice(l,l+2),16))),s=.2126*n+.7152*a+.0722*o,r=1.05/(s+.05),i=(s+.05)/(.0098+.05);return r>=i?"#FFFFFF":"#18181B"}const Te={id:"colour",title:"Colour",hint:"Brand colour · neutral tint · mode",uses:["--twd-primary","--twd-primary-hover","--twd-on-primary","--twd-focus",...sn.map(t=>`--twd-${t}`)],tokens(t){const e=t.colour||{},n={},a=e.mode==="dark",o=lt[e.primary];if(!W(e.brand)&&o){const i=dt(e);n["--twd-primary"]=o[i],n["--twd-primary-hover"]=o[a?i-100:i+100],n["--twd-on-primary"]=ln(o[i]),n["--twd-focus"]=o[500]}W(e.brand)&&(n["--twd-primary"]=e.brand,n["--twd-primary-hover"]=a?`color-mix(in oklch, ${e.brand} 85%, white)`:`color-mix(in oklch, ${e.brand} 86%, black)`,n["--twd-on-primary"]=ln(e.brand),n["--twd-focus"]=e.brand);const s=e.tint==="subtle"?W(e.brand)?e.brand:F("--twd-primary")||rn:e.tint==="warm"?Va:null,r=it[e.neutral];if(r){const i=a?{bg:r[950],surface:r[900],"surface-raised":r[800],text:r[100],"text-muted":r[400],border:r[800]}:{bg:r[50],surface:"#ffffff","surface-raised":"#ffffff",text:r[900],"text-muted":r[500],border:r[200]};Object.entries(i).forEach(([l,p])=>{n[`--twd-${l}`]=p})}else(a||s)&&sn.forEach(i=>{const l=a?_a[i]:F(`--twd-${i}`);l&&(n[`--twd-${i}`]=s?`color-mix(in oklch, ${l} ${100-Ka[i]}%, ${s})`:l)});return n},parts:{themeTiles(t,e,{label:n="Theme"}={}){const a=o=>{const s=it[o.neutral],r=lt[o.primary];return`<span class="theme" style="--bg:${s[50]};--line:${s[200]};--ink:${s[900]};--soft:${s[500]};--pri:${r[600]}"><i><b></b><s></s><u></u></i></span><span class="palette">${[r[400],r[500],r[600],r[700],r[800],s[200],s[500],s[900]].map(i=>`<i style="background:${i}"></i>`).join("")}</span>`};t.append(V(e,{section:"colour",key:"theme",label:n,columns:2,className:"tiles-themes",options:Me.map(o=>({value:o.value,label:o.label,preview:a(o)})),current:o=>{const s=o.colour||{};return W(s.brand)?null:Me.find(r=>r.primary===s.primary&&r.neutral===s.neutral)?.value||null},select:o=>{const s=Me.find(r=>r.value===o);e.setSection("colour",{primary:s.primary,neutral:s.neutral,shade:null,brand:null,tint:null})},valueText:(o,s)=>{const r=s.colour||{};return o?"":r.primary||r.neutral||r.brand?"Custom":"Prototype colours"}}))},primary(t,e,{label:n="Primary"}={}){const a=D(n),o=V(e,{section:"colour",key:"primary",label:`${n} colour family`,columns:9,className:"tiles-swatches",options:Object.entries(lt).map(([i,l])=>({value:i,label:ct(i),title:ct(i),preview:`<span class="dot" style="background:${l[500]}"></span>`})),current:i=>{const l=i.colour||{};return W(l.brand)?null:l.primary||null},select:i=>e.setSection("colour",{primary:i,brand:null})});o.querySelector(".field-head").remove();const s=ne({label:"Shade",options:[500,600,700].map(i=>({value:String(i),label:String(i)})),onSelect:i=>e.setSection("colour",{shade:Number(i)})});a.append(o,s.el);const r=()=>{const i=e.getState().colour||{};s.setValue(String(dt(i))),a.setValue(W(i.brand)?i.brand.toLowerCase():i.primary?`${i.primary}-${dt(i)}`:"")};r(),e.onChange(r),t.append(a.el)},neutralTiles(t,e,{label:n="Neutral"}={}){t.append(V(e,{section:"colour",key:"neutral",label:n,columns:5,className:"tiles-greys",options:Object.entries(it).map(([a,o])=>({value:a,label:ct(a),preview:`<span class="greys">${[o[50],o[200],o[500],o[900]].map(s=>`<i style="background:${s}"></i>`).join("")}</span>`})),select:a=>e.setSection("colour",{neutral:a,tint:null}),valueText:a=>a||""}))},custom(t,e){const n=document.createElement("details");n.className="more more-custom",n.innerHTML='<summary><span class="rainbow" aria-hidden="true"></span><span>Custom colour…</span><span class="muted">any hex</span></summary>';const a=document.createElement("div");a.className="more-body",n.append(a),Te.parts.brand(a,e,{label:"Brand"}),W((e.getState().colour||{}).brand)&&(n.open=!0),t.append(n)},brand(t,e,{label:n="Brand"}={}){const a=D(n),o=Ba({label:"Brand colour",onInput:r=>e.setSection("colour",{brand:r})});a.append(o.el);const s=()=>o.setValue((e.getState().colour||{}).brand||(e.readToken||F)("--twd-primary")||rn);s(),e.onChange(s),t.append(a.el)},neutral(t,e,{label:n="Neutral"}={}){const a=D(n),o=Ua({label:"Neutral tint",options:Ha,onSelect:r=>e.setSection("colour",{tint:r})});a.append(o.el);const s=()=>o.setValue((e.getState().colour||{}).tint||"pure");s(),e.onChange(s),t.append(a.el)},mode(t,e,{label:n="Mode"}={}){t.append(ue(e,{section:"colour",key:"mode",label:n,fallback:"light",options:[{value:"light",label:"Light"},{value:"dark",label:"Dark"}]}))}},render(t,e){["brand","neutral","mode"].forEach(n=>this.parts[n](t,e))}},Ae=(t,e="var(--twd-surface)")=>`color-mix(in oklch, var(--twd-primary) ${t}%, ${e})`,Ga={soft:{bg:Ae(14),fg:"var(--twd-primary)",border:"transparent",hover:Ae(22)},outline:{bg:"transparent",fg:"var(--twd-primary)",border:"var(--twd-primary)",hover:Ae(8,"transparent")},ghost:{bg:"transparent",fg:"var(--twd-primary)",border:"transparent",hover:Ae(10,"transparent")}},Wa={small:{height:.8,pad:.75},large:{height:1.2,pad:1.25}},dn=en({id:"buttons",title:"Buttons",hint:"Style · corners · size",token:"--twd-radius-control",shape:"button",uses:["--twd-control-height","--twd-control-pad-x","--twd-button-bg","--twd-button-fg","--twd-button-border","--twd-button-hover"],max:24,presets:[{value:"square",label:"Square",radius:0},{value:"soft",label:"Soft",radius:4},{value:"rounded",label:"Rounded",radius:8},{value:"pill",label:"Pill",radius:999}],extraTokens(t){const e={},n=Ga[t.style];n&&Object.entries(n).forEach(([r,i])=>{e[`--twd-button-${r}`]=i});const a=Wa[t.size];if(!a)return e;const o=pe(F("--twd-control-height"),a.height),s=pe(F("--twd-control-pad-x"),a.pad);return o&&(e["--twd-control-height"]=o),s&&(e["--twd-control-pad-x"]=s),e},extra:[{key:"style",label:"Style",fallback:"solid",columns:4,preview:t=>`<span class="shape shape-button style-${t}"></span>`,options:[{value:"solid",label:"Solid"},{value:"soft",label:"Soft"},{value:"outline",label:"Outline"},{value:"ghost",label:"Ghost"}]},{key:"size",label:"Size",fallback:"medium",preview:t=>`<span class="shape shape-button size-${t}"></span>`,options:[{value:"small",label:"Small"},{value:"medium",label:"Medium"},{value:"large",label:"Large"}]}]}),Ya={outlined:{bg:"transparent",border:"color-mix(in oklch, var(--twd-border) 60%, var(--twd-text))",shadow:"none"},elevated:{bg:"var(--twd-surface-raised)",border:"transparent",shadow:"var(--twd-shadow-md)"},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"}},pt=en({id:"cards",title:"Cards",hint:"Style · corners · border",token:"--twd-radius-container",shape:"card",uses:["--twd-border-width-container","--twd-card-bg","--twd-card-border","--twd-card-shadow"],max:32,presets:[{value:"square",label:"Square",radius:0},{value:"soft",label:"Soft",radius:6},{value:"rounded",label:"Rounded",radius:12},{value:"large",label:"Large",radius:20}],extraTokens(t){const e={},n=Ya[t.style];if(n&&Object.entries(n).forEach(([a,o])=>{e[`--twd-card-${a}`]=o}),t.border==="none"&&(e["--twd-border-width-container"]="0px"),t.border==="thick"){const a=pe(F("--twd-border-width-container"),2);a&&(e["--twd-border-width-container"]=a)}return e},extra:[{key:"style",label:"Style",fallback:"filled",columns:4,preview:t=>`<span class="shape shape-card style-${t}"></span>`,options:[{value:"filled",label:"Filled"},{value:"outlined",label:"Outlined"},{value:"elevated",label:"Elevated"},{value:"tinted",label:"Tinted"}]},{key:"border",label:"Border",fallback:"thin",preview:t=>`<span class="shape shape-card border-${t}"></span>`,options:[{value:"none",label:"None"},{value:"thin",label:"Thin"},{value:"thick",label:"Thick"}]}]}),re=60,ut={soft:{sm:[0,1,2,0,.06],md:[0,4,12,0,.08],lg:[0,12,32,0,.12]},crisp:{sm:[0,1,1,0,.12],md:[0,2,4,0,.14],lg:[0,4,8,0,.16]},bold:{sm:[2,2,0,0,.85],md:[3,3,0,0,.85],lg:[5,5,0,0,.85]}},Le=([t,e,n,a,o],s)=>{const r=Math.min(1,+(o*s).toFixed(3));return r<=0?"none":`${t}px ${e}px ${n}px ${a}px rgb(0 0 0 / ${r})`},ht={id:"depth",title:"Depth",hint:"Flat · soft · crisp · bold",uses:["--twd-shadow-sm","--twd-shadow-md","--twd-shadow-lg"],tokens(t){const e=t.depth||{},n=e.style||"soft",a=typeof e.intensity=="number"?Math.min(100,Math.max(0,e.intensity)):re;if(n==="flat")return{"--twd-shadow-sm":"none","--twd-shadow-md":"none","--twd-shadow-lg":"none"};const o=ut[n];if(!o)return{};if(n==="soft"&&a===re)return{};const s=a/re;return{"--twd-shadow-sm":Le(o.sm,s),"--twd-shadow-md":Le(o.md,s),"--twd-shadow-lg":Le(o.lg,s)}},parts:{styleTiles(t,e,{label:n="Style"}={}){const a=o=>`<span class="shape shape-card shadow-${o}" style="box-shadow:${ut[o]?Le(ut[o].md,1):"none"}"></span>`;t.append(V(e,{section:"depth",key:"style",label:n,fallback:"soft",columns:4,options:["flat","soft","crisp","bold"].map(o=>({value:o,label:o[0].toUpperCase()+o.slice(1),preview:a(o)}))}))},style(t,e,{label:n="Style"}={}){t.append(ue(e,{section:"depth",key:"style",label:n,fallback:"soft",options:[{value:"flat",label:"Flat"},{value:"soft",label:"Soft"},{value:"crisp",label:"Crisp"},{value:"bold",label:"Bold"}]}))},intensity(t,e,{label:n="Intensity"}={}){t.append(Pa(e,{section:"depth",key:"intensity",label:n,min:0,max:100,fallback:re,format:a=>`${a}%`}))}},render(t,e){Object.entries(this.parts).filter(([n])=>!n.endsWith("Tiles")).forEach(([,n])=>n(t,e))}},Za=t=>Math.min(1,Math.max(0,t)),cn=t=>Math.round(t/50)*50,ft=t=>`${+t.toFixed(1)}%`;function gt(t={}){return typeof t.bold=="number"&&isFinite(t.bold)&&t.bold!==.5?Za(t.bold):null}const Oe=(t,e,n)=>(t.tokens(e)||{})[n]||F(n),Xa={id:"character",title:"Character",hint:"Subtle ↔ Bold",uses:[],tokens(t){const e=gt(t.character);if(e===null)return{};const n={},a=2*e-1,o=Math.max(0,a),s=Math.max(0,-a);n["--twd-weight-heading"]=String(cn(600+200*a)),n["--twd-weight-strong"]=String(cn(600+100*a));const r=Oe(Te,t,"--twd-border");if(s&&(n["--twd-border"]=`color-mix(in oklch, ${r} ${ft(100-50*s)}, var(--twd-bg))`),o){n["--twd-border"]=`color-mix(in oklch, ${r} ${ft(100-90*o)}, var(--twd-text))`;const l=Oe(Te,t,"--twd-text-muted");n["--twd-text-muted"]=`color-mix(in oklch, ${l} ${ft(100-35*o)}, var(--twd-text))`,["--twd-border-width","--twd-border-width-container"].forEach(p=>{const c=p==="--twd-border-width-container"?Oe(pt,t,p):F(p),h=parseFloat(c);isNaN(h)||(n[p]=`${Math.round(h*(1+o))}px`)}),[[dn,"--twd-radius-control"],[pt,"--twd-radius-container"]].forEach(([p,c])=>{const h=parseFloat(Oe(p,t,c));!isNaN(h)&&h<999&&(n[c]=pe(`${h}px`,1-.5*o))})}const i=t.depth||{};if(!i.style){const l=typeof i.intensity=="number"?i.intensity:re,p=s?ht.tokens({depth:{style:"soft",intensity:l*(1-s)}}):ht.tokens({depth:{style:"bold",intensity:re*o}});Object.assign(n,p)}return n},describe:(t,e)=>t==="bold"?{label:"Subtle ↔ Bold",value:`${Math.round(e*100)}%`}:null},Ja='<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>',Qa='<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>';let eo=0;function to({label:t,options:e,onSelect:n,placeholder:a,onOpen:o}){const s=`twd-fonts-${++eo}`,r=document.createElement("div");r.className="font-select";const i=document.createElement("button");i.type="button",i.className="font-trigger",i.setAttribute("aria-haspopup","listbox"),i.setAttribute("aria-expanded","false"),i.setAttribute("aria-controls",s),i.innerHTML=`
|
|
778
|
+
<span class="font-aa" aria-hidden="true">Aa</span>
|
|
779
|
+
<span class="font-name"></span>
|
|
780
|
+
<span class="font-fonts"></span>
|
|
781
|
+
<span class="font-chevron">${Ja}</span>`;const l=document.createElement("div");l.className="font-menu",l.id=s,l.setAttribute("role","listbox"),l.setAttribute("aria-label",t),l.hidden=!0;const p=e.map(u=>{const v=document.createElement("div");return v.className="font-option",v.setAttribute("role","option"),v.tabIndex=-1,v.dataset.value=u.value,v.innerHTML=`
|
|
782
|
+
<span class="font-aa" style="font-family:${u.preview}" aria-hidden="true">Aa</span>
|
|
783
|
+
<span class="font-text"><span class="font-name">${u.name}</span><span class="font-fonts">${u.fonts}</span></span>
|
|
784
|
+
<span class="font-check">${Qa}</span>`,v.addEventListener("click",()=>b(u.value)),v});l.append(...p),r.append(i,l);let c=null;function h(u){const v=e.find(E=>E.value===u),O=v||a||e[0];c=v?v.value:a?null:e[0].value,i.querySelector(".font-name").textContent=O.name,i.querySelector(".font-fonts").textContent=O.fonts,i.querySelector(".font-aa").style.fontFamily=O.preview,i.setAttribute("aria-label",`${t}: ${O.name}, ${O.fonts}`),p.forEach(E=>E.setAttribute("aria-selected",String(E.dataset.value===c)))}function y(){const u=i.getBoundingClientRect(),v=l.offsetHeight,E=window.innerHeight-u.bottom-8>=v?u.bottom+4:Math.max(8,u.top-4-v);l.style.top=`${E}px`,l.style.left=`${u.left}px`,l.style.width=`${u.width}px`}function f(){l.hidden&&(l.hidden=!1,i.setAttribute("aria-expanded","true"),o&&o(),y(),(p.find(u=>u.dataset.value===c)||p[0]).focus(),setTimeout(()=>document.addEventListener("pointerdown",x,!0)),window.addEventListener("resize",m),r.closest(".body")?.addEventListener("scroll",m,{once:!0}))}function m(u){l.hidden||(l.hidden=!0,i.setAttribute("aria-expanded","false"),document.removeEventListener("pointerdown",x,!0),window.removeEventListener("resize",m),u===!0&&i.focus())}function x(u){u.composedPath().includes(r)||m()}function b(u){u!==c&&(h(u),n(u)),m(!0)}return i.addEventListener("click",()=>l.hidden?f():m(!0)),i.addEventListener("keydown",u=>{(u.key==="ArrowDown"||u.key==="ArrowUp")&&(u.preventDefault(),f())}),l.addEventListener("keydown",u=>{const v=p.indexOf(u.target);let O=null;if(u.key==="ArrowDown")O=Math.min(p.length-1,v+1);else if(u.key==="ArrowUp")O=Math.max(0,v-1);else if(u.key==="Home")O=0;else if(u.key==="End")O=p.length-1;else if(u.key==="Enter"||u.key===" "){u.preventDefault(),b(u.target.dataset.value);return}else if(u.key==="Escape"){u.preventDefault(),u.stopPropagation(),m(!0);return}else if(u.key==="Tab"){m();return}O!==null&&(u.preventDefault(),p[O].focus())}),h(a?null:e[0].value),{el:r,setValue:h}}const z='ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, sans-serif',Pe='Georgia, "Times New Roman", serif',Y=[{value:"neutral",name:"Neutral",fonts:"Inter · Inter",heading:`"Inter", ${z}`,body:`"Inter", ${z}`,load:["Inter:wght@400;500;600;700"]},{value:"modern",name:"Modern",fonts:"Geist · Geist",heading:`"Geist", ${z}`,body:`"Geist", ${z}`,load:["Geist:wght@400;500;600;700"]},{value:"editorial",name:"Editorial",fonts:"Fraunces · Inter",heading:`"Fraunces", ${Pe}`,body:`"Inter", ${z}`,load:["Fraunces:wght@400;600;700","Inter:wght@400;500;600;700"]},{value:"technical",name:"Technical",fonts:"Space Grotesk · DM Sans",heading:`"Space Grotesk", ${z}`,body:`"DM Sans", ${z}`,load:["Space+Grotesk:wght@500;600;700","DM+Sans:wght@400;500;600;700"]},{value:"classic",name:"Classic",fonts:"Playfair · DM Sans",heading:`"Playfair Display", ${Pe}`,body:`"DM Sans", ${z}`,load:["Playfair+Display:wght@600;700","DM+Sans:wght@400;500;600;700"]},{value:"plex",name:"Plex",fonts:"Plex Serif · Plex Sans",heading:`"IBM Plex Serif", ${Pe}`,body:`"IBM Plex Sans", ${z}`,load:["IBM+Plex+Serif:wght@500;600;700","IBM+Plex+Sans:wght@400;500;600"]},{value:"elegant",name:"Elegant",fonts:"Instrument Serif · Inter",heading:`"Instrument Serif", ${Pe}`,body:`"Inter", ${z}`,load:["Instrument+Serif","Inter:wght@400;500;600;700"]},{value:"friendly",name:"Friendly",fonts:"Manrope · Manrope",heading:`"Manrope", ${z}`,body:`"Manrope", ${z}`,load:["Manrope:wght@400;500;600;700"]}],ge={compact:1.125,balanced:1.2,expressive:1.333},pn={xs:-2,sm:-1,base:0,lg:1,xl:2,"2xl":3,"3xl":4},un=new Set;function mt(t){const e=t.filter(a=>!un.has(a));if(!e.length)return;e.forEach(a=>un.add(a));const n=document.createElement("link");n.rel="stylesheet",n.href=`https://fonts.googleapis.com/css2?${e.map(a=>`family=${a}`).join("&")}&display=swap`,n.dataset.twiddle="fonts",document.head.appendChild(n)}const no={id:"typography",title:"Typography",hint:"Font pairing · base size · scale",uses:["--twd-font-heading","--twd-font-body",...Object.keys(pn).map(t=>`--twd-text-${t}`)],tokens(t){const e=t.typography||{},n={},a=Y.find(o=>o.value===e.font);if(a&&(mt(a.load),n["--twd-font-heading"]=a.heading,n["--twd-font-body"]=a.body),e.base||e.scale){const o=Number(e.base)||16,s=ge[e.scale]||ge.balanced;Object.entries(pn).forEach(([r,i])=>{n[`--twd-text-${r}`]=`${+(o*s**i/16).toFixed(3)}rem`})}return n},parts:{fonts(t,e,{label:n="Fonts"}={}){const a=D(n),o=to({label:"Font pairing",options:Y.map(r=>({value:r.value,name:r.name,fonts:r.fonts,preview:r.heading})),placeholder:{name:"Default",fonts:"Prototype fonts",preview:z},onOpen:()=>mt([...new Set(Y.flatMap(r=>r.load))]),onSelect:r=>e.setSection("typography",{font:r})});a.append(o.el);const s=()=>o.setValue((e.getState().typography||{}).font||null);s(),e.onChange(s),t.append(a.el)},base(t,e,{label:n="Base size"}={}){t.append(ue(e,{section:"typography",key:"base",label:n,fallback:"16",options:["14","15","16"].map(a=>({value:a,label:a})),valueText:a=>`${a}px`}))},fontTiles(t,e,{label:n="Fonts"}={}){const a=i=>i.replace(/"/g,"""),o=i=>`<span class="tile-aa" style="font-family:${a(i)}">Aa</span>`,s=V(e,{section:"typography",key:"font",label:n,columns:2,className:"tiles-fonts",options:[{value:"default",label:"Prototype fonts",sub:"Default",preview:o(z),wide:!0},...Y.map(i=>({value:i.value,label:i.name,sub:i.fonts,preview:o(i.heading)}))],current:i=>(i.typography||{}).font||"default",select:i=>e.setSection("typography",{font:i==="default"?null:i}),valueText:i=>i==="default"?"Default":Y.find(l=>l.value===i)?.name||""}),r=new IntersectionObserver(i=>{i.some(l=>l.isIntersecting)&&(mt([...new Set(Y.flatMap(l=>l.load))]),r.disconnect())});r.observe(s),t.append(s)},scaleTiles(t,e,{label:n="Scale"}={}){const a=o=>`<span class="ladder">${[-1,0,1,2].map(s=>`<b style="font-size:${Math.round(13*o**s)}px">A</b>`).join("")}</span>`;t.append(V(e,{section:"typography",key:"scale",label:n,fallback:"balanced",options:Object.entries(ge).map(([o,s])=>({value:o,label:o[0].toUpperCase()+o.slice(1),preview:a(s)})),valueText:o=>String(ge[o])}))},scale(t,e,{label:n="Scale"}={}){t.append(ue(e,{section:"typography",key:"scale",label:n,fallback:"balanced",options:[{value:"compact",label:"Compact"},{value:"balanced",label:"Balanced"},{value:"expressive",label:"Expressive"}],valueText:a=>String(ge[a])}))}},render(t,e){Object.entries(this.parts).filter(([n])=>!n.endsWith("Tiles")).forEach(([,n])=>n(t,e))}},[hn,Fe]=ot;function ao(t){return t>.56?"Bold":t<.44?"Subtle":"Balanced"}function fn(t){return t>1.06?"Comfy":t<.94?"Compact":"Regular"}const Ne=t=>t&&t[0].toUpperCase()+t.slice(1),gn=[["colour","Colour",t=>{const e=t.colour||{},n=Me.find(o=>o.primary===e.primary&&o.neutral===e.neutral);return{text:`${e.brand?e.brand.toUpperCase():n&&!e.shade?n.label:e.primary?`${Ne(e.primary)}${e.neutral?` · ${Ne(e.neutral)}`:""}`:"Prototype colours"}${e.mode==="dark"?" · Dark":""}`,swatch:F("--twd-primary")}}],["type","Type",t=>{const e=t.typography||{};return{text:`${Y.find(n=>n.value===e.font)?.name||"Prototype fonts"} · ${e.base||16}px`}}],["spacing","Spacing",t=>({text:fn(oe(t.density))})],["shape","Shape",t=>({text:`${Ne((t.buttons||{}).corners)||"Default"} corners`})],["shadows","Shadows",t=>({text:Ne((t.depth||{}).style)||(gt(t.character)!==null?"From the pad":"Default")})]],oo={summary(t,e,{label:n="Current look",goTab:a}={}){const o=D(n),s=document.createElement("div");s.className="summary",gn.forEach(([i,l])=>{const p=document.createElement("button");p.type="button",p.className="summary-row",p.dataset.summary=i,p.innerHTML=`<span class="summary-name"></span><span class="summary-swatch" hidden></span><span class="summary-value"></span><span class="chev" aria-hidden="true">${A.chevron}</span>`,p.querySelector(".summary-name").textContent=l,p.addEventListener("click",()=>a&&a(i)),s.append(p)}),o.append(s);const r=()=>{const i=e.getState();gn.forEach(([l,,p])=>{const c=s.querySelector(`[data-summary="${l}"]`),h=p(i);c.querySelector(".summary-value").textContent=h.text;const y=c.querySelector(".summary-swatch");y.hidden=!h.swatch,h.swatch&&(y.style.background=h.swatch)})};r(),e.onChange(r),t.append(o.el)},character(t,e,{label:n="Character"}={}){const a=D(n),o=Aa({label:n,ends:{top:"Spacious",bottom:"Compact",left:"Subtle",right:"Bold"},onInput:(r,i)=>{const l=+(Fe-i*(Fe-hn)).toFixed(3),p=+r.toFixed(3);e.setSections({density:{factor:l===1?null:l,spacing:null},character:{bold:p===.5?null:p}},"character")}});a.append(o.el);const s=()=>{const r=e.getState(),i=oe(r.density),l=gt(r.character),p=l===null?.5:l,c=`${fn(i)} · ${ao(p)}`;o.setValue(p,(Fe-i)/(Fe-hn),c),a.setValue(c)};s(),e.onChange(s),t.append(a.el)}},bt=[{key:"page-pad",label:"Page padding",step:5},{key:"section-gap",label:"Section gap",step:6},{key:"card-pad",label:"Card padding",step:5},{key:"card-gap",label:"Card gap",step:2},{key:"control-gap",label:"Control gap",step:3},{key:"control-pad-x",label:"Control padding",step:null}],ro=[1,2,3,4,5,6,7,8],so=/^var\(\s*--twd-space-(\d)\s*\)$/,xt=t=>{const e=/^(-?\d*\.?\d+)(px|rem)?$/.exec(String(t).trim());return e?+(parseFloat(e[1])*(e[2]==="rem"?16:1)).toFixed(1):null};function io(t,e,n){const a=`--twd-${e.key}`,o=document.createElement("div");o.className="role-row",n||o.classList.add("unused"),o.innerHTML=`
|
|
785
|
+
<span class="role-label" title="${a}${n?"":" (not used on this page)"}">${e.label}</span>
|
|
651
786
|
<label class="token-value role-fixed" hidden><input type="text" inputmode="decimal" spellcheck="false" aria-label="${e.label}, fixed value"><span class="token-unit">px</span></label>
|
|
652
787
|
<span class="step-select">
|
|
653
788
|
<select aria-label="${e.label}"></select>
|
|
654
|
-
<span class="step-chevron" aria-hidden="true">${
|
|
789
|
+
<span class="step-chevron" aria-hidden="true">${A.down}</span>
|
|
655
790
|
</span>
|
|
656
|
-
<button class="icon-btn token-reset" title="Back to the default" aria-label="Reset ${e.label}" hidden>${
|
|
657
|
-
`;const s=
|
|
658
|
-
<details data-section="${
|
|
659
|
-
<summary>${
|
|
660
|
-
<div class="section-body"><div class="placeholder">${
|
|
791
|
+
<button class="icon-btn token-reset" title="Back to the default" aria-label="Reset ${e.label}" hidden>${A.reset}</button>
|
|
792
|
+
`;const s=o.querySelector("select"),r=o.querySelector(".role-fixed"),i=r.querySelector("input"),l=o.querySelector(".token-reset"),p=()=>(t.getState().custom||{})[e.key],c=()=>{const x=p();if(x==null)return e.step?{step:e.step}:{fixed:F(a)};const b=so.exec(x);return b?{step:+b[1]}:{fixed:x}},h=x=>t.setSection("custom",{[e.key]:x}),y=x=>e.step?x===`var(--twd-space-${e.step})`:!1;s.addEventListener("change",()=>{if(s.value==="fixed"){const b=xt(F(a));h(b!=null?`${b}px`:F(a)),i.focus(),i.select();return}const x=`var(--twd-space-${s.value})`;h(y(x)?null:x)});const f=()=>{const x=i.value.trim();if(!x)return h(null);h(/^-?\d*\.?\d+$/.test(x)?`${x}px`:x)};i.addEventListener("change",f),i.addEventListener("blur",()=>m()),i.addEventListener("keydown",x=>{x.key==="Enter"&&(x.preventDefault(),i.blur()),x.key==="Escape"&&(x.stopPropagation(),m(),i.blur())}),l.addEventListener("click",()=>h(null));function m(){const x=c();if(s.innerHTML=ro.map(u=>`<option value="${u}">space-${u} · ${xt(F(`--twd-space-${u}`))??"?"}</option>`).join("")+'<option value="fixed">Fixed</option>',s.value=x.step?String(x.step):"fixed",r.hidden=!x.fixed,o.classList.toggle("is-fixed",!!x.fixed),x.fixed&&o.getRootNode().activeElement!==i){const u=xt(x.fixed);i.value=u!=null?String(u):x.fixed}const b=p()!=null;o.classList.toggle("edited",b),l.hidden=!b}return m(),t.onChange(m),o}const lo={spacing(t,e,{label:n="Roles"}={}){const a=Ma(),o=D(n);o.el.classList.add("token-field");const s=bt.filter(l=>!a.has(`--twd-${l.key}`));o.setValue(s.length===bt.length?"not used on this page":"");const r=document.createElement("div");r.className="token-rows",bt.forEach(l=>r.append(io(e,l,a.has(`--twd-${l.key}`)))),o.append(r),t.append(o.el);const i=document.createElement("p");i.className="role-note",i.textContent=s.length?`Only elements styled with these tokens change. Not used on this page: ${s.map(l=>l.label).join(", ")}.`:"Each role points at a spacing step, so Density still scales it. Pick another step, or a fixed value.",t.append(i)}},me=[{id:"overview",title:"Overview",icon:"tabOverview",parts:[["simple","character"],["simple","summary"]]},{id:"colour",title:"Colour",icon:"tabColour",parts:[["colour","themeTiles"],{heading:"Fine-tune",note:"Tailwind palette"},["colour","primary"],["colour","neutralTiles"],["colour","custom"],["colour","mode"],"warnings",{more:"Colour tokens",parts:[["custom","colours"]]}]},{id:"type",title:"Type",icon:"tabType",parts:[["typography","fontTiles"],["typography","base"],["typography","scaleTiles"],{more:"Type tokens",parts:[["custom","fonts"],["custom","type"],["custom","leading"],["custom","weights"]]}]},{id:"spacing",title:"Spacing",icon:"tabSpacing",parts:[["density","spacingTiles"],{more:"Layout roles",parts:[["roles","spacing"]]},{more:"Spacing tokens",parts:[["custom","spacing"]]}]},{id:"shape",title:"Shape",icon:"tabShape",parts:[{heading:"Buttons"},["buttons","styleTiles",{label:"Style"}],["buttons","cornerTiles",{label:"Corners"}],["buttons","sizeTiles",{label:"Size"}],{heading:"Cards"},["cards","styleTiles",{label:"Style"}],["cards","cornerTiles",{label:"Corners"}],["cards","borderTiles",{label:"Borders"}],{more:"Shape tokens",parts:[["custom","buttonStyle"],["custom","cardStyle"],["custom","cardShadow"],["custom","corners"],["custom","controls"],["custom","borders"]]}]},{id:"shadows",title:"Shadows",icon:"tabShadows",parts:[["depth","styleTiles"],["depth","intensity"],{more:"Shadow tokens",parts:[["custom","shadows"]]}]}],P=t=>String(t).replace(/[&<>"]/g,e=>({"&":"&","<":"<",">":">",'"':"""})[e]);function co({sections:t,store:e,view:n}){const a=document.createElement("div");a.id="twiddle-root",document.body.appendChild(a);const o=a.attachShadow({mode:"open"}),s=d=>d.map(g=>`
|
|
793
|
+
<details data-section="${g.id}">
|
|
794
|
+
<summary>${g.title}<span class="chev">${A.chevron}</span></summary>
|
|
795
|
+
<div class="section-body"><div class="placeholder">${g.hint}</div></div>
|
|
661
796
|
</details>
|
|
662
|
-
`).join("");
|
|
663
|
-
<style>${
|
|
797
|
+
`).join("");o.innerHTML=`
|
|
798
|
+
<style>${sa}</style>
|
|
664
799
|
<div class="pick-box" hidden><span class="pick-tag"></span></div>
|
|
665
800
|
<div class="wrap">
|
|
666
801
|
<div class="toast" role="status"></div>
|
|
667
802
|
<div class="panel" role="dialog" aria-label="Panel" hidden>
|
|
668
803
|
<div class="head">
|
|
669
804
|
<span class="brand">Panel</span>
|
|
670
|
-
<button class="icon-btn" data-action="pick" title="Pick an element to tweak on its own" aria-label="Pick an element" aria-pressed="false">${
|
|
671
|
-
<button class="icon-btn" data-action="compare" title="Hold to see the original (Alt+C toggles)" aria-label="Compare with original" aria-pressed="false">${
|
|
672
|
-
<button class="icon-btn" data-action="copy" title="Copy link to this version" aria-label="Copy link">${
|
|
673
|
-
<button class="icon-btn" data-action="reset" title="Reset to defaults" aria-label="Reset">${
|
|
674
|
-
<button class="icon-btn" data-action="
|
|
675
|
-
|
|
676
|
-
<div class="head subhead" hidden>
|
|
677
|
-
<button class="icon-btn" data-action="page-back" title="Back" aria-label="Back">${C.back}</button>
|
|
678
|
-
<span class="brand page-title"></span>
|
|
679
|
-
<button class="icon-btn" data-action="close" title="Close (Alt+T)" aria-label="Close">${C.close}</button>
|
|
680
|
-
</div>
|
|
681
|
-
<div class="original-pill" hidden>Showing original</div>
|
|
682
|
-
<div class="body" data-view="global"><div class="setup-hint" role="status" hidden></div>
|
|
683
|
-
<div class="page page-fields" data-page="simple"></div>
|
|
684
|
-
<div class="page" data-page="edit" hidden>
|
|
685
|
-
${me.map(i=>`<button class="nav-row" data-go="${i.id}">${i.title}<span class="chev">${C.chevron}</span></button>`).join("")}
|
|
686
|
-
</div>
|
|
687
|
-
${me.map(i=>`<div class="page page-fields" data-page="${i.id}" hidden></div>`).join("")}
|
|
805
|
+
<button class="icon-btn" data-action="pick" title="Pick an element to tweak on its own" aria-label="Pick an element" aria-pressed="false">${A.pick}</button>
|
|
806
|
+
<button class="icon-btn" data-action="compare" title="Hold to see the original (Alt+C toggles)" aria-label="Compare with original" aria-pressed="false">${A.compare}</button>
|
|
807
|
+
<button class="icon-btn" data-action="copy" title="Copy link to this version" aria-label="Copy link">${A.link}</button>
|
|
808
|
+
<button class="icon-btn" data-action="reset" title="Reset to defaults" aria-label="Reset">${A.reset}</button>
|
|
809
|
+
<button class="icon-btn" data-action="minimise" title="Minimise to the tabs" aria-label="Minimise to the tabs">${A.minimise}</button>
|
|
810
|
+
<button class="icon-btn" data-action="close" title="Close (Alt+T)" aria-label="Close">${A.close}</button>
|
|
688
811
|
</div>
|
|
689
|
-
<div class="
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
<div class="foot">
|
|
693
|
-
<button class="icon-btn" data-action="undo" title="Undo (⌘Z)" aria-label="Undo">${C.undo}</button>
|
|
694
|
-
<button class="icon-btn" data-action="redo" title="Redo (⇧⌘Z)" aria-label="Redo">${C.redo}</button>
|
|
812
|
+
<div class="actions">
|
|
813
|
+
<button class="icon-btn" data-action="undo" title="Undo (⌘Z)" aria-label="Undo">${A.undo}</button>
|
|
814
|
+
<button class="icon-btn" data-action="redo" title="Redo (⇧⌘Z)" aria-label="Redo">${A.redo}</button>
|
|
695
815
|
<button class="text-btn" data-action="changes" aria-pressed="false">Changes <span class="badge" hidden></span></button>
|
|
696
816
|
<span class="spacer"></span>
|
|
697
817
|
<div class="apply">
|
|
698
818
|
<button class="apply-btn" data-action="apply" title="Copy these tweaks as a prompt for your coding agent">Copy prompt</button>
|
|
699
|
-
<button class="apply-menu-btn" data-action="apply-menu" aria-label="Copy prompt options" aria-haspopup="true" aria-expanded="false">${
|
|
819
|
+
<button class="apply-menu-btn" data-action="apply-menu" aria-label="Copy prompt options" aria-haspopup="true" aria-expanded="false">${A.down}</button>
|
|
700
820
|
<div class="menu apply-menu" role="menu" hidden>
|
|
701
821
|
<button role="menuitemradio" data-apply-mode="preview">Preview before copying</button>
|
|
702
822
|
<button role="menuitemradio" data-apply-mode="copy">Copy without preview</button>
|
|
703
823
|
</div>
|
|
704
824
|
</div>
|
|
705
825
|
</div>
|
|
826
|
+
<div class="original-pill" hidden>Showing original</div>
|
|
827
|
+
<div class="body" data-view="global"><div class="setup-hint" role="status" hidden></div>
|
|
828
|
+
${me.map(d=>`<div class="page page-fields" data-page="${d.id}" hidden></div>`).join("")}
|
|
829
|
+
</div>
|
|
830
|
+
<div class="body" data-view="local" hidden></div>
|
|
831
|
+
<div class="body" data-view="changes" hidden></div>
|
|
832
|
+
<nav class="tabbar" aria-label="Areas">
|
|
833
|
+
${me.map(d=>`<button class="tab" data-tab="${d.id}" aria-pressed="false">${A[d.icon]}<span>${d.title}</span></button>`).join("")}
|
|
834
|
+
</nav>
|
|
706
835
|
</div>
|
|
707
|
-
<button class="launcher" aria-label="Open Panel" aria-expanded="false">${
|
|
836
|
+
<button class="launcher" aria-label="Open Panel" aria-expanded="false">${A.panelMark}</button>
|
|
708
837
|
</div>
|
|
709
838
|
<div class="dialog-backdrop" hidden>
|
|
710
839
|
<div class="dialog" role="dialog" aria-modal="true" aria-labelledby="twd-dialog-title">
|
|
711
840
|
<div class="dialog-head">
|
|
712
841
|
<span id="twd-dialog-title">Prompt for your agent</span>
|
|
713
|
-
<button class="icon-btn" data-action="dialog-close" aria-label="Close">${
|
|
842
|
+
<button class="icon-btn" data-action="dialog-close" aria-label="Close">${A.close}</button>
|
|
714
843
|
</div>
|
|
715
844
|
<textarea class="prompt-text" readonly spellcheck="false" aria-label="Generated prompt"></textarea>
|
|
716
845
|
<div class="dialog-foot">
|
|
@@ -719,50 +848,43 @@ ${Object.entries(r).map(([d,l])=>` ${d}: ${l} !important;`).join(`
|
|
|
719
848
|
</div>
|
|
720
849
|
</div>
|
|
721
850
|
</div>
|
|
722
|
-
`;const r=
|
|
851
|
+
`;const r=d=>o.querySelector(d),i=r(".panel"),l=r(".launcher"),p=r(".toast"),c={global:r('[data-view="global"]'),local:r('[data-view="local"]'),changes:r('[data-view="changes"]')},h=r(".pick-box"),y=r(".pick-tag"),f={getState:e.getState,setSection:e.setSection,setSections:e.setSections,onChange:e.onChange};function m(d,g,w){g.forEach(k=>{if(typeof k.render!="function")return;const C=d.querySelector(`[data-section="${k.id}"] .section-body`);C.innerHTML="",k.render(C,w)});const $=[...d.querySelectorAll("details")];return $.forEach(k=>k.addEventListener("toggle",()=>{k.open&&$.forEach(C=>{C!==k&&(C.open=!1)})})),$}const x=Object.fromEntries(t.map(d=>[d.id,d]));function b(d,g){g.forEach(w=>{if(w==="warnings"){const S=document.createElement("div");S.className="warnings page-warnings",d.append(S);return}if(w.heading){const S=document.createElement("div");S.className="page-heading",S.innerHTML=`<span></span>${w.note?'<span class="muted"></span>':""}`,S.firstChild.textContent=w.heading,w.note&&(S.lastChild.textContent=w.note),d.append(S);return}if(w.more){const S=document.createElement("details");S.className="more",S.innerHTML=`<summary><span class="chev" aria-hidden="true">${A.chevron}</span><span></span></summary><div class="more-body"></div>`,S.querySelector("summary span:last-child").textContent=w.more,b(S.querySelector(".more-body"),w.parts),d.append(S);return}if(w.tabs){const S=w.tabs.map(j=>{const I=document.createElement("div");return I.className="tab-pane",b(I,j.parts),I}),ke=ne({label:"View",options:w.tabs.map((j,I)=>({value:String(I),label:j.label})),onSelect:j=>{ke.setValue(j),S.forEach((I,$o)=>{I.hidden=String($o)!==j})}});ke.setValue("0"),S.forEach((j,I)=>{j.hidden=I!==0}),d.append(ke.el,...S);return}const[$,k,C={}]=w,q=$==="simple"?oo[k]:$==="roles"?lo[k]:x[$]?.parts?.[k];q&&q(d,f,{...C,buttons:x.buttons,cards:x.cards,goTab:S=>{X("global"),E(S)}})})}me.forEach(d=>b(c.global.querySelector(`[data-page="${d.id}"]`),d.parts));const u=[...o.querySelectorAll(".tab")];let v=me.some(d=>d.id===te("tab"))?te("tab"):me[0].id;function O(){u.forEach(d=>d.setAttribute("aria-pressed",String(Z==="global"&&d.dataset.tab===v)))}function E(d){v=d,ce("tab",d),c.global.querySelectorAll(".page").forEach(g=>{g.hidden=g.dataset.page!==d}),c.global.scrollTop=0,O()}const se=d=>d.map(g=>`<div class="warning">${A.warn}<span>${P(g.text)}</span></div>`).join("");let Z="global";function X(d){Z=d,Object.entries(c).forEach(([g,w])=>{w.hidden=g!==d}),r('[data-action="changes"]').setAttribute("aria-pressed",String(d==="changes")),d!=="local"&&xo(),d==="changes"&&jn(),O()}E(v);const wt="cubic-bezier(0.3, 0.7, 0.2, 1)",vt="cubic-bezier(0.2, 0.8, 0.2, 1)",je=640,be=100,yt=50,fo=()=>l.querySelector(".mark-knob"),go=()=>[l.querySelector(".mark-t1"),l.querySelector(".mark-t2")];function bn(d){if(matchMedia("(prefers-reduced-motion: reduce)").matches||!l.animate)return;const g=fo(),[w,$]=go(),k=C=>`translateY(${C}px)`;if(d){g.animate([{transform:k(32)},{transform:k(-6),offset:.78},{transform:k(0)}],{duration:je,easing:wt});const C=[{transform:"scale(0.4)",opacity:0},{transform:"scale(1)",opacity:1}];$.animate(C,{duration:be*2,delay:je*.12,easing:wt,fill:"backwards"}),w.animate(C,{duration:be*2,delay:je*.32+yt,easing:wt,fill:"backwards"})}else{const C=[{opacity:1},{opacity:0}];w.animate(C,{duration:be,easing:vt}),$.animate(C,{duration:be,delay:yt/2,easing:vt,fill:"backwards"}),g.animate([{transform:k(0)},{transform:k(34),offset:.8},{transform:k(32)}],{duration:je*.7,delay:be+yt/2,easing:vt,fill:"backwards"})}}const xn=r(".wrap");let wn=!1;function Re(d){wn=d,i.classList.toggle("minimised",d),i.hidden||ce("panel",d?"tabs":"open")}function J({animate:d=!0}={}){i.hidden&&d&&bn(!0),i.hidden=!1,xn.classList.add("is-open"),l.setAttribute("aria-expanded","true"),l.setAttribute("aria-label","Close Panel"),Re(!1)}function mo(){i.hidden&&J(),Re(!0)}function kt(){i.hidden||bn(!1),i.hidden=!0,xn.classList.remove("is-open"),l.setAttribute("aria-expanded","false"),l.setAttribute("aria-label","Open Panel"),ce("panel","closed"),ze()}function St(){i.hidden?J():kt()}let vn;function _(d){p.textContent=d,p.classList.add("show"),clearTimeout(vn),vn=setTimeout(()=>p.classList.remove("show"),1600)}function xe(d,g){navigator.clipboard.writeText(d).then(()=>_(g)).catch(()=>_("Couldn’t copy — select the text and copy it instead"))}let $t=null;function ie(d,g){if($t=d,!d){h.hidden=!0;return}const w=d.getBoundingClientRect();Object.assign(h.style,{top:`${w.top}px`,left:`${w.left}px`,width:`${w.width}px`,height:`${w.height}px`}),y.textContent=g||Je(d),h.hidden=!1}const yn=()=>{$t&&!h.hidden&&ie($t,y.textContent)};window.addEventListener("scroll",yn,!0),window.addEventListener("resize",yn);let we=!1;const kn=r('[data-action="pick"]'),Sn=d=>d.composedPath().includes(a);function $n(d){if(Sn(d))return;const g=d.target;g&&g.nodeType===1&&g!==document.documentElement&&g!==document.body&&ie(g)}function En(d){if(Sn(d)||(d.preventDefault(),d.stopPropagation(),d.type!=="click"))return;const g=d.target;!g||g===document.documentElement||g===document.body||(ze(),An(g))}function Cn(d){d.key==="Escape"&&(d.preventDefault(),ze(),T&&ie(T.el))}const Mn=["pointerdown","mousedown","mouseup","click"];function Tn(){if(!we){if(we=!0,!document.getElementById("twiddle-picking")){const d=document.createElement("style");d.id="twiddle-picking",d.textContent="html.twd-picking, html.twd-picking * { cursor: crosshair !important; }",document.head.appendChild(d)}J(),kn.setAttribute("aria-pressed","true"),document.documentElement.classList.add("twd-picking"),document.addEventListener("pointermove",$n,!0),Mn.forEach(d=>document.addEventListener(d,En,!0)),document.addEventListener("keydown",Cn,!0),_("Click an element · Esc to cancel")}}function ze(){we&&(we=!1,kn.setAttribute("aria-pressed","false"),document.documentElement.classList.remove("twd-picking"),document.removeEventListener("pointermove",$n,!0),Mn.forEach(d=>document.removeEventListener(d,En,!0)),document.removeEventListener("keydown",Cn,!0),ie(T?T.el:null))}let T=null;function bo(d,g){const w=[];return{ctx:{getState:()=>(e.getState().scopes||{})[d]||{},setSection:($,k)=>e.setScope(d,$,k),onChange:$=>{const k=e.onChange($);return w.push(k),k},readToken:$=>getComputedStyle(g).getPropertyValue($).trim()},dispose:()=>w.forEach($=>$())}}function An(d,g){const w=ua(d),$=e.getState().scopes||{};g||(g=!$[w.elementSelector]&&w.classSelector&&$[w.classSelector]?"class":"element"),T&&T.dispose(),T={el:d,info:w,target:g,dispose:()=>{}},Et(),X("local"),J(),ie(d)}const Ln=()=>T.target==="class"?T.info.classSelector:T.info.elementSelector;function Et(){T.dispose();const{info:d}=T,g=t.filter(j=>(j.uses||[]).some(I=>d.tokens.has(I))),w=c.local;if(w.innerHTML=`
|
|
723
852
|
<div class="scope-bar">
|
|
724
853
|
<div class="scope-head">
|
|
725
|
-
<button class="icon-btn" data-action="back" title="Back to the whole page" aria-label="Back to the whole page">${
|
|
854
|
+
<button class="icon-btn" data-action="back" title="Back to the whole page" aria-label="Back to the whole page">${A.back}</button>
|
|
726
855
|
<div class="scope-name">
|
|
727
|
-
<code>${
|
|
728
|
-
${
|
|
856
|
+
<code>${P(Je(d.el))}</code>
|
|
857
|
+
${d.text?`<span class="muted">“${P(d.text)}”</span>`:""}
|
|
729
858
|
</div>
|
|
730
859
|
</div>
|
|
731
860
|
<div class="scope-target"></div>
|
|
732
861
|
<div class="warnings"></div>
|
|
733
862
|
</div>
|
|
734
|
-
${
|
|
735
|
-
`,
|
|
863
|
+
${g.length?s(g):'<div class="empty">This element doesn’t use Panel tokens yet, so there’s nothing to tweak here. Style it with <code>var(--twd-…)</code> to make it tweakable.</div>'}
|
|
864
|
+
`,d.classSelector){const j=ne({label:"Apply to",options:[{value:"element",label:"This element"},{value:"class",label:`All ${d.classSelector} (${d.classCount})`,title:`Every element matching ${d.classSelector}`}],onSelect:I=>{I==="class"&&e.moveScope(d.elementSelector,d.classSelector),T.target=I,Et()}});j.setValue(T.target),w.querySelector(".scope-target").append(j.el)}const{ctx:$,dispose:k}=bo(Ln(),d.el),C=m(w,g,$);C[0]&&(C[0].open=!0);const q=w.querySelector(".warnings"),S=()=>{const j=d.tokens.size?ya(d.el):null;q.innerHTML=j?se([j]):""};S();const ke=e.onChange(S);T.dispose=()=>{k(),ke()}}function On(){if(!T||!T.info.classSelector)return;const d=e.getState().scopes||{},g=T.target==="class"?"element":"class",w=g==="class"?T.info.classSelector:T.info.elementSelector;!d[Ln()]&&d[w]&&(T.target=g,Et())}const Pn=()=>{e.undo(),On()},Fn=()=>{e.redo(),On()};function xo(){T&&(T.dispose(),T=null,c.local.innerHTML="",ie(null))}const Nn=d=>d.kind==="global"?"Whole page":d.kind==="class"?`All ${d.selector}`:"One element";function jn(){const d=Vt(e.getState(),t),g=nt(),w=c.changes;if(!d.length){w.innerHTML=`<div class="empty">No changes yet. Tweak a section, or pick an element to change it on its own.</div>${se(g)}`;return}const $=new Map;d.forEach(k=>{const C=k.selector||"";$.has(C)||$.set(C,[]),$.get(C).push(k)}),w.innerHTML=(g.length?`<div class="warnings">${se(g)}</div>`:"")+[...$].map(([k,C])=>`
|
|
736
865
|
<div class="change-group">
|
|
737
866
|
<div class="change-scope">
|
|
738
|
-
${
|
|
867
|
+
${k?`<button class="link-btn" data-select="${P(k)}" title="Select it on the page">${P(Nn(C[0]))}</button><code>${P(k)}</code>`:`<span>${Nn(C[0])}</span>`}
|
|
739
868
|
</div>
|
|
740
|
-
${
|
|
869
|
+
${C.map(q=>`
|
|
741
870
|
<div class="change-row">
|
|
742
871
|
<div class="change-main">
|
|
743
|
-
<div class="change-title">${
|
|
744
|
-
${
|
|
872
|
+
<div class="change-title">${P(q.title)} <span class="muted">›</span> ${q.settings.map(S=>`${P(S.label)}: <b>${P(S.value)}</b>`).join(", ")}</div>
|
|
873
|
+
${q.tokens.map(S=>`<div class="change-token"><code>${P(S.name)}</code> ${S.from?`${P(S.from)} → `:""}${P(S.to)}</div>`).join("")}
|
|
745
874
|
</div>
|
|
746
|
-
<button class="icon-btn" data-remove="${
|
|
875
|
+
<button class="icon-btn" data-remove="${P(q.sectionId)}" data-remove-scope="${P(k)}" aria-label="Remove ${P(q.title)} change">${A.close}</button>
|
|
747
876
|
</div>`).join("")}
|
|
748
|
-
</div>`).join("")}function
|
|
749
|
-
<div class="setup-head">${
|
|
750
|
-
<button class="icon-btn" data-action="setup-dismiss" title="Hide this message" aria-label="Hide this message">${
|
|
877
|
+
</div>`).join("")}function wo(d,g){if(g)return e.removeScope(g,d);const w=e.getState()[d]||{};e.setSection(d,Object.fromEntries(Object.keys(w).map($=>[$,null])))}const ve=r(".apply-menu"),Rn=r('[data-action="apply-menu"]'),zn=()=>te("apply-mode")==="copy"?"copy":"preview";function vo(){ve.querySelectorAll("[data-apply-mode]").forEach(d=>d.setAttribute("aria-checked",String(d.dataset.applyMode===zn())))}function Ie(d){ve.hidden=!d,Rn.setAttribute("aria-expanded",String(d)),d&&vo()}function In(){return ba(Vt(e.getState(),t),{warnings:nt()})}const De=r(".dialog-backdrop"),Dn=r(".prompt-text");function yo(){const d=In();if(!d)return _("No changes to copy yet");if(zn()==="copy")return xe(d,"Prompt copied · paste it into your agent");Dn.value=d,De.hidden=!1,r('[data-action="dialog-copy"]').focus()}function Ct(){De.hidden=!0,r('[data-action="apply"]').focus()}const le=r('[data-action="compare"]'),ko=r(".original-pill");function Be(d){d?n.suspend():n.resume(),le.setAttribute("aria-pressed",String(d)),ko.hidden=!d}let Bn=null,ye=!1;le.addEventListener("pointerdown",()=>{ye=!1,Bn=setTimeout(()=>{ye=!0,Be(!0)},180)});const Un=()=>{clearTimeout(Bn),ye&&(Be(!1),ye=!1)};le.addEventListener("pointerup",Un),le.addEventListener("pointerleave",Un);const Ue=r(".setup-hint"),qn=`setup-hint-dismissed:${location.pathname}`,So={"no-tokens":{title:"The Panel tokens aren’t loaded",text:"The knobs change the --twd-* variables, but this page doesn’t load them. Add the token stylesheet before your own CSS:",snippets:Jt,link:`${Xt}/#install`},unused:{title:"Nothing here uses the Panel tokens yet",text:"The tokens are loaded, but no style on this page uses var(--twd-…), so the knobs won’t change anything. Ask your coding agent to convert the styles:",copy:"Copy prompt for your agent",copied:"Prompt copied",text2copy:Ta,link:`${Xt}/#tokens`}};let B=null;function qe(){const d=Ca();B=te(qn)===d?null:So[d]||null,l.toggleAttribute("data-hint",!!B),Ue.hidden=!B,B&&(Ue.innerHTML=`
|
|
878
|
+
<div class="setup-head">${A.warn}<b>${P(B.title)}</b>
|
|
879
|
+
<button class="icon-btn" data-action="setup-dismiss" title="Hide this message" aria-label="Hide this message">${A.close}</button>
|
|
751
880
|
</div>
|
|
752
|
-
<p>${
|
|
753
|
-
${(
|
|
881
|
+
<p>${P(B.text)}</p>
|
|
882
|
+
${(B.snippets||[]).map((g,w)=>`
|
|
754
883
|
<div class="setup-snippet">
|
|
755
|
-
<span>${
|
|
756
|
-
<div class="setup-code"><code>${
|
|
884
|
+
<span>${P(g.label)}</span>
|
|
885
|
+
<div class="setup-code"><code>${P(g.code)}</code><button class="text-btn" data-setup-snippet="${w}">Copy</button></div>
|
|
757
886
|
</div>`).join("")}
|
|
758
887
|
<div class="setup-actions">
|
|
759
|
-
${
|
|
760
|
-
<a href="${
|
|
761
|
-
</div>`,
|
|
762
|
-
<span class="font-aa" aria-hidden="true">Aa</span>
|
|
763
|
-
<span class="font-name"></span>
|
|
764
|
-
<span class="font-fonts"></span>
|
|
765
|
-
<span class="font-chevron">${vo}</span>`;const l=document.createElement("div");l.className="font-menu",l.id=s,l.setAttribute("role","listbox"),l.setAttribute("aria-label",t),l.hidden=!0;const c=e.map(u=>{const y=document.createElement("div");return y.className="font-option",y.setAttribute("role","option"),y.tabIndex=-1,y.dataset.value=u.value,y.innerHTML=`
|
|
766
|
-
<span class="font-aa" style="font-family:${u.preview}" aria-hidden="true">Aa</span>
|
|
767
|
-
<span class="font-text"><span class="font-name">${u.name}</span><span class="font-fonts">${u.fonts}</span></span>
|
|
768
|
-
<span class="font-check">${yo}</span>`,y.addEventListener("click",()=>g(u.value)),y});l.append(...c),r.append(d,l);let p=null;function m(u){const y=e.find(R=>R.value===u),k=y||o||e[0];p=y?y.value:o?null:e[0].value,d.querySelector(".font-name").textContent=k.name,d.querySelector(".font-fonts").textContent=k.fonts,d.querySelector(".font-aa").style.fontFamily=k.preview,d.setAttribute("aria-label",`${t}: ${k.name}, ${k.fonts}`),c.forEach(R=>R.setAttribute("aria-selected",String(R.dataset.value===p)))}function v(){const u=d.getBoundingClientRect(),y=l.offsetHeight,R=window.innerHeight-u.bottom-8>=y?u.bottom+4:Math.max(8,u.top-4-y);l.style.top=`${R}px`,l.style.left=`${u.left}px`,l.style.width=`${u.width}px`}function f(){l.hidden&&(l.hidden=!1,d.setAttribute("aria-expanded","true"),a&&a(),v(),(c.find(u=>u.dataset.value===p)||c[0]).focus(),setTimeout(()=>document.addEventListener("pointerdown",b,!0)),window.addEventListener("resize",x),r.closest(".body")?.addEventListener("scroll",x,{once:!0}))}function x(u){l.hidden||(l.hidden=!0,d.setAttribute("aria-expanded","false"),document.removeEventListener("pointerdown",b,!0),window.removeEventListener("resize",x),u===!0&&d.focus())}function b(u){u.composedPath().includes(r)||x()}function g(u){u!==p&&(m(u),n(u)),x(!0)}return d.addEventListener("click",()=>l.hidden?f():x(!0)),d.addEventListener("keydown",u=>{(u.key==="ArrowDown"||u.key==="ArrowUp")&&(u.preventDefault(),f())}),l.addEventListener("keydown",u=>{const y=c.indexOf(u.target);let k=null;if(u.key==="ArrowDown")k=Math.min(c.length-1,y+1);else if(u.key==="ArrowUp")k=Math.max(0,y-1);else if(u.key==="Home")k=0;else if(u.key==="End")k=c.length-1;else if(u.key==="Enter"||u.key===" "){u.preventDefault(),g(u.target.dataset.value);return}else if(u.key==="Escape"){u.preventDefault(),u.stopPropagation(),x(!0);return}else if(u.key==="Tab"){x();return}k!==null&&(u.preventDefault(),c[k].focus())}),m(o?null:e[0].value),{el:r,setValue:m}}const z='ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, sans-serif',be='Georgia, "Times New Roman", serif',We=[{value:"neutral",name:"Neutral",fonts:"Inter · Inter",heading:`"Inter", ${z}`,body:`"Inter", ${z}`,load:["Inter:wght@400;500;600;700"]},{value:"modern",name:"Modern",fonts:"Geist · Geist",heading:`"Geist", ${z}`,body:`"Geist", ${z}`,load:["Geist:wght@400;500;600;700"]},{value:"editorial",name:"Editorial",fonts:"Fraunces · Inter",heading:`"Fraunces", ${be}`,body:`"Inter", ${z}`,load:["Fraunces:wght@400;600;700","Inter:wght@400;500;600;700"]},{value:"technical",name:"Technical",fonts:"Space Grotesk · DM Sans",heading:`"Space Grotesk", ${z}`,body:`"DM Sans", ${z}`,load:["Space+Grotesk:wght@500;600;700","DM+Sans:wght@400;500;600;700"]},{value:"classic",name:"Classic",fonts:"Playfair · DM Sans",heading:`"Playfair Display", ${be}`,body:`"DM Sans", ${z}`,load:["Playfair+Display:wght@600;700","DM+Sans:wght@400;500;600;700"]},{value:"plex",name:"Plex",fonts:"Plex Serif · Plex Sans",heading:`"IBM Plex Serif", ${be}`,body:`"IBM Plex Sans", ${z}`,load:["IBM+Plex+Serif:wght@500;600;700","IBM+Plex+Sans:wght@400;500;600"]},{value:"elegant",name:"Elegant",fonts:"Instrument Serif · Inter",heading:`"Instrument Serif", ${be}`,body:`"Inter", ${z}`,load:["Instrument+Serif","Inter:wght@400;500;600;700"]},{value:"friendly",name:"Friendly",fonts:"Manrope · Manrope",heading:`"Manrope", ${z}`,body:`"Manrope", ${z}`,load:["Manrope:wght@400;500;600;700"]}],Ye={compact:1.125,balanced:1.2,expressive:1.333},zt={xs:-2,sm:-1,base:0,lg:1,xl:2,"2xl":3,"3xl":4},It=new Set;function Dt(t){const e=t.filter(o=>!It.has(o));if(!e.length)return;e.forEach(o=>It.add(o));const n=document.createElement("link");n.rel="stylesheet",n.href=`https://fonts.googleapis.com/css2?${e.map(o=>`family=${o}`).join("&")}&display=swap`,n.dataset.twiddle="fonts",document.head.appendChild(n)}const Eo={id:"typography",title:"Typography",hint:"Font pairing · base size · scale",uses:["--twd-font-heading","--twd-font-body",...Object.keys(zt).map(t=>`--twd-text-${t}`)],tokens(t){const e=t.typography||{},n={},o=We.find(a=>a.value===e.font);if(o&&(Dt(o.load),n["--twd-font-heading"]=o.heading,n["--twd-font-body"]=o.body),e.base||e.scale){const a=Number(e.base)||16,s=Ye[e.scale]||Ye.balanced;Object.entries(zt).forEach(([r,d])=>{n[`--twd-text-${r}`]=`${+(a*s**d/16).toFixed(3)}rem`})}return n},parts:{fonts(t,e,{label:n="Fonts"}={}){const o=B(n),a=So({label:"Font pairing",options:We.map(r=>({value:r.value,name:r.name,fonts:r.fonts,preview:r.heading})),placeholder:{name:"Default",fonts:"Prototype fonts",preview:z},onOpen:()=>Dt([...new Set(We.flatMap(r=>r.load))]),onSelect:r=>e.setSection("typography",{font:r})});o.append(a.el);const s=()=>a.setValue((e.getState().typography||{}).font||null);s(),e.onChange(s),t.append(o.el)},base(t,e,{label:n="Base size"}={}){t.append(Q(e,{section:"typography",key:"base",label:n,fallback:"16",options:["14","15","16"].map(o=>({value:o,label:o})),valueText:o=>`${o}px`}))},scale(t,e,{label:n="Scale"}={}){t.append(Q(e,{section:"typography",key:"scale",label:n,fallback:"balanced",options:[{value:"compact",label:"Compact"},{value:"balanced",label:"Balanced"},{value:"expressive",label:"Expressive"}],valueText:o=>String(Ye[o])}))}},render(t,e){Object.values(this.parts).forEach(n=>n(t,e))}},$o='<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.9" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M14 6l4 4M4 20l1-4 9.5-9.5a2.1 2.1 0 013 3L8 19l-4 1z"/></svg>',Co=[[50,"white",10],[100,"white",20],[200,"white",36],[300,"white",56],[400,"white",78],[500,null,100],[600,"black",86],[700,"black",72],[800,"black",58],[900,"black",45],[950,"black",30]],Xe=t=>{let e=String(t).trim().replace(/^#/,"");return/^[0-9a-f]{3}$/i.test(e)&&(e=e.split("").map(n=>n+n).join("")),/^[0-9a-f]{6}$/i.test(e)?`#${e.toUpperCase()}`:null};function Mo({label:t,onInput:e}){const n=document.createElement("div");n.className="colour";const o=document.createElement("div");o.className="colour-field";const a=document.createElement("input");a.type="color",a.className="colour-picker",a.tabIndex=-1,a.setAttribute("aria-hidden","true");const s=document.createElement("button");s.type="button",s.className="colour-swatch",s.setAttribute("aria-label",`${t}: open colour picker`);const r=document.createElement("input");r.type="text",r.className="colour-hex",r.spellcheck=!1,r.maxLength=7,r.setAttribute("aria-label",`${t} hex value`);const d=document.createElement("button");d.type="button",d.className="colour-pipette",d.innerHTML=$o,d.title="Pick a colour from the screen",d.setAttribute("aria-label","Pick a colour from the screen"),o.append(a,s,r,d);const l=document.createElement("div");l.className="ramp",l.setAttribute("aria-hidden","true"),l.innerHTML=Co.map(([f,x,b])=>{const g=x?`color-mix(in oklch, var(--brand) ${b}%, ${x})`:"var(--brand)";return`<span title="${f}" style="background:${g}"></span>`}).join(""),n.append(o,l);let c="#000000";const p=f=>{c=f,a.value=f.toLowerCase(),s.style.background=f,n.getRootNode().activeElement!==r&&(r.value=f),n.style.setProperty("--brand",f)},m=f=>{f!==c&&(p(f),e(f))};s.addEventListener("click",()=>{if(a.showPicker)try{a.showPicker();return}catch{}a.click()}),a.addEventListener("input",()=>m(a.value.toUpperCase())),r.addEventListener("input",()=>{const f=Xe(r.value);f&&m(f)});const v=()=>{r.value=c};return r.addEventListener("blur",v),r.addEventListener("keydown",f=>{f.key==="Enter"&&(v(),r.select())}),d.addEventListener("click",async()=>{if("EyeDropper"in window)try{const{sRGBHex:f}=await new window.EyeDropper().open(),x=Xe(f);x&&m(x)}catch{}else s.click()}),{el:n,setValue:f=>p(Xe(f)||c)}}function Ao({label:t,options:e,onSelect:n}){const o=document.createElement("div");o.className="swatches",o.setAttribute("role","radiogroup"),o.setAttribute("aria-label",t);const a=e.map(l=>{const c=document.createElement("button");return c.type="button",c.className="swatch",c.setAttribute("role","radio"),c.dataset.value=l.value,c.innerHTML=`<span class="swatch-ring"><span class="swatch-dot" style="background:${l.colour}"></span></span><span class="swatch-label">${l.label}</span>`,c.addEventListener("click",()=>d(l.value)),c});o.append(...a);let s=null;function r(l){s=l,a.forEach(p=>p.setAttribute("aria-checked",String(p.dataset.value===l)));const c=Math.max(0,a.findIndex(p=>p.dataset.value===l));a.forEach((p,m)=>{p.tabIndex=m===c?0:-1})}function d(l,c){l!==s&&(r(l),n(l)),c&&a.find(p=>p.dataset.value===l).focus()}return o.addEventListener("keydown",l=>{const c=a.indexOf(l.target.closest(".swatch"));if(c<0)return;const p={ArrowRight:1,ArrowDown:1,ArrowLeft:-1,ArrowUp:-1}[l.key];let m;if(p)m=(c+p+a.length)%a.length;else if(l.key==="Home")m=0;else if(l.key==="End")m=a.length-1;else return;l.preventDefault(),d(a[m].dataset.value,!0)}),r(null),{el:o,setValue:r}}const Bt="#4F46E5",To="#A0743C",Lo=[{value:"pure",label:"Pure",colour:"#8E8E93"},{value:"subtle",label:"Subtle",colour:"#8A89A6"},{value:"warm",label:"Warm",colour:"#9C9389"}],Ut=["bg","surface","surface-raised","text","text-muted","border"],Po={bg:"#0F0F11",surface:"#18181B","surface-raised":"#1F1F23",text:"#F4F4F5","text-muted":"#A1A1AA",border:"#2E2E33"},Fo={bg:4,surface:2,"surface-raised":2,text:5,"text-muted":12,border:10},Vt=t=>/^#[0-9a-f]{6}$/i.test(t||"");function Oo(t){const e=l=>(l/=255,l<=.03928?l/12.92:((l+.055)/1.055)**2.4),[n,o,a]=[1,3,5].map(l=>e(parseInt(t.slice(l,l+2),16))),s=.2126*n+.7152*o+.0722*a,r=1.05/(s+.05),d=(s+.05)/(.0098+.05);return r>=d?"#FFFFFF":"#18181B"}const Ro={id:"colour",title:"Colour",hint:"Brand colour · neutral tint · mode",uses:["--twd-primary","--twd-primary-hover","--twd-on-primary","--twd-focus",...Ut.map(t=>`--twd-${t}`)],tokens(t){const e=t.colour||{},n={},o=e.mode==="dark";Vt(e.brand)&&(n["--twd-primary"]=e.brand,n["--twd-primary-hover"]=o?`color-mix(in oklch, ${e.brand} 85%, white)`:`color-mix(in oklch, ${e.brand} 86%, black)`,n["--twd-on-primary"]=Oo(e.brand),n["--twd-focus"]=e.brand);const a=e.tint==="subtle"?Vt(e.brand)?e.brand:P("--twd-primary")||Bt:e.tint==="warm"?To:null;return(o||a)&&Ut.forEach(s=>{const r=o?Po[s]:P(`--twd-${s}`);r&&(n[`--twd-${s}`]=a?`color-mix(in oklch, ${r} ${100-Fo[s]}%, ${a})`:r)}),n},parts:{brand(t,e,{label:n="Brand"}={}){const o=B(n),a=Mo({label:"Brand colour",onInput:r=>e.setSection("colour",{brand:r})});o.append(a.el);const s=()=>a.setValue((e.getState().colour||{}).brand||(e.readToken||P)("--twd-primary")||Bt);s(),e.onChange(s),t.append(o.el)},neutral(t,e,{label:n="Neutral"}={}){const o=B(n),a=Ao({label:"Neutral tint",options:Lo,onSelect:r=>e.setSection("colour",{tint:r})});o.append(a.el);const s=()=>a.setValue((e.getState().colour||{}).tint||"pure");s(),e.onChange(s),t.append(o.el)},mode(t,e,{label:n="Mode"}={}){t.append(Q(e,{section:"colour",key:"mode",label:n,fallback:"light",options:[{value:"light",label:"Light"},{value:"dark",label:"Dark"}]}))}},render(t,e){Object.values(this.parts).forEach(n=>n(t,e))}},No={small:{height:.8,pad:.75},large:{height:1.2,pad:1.25}},jo=Lt({id:"buttons",title:"Buttons",hint:"Corners · size",token:"--twd-radius-control",uses:["--twd-control-height","--twd-control-pad-x"],max:24,presets:[{value:"square",label:"Square",radius:0},{value:"soft",label:"Soft",radius:4},{value:"rounded",label:"Rounded",radius:8},{value:"pill",label:"Pill",radius:999}],extraTokens(t){const e=No[t.size];if(!e)return{};const n={},o=fe(P("--twd-control-height"),e.height),a=fe(P("--twd-control-pad-x"),e.pad);return o&&(n["--twd-control-height"]=o),a&&(n["--twd-control-pad-x"]=a),n},extra:[{key:"size",label:"Size",fallback:"medium",options:[{value:"small",label:"Small"},{value:"medium",label:"Medium"},{value:"large",label:"Large"}]}]}),zo=Lt({id:"cards",title:"Cards",hint:"Corners · border",token:"--twd-radius-container",uses:["--twd-border-width-container"],max:32,presets:[{value:"square",label:"Square",radius:0},{value:"soft",label:"Soft",radius:6},{value:"rounded",label:"Rounded",radius:12},{value:"large",label:"Large",radius:20}],extraTokens(t){if(t.border==="none")return{"--twd-border-width-container":"0px"};if(t.border==="thick"){const e=fe(P("--twd-border-width-container"),2);return e?{"--twd-border-width-container":e}:{}}return{}},extra:[{key:"border",label:"Border",fallback:"thin",options:[{value:"none",label:"None"},{value:"thin",label:"Thin"},{value:"thick",label:"Thick"}]}]}),qt=[Eo,Ro,jo,zo,lo,po,io],Io=':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-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)}';function Do(){if(getComputedStyle(document.documentElement).getPropertyValue("--twd-radius-control").trim()||document.getElementById("twiddle-tokens"))return;const e=document.createElement("style");e.id="twiddle-tokens",e.textContent=Io,document.head.prepend(e)}if(!window.Twiddle){Do(),qt.forEach(n=>$n(n.tokens)),lt(Oe);let t;const e=()=>{Oe(Te()),t=wo({sections:qt,store:En,view:{suspend:Tn,resume:Ln}})};document.readyState==="loading"?document.addEventListener("DOMContentLoaded",e):e(),window.Twiddle={open:()=>t&&t.open(),close:()=>t&&t.close(),toggle:()=>t&&t.toggle(),reset:()=>rt(),undo:()=>st(),redo:()=>it(),pick:()=>t&&t.pick(),prompt:()=>t?t.prompt():"",getState:Te}}const Bo=window.Twiddle;return Ce.Twiddle=Bo,Object.defineProperty(Ce,Symbol.toStringTag,{value:"Module"}),Ce})({});
|
|
888
|
+
${B.copy?`<button class="apply-btn" data-action="setup-copy">${P(B.copy)}</button>`:""}
|
|
889
|
+
<a href="${B.link}" target="_blank" rel="noopener">Setup guide</a>
|
|
890
|
+
</div>`,Ue.dataset.status=d)}qe(),document.readyState!=="complete"&&window.addEventListener("load",qe,{once:!0}),setTimeout(qe,1500);const Vn=r(".badge");function Hn(){r('[data-action="undo"]').disabled=!e.canUndo(),r('[data-action="redo"]').disabled=!e.canRedo();const d=ga(e.getState());Vn.textContent=d,Vn.hidden=!d;const g=se(nt());c.global.querySelectorAll(".page-warnings").forEach(w=>{w.innerHTML=g}),Z==="changes"&&jn()}return e.onChange(Hn),Hn(),o.addEventListener("click",d=>{if(d.target===De)return Ct();const g=d.target.closest("button");if(g){if(g!==Rn&&!ve.contains(g)&&Ie(!1),g===l)return St();if(g.dataset.select){const w=document.querySelector(g.dataset.select);return w?An(w):_("That element isn’t on this page")}if(g.dataset.setupSnippet)return xe(Jt[g.dataset.setupSnippet].code,"Copied");if(g.dataset.tab)return X("global"),wn&&Re(!1),E(g.dataset.tab);if(g.dataset.remove)return wo(g.dataset.remove,g.dataset.removeScope);if(g.dataset.applyMode)return ce("apply-mode",g.dataset.applyMode),Ie(!1),_(g.dataset.applyMode==="copy"?"Copy prompt copies straight away":"Copy prompt shows a preview first");switch(g.dataset.action){case"close":return kt();case"minimise":return mo(),(o.querySelector('.tab[aria-pressed="true"]')||u[0]).focus();case"reset":return e.resetState(),_("Reset to defaults · ⌘Z to undo");case"copy":return xe(location.href,"Link copied");case"pick":return we?ze():Tn();case"compare":ye||Be(le.getAttribute("aria-pressed")!=="true");return;case"undo":return Pn();case"redo":return Fn();case"back":return X("global");case"changes":return X(Z==="changes"?"global":"changes");case"apply":return yo();case"apply-menu":return Ie(ve.hidden);case"dialog-close":return Ct();case"dialog-copy":return xe(Dn.value,"Prompt copied · paste it into your agent");case"setup-copy":return B&&xe(B.text2copy,B.copied);case"setup-dismiss":return ce(qn,Ue.dataset.status),qe()}}}),o.addEventListener("keydown",d=>{if(d.key==="Escape"){if(!De.hidden)return Ct();if(!ve.hidden)return Ie(!1)}!(d.metaKey||d.ctrlKey)||d.key.toLowerCase()!=="z"||d.target.matches?.('input[type="text"], textarea')||(d.preventDefault(),d.shiftKey?Fn():Pn())}),document.addEventListener("keydown",d=>{d.altKey&&(d.code==="KeyT"&&(d.preventDefault(),St()),d.code==="KeyC"&&(d.preventDefault(),Be(le.getAttribute("aria-pressed")!=="true")))}),te("panel")==="open"?J({animate:!1}):te("panel")==="tabs"&&(J({animate:!1}),Re(!0)),{open:J,close:kt,toggle:St,toast:_,pick:Tn,prompt:In}}const mn=[no,Te,dn,pt,za,ht,Xa,Ra],po=':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)}';function uo(){if(getComputedStyle(document.documentElement).getPropertyValue("--twd-radius-control").trim()||document.getElementById("twiddle-tokens"))return;const e=document.createElement("style");e.id="twiddle-tokens",e.textContent=po,document.head.prepend(e)}if(!window.Twiddle){uo(),mn.forEach(n=>ea(n.tokens)),Pt(Ze);let t;const e=()=>{Ze(Ke()),t=co({sections:mn,store:Qn,view:{suspend:oa,resume:ra}})};document.readyState==="loading"?document.addEventListener("DOMContentLoaded",e):e(),window.Twiddle={open:()=>t&&t.open(),close:()=>t&&t.close(),toggle:()=>t&&t.toggle(),reset:()=>At(),undo:()=>Lt(),redo:()=>Ot(),pick:()=>t&&t.pick(),prompt:()=>t?t.prompt():"",getState:Ke}}const ho=window.Twiddle;return Ve.Twiddle=ho,Object.defineProperty(Ve,Symbol.toStringTag,{value:"Module"}),Ve})({});
|