@wildwinter/app-shell 0.26.0 → 0.28.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +154 -136
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +12 -1
- package/dist/index.d.ts +12 -1
- package/dist/index.js +154 -136
- package/dist/index.js.map +1 -1
- package/dist/session.cjs +3 -4
- package/dist/session.cjs.map +1 -1
- package/dist/session.d.cts +12 -2
- package/dist/session.d.ts +12 -2
- package/dist/session.js +3 -4
- package/dist/session.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -1,5 +1,154 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
+
// src/tooltip.ts
|
|
4
|
+
var B_OPEN = "";
|
|
5
|
+
var B_CLOSE = "";
|
|
6
|
+
function tipBold(s) {
|
|
7
|
+
return `${B_OPEN}${s}${B_CLOSE}`;
|
|
8
|
+
}
|
|
9
|
+
function renderTip(host, text) {
|
|
10
|
+
host.textContent = "";
|
|
11
|
+
const re = /\u0002([^\u0003]*)\u0003/g;
|
|
12
|
+
let last = 0;
|
|
13
|
+
let m;
|
|
14
|
+
while ((m = re.exec(text)) !== null) {
|
|
15
|
+
if (m.index > last) host.append(text.slice(last, m.index));
|
|
16
|
+
const strong = document.createElement("strong");
|
|
17
|
+
strong.textContent = m[1] ?? "";
|
|
18
|
+
host.append(strong);
|
|
19
|
+
last = m.index + m[0].length;
|
|
20
|
+
}
|
|
21
|
+
if (last < text.length) host.append(text.slice(last));
|
|
22
|
+
}
|
|
23
|
+
var inited = false;
|
|
24
|
+
var checked = false;
|
|
25
|
+
var suppressed;
|
|
26
|
+
var SHOW_DELAY = 350;
|
|
27
|
+
var EDGE = 6;
|
|
28
|
+
var GAP = 7;
|
|
29
|
+
var tip = null;
|
|
30
|
+
var timer = 0;
|
|
31
|
+
var active = null;
|
|
32
|
+
var activeKey = null;
|
|
33
|
+
function ensureEl() {
|
|
34
|
+
if (tip) return tip;
|
|
35
|
+
const el2 = document.createElement("div");
|
|
36
|
+
el2.className = "tooltip";
|
|
37
|
+
el2.setAttribute("role", "tooltip");
|
|
38
|
+
el2.hidden = true;
|
|
39
|
+
document.body.appendChild(el2);
|
|
40
|
+
tip = el2;
|
|
41
|
+
return el2;
|
|
42
|
+
}
|
|
43
|
+
var rectOf = (anchor) => anchor instanceof HTMLElement ? anchor.getBoundingClientRect() : anchor;
|
|
44
|
+
function place(anchor) {
|
|
45
|
+
const t = ensureEl();
|
|
46
|
+
const r = rectOf(anchor);
|
|
47
|
+
const tr = t.getBoundingClientRect();
|
|
48
|
+
let top = r.top - tr.height - GAP;
|
|
49
|
+
if (top < EDGE) top = r.top + r.height + GAP;
|
|
50
|
+
let left = r.left + r.width / 2 - tr.width / 2;
|
|
51
|
+
left = Math.max(EDGE, Math.min(left, window.innerWidth - tr.width - EDGE));
|
|
52
|
+
t.style.left = `${Math.round(left)}px`;
|
|
53
|
+
t.style.top = `${Math.round(top)}px`;
|
|
54
|
+
}
|
|
55
|
+
function show(anchor) {
|
|
56
|
+
const text = anchor.dataset["tip"];
|
|
57
|
+
if (!text) return;
|
|
58
|
+
paint(anchor, text);
|
|
59
|
+
}
|
|
60
|
+
function paint(anchor, text) {
|
|
61
|
+
if (suppressed?.()) return;
|
|
62
|
+
const t = ensureEl();
|
|
63
|
+
const host = (anchor instanceof HTMLElement ? anchor.closest("dialog[open]") : null) ?? document.body;
|
|
64
|
+
if (t.parentElement !== host) host.appendChild(t);
|
|
65
|
+
active = anchor instanceof HTMLElement ? anchor : null;
|
|
66
|
+
renderTip(t, text);
|
|
67
|
+
t.hidden = false;
|
|
68
|
+
t.classList.remove("show");
|
|
69
|
+
void t.offsetWidth;
|
|
70
|
+
place(anchor);
|
|
71
|
+
t.classList.add("show");
|
|
72
|
+
}
|
|
73
|
+
function hide() {
|
|
74
|
+
if (timer) {
|
|
75
|
+
window.clearTimeout(timer);
|
|
76
|
+
timer = 0;
|
|
77
|
+
}
|
|
78
|
+
active = null;
|
|
79
|
+
activeKey = null;
|
|
80
|
+
if (tip) {
|
|
81
|
+
tip.hidden = true;
|
|
82
|
+
tip.classList.remove("show");
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
function schedule(anchor) {
|
|
86
|
+
if (anchor === active) return;
|
|
87
|
+
if (timer) window.clearTimeout(timer);
|
|
88
|
+
timer = window.setTimeout(() => show(anchor), SHOW_DELAY);
|
|
89
|
+
}
|
|
90
|
+
function tipAt(key, rect, text) {
|
|
91
|
+
if (key === activeKey) {
|
|
92
|
+
if (tip && !tip.hidden) {
|
|
93
|
+
renderTip(tip, text);
|
|
94
|
+
place(rect);
|
|
95
|
+
}
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
hide();
|
|
99
|
+
activeKey = key;
|
|
100
|
+
timer = window.setTimeout(() => {
|
|
101
|
+
timer = 0;
|
|
102
|
+
paint(rect, text);
|
|
103
|
+
}, SHOW_DELAY);
|
|
104
|
+
}
|
|
105
|
+
function hideTip() {
|
|
106
|
+
hide();
|
|
107
|
+
}
|
|
108
|
+
function ensureTooltipHost() {
|
|
109
|
+
initTooltips();
|
|
110
|
+
}
|
|
111
|
+
function checkTooltipHost() {
|
|
112
|
+
if (checked) return;
|
|
113
|
+
checked = true;
|
|
114
|
+
setTimeout(() => {
|
|
115
|
+
if (inited || typeof document === "undefined") return;
|
|
116
|
+
if (document.querySelector("[data-tip]")) {
|
|
117
|
+
console.warn("app-shell: something set `data-tip` but no tooltip host is mounted, so those rollovers will not draw. Call initTooltips() once per window.");
|
|
118
|
+
}
|
|
119
|
+
}, 0);
|
|
120
|
+
}
|
|
121
|
+
var tipAncestor = (n) => n instanceof Element ? n.closest("[data-tip]") : null;
|
|
122
|
+
function initTooltips(opts = {}) {
|
|
123
|
+
if (opts.suppressed !== void 0) suppressed = opts.suppressed;
|
|
124
|
+
if (inited) return;
|
|
125
|
+
inited = true;
|
|
126
|
+
document.addEventListener("pointerover", (e) => {
|
|
127
|
+
const el2 = tipAncestor(e.target);
|
|
128
|
+
if (el2) schedule(el2);
|
|
129
|
+
});
|
|
130
|
+
document.addEventListener("pointerout", (e) => {
|
|
131
|
+
const el2 = tipAncestor(e.target);
|
|
132
|
+
if (!el2) return;
|
|
133
|
+
const to = e.relatedTarget;
|
|
134
|
+
if (to instanceof Node && el2.contains(to)) return;
|
|
135
|
+
hide();
|
|
136
|
+
});
|
|
137
|
+
document.addEventListener("focusin", (e) => {
|
|
138
|
+
const el2 = tipAncestor(e.target);
|
|
139
|
+
if (el2) schedule(el2);
|
|
140
|
+
});
|
|
141
|
+
document.addEventListener("focusout", () => hide());
|
|
142
|
+
document.addEventListener("pointerdown", () => hide(), true);
|
|
143
|
+
document.addEventListener("scroll", () => {
|
|
144
|
+
if (active) hide();
|
|
145
|
+
}, true);
|
|
146
|
+
document.addEventListener("keydown", (e) => {
|
|
147
|
+
if (e.key === "Escape") hide();
|
|
148
|
+
});
|
|
149
|
+
window.addEventListener("blur", () => hide());
|
|
150
|
+
}
|
|
151
|
+
|
|
3
152
|
// src/dom.ts
|
|
4
153
|
function el(tag, classNameOrProps, ...children) {
|
|
5
154
|
const node = document.createElement(tag);
|
|
@@ -10,12 +159,14 @@ function el(tag, classNameOrProps, ...children) {
|
|
|
10
159
|
if (props.tip !== void 0) {
|
|
11
160
|
node.dataset["tip"] = props.tip;
|
|
12
161
|
node.setAttribute("aria-label", props.tip);
|
|
162
|
+
ensureTooltipHost();
|
|
13
163
|
}
|
|
14
164
|
if (props.onClick) node.addEventListener("click", props.onClick);
|
|
15
165
|
for (const child of children) {
|
|
16
166
|
if (child === null || child === void 0) continue;
|
|
17
167
|
node.append(child);
|
|
18
168
|
}
|
|
169
|
+
checkTooltipHost();
|
|
19
170
|
return node;
|
|
20
171
|
}
|
|
21
172
|
function iconBtn(glyph, title, onClick, disabled = false, danger = false) {
|
|
@@ -485,7 +636,9 @@ function pinButton(opts) {
|
|
|
485
636
|
const reflect = () => {
|
|
486
637
|
b.classList.toggle("on", pinned);
|
|
487
638
|
b.setAttribute("aria-pressed", String(pinned));
|
|
488
|
-
|
|
639
|
+
const label2 = pinned ? "Pinned on top: click to unpin" : "Click to keep on top";
|
|
640
|
+
b.dataset["tip"] = label2;
|
|
641
|
+
b.setAttribute("aria-label", label2);
|
|
489
642
|
};
|
|
490
643
|
reflect();
|
|
491
644
|
b.addEventListener("click", () => {
|
|
@@ -1196,141 +1349,6 @@ function mountJobProgress(host, opts) {
|
|
|
1196
1349
|
// src/job.ts
|
|
1197
1350
|
var JOB_PROGRESS = "job:progress";
|
|
1198
1351
|
|
|
1199
|
-
// src/tooltip.ts
|
|
1200
|
-
var B_OPEN = "";
|
|
1201
|
-
var B_CLOSE = "";
|
|
1202
|
-
function tipBold(s) {
|
|
1203
|
-
return `${B_OPEN}${s}${B_CLOSE}`;
|
|
1204
|
-
}
|
|
1205
|
-
function renderTip(host, text) {
|
|
1206
|
-
host.textContent = "";
|
|
1207
|
-
const re = /\u0002([^\u0003]*)\u0003/g;
|
|
1208
|
-
let last = 0;
|
|
1209
|
-
let m;
|
|
1210
|
-
while ((m = re.exec(text)) !== null) {
|
|
1211
|
-
if (m.index > last) host.append(text.slice(last, m.index));
|
|
1212
|
-
const strong = document.createElement("strong");
|
|
1213
|
-
strong.textContent = m[1] ?? "";
|
|
1214
|
-
host.append(strong);
|
|
1215
|
-
last = m.index + m[0].length;
|
|
1216
|
-
}
|
|
1217
|
-
if (last < text.length) host.append(text.slice(last));
|
|
1218
|
-
}
|
|
1219
|
-
var inited = false;
|
|
1220
|
-
var suppressed;
|
|
1221
|
-
var SHOW_DELAY = 350;
|
|
1222
|
-
var EDGE = 6;
|
|
1223
|
-
var GAP = 7;
|
|
1224
|
-
var tip = null;
|
|
1225
|
-
var timer = 0;
|
|
1226
|
-
var active = null;
|
|
1227
|
-
var activeKey = null;
|
|
1228
|
-
function ensureEl() {
|
|
1229
|
-
if (tip) return tip;
|
|
1230
|
-
const el2 = document.createElement("div");
|
|
1231
|
-
el2.className = "tooltip";
|
|
1232
|
-
el2.setAttribute("role", "tooltip");
|
|
1233
|
-
el2.hidden = true;
|
|
1234
|
-
document.body.appendChild(el2);
|
|
1235
|
-
tip = el2;
|
|
1236
|
-
return el2;
|
|
1237
|
-
}
|
|
1238
|
-
var rectOf = (anchor) => anchor instanceof HTMLElement ? anchor.getBoundingClientRect() : anchor;
|
|
1239
|
-
function place(anchor) {
|
|
1240
|
-
const t = ensureEl();
|
|
1241
|
-
const r = rectOf(anchor);
|
|
1242
|
-
const tr = t.getBoundingClientRect();
|
|
1243
|
-
let top = r.top - tr.height - GAP;
|
|
1244
|
-
if (top < EDGE) top = r.top + r.height + GAP;
|
|
1245
|
-
let left = r.left + r.width / 2 - tr.width / 2;
|
|
1246
|
-
left = Math.max(EDGE, Math.min(left, window.innerWidth - tr.width - EDGE));
|
|
1247
|
-
t.style.left = `${Math.round(left)}px`;
|
|
1248
|
-
t.style.top = `${Math.round(top)}px`;
|
|
1249
|
-
}
|
|
1250
|
-
function show(anchor) {
|
|
1251
|
-
const text = anchor.dataset["tip"];
|
|
1252
|
-
if (!text) return;
|
|
1253
|
-
paint(anchor, text);
|
|
1254
|
-
}
|
|
1255
|
-
function paint(anchor, text) {
|
|
1256
|
-
if (suppressed?.()) return;
|
|
1257
|
-
const t = ensureEl();
|
|
1258
|
-
const host = (anchor instanceof HTMLElement ? anchor.closest("dialog[open]") : null) ?? document.body;
|
|
1259
|
-
if (t.parentElement !== host) host.appendChild(t);
|
|
1260
|
-
active = anchor instanceof HTMLElement ? anchor : null;
|
|
1261
|
-
renderTip(t, text);
|
|
1262
|
-
t.hidden = false;
|
|
1263
|
-
t.classList.remove("show");
|
|
1264
|
-
void t.offsetWidth;
|
|
1265
|
-
place(anchor);
|
|
1266
|
-
t.classList.add("show");
|
|
1267
|
-
}
|
|
1268
|
-
function hide() {
|
|
1269
|
-
if (timer) {
|
|
1270
|
-
window.clearTimeout(timer);
|
|
1271
|
-
timer = 0;
|
|
1272
|
-
}
|
|
1273
|
-
active = null;
|
|
1274
|
-
activeKey = null;
|
|
1275
|
-
if (tip) {
|
|
1276
|
-
tip.hidden = true;
|
|
1277
|
-
tip.classList.remove("show");
|
|
1278
|
-
}
|
|
1279
|
-
}
|
|
1280
|
-
function schedule(anchor) {
|
|
1281
|
-
if (anchor === active) return;
|
|
1282
|
-
if (timer) window.clearTimeout(timer);
|
|
1283
|
-
timer = window.setTimeout(() => show(anchor), SHOW_DELAY);
|
|
1284
|
-
}
|
|
1285
|
-
function tipAt(key, rect, text) {
|
|
1286
|
-
if (key === activeKey) {
|
|
1287
|
-
if (tip && !tip.hidden) {
|
|
1288
|
-
renderTip(tip, text);
|
|
1289
|
-
place(rect);
|
|
1290
|
-
}
|
|
1291
|
-
return;
|
|
1292
|
-
}
|
|
1293
|
-
hide();
|
|
1294
|
-
activeKey = key;
|
|
1295
|
-
timer = window.setTimeout(() => {
|
|
1296
|
-
timer = 0;
|
|
1297
|
-
paint(rect, text);
|
|
1298
|
-
}, SHOW_DELAY);
|
|
1299
|
-
}
|
|
1300
|
-
function hideTip() {
|
|
1301
|
-
hide();
|
|
1302
|
-
}
|
|
1303
|
-
var tipAncestor = (n) => n instanceof Element ? n.closest("[data-tip]") : null;
|
|
1304
|
-
function initTooltips(opts = {}) {
|
|
1305
|
-
if (inited) return;
|
|
1306
|
-
inited = true;
|
|
1307
|
-
suppressed = opts.suppressed;
|
|
1308
|
-
document.addEventListener("pointerover", (e) => {
|
|
1309
|
-
const el2 = tipAncestor(e.target);
|
|
1310
|
-
if (el2) schedule(el2);
|
|
1311
|
-
});
|
|
1312
|
-
document.addEventListener("pointerout", (e) => {
|
|
1313
|
-
const el2 = tipAncestor(e.target);
|
|
1314
|
-
if (!el2) return;
|
|
1315
|
-
const to = e.relatedTarget;
|
|
1316
|
-
if (to instanceof Node && el2.contains(to)) return;
|
|
1317
|
-
hide();
|
|
1318
|
-
});
|
|
1319
|
-
document.addEventListener("focusin", (e) => {
|
|
1320
|
-
const el2 = tipAncestor(e.target);
|
|
1321
|
-
if (el2) schedule(el2);
|
|
1322
|
-
});
|
|
1323
|
-
document.addEventListener("focusout", () => hide());
|
|
1324
|
-
document.addEventListener("pointerdown", () => hide(), true);
|
|
1325
|
-
document.addEventListener("scroll", () => {
|
|
1326
|
-
if (active) hide();
|
|
1327
|
-
}, true);
|
|
1328
|
-
document.addEventListener("keydown", (e) => {
|
|
1329
|
-
if (e.key === "Escape") hide();
|
|
1330
|
-
});
|
|
1331
|
-
window.addEventListener("blur", () => hide());
|
|
1332
|
-
}
|
|
1333
|
-
|
|
1334
1352
|
// src/save.ts
|
|
1335
1353
|
function createSaveController(opts) {
|
|
1336
1354
|
const delayMs = opts.delayMs ?? 700;
|