@wildwinter/app-shell 0.27.0 → 0.29.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 +175 -135
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +53 -2
- package/dist/index.d.ts +53 -2
- package/dist/index.js +171 -136
- package/dist/index.js.map +1 -1
- package/dist/settings.css +4 -0
- package/dist/settings.css.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) {
|
|
@@ -721,6 +872,25 @@ function isValidGameId(gameId) {
|
|
|
721
872
|
return /^[a-z0-9]([a-z0-9-]*[a-z0-9])?$/.test(gameId);
|
|
722
873
|
}
|
|
723
874
|
|
|
875
|
+
// src/property-names.ts
|
|
876
|
+
var RESERVED_PROPERTY_NAMES = ["true", "false", "and", "or", "not"];
|
|
877
|
+
var PROPERTY_NAME_HINT = "Lower case letters, digits and underscores. Cannot start with a digit. No hyphens or spaces.";
|
|
878
|
+
function propertyNameify(text) {
|
|
879
|
+
const trimmed = text.trim();
|
|
880
|
+
const deliberateLeading = trimmed.startsWith("_");
|
|
881
|
+
let out = trimmed.toLowerCase().replace(/['’]/g, "").replace(/[^a-z0-9_]+/g, "_").replace(/_+/g, "_").replace(/^_+|_+$/g, "");
|
|
882
|
+
if (out === "") return "";
|
|
883
|
+
if (deliberateLeading || /^[0-9]/.test(out)) out = `_${out}`;
|
|
884
|
+
if (RESERVED_PROPERTY_NAMES.includes(out)) out = `${out}_`;
|
|
885
|
+
return out;
|
|
886
|
+
}
|
|
887
|
+
function isValidPropertyName(name) {
|
|
888
|
+
return /^[a-z_][a-z0-9_]*$/.test(name) && !RESERVED_PROPERTY_NAMES.includes(name);
|
|
889
|
+
}
|
|
890
|
+
function isCaseOnlyPropertyName(name) {
|
|
891
|
+
return !isValidPropertyName(name) && isValidPropertyName(name.toLowerCase());
|
|
892
|
+
}
|
|
893
|
+
|
|
724
894
|
// src/id-editor.ts
|
|
725
895
|
function openGameIdEditor(opts) {
|
|
726
896
|
const slugify = opts.slugify ?? gameIdify;
|
|
@@ -1198,141 +1368,6 @@ function mountJobProgress(host, opts) {
|
|
|
1198
1368
|
// src/job.ts
|
|
1199
1369
|
var JOB_PROGRESS = "job:progress";
|
|
1200
1370
|
|
|
1201
|
-
// src/tooltip.ts
|
|
1202
|
-
var B_OPEN = "";
|
|
1203
|
-
var B_CLOSE = "";
|
|
1204
|
-
function tipBold(s) {
|
|
1205
|
-
return `${B_OPEN}${s}${B_CLOSE}`;
|
|
1206
|
-
}
|
|
1207
|
-
function renderTip(host, text) {
|
|
1208
|
-
host.textContent = "";
|
|
1209
|
-
const re = /\u0002([^\u0003]*)\u0003/g;
|
|
1210
|
-
let last = 0;
|
|
1211
|
-
let m;
|
|
1212
|
-
while ((m = re.exec(text)) !== null) {
|
|
1213
|
-
if (m.index > last) host.append(text.slice(last, m.index));
|
|
1214
|
-
const strong = document.createElement("strong");
|
|
1215
|
-
strong.textContent = m[1] ?? "";
|
|
1216
|
-
host.append(strong);
|
|
1217
|
-
last = m.index + m[0].length;
|
|
1218
|
-
}
|
|
1219
|
-
if (last < text.length) host.append(text.slice(last));
|
|
1220
|
-
}
|
|
1221
|
-
var inited = false;
|
|
1222
|
-
var suppressed;
|
|
1223
|
-
var SHOW_DELAY = 350;
|
|
1224
|
-
var EDGE = 6;
|
|
1225
|
-
var GAP = 7;
|
|
1226
|
-
var tip = null;
|
|
1227
|
-
var timer = 0;
|
|
1228
|
-
var active = null;
|
|
1229
|
-
var activeKey = null;
|
|
1230
|
-
function ensureEl() {
|
|
1231
|
-
if (tip) return tip;
|
|
1232
|
-
const el2 = document.createElement("div");
|
|
1233
|
-
el2.className = "tooltip";
|
|
1234
|
-
el2.setAttribute("role", "tooltip");
|
|
1235
|
-
el2.hidden = true;
|
|
1236
|
-
document.body.appendChild(el2);
|
|
1237
|
-
tip = el2;
|
|
1238
|
-
return el2;
|
|
1239
|
-
}
|
|
1240
|
-
var rectOf = (anchor) => anchor instanceof HTMLElement ? anchor.getBoundingClientRect() : anchor;
|
|
1241
|
-
function place(anchor) {
|
|
1242
|
-
const t = ensureEl();
|
|
1243
|
-
const r = rectOf(anchor);
|
|
1244
|
-
const tr = t.getBoundingClientRect();
|
|
1245
|
-
let top = r.top - tr.height - GAP;
|
|
1246
|
-
if (top < EDGE) top = r.top + r.height + GAP;
|
|
1247
|
-
let left = r.left + r.width / 2 - tr.width / 2;
|
|
1248
|
-
left = Math.max(EDGE, Math.min(left, window.innerWidth - tr.width - EDGE));
|
|
1249
|
-
t.style.left = `${Math.round(left)}px`;
|
|
1250
|
-
t.style.top = `${Math.round(top)}px`;
|
|
1251
|
-
}
|
|
1252
|
-
function show(anchor) {
|
|
1253
|
-
const text = anchor.dataset["tip"];
|
|
1254
|
-
if (!text) return;
|
|
1255
|
-
paint(anchor, text);
|
|
1256
|
-
}
|
|
1257
|
-
function paint(anchor, text) {
|
|
1258
|
-
if (suppressed?.()) return;
|
|
1259
|
-
const t = ensureEl();
|
|
1260
|
-
const host = (anchor instanceof HTMLElement ? anchor.closest("dialog[open]") : null) ?? document.body;
|
|
1261
|
-
if (t.parentElement !== host) host.appendChild(t);
|
|
1262
|
-
active = anchor instanceof HTMLElement ? anchor : null;
|
|
1263
|
-
renderTip(t, text);
|
|
1264
|
-
t.hidden = false;
|
|
1265
|
-
t.classList.remove("show");
|
|
1266
|
-
void t.offsetWidth;
|
|
1267
|
-
place(anchor);
|
|
1268
|
-
t.classList.add("show");
|
|
1269
|
-
}
|
|
1270
|
-
function hide() {
|
|
1271
|
-
if (timer) {
|
|
1272
|
-
window.clearTimeout(timer);
|
|
1273
|
-
timer = 0;
|
|
1274
|
-
}
|
|
1275
|
-
active = null;
|
|
1276
|
-
activeKey = null;
|
|
1277
|
-
if (tip) {
|
|
1278
|
-
tip.hidden = true;
|
|
1279
|
-
tip.classList.remove("show");
|
|
1280
|
-
}
|
|
1281
|
-
}
|
|
1282
|
-
function schedule(anchor) {
|
|
1283
|
-
if (anchor === active) return;
|
|
1284
|
-
if (timer) window.clearTimeout(timer);
|
|
1285
|
-
timer = window.setTimeout(() => show(anchor), SHOW_DELAY);
|
|
1286
|
-
}
|
|
1287
|
-
function tipAt(key, rect, text) {
|
|
1288
|
-
if (key === activeKey) {
|
|
1289
|
-
if (tip && !tip.hidden) {
|
|
1290
|
-
renderTip(tip, text);
|
|
1291
|
-
place(rect);
|
|
1292
|
-
}
|
|
1293
|
-
return;
|
|
1294
|
-
}
|
|
1295
|
-
hide();
|
|
1296
|
-
activeKey = key;
|
|
1297
|
-
timer = window.setTimeout(() => {
|
|
1298
|
-
timer = 0;
|
|
1299
|
-
paint(rect, text);
|
|
1300
|
-
}, SHOW_DELAY);
|
|
1301
|
-
}
|
|
1302
|
-
function hideTip() {
|
|
1303
|
-
hide();
|
|
1304
|
-
}
|
|
1305
|
-
var tipAncestor = (n) => n instanceof Element ? n.closest("[data-tip]") : null;
|
|
1306
|
-
function initTooltips(opts = {}) {
|
|
1307
|
-
if (inited) return;
|
|
1308
|
-
inited = true;
|
|
1309
|
-
suppressed = opts.suppressed;
|
|
1310
|
-
document.addEventListener("pointerover", (e) => {
|
|
1311
|
-
const el2 = tipAncestor(e.target);
|
|
1312
|
-
if (el2) schedule(el2);
|
|
1313
|
-
});
|
|
1314
|
-
document.addEventListener("pointerout", (e) => {
|
|
1315
|
-
const el2 = tipAncestor(e.target);
|
|
1316
|
-
if (!el2) return;
|
|
1317
|
-
const to = e.relatedTarget;
|
|
1318
|
-
if (to instanceof Node && el2.contains(to)) return;
|
|
1319
|
-
hide();
|
|
1320
|
-
});
|
|
1321
|
-
document.addEventListener("focusin", (e) => {
|
|
1322
|
-
const el2 = tipAncestor(e.target);
|
|
1323
|
-
if (el2) schedule(el2);
|
|
1324
|
-
});
|
|
1325
|
-
document.addEventListener("focusout", () => hide());
|
|
1326
|
-
document.addEventListener("pointerdown", () => hide(), true);
|
|
1327
|
-
document.addEventListener("scroll", () => {
|
|
1328
|
-
if (active) hide();
|
|
1329
|
-
}, true);
|
|
1330
|
-
document.addEventListener("keydown", (e) => {
|
|
1331
|
-
if (e.key === "Escape") hide();
|
|
1332
|
-
});
|
|
1333
|
-
window.addEventListener("blur", () => hide());
|
|
1334
|
-
}
|
|
1335
|
-
|
|
1336
1371
|
// src/save.ts
|
|
1337
1372
|
function createSaveController(opts) {
|
|
1338
1373
|
const delayMs = opts.delayMs ?? 700;
|
|
@@ -1524,6 +1559,8 @@ exports.JOB_PROGRESS = JOB_PROGRESS;
|
|
|
1524
1559
|
exports.PALETTE = PALETTE;
|
|
1525
1560
|
exports.PALETTE_SIZE = PALETTE_SIZE;
|
|
1526
1561
|
exports.PANE_MENU = PANE_MENU;
|
|
1562
|
+
exports.PROPERTY_NAME_HINT = PROPERTY_NAME_HINT;
|
|
1563
|
+
exports.RESERVED_PROPERTY_NAMES = RESERVED_PROPERTY_NAMES;
|
|
1527
1564
|
exports.askIdentity = askIdentity;
|
|
1528
1565
|
exports.closeAnchoredPanel = closeAnchoredPanel;
|
|
1529
1566
|
exports.closeWithExit = closeWithExit;
|
|
@@ -1542,7 +1579,9 @@ exports.icon = icon;
|
|
|
1542
1579
|
exports.iconBtn = iconBtn;
|
|
1543
1580
|
exports.iconSvg = iconSvg;
|
|
1544
1581
|
exports.initTooltips = initTooltips;
|
|
1582
|
+
exports.isCaseOnlyPropertyName = isCaseOnlyPropertyName;
|
|
1545
1583
|
exports.isValidGameId = isValidGameId;
|
|
1584
|
+
exports.isValidPropertyName = isValidPropertyName;
|
|
1546
1585
|
exports.labelled = labelled;
|
|
1547
1586
|
exports.lockControls = lockControls;
|
|
1548
1587
|
exports.lockNotice = lockNotice;
|
|
@@ -1557,6 +1596,7 @@ exports.openNotesEditor = openNotesEditor;
|
|
|
1557
1596
|
exports.paintVcBadges = paintVcBadges;
|
|
1558
1597
|
exports.pinButton = pinButton;
|
|
1559
1598
|
exports.placeAnchored = placeAnchored;
|
|
1599
|
+
exports.propertyNameify = propertyNameify;
|
|
1560
1600
|
exports.renderStepperBar = renderStepperBar;
|
|
1561
1601
|
exports.saveIndicator = saveIndicator;
|
|
1562
1602
|
exports.showAbout = showAbout;
|