wicked-studio 0.7.12 → 0.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,35 @@
1
+ {
2
+ "id": "wicked-deck",
3
+ "title": "Slides",
4
+ "version": "0.8.0",
5
+ "protocol": [
6
+ 1
7
+ ],
8
+ "kinds": [
9
+ "deck"
10
+ ],
11
+ "entry": "index.html",
12
+ "sizes": [
13
+ "inline",
14
+ "pane",
15
+ "full"
16
+ ],
17
+ "permissions": [
18
+ {
19
+ "id": "artifact.read",
20
+ "why": "to show the slides and read their words and speaker notes"
21
+ },
22
+ {
23
+ "id": "artifact.write",
24
+ "why": "to add, duplicate, move or delete a slide, change its words or its notes, each as one version with Undo"
25
+ },
26
+ {
27
+ "id": "selection.chip",
28
+ "why": "to make the slide or the line you click the subject of your next message"
29
+ },
30
+ {
31
+ "id": "ui.fullscreen",
32
+ "why": "to present the deck full screen"
33
+ }
34
+ ]
35
+ }
@@ -0,0 +1,184 @@
1
+ <!doctype html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="utf-8">
5
+ <meta name="wicked-editor" content="wicked-deck">
6
+ <meta name="wicked-editor-version" content="0.8.0">
7
+ <title>Slides</title>
8
+ <style>
9
+ /* The editor's own chrome takes the host's tokens (`host.hello.theme` / `host.theme`), with plain
10
+ fallbacks for a host that passes none. The DECK inside the nested frames styles itself. */
11
+ :root {
12
+ --surface-base: #ffffff; --surface-card: #f6f7f9; --surface-raised: #ffffff; --ink-high: #0d1117; --ink-body: #2b333d;
13
+ --ink-muted: #5b6673; --border: #d5dae1; --accent: #224a5e; --status-fail: #b4232c;
14
+ --font-sans: system-ui, sans-serif;
15
+ }
16
+ html, body { height: 100%; margin: 0; }
17
+ body { font: 13px var(--font-sans); color: var(--ink-high); background: var(--surface-base); overflow: hidden; }
18
+ [hidden] { display: none !important; }
19
+ .deck { position: relative; display: grid; grid-template-columns: 196px minmax(0, 1fr); width: 100%; height: 100%; outline: none; }
20
+ .deck:focus { box-shadow: inset 0 0 0 2px var(--accent); }
21
+ body[data-size="inline"] .deck, body[data-present="true"] .deck { grid-template-columns: minmax(0, 1fr); }
22
+ body[data-size="inline"] .deck { pointer-events: none; }
23
+ body[data-size="inline"] .strip, body[data-size="inline"] .tools, body[data-size="inline"] .notes,
24
+ body[data-present="true"] .strip, body[data-present="true"] .tools, body[data-present="true"] .notes { display: none; }
25
+
26
+ /* The filmstrip: the deck's slides in document order. */
27
+ .strip { overflow-y: auto; overflow-x: hidden; padding: 12px 8px 24px; border-right: 1px solid var(--border); background: var(--surface-card); }
28
+ .strip ol { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 6px; }
29
+ .thumb { display: grid; grid-template-columns: 16px 128px; gap: 6px; box-sizing: border-box; align-items: start; width: 100%; padding: 4px; border: 1px solid transparent; border-radius: 6px; background: transparent; color: var(--ink-body); font: inherit; text-align: left; cursor: pointer; }
30
+ .thumb:hover { background: var(--surface-base); }
31
+ .thumb[aria-current="true"] { border-color: var(--accent); background: color-mix(in srgb, var(--accent) 16%, var(--surface-card)); }
32
+ .thumb[aria-current="true"] .t { color: var(--ink-high); }
33
+ .thumb:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
34
+ .thumb[data-drop="before"] { box-shadow: 0 -3px 0 var(--accent); }
35
+ .thumb[data-drop="after"] { box-shadow: 0 3px 0 var(--accent); }
36
+ .thumb .n { font-size: 11px; color: var(--ink-muted); text-align: right; padding-top: 2px; }
37
+ .thumb .mini { position: relative; display: block; width: 128px; height: 72px; overflow: hidden; border: 1px solid var(--border); border-radius: 3px; background: var(--surface-base); }
38
+ .thumb .mini iframe { position: absolute; left: 0; top: 0; width: 1280px; height: 720px; border: 0; transform: scale(0.1); transform-origin: 0 0; pointer-events: none; }
39
+ .thumb .t { grid-column: 2; display: block; font-size: 11px; line-height: 1.3; color: var(--ink-body); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; max-width: 128px; }
40
+
41
+ .main { position: relative; display: flex; flex-direction: column; min-width: 0; min-height: 0; }
42
+ .tools { display: flex; flex-wrap: wrap; align-items: center; gap: 4px; padding: 6px 10px; border-bottom: 1px solid var(--border); background: var(--surface-card); }
43
+ .tools .count { margin-right: auto; font-size: 12px; color: var(--ink-muted); }
44
+ .tools button, .menu button, .notes button { font: inherit; font-size: 12px; line-height: 20px; padding: 1px 9px; border: 1px solid var(--border); border-radius: 4px; background: var(--surface-base); color: var(--ink-high); cursor: pointer; }
45
+ .tools button:disabled { opacity: .45; cursor: default; }
46
+ .tools button:focus-visible, .menu button:focus-visible, .notes button:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
47
+ .tools .danger { color: var(--status-fail); }
48
+ .menu { position: absolute; z-index: 4; top: 36px; left: 10px; display: flex; flex-direction: column; gap: 2px; min-width: 220px; max-height: 60%; overflow-y: auto; padding: 6px; background: var(--surface-raised); border: 1px solid var(--border); border-radius: 6px; box-shadow: 0 4px 14px rgba(0,0,0,.14); }
49
+ .menu .word { font-size: 11px; color: var(--ink-muted); padding: 2px 4px 4px; }
50
+ .menu button { text-align: left; border-color: transparent; }
51
+
52
+ .stage { position: relative; flex: 1 1 auto; min-height: 0; overflow: hidden; background: var(--surface-card); }
53
+ .stage iframe { position: absolute; left: 0; top: 0; border: 0; background: var(--surface-base); transform-origin: 0 0; box-shadow: 0 1px 6px rgba(0,0,0,.08); }
54
+ body[data-present="true"] .stage { background: #111; }
55
+ .box { position: absolute; pointer-events: none; border: 2px solid var(--accent); border-radius: 3px; box-sizing: border-box; z-index: 2; }
56
+ .box--hover { border-style: dashed; opacity: .55; }
57
+ .input { position: absolute; z-index: 3; box-sizing: border-box; font: inherit; font-size: 14px; line-height: 1.35; padding: 4px 6px; border: 2px solid var(--accent); border-radius: 3px; background: var(--surface-base); color: var(--ink-high); outline: none; resize: none; overflow: auto; }
58
+ .handle { position: absolute; left: 0; top: 0; width: 1px; height: 1px; opacity: 0; }
59
+ .hint, .note { margin: 0; padding: 4px 10px; font-size: 12px; color: var(--ink-muted); }
60
+ .note { color: var(--status-fail); }
61
+ .badge { position: absolute; right: 10px; bottom: 10px; z-index: 2; padding: 2px 8px; font-size: 12px; color: var(--ink-body); background: var(--surface-base); border: 1px solid var(--border); border-radius: 10px; }
62
+ .present-bar { position: absolute; right: 12px; bottom: 12px; z-index: 3; padding: 3px 10px; font-size: 12px; color: #eee; background: rgba(0,0,0,.55); border-radius: 10px; }
63
+
64
+ .notes { display: grid; grid-template-columns: minmax(0, 1fr); gap: 4px; padding: 8px 10px 10px; border-top: 1px solid var(--border); background: var(--surface-base); }
65
+ .notes label { font-size: 11px; color: var(--ink-muted); }
66
+ .notes textarea { box-sizing: border-box; width: 100%; min-height: 54px; max-height: 120px; resize: vertical; font: inherit; font-size: 13px; line-height: 1.4; padding: 6px 8px; border: 1px solid var(--border); border-radius: 4px; background: var(--surface-base); color: var(--ink-high); }
67
+ .notes textarea:focus-visible { outline: 2px solid var(--accent); outline-offset: 0; }
68
+ body[data-size="pane"] .notes textarea { min-height: 40px; }
69
+ @media (prefers-reduced-motion: no-preference) { .box { transition: left 80ms linear, top 80ms linear; } }
70
+ </style>
71
+ </head>
72
+ <body data-size="pane">
73
+ <script>var wickedEditor=(function(le){"use strict";const pe="section, [data-slide], .slide",ot=new Set(["area","base","br","col","embed","hr","img","input","link","meta","source","track","wbr"]),se="aside[data-notes-for]",Be=80,Ne=o=>{const i=o.tagName.toLowerCase();return!ot.has(i)&&!(i==="aside"&&o.hasAttribute("data-notes-for"))};function Ye(o){return Array.from(o.querySelectorAll(pe)).filter(i=>{if(!Ne(i)||i.closest(se)!==null)return!1;for(let d=i.parentElement;d!==null;d=d.parentElement)if(d.matches(pe)&&Ne(d))return!1;return!0})}const ye=o=>o.replace(/\s+/g," ").trim(),it=o=>o.length>Be?`${o.slice(0,Be-1).trimEnd()}…`:o;function rt(o){const i=Array.from(o.querySelectorAll(se)).find(d=>d.parentElement?.closest(pe)===o);return i===void 0?"":(i.textContent??"").trim()}function lt(o){const i=o.cloneNode(!0);for(const d of Array.from(i.querySelectorAll(se)))d.remove();for(const d of Array.from(i.querySelectorAll("h1,h2,h3,h4,h5,h6,p,li,td,th,div,section,figcaption,blockquote,br")))d.append(" ");return ye(i.textContent??"")}function st(o){const i=new DOMParser().parseFromString(o,"text/html");return Ye(i).map((d,c)=>{const y=Array.from(d.querySelectorAll("h1,h2,h3,h4,h5,h6")).find(b=>b.closest(se)===null&&ye(b.textContent??"")!==""),g=lt(d);return{id:d.getAttribute("data-slide-id"),wid:d.getAttribute("data-wid"),n:c+1,title:it(y!==void 0?ye(y.textContent??""):g),notes:rt(d),text:g}})}function at(o,i,d){return{left:o.left-(d.scrollX-i.scrollX),top:o.top-(d.scrollY-i.scrollY),width:o.width,height:o.height}}const dt=/^[A-Za-z0-9_.:-]{1,100}$/;function E(o){return typeof o=="number"&&isFinite(o)}function ct(o){if(typeof o!="object"||o===null)return!1;const i=o;return i.section!==void 0&&(typeof i.section!="string"||!dt.test(i.section))?!1:typeof i.text=="string"&&typeof i.composite=="boolean"}function ut(o){if(typeof o!="object"||o===null)return!1;const i=o;return E(i.x)&&E(i.y)&&E(i.width)&&E(i.height)&&E(i.top)&&E(i.left)&&E(i.right)&&E(i.bottom)}function ft(o){if(typeof o!="object"||o===null)return null;const i=o;if(i.v!==1)return null;const d=i.type;if(d==="wid-inventory"){const c=i.widMap,y=i.scrollX,g=i.scrollY;if(typeof c!="object"||c===null||!E(y)||!E(g))return null;const b={};for(const[V,w]of Object.entries(c)){if(!ut(w))return null;b[V]=w}const j=i.blocks;if(j===void 0)return{v:1,type:"wid-inventory",widMap:b,scrollX:y,scrollY:g};if(typeof j!="object"||j===null)return null;const ne={};for(const[V,w]of Object.entries(j)){if(!ct(w))return null;ne[V]={text:w.text,composite:w.composite,...w.cut===!0?{cut:!0}:{},...w.section!==void 0?{section:w.section}:{}}}return{v:1,type:"wid-inventory",widMap:b,scrollX:y,scrollY:g,blocks:ne}}if(d==="scroll-state"){const c=i.scrollX,y=i.scrollY;return!E(c)||!E(y)?null:{v:1,type:"scroll-state",scrollX:c,scrollY:y}}if(d==="scroll-ack"){const c=i.wid;if(typeof c!="string"||c==="")return null;const y=i.scrollX,g=i.scrollY,b=i.seq;return{v:1,type:"scroll-ack",wid:c,...E(y)&&E(g)?{scrollX:y,scrollY:g}:{},...typeof b=="number"&&Number.isInteger(b)&&b>0?{seq:b}:{}}}if(d==="wid-click"){const c=i.wid;return typeof c!="string"||c===""?null:{v:1,type:"wid-click",wid:c}}if(d==="wid-hover"){const c=i.wid;return c!==null&&(typeof c!="string"||c==="")?null:{v:1,type:"wid-hover",wid:c}}return null}const pt=Object.freeze({v:1,type:"request-inventory"}),yt="request-inventory";function vt(o){return o.includes(yt)}const ht=`
74
+ (function () {
75
+ if (window.__wickedInstrumentBridge) return;
76
+ window.__wickedInstrumentBridge = 1;
77
+ function nearest(node) {
78
+ var el = node;
79
+ while (el) {
80
+ if (el.getAttribute && el.getAttribute('data-wid')) return el;
81
+ el = el.parentElement;
82
+ }
83
+ return null;
84
+ }
85
+ function inventory() {
86
+ var widMap = {};
87
+ var blocks = {};
88
+ var nodes = document.querySelectorAll('[data-wid]');
89
+ for (var i = 0; i < nodes.length; i++) {
90
+ var el = nodes[i];
91
+ var wid = el.getAttribute('data-wid');
92
+ var r = el.getBoundingClientRect();
93
+ widMap[wid] = { x: r.x, y: r.y, width: r.width, height: r.height,
94
+ top: r.top, left: r.left, right: r.right, bottom: r.bottom };
95
+ var text = (el.textContent || '').replace(/\\s+/g, ' ').trim();
96
+ var composite = el.querySelector('[data-wid]') !== null;
97
+ var cap = composite ? 400 : 20000;
98
+ blocks[wid] = { text: text.length > cap ? text.slice(0, cap) : text, composite: composite };
99
+ if (text.length > cap) blocks[wid].cut = true;
100
+ var sec = el.parentElement ? el.parentElement.closest('section[data-wid], [data-wid^="section-"]') : null;
101
+ var secWid = sec ? sec.getAttribute('data-wid') : null;
102
+ // Only an id the parent's parser accepts: an odd one would invalidate the whole inventory.
103
+ if (secWid && /^[A-Za-z0-9_.:-]{1,100}$/.test(secWid)) blocks[wid].section = secWid;
104
+ }
105
+ return { v: 1, type: 'wid-inventory', widMap: widMap, blocks: blocks,
106
+ scrollX: window.scrollX, scrollY: window.scrollY };
107
+ }
108
+ function post(msg) { parent.postMessage(msg, '*'); }
109
+ window.addEventListener('message', function (e) {
110
+ var m = e.data;
111
+ if (!m || m.v !== 1) return;
112
+ if (m.type === 'request-inventory') {
113
+ post(inventory());
114
+ } else if (m.type === 'scroll-to-wid' && typeof m.wid === 'string') {
115
+ var el = document.querySelector('[data-wid="' + m.wid.replace(/["\\\\]/g, '') + '"]');
116
+ // An instant jump, whatever the document's own scroll-behavior: the position read on the
117
+ // next line is then where it landed.
118
+ if (el && el.scrollIntoView) el.scrollIntoView({ block: 'center', behavior: 'instant' });
119
+ post({ v: 1, type: 'scroll-ack', wid: m.wid, seq: m.seq, scrollX: window.scrollX, scrollY: window.scrollY });
120
+ }
121
+ });
122
+ document.addEventListener('scroll', function (e) {
123
+ if (e.target === document || e.target === document.documentElement || e.target === document.body) {
124
+ post({ v: 1, type: 'scroll-state', scrollX: window.scrollX, scrollY: window.scrollY });
125
+ } else {
126
+ post(inventory());
127
+ }
128
+ }, { passive: true, capture: true });
129
+ window.addEventListener('resize', function () { post(inventory()); });
130
+ document.addEventListener('click', function (e) {
131
+ var el = nearest(e.target);
132
+ if (!el) return;
133
+ e.preventDefault();
134
+ post({ v: 1, type: 'wid-click', wid: el.getAttribute('data-wid') });
135
+ });
136
+ var lastHover = null;
137
+ document.addEventListener('mousemove', function (e) {
138
+ var el = nearest(e.target);
139
+ var wid = el ? el.getAttribute('data-wid') : null;
140
+ if (wid !== lastHover) {
141
+ lastHover = wid;
142
+ post({ v: 1, type: 'wid-hover', wid: wid });
143
+ }
144
+ });
145
+ if (document.readyState === 'loading') {
146
+ document.addEventListener('DOMContentLoaded', function () { post(inventory()); });
147
+ } else {
148
+ post(inventory());
149
+ }
150
+ })();
151
+ `;function mt(o){const i=`<script>${ht}<\/script>`;return/<\/body>/i.test(o)?o.replace(/<\/body>/i,()=>`${i}</body>`):`${o}${i}`}const F="wicked.editor",G=1,wt="wicked-deck",ve=1280,he=720,gt=[0,250,750,1500],bt=1500,kt=`
152
+ <div data-testid="deck-editor" id="deck" class="deck" data-kind="deck" data-head="" data-current="" data-count="0" data-size="pane" data-present="false" data-selected="" tabindex="0" role="application" aria-label="The deck">
153
+ <nav id="strip" class="strip" aria-label="Slides" data-testid="deck-strip"><ol id="thumbs"></ol></nav>
154
+ <div class="main">
155
+ <div data-testid="deck-tools" id="tools" class="tools" role="toolbar" aria-label="Slide actions">
156
+ <span id="count" class="count" data-testid="deck-count"></span>
157
+ <button type="button" id="add" data-testid="deck-add" aria-haspopup="menu" aria-expanded="false" title="Add a slide laid out like one of the deck’s own (⌘⇧N: like this one)">Add ▾</button>
158
+ <button type="button" id="dup" data-testid="deck-duplicate" title="Duplicate this slide (⌘D)">Duplicate</button>
159
+ <button type="button" id="up" data-testid="deck-move-up" title="Move this slide up (⌥↑)" aria-label="Move up">↑ Up</button>
160
+ <button type="button" id="down" data-testid="deck-move-down" title="Move this slide down (⌥↓)" aria-label="Move down">↓ Down</button>
161
+ <button type="button" id="del" class="danger" data-testid="deck-delete" title="Delete this slide (⌘⌫) — Undo puts it back">Delete</button>
162
+ <button type="button" id="present" data-testid="deck-present" title="Show the slide on its own; ← → move, Esc leaves">Present</button>
163
+ </div>
164
+ <div data-testid="deck-add-menu" id="menu" class="menu" role="menu" aria-label="Add a slide like" hidden></div>
165
+ <div data-testid="deck-stage" id="stage" class="stage">
166
+ <div data-testid="deck-hover-box" id="hover" class="box box--hover" hidden></div>
167
+ <div data-testid="deck-selected-box" id="selected" class="box" data-wid="" hidden></div>
168
+ <textarea data-testid="deck-edit-input" id="input" class="input" rows="1" aria-label="New text" hidden></textarea>
169
+ <span data-testid="deck-inline-count" id="badge" class="badge" hidden></span>
170
+ <span data-testid="deck-present-bar" id="present-bar" class="present-bar" hidden></span>
171
+ </div>
172
+ <p data-testid="deck-hint" id="hint" class="hint" hidden></p>
173
+ <p data-testid="deck-note" id="note" class="note" hidden></p>
174
+ <div id="notes-box" class="notes">
175
+ <label for="notes" id="notes-label" data-testid="deck-notes-label">Speaker notes</label>
176
+ <textarea id="notes" data-testid="deck-notes" placeholder="What to say on this slide. Saved when you leave the field; Undo puts the old notes back."></textarea>
177
+ </div>
178
+ </div>
179
+ <div data-testid="deck-handle" id="handle" class="handle" tabindex="-1"></div>
180
+ </div>`;function u(o){const i=document.getElementById(o);if(i===null)throw new Error(`wicked-deck: no #${o}`);return i}const m=o=>o.id??`#${o.n}`;function me(o,i,d){const c=new DOMParser().parseFromString(o,"text/html");Ye(c).forEach((g,b)=>{b!==i&&g.setAttribute("data-wi-deck-off","")});const y=c.createElement("style");if(y.textContent=`[data-wi-deck-off]{display:none!important}${d.thumbnail?"html,body{overflow:hidden!important}":""}`,c.head.append(y),d.thumbnail)for(const g of Array.from(c.querySelectorAll("script")))g.remove();return`<!doctype html>${c.documentElement.outerHTML}`}function Xe(){document.body.insertAdjacentHTML("afterbegin",kt);const o=u("deck");u("strip");const i=u("thumbs"),d=u("count"),c=u("tools"),y=u("add"),g=u("dup"),b=u("up"),j=u("down"),ne=u("del"),V=u("present"),w=u("menu"),Z=u("stage"),Et=u("hover"),je=u("selected"),x=u("input"),ze=u("badge"),Re=u("present-bar"),Q=u("hint"),we=u("note"),$=u("notes"),xt=u("notes-label"),B=u("handle");let z=null,oe=[],D="pane",St=0;const ge=new Map,T=(e,t)=>{z?.postMessage({p:F,v:G,type:e,payload:t})},be=(e,t)=>new Promise(n=>{if(z===null){n({ok:!1,error:{code:"unavailable",message:"no host yet"}});return}const l=`wd-${++St}`;ge.set(l,n),z.postMessage({p:F,v:G,type:e,id:l,payload:t})}),J=e=>T("ui.status",{line:e.slice(0,120)}),ke=()=>oe.includes("artifact.write");let S=null,ae="",a=[],C=null,R=null,k=!1,_=!1,Ee=!1,ee=null,I=!1,P="",xe=null,W=null,A=null,Se=0,_e=-1,Ae=[],L=null,$e={scrollX:0,scrollY:0},de=null,h=null,q=null;const K=()=>{const e=a.findIndex(t=>m(t)===C);return e<0?0:e},O=()=>a[K()]??null,Pe=()=>{const e=Z.clientWidth,t=Z.clientHeight;if(e===0||t===0)return{x:0,y:0,s:1};const n=Math.min(e/ve,t/he);return{x:Math.max(0,(e-ve*n)/2),y:Math.max(0,(t-he*n)/2),s:n}},te=()=>{if(A===null)return;const e=Pe();A.style.cssText=`left:${e.x}px;top:${e.y}px;width:${ve}px;height:${he}px;transform:scale(${e.s})`},De=e=>{if(e===null||L===null)return null;const t=L.widMap[e];if(t===void 0||t.width===0&&t.height===0)return null;const n=at(t,L.measured,$e),l=Pe();return{left:l.x+n.left*l.s,top:l.y+n.top*l.s,width:n.width*l.s,height:n.height*l.s}},Le=(e,t,n=0,l=0)=>{if(t===null){e.hidden=!0;return}e.hidden=!1,e.style.left=`${t.left}px`,e.style.top=`${t.top}px`,e.style.width=`${Math.max(t.width,n)}px`,e.style.height=`${Math.max(t.height,l)}px`},We=e=>{const t=L?.blocks[e];return L===null||t===void 0||L.widMap[e]===void 0?"unmeasured":t.composite?"container":t.cut===!0?"cut":"yes"},v=()=>{const e=O(),t=a.length;o.dataset.head=S===null?"":String(S),o.dataset.current=e?.id??"",o.dataset.currentN=e===null?"":String(e.n),o.dataset.count=String(t),o.dataset.size=D,o.dataset.present=String(k),o.dataset.selected=h??"",document.body.dataset.present=String(k),d.textContent=t===0?"No slides yet":`${e?.n??1} of ${t}`,d.title=t===0?"":`Slide ${e?.n??1} of ${t}`;const n=ke()&&!_&&e!==null;for(const r of[y,g,ne])r.disabled=!n||e?.id===null;b.disabled=!n||K()===0||e?.id===null,j.disabled=!n||K()>=t-1||e?.id===null,V.disabled=t===0,y.setAttribute("aria-expanded",String(I)),w.hidden=!I||D==="inline",ze.hidden=D!=="inline"||t===0,ze.textContent=`${t} slide${t===1?"":"s"}`,Re.hidden=!k,Re.textContent=`${e?.n??0} / ${t} · ← → · Esc leaves`;for(const r of Array.from(i.children)){const f=r.querySelector("button");f!==null&&f.setAttribute("aria-current",String(f.dataset.key===C))}xt.textContent=e===null?"Speaker notes":`Speaker notes · slide ${e.n}`,document.activeElement!==$&&($.value=N!==null&&N.key===C?N.text:e?.notes??""),$.readOnly=!n;const l=D!=="inline"&&!k&&L!==null;if(Le(Et,l&&de!==h&&q===null?De(de):null),je.dataset.wid=h??"",Le(je,l&&q===null?De(h):null),q!==null?Le(x,De(q.wid),160,30):x.hidden=!0,c.hidden=D==="inline"||k,D==="inline"||k||q!==null){Q.hidden=!0;return}if(Q.hidden=!1,h===null){Q.removeAttribute("data-editable"),Q.textContent=t===0?"":"← → to move between slides · click a line to point at it · type on it to change it";return}const s=We(h);Q.dataset.editable=String(s==="yes"),Q.textContent=s==="yes"?"Type to change it · Enter to edit its text · Esc to let go":s==="container"?"This part holds other parts: click a line inside it to change the words · Esc to let go":"This can’t be changed by typing: say what to change in the message box · Esc to let go"},ce=new Map,At=()=>{const e=new Set,t=[];a.forEach((n,l)=>{const s=m(n);e.add(s);const r=me(ae,l,{thumbnail:!0});let f=ce.get(s);if(f===void 0){const Je=document.createElement("li"),p=document.createElement("button");p.type="button",p.className="thumb";for(const[X,H]of Object.entries({"data-testid":"deck-thumb"}))p.setAttribute(X,H);p.innerHTML='<span class="n"></span><span class="mini"><iframe sandbox="" tabindex="-1" aria-hidden="true"></iframe></span><span class="t"></span>',p.addEventListener("click",()=>{ie(p.dataset.key??null),Ue(),B.focus()}),p.draggable=!0,p.addEventListener("dragstart",X=>{W=p.dataset.key??null,X.dataTransfer?.setData("text/plain",W??"")}),p.addEventListener("dragover",X=>{if(W===null||W===p.dataset.key)return;X.preventDefault();const H=p.getBoundingClientRect();p.dataset.drop=X.clientY<H.top+H.height/2?"before":"after"}),p.addEventListener("dragleave",()=>{delete p.dataset.drop}),p.addEventListener("drop",X=>{X.preventDefault();const H=p.dataset.drop;delete p.dataset.drop;const et=W;if(W=null,et===null||H===void 0)return;const tt=a.findIndex(Yt=>m(Yt)===p.dataset.key),nt=a[tt];if(nt?.id==null)return;const Nt=H==="after"?nt.id:a[tt-1]?.id??null;Ce(et,Nt)}),p.addEventListener("dragend",()=>{W=null}),Je.appendChild(p),f={li:Je,srcdoc:""},ce.set(s,f)}const M=f.li.querySelector("button");M.dataset.key=s,M.dataset.slideId=n.id??"",M.dataset.n=String(n.n),M.setAttribute("aria-label",n.title===""?`Slide ${n.n}`:`Slide ${n.n}: ${n.title}`),M.querySelector(".n").textContent=String(n.n),M.querySelector(".t").textContent=n.title===""?`Slide ${n.n}`:n.title,f.srcdoc!==r&&(f.srcdoc=r,M.querySelector("iframe").srcdoc=r),t.push(f.li)});for(const[n,l]of ce)e.has(n)||(l.li.remove(),ce.delete(n));i.replaceChildren(...t)},$t=e=>{if(e===A){_e=Se;for(const t of Ae)clearTimeout(t);Ae=gt.map(t=>setTimeout(()=>A?.contentWindow?.postMessage(pt,"*"),t))}},Me=()=>{Se+=1,L=null,de=null,h=null,Y();const e=D==="inline"?0:K();if(a.length===0){A?.remove(),A=null,v();return}const t=me(ae,e,{thumbnail:!1}),n=document.createElement("iframe");for(const[s,r]of Object.entries({"data-testid":"deck-frame",sandbox:"allow-scripts",title:`Slide ${e+1}`}))n.setAttribute(s,r);A=n;const l=()=>{for(const s of Array.from(Z.querySelectorAll("iframe")))s!==A&&s.remove()};n.addEventListener("load",()=>{$t(n),A===n&&l()}),n.srcdoc=vt(t)?t:mt(t),Z.insertBefore(n,Z.firstChild),te(),setTimeout(()=>{A===n&&l()},2e3),v()},ie=e=>{if(e===null||e===C||!a.some(t=>m(t)===e)){v();return}Ke(),C=e,Me()},ue=e=>{const t=Math.max(0,Math.min(a.length-1,K()+e)),n=a[t];n!==void 0&&ie(m(n))},Ue=()=>{const e=O()?.wid;e!=null&&oe.includes("selection.chip")&&T("selection.set",{anchors:[{kind:"element",id:e}]})},Dt=(e,t)=>e.version===void 0||t.version===void 0?{}:e.version>=t.version?e:t,re=async e=>{if(!(e!==void 0&&S!==null&&e<=S)){if(Ee){const t=e===void 0?{}:{version:e};ee=ee===null?t:Dt(ee,t);return}Ee=!0;try{const t=await be("artifact.read",e===void 0?{}:{version:e});if(!t.ok){we.hidden=!1,we.textContent=t.error.code==="not_granted"?"This editor may not read the deck here.":`The deck could not be read (${t.error.code}).`;return}const n=t.payload.version;if(typeof n=="number"&&S!==null&&n<S)return;we.hidden=!0;const l=t.payload.content;if(ae=typeof l?.html=="string"?l.html:"",S=typeof n=="number"?n:S,a=st(ae),R!==null){const s=a[Math.max(0,Math.min(a.length-1,R))];C=s===void 0?null:m(s),R=null}else a.some(s=>m(s)===C)||(C=a[0]===void 0?null:m(a[0]));At(),Me()}finally{if(Ee=!1,ee!==null){const t=ee;ee=null,(t.version===void 0||S===null||t.version>S)&&re(t.version)}}}};window.addEventListener("message",e=>{if(A===null||A.contentWindow===null||e.source!==A.contentWindow||_e!==Se)return;const t=ft(e.data);if(t!==null){if(t.type==="wid-inventory"){for(const n of Ae)clearTimeout(n);L={widMap:t.widMap,blocks:t.blocks??{},measured:{scrollX:t.scrollX,scrollY:t.scrollY}},$e={scrollX:t.scrollX,scrollY:t.scrollY},v()}else if(t.type==="scroll-state"||t.type==="scroll-ack")t.scrollX!==void 0&&t.scrollY!==void 0&&($e={scrollX:t.scrollX,scrollY:t.scrollY},v());else if(t.type==="wid-hover")de=t.wid,v();else if(t.type==="wid-click"){if(D==="inline")return;if(k){ue(1);return}Te(t.wid===O()?.wid?null:t.wid),t.wid===O()?.wid&&Ue()}}});const Te=e=>{h=e,Y(),v(),e!==null&&(oe.includes("selection.chip")&&T("selection.set",{anchors:[{kind:"element",id:e}]}),B.focus())},U=async(e,t,n,l=S,s)=>{if(l===null||_||!ke())return!1;_=!0,I=!1,v(),J(n);try{const r=await be("version.write",{base:l,ops:e,summary:t});if(r.ok)return await re(typeof r.payload.version=="number"?r.payload.version:void 0),!0;if(R=null,r.error.code==="stale"||r.error.code==="head_moved"){s!==void 0?s():J(r.error.code==="stale"&&r.error.message?r.error.message:"Not changed: the deck changed meanwhile");const f=r.payload?.head;typeof f=="number"&&f!==S&&await re(f)}else r.error.code==="timeout"||J(r.error.message?r.error.code==="refused"||r.error.message.startsWith("Not changed")?r.error.message:`Not changed: ${r.error.message}`:"Nothing changed");return!1}finally{_=!1,v()}},Ce=async(e,t)=>{const n=a.find(r=>m(r)===e);if(n?.id==null)return;const l=a.indexOf(n),s=t===null?-1:a.findIndex(r=>r.id===t);t===n.id||s===l-1||(C=m(n),await U([{op:"slide-move",slide:n.id,after:t}],`slide ${n.n}`,`Moving slide ${n.n}…`))},Oe=e=>{const t=K(),n=a[t];n?.id!=null&&(e===-1&&t>0&&Ce(m(n),a[t-2]?.id??null),e===1&&t<a.length-1&&Ce(m(n),a[t+1]?.id??null))},He=()=>{const e=O();e?.id!=null&&(R=K()+1,U([{op:"slide-duplicate",slide:e.id}],`slide ${e.n}`,`Duplicating slide ${e.n}…`))},Fe=e=>{const t=O();e.id===null||t?.id==null||(R=K()+1,U([{op:"slide-insert",slide:e.id,after:t.id}],`a slide after slide ${t.n}`,`Adding a slide after slide ${t.n}…`))},Ge=()=>{const e=O();e?.wid==null||a.length===0||(R=Math.max(0,K()-(K()===a.length-1?1:0)),U([{op:"remove",anchor:e.wid}],`slide ${e.n}`,`Deleting slide ${e.n}…`))},Lt=e=>{L?.widMap[e]!==void 0&&U([{op:"remove",anchor:e}],"part of the slide","Removing it…")};let fe=null,qe=null,N=null;const Ke=()=>{const e=a.find(f=>m(f)===fe),t=qe;if(fe=null,qe=null,e?.id==null||$.readOnly)return;const n=$.value.replace(/\r\n/g,`
181
+ `),l=e.notes,s=m(e),r=()=>{N?.key===s&&(N=null)};if(n.trim()===l.trim()){r();return}U([{op:"notes-set",slide:e.id,text:n}],`slide ${e.n}’s notes`,`Saving slide ${e.n}’s notes…`,t,()=>{N={key:s,text:n},J(`Not saved: the deck changed while you typed slide ${e.n}’s notes. They are still in the field; leave it again to save them over the change.`),v()}).then(f=>{f&&r()})};$.addEventListener("focus",()=>{fe=C,qe=S}),$.addEventListener("blur",()=>Ke()),$.addEventListener("keydown",e=>{if(e.stopPropagation(),e.key==="Escape"){e.preventDefault(),N?.key===C&&(N=null),$.value=O()?.notes??"",fe=null,B.focus();return}if(e.key==="Enter"&&(e.metaKey||e.ctrlKey)){e.preventDefault(),B.focus();return}if((e.metaKey||e.ctrlKey)&&!e.altKey&&e.key.toLowerCase()==="k"){e.preventDefault(),T("ui.key",{key:"Mod+K"});return}if(e.key==="Tab"&&!e.shiftKey){e.preventDefault(),$.blur(),T("ui.key",{key:"Tab"});return}e.key==="Tab"&&e.shiftKey&&(e.preventDefault(),B.focus())});const Y=()=>{q!==null&&(q=null,x.hidden=!0,x.value="",v())},Ve=(e,t)=>{if(_||!ke()||L===null||We(e)!=="yes")return;const n=L.blocks[e]?.text??"";q={wid:e,before:n},x.value=t??n,v(),x.focus(),t===null?x.select():x.setSelectionRange(x.value.length,x.value.length)},Mt=async()=>{if(q===null)return;const{wid:e,before:t}=q,n=x.value.replace(/\s*\n\s*/g," ");Y(),B.focus(),n!==t&&await U([{op:"text",anchor:e,value:n,before:t}],`slide ${O()?.n??""}`,"Changing the text…")};x.addEventListener("keydown",e=>{if(e.stopPropagation(),(e.metaKey||e.ctrlKey)&&!e.altKey&&e.key.toLowerCase()==="k"){e.preventDefault(),Y(),T("ui.key",{key:"Mod+K"});return}e.key==="Enter"?(e.preventDefault(),Mt()):e.key==="Escape"&&(e.preventDefault(),Y(),B.focus())}),x.addEventListener("blur",()=>Y());const Tt=()=>{w.replaceChildren();const e=document.createElement("span");e.className="word",e.textContent="A blank slide laid out like",w.appendChild(e);for(const t of a){if(t.id===null)continue;const n=document.createElement("button");n.type="button";for(const[l,s]of Object.entries({role:"menuitem","data-testid":"deck-add-like"}))n.setAttribute(l,s);n.dataset.slideId=t.id,n.textContent=t.title===""?`Slide ${t.n}`:`Slide ${t.n} — ${t.title}`,n.addEventListener("click",()=>Fe(t)),w.appendChild(n)}I=!0,v(),w.querySelector("button")?.focus()},Ie=()=>{I&&(I=!1,v(),y.focus())};w.addEventListener("keydown",e=>{if(e.key==="Escape"){e.preventDefault(),e.stopPropagation(),Ie();return}if(e.key!=="ArrowDown"&&e.key!=="ArrowUp")return;e.preventDefault(),e.stopPropagation();const t=Array.from(w.querySelectorAll("button")),n=t.indexOf(document.activeElement);t[(n+(e.key==="ArrowDown"?1:t.length-1)+t.length)%t.length]?.focus()}),y.addEventListener("click",()=>I?Ie():Tt()),g.addEventListener("click",()=>He()),b.addEventListener("click",()=>Oe(-1)),j.addEventListener("click",()=>Oe(1)),ne.addEventListener("click",()=>Ge()),V.addEventListener("click",()=>void Ct());const Ct=async()=>{a.length!==0&&(Ke(),k=!0,Te(null),oe.includes("ui.fullscreen")&&await be("ui.fullscreen",{}),v(),te(),o.focus())},Ot=()=>{k=!1,v(),te(),o.focus()};window.addEventListener("resize",()=>{te(),v()}),typeof ResizeObserver=="function"&&new ResizeObserver(()=>{te(),v()}).observe(Z);const qt=()=>[...Array.from(i.querySelectorAll("button")).filter(()=>D!=="inline"&&!k),...Array.from(c.querySelectorAll("button")).filter(e=>!c.hidden&&!e.disabled),B,...D==="inline"||k?[]:[$]],Kt=e=>{P=`${P}${e}`.slice(-3),xe!==null&&clearTimeout(xe),xe=setTimeout(()=>{P=""},bt),J(`Go to slide ${P} — Enter`)};o.addEventListener("keydown",e=>{if(e.target===x||e.target===$)return;const t=e.target?.tagName==="BUTTON",n=e.target?.dataset?.testid==="deck-thumb",l=e.key==="Enter"&&n&&P!=="";if(t&&!l&&(e.key==="Enter"||e.key===" "))return;const s=e.metaKey||e.ctrlKey;if(e.key==="Escape"){if(e.preventDefault(),I){Ie();return}if(k){Ot();return}if(h!==null){Te(null);return}T("ui.key",{key:"Escape"});return}if(s&&!e.altKey&&e.key.toLowerCase()==="k"){e.preventDefault(),T("ui.key",{key:"Mod+K"});return}if(s&&e.shiftKey&&!e.altKey&&e.key.toLowerCase()==="n"){e.preventDefault();const r=O();r!==null&&Fe(r);return}if(s&&!e.shiftKey&&!e.altKey&&e.key.toLowerCase()==="d"){e.preventDefault(),He();return}if(s&&!e.altKey&&(e.key==="Backspace"||e.key==="Delete")){e.preventDefault(),h!==null&&h!==O()?.wid?Lt(h):Ge();return}if(e.altKey&&!s&&(e.key==="ArrowUp"||e.key==="ArrowDown")){e.preventDefault(),Oe(e.key==="ArrowUp"?-1:1);return}if(e.altKey&&!s&&/^Key[A-Z]$/.test(e.code)){e.preventDefault(),T("ui.key",{key:`Alt+${e.code.slice(3)}`});return}if(e.key==="Tab"){e.preventDefault();const r=qt(),f=r.indexOf(document.activeElement),M=f===-1&&document.activeElement===o&&!e.shiftKey?0:f+(e.shiftKey?-1:1);if(f===-1&&M!==0||M<0||M>=r.length){T("ui.key",{key:e.shiftKey?"Shift+Tab":"Tab"});return}r[M].focus();return}if(!(s||e.altKey)){if(e.key==="ArrowRight"||e.key==="PageDown"||e.key==="ArrowDown"&&!t){e.preventDefault(),ue(1);return}if(e.key==="ArrowLeft"||e.key==="PageUp"||e.key==="ArrowUp"&&!t){e.preventDefault(),ue(-1);return}if(e.key==="Home"){e.preventDefault();const r=a[0];r!==void 0&&ie(m(r));return}if(e.key==="End"){e.preventDefault();const r=a[a.length-1];r!==void 0&&ie(m(r));return}if(k&&e.key===" "){e.preventDefault(),ue(1);return}if(l){e.preventDefault();const r=a[Number(P)-1];P="",r!==void 0&&(ie(m(r)),i.querySelector(`[data-key="${CSS.escape(m(r))}"]`)?.focus()),J(r===void 0?"There is no such slide":`Slide ${r.n}`);return}if(!(t&&e.key.length!==1)){if(e.key==="Enter"){h!==null&&!_&&(e.preventDefault(),Ve(h,null));return}if(e.key.length===1){if(e.preventDefault(),h!==null&&!_){Ve(h,e.key);return}if(/^[0-9]$/.test(e.key)&&n){Kt(e.key);return}T("ui.typed",{grapheme:e.key})}}}});const Ze=e=>{const t=D;D=e,document.body.dataset.size=e,e==="inline"&&(k=!1,Y(),h=null,I=!1,document.activeElement?.blur?.()),e!=="full"&&k&&(k=!1),t==="inline"!=(e==="inline")&&a.length>0&&Me(),te(),v()},Qe=e=>{if(!(typeof e!="object"||e===null))for(const[t,n]of Object.entries(e))/^--[a-z0-9-]+$/.test(t)&&typeof n=="string"&&n.length<=200&&!/url\(/i.test(n)&&document.documentElement.style.setProperty(t,n)},It=e=>{const t=e.data;try{if(t===null||typeof t!="object"||t.p!==F||t.v!==G)return;if(typeof t.re=="string"){const l=ge.get(t.re);if(l===void 0)return;ge.delete(t.re);const s=typeof t.payload=="object"&&t.payload!==null?t.payload:{};t.ok===!0?l({ok:!0,payload:s}):l({ok:!1,error:t.error??{code:"unavailable",message:"no answer"},payload:s});return}const n=typeof t.payload=="object"&&t.payload!==null?t.payload:{};switch(t.type){case"host.ping":typeof t.id=="string"&&z?.postMessage({p:F,v:G,re:t.id,ok:!0,payload:{}});return;case"host.size":(n.size==="inline"||n.size==="pane"||n.size==="full")&&Ze(n.size);return;case"host.theme":Qe(n.theme);return;case"artifact.changed":{const l=n.version;typeof l=="number"&&l!==S&&re(l);return}case"selection.cleared":h!==null&&(h=null,Y(),v());return;default:return}}catch{}};window.addEventListener("message",e=>{const t=e.data;if(z!==null||t===null||typeof t!="object"||t.p!==F||t.type!=="host.hello"||e.ports[0]===void 0)return;z=e.ports[0],z.onmessage=It;const n=typeof t.payload=="object"&&t.payload!==null?t.payload:{};oe=Array.isArray(n.grants)?n.grants.filter(l=>typeof l=="string"):[],Qe(n.theme),Ze(n.size==="inline"||n.size==="full"?n.size:"pane"),re()});const Bt=document.querySelector('meta[name="wicked-editor-version"]')?.getAttribute("content")??"0.0.0";parent.postMessage({p:F,v:G,type:"plugin.ready",payload:{editor:wt,version:Bt,protocol:[G]}},"*")}return Xe(),le.oneSlideHtml=me,le.start=Xe,Object.defineProperty(le,Symbol.toStringTag,{value:"Module"}),le})({});
182
+ </script>
183
+ </body>
184
+ </html>
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "id": "wicked-page",
3
- "title": "Page editor",
4
- "version": "0.7.12",
3
+ "title": "Document",
4
+ "version": "0.8.0",
5
5
  "protocol": [
6
6
  1
7
7
  ],
@@ -3,8 +3,8 @@
3
3
  <head>
4
4
  <meta charset="utf-8">
5
5
  <meta name="wicked-editor" content="wicked-page">
6
- <meta name="wicked-editor-version" content="0.7.12">
7
- <title>Page editor</title>
6
+ <meta name="wicked-editor-version" content="0.8.0">
7
+ <title>Document</title>
8
8
  <style>
9
9
  /* The plugin's own chrome takes the host's tokens (`host.hello.theme` / `host.theme`), with plain
10
10
  fallbacks for a host that passes none. The PAGE inside the nested frame styles itself. */
package/dist/index.html CHANGED
@@ -4,8 +4,8 @@
4
4
  <meta charset="UTF-8" />
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
6
  <title>wicked-studio</title>
7
- <script type="module" crossorigin src="/assets/index-DlZl1q2Q.js"></script>
8
- <link rel="stylesheet" crossorigin href="/assets/index-eLCOoPWX.css">
7
+ <script type="module" crossorigin src="/assets/index-R8uK_NlG.js"></script>
8
+ <link rel="stylesheet" crossorigin href="/assets/index-BSPM1fFW.css">
9
9
  </head>
10
10
  <body>
11
11
  <div id="root"></div>