@21stware/rpui 0.4.4 → 0.5.4
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/core/live-render.d.ts +6 -0
- package/dist/gallery.d.ts +4 -1
- package/dist/gallery.js +137 -70
- package/dist/gallery.js.map +1 -1
- package/dist/rpui.d.ts +2 -1
- package/dist/rpui.js +25 -0
- package/dist/rpui.js.map +1 -1
- package/dist/serve.js +48 -8
- package/package.json +2 -4
package/dist/gallery.d.ts
CHANGED
|
@@ -2,4 +2,7 @@ export interface RpmlDoc {
|
|
|
2
2
|
path: string;
|
|
3
3
|
source: string;
|
|
4
4
|
}
|
|
5
|
-
export
|
|
5
|
+
export interface GalleryController {
|
|
6
|
+
update(newDocs: RpmlDoc[]): void;
|
|
7
|
+
}
|
|
8
|
+
export declare function mountGallery(docs: RpmlDoc[], host?: HTMLElement): GalleryController;
|
package/dist/gallery.js
CHANGED
|
@@ -1,6 +1,59 @@
|
|
|
1
1
|
var __defProp = Object.defineProperty;
|
|
2
2
|
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
3
3
|
var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
4
|
+
function attr(el, name, fallback = "") {
|
|
5
|
+
return el.getAttribute(name) ?? fallback;
|
|
6
|
+
}
|
|
7
|
+
function intAttr(el, name, fallback) {
|
|
8
|
+
const raw = el.getAttribute(name);
|
|
9
|
+
const value = raw === null || raw === "" ? NaN : Number(raw);
|
|
10
|
+
return Number.isFinite(value) ? value : fallback;
|
|
11
|
+
}
|
|
12
|
+
function escapeHtml(value) {
|
|
13
|
+
return value.replace(/[&<>'"]/g, (c) => ({ "&": "&", "<": "<", ">": ">", "'": "'", '"': """ })[c] || c);
|
|
14
|
+
}
|
|
15
|
+
function csv(el, name, fallback) {
|
|
16
|
+
return attr(el, name, fallback).split(",").map((s) => s.trim()).filter(Boolean);
|
|
17
|
+
}
|
|
18
|
+
const deviceWidths = { web: 1440, ipad: 834, mobile: 390 };
|
|
19
|
+
function resolveWidth(el, fallback) {
|
|
20
|
+
const raw = el.getAttribute("width");
|
|
21
|
+
const width = raw === null || raw === "" ? NaN : Number(raw);
|
|
22
|
+
if (Number.isFinite(width)) return width;
|
|
23
|
+
return deviceWidths[attr(el, "device")] ?? fallback;
|
|
24
|
+
}
|
|
25
|
+
function hasExplicitNumericHeight(el) {
|
|
26
|
+
const raw = el.getAttribute("height");
|
|
27
|
+
return raw !== null && raw !== "" && Number.isFinite(Number(raw));
|
|
28
|
+
}
|
|
29
|
+
function usesAutoHeight(el) {
|
|
30
|
+
const raw = el.getAttribute("height");
|
|
31
|
+
return raw === "auto" || el.hasAttribute("auto-height") || !!el.getAttribute("device") && !hasExplicitNumericHeight(el);
|
|
32
|
+
}
|
|
33
|
+
function resolveHeight(el, fallback) {
|
|
34
|
+
const raw = el.getAttribute("height");
|
|
35
|
+
const height = raw === null || raw === "" ? NaN : Number(raw);
|
|
36
|
+
return Number.isFinite(height) ? height : fallback;
|
|
37
|
+
}
|
|
38
|
+
function isTopAnnotation(node) {
|
|
39
|
+
if (!(node instanceof HTMLElement)) return false;
|
|
40
|
+
const tag = node.tagName.toLowerCase();
|
|
41
|
+
return tag === "annotation-el" || tag === "annotation-el";
|
|
42
|
+
}
|
|
43
|
+
function isGlobalAnnotation(node) {
|
|
44
|
+
return node instanceof HTMLElement && node.tagName.toLowerCase() === "annotation-global-el";
|
|
45
|
+
}
|
|
46
|
+
function isViewportNode(node) {
|
|
47
|
+
if (!(node instanceof HTMLElement)) return false;
|
|
48
|
+
const tag = node.tagName.toLowerCase();
|
|
49
|
+
return tag === "viewport-el" || tag === "viewport-el";
|
|
50
|
+
}
|
|
51
|
+
function define(name, ctor) {
|
|
52
|
+
if (customElements.get(name)) return;
|
|
53
|
+
const Alias = class extends ctor {
|
|
54
|
+
};
|
|
55
|
+
customElements.define(name, Alias);
|
|
56
|
+
}
|
|
4
57
|
const PRIMITIVES = [
|
|
5
58
|
// layout
|
|
6
59
|
"viewport",
|
|
@@ -187,59 +240,6 @@ function parseToPage(source) {
|
|
|
187
240
|
if (!root) throw new Error("RPML parse error: no <page> root element found");
|
|
188
241
|
return root;
|
|
189
242
|
}
|
|
190
|
-
function attr(el, name, fallback = "") {
|
|
191
|
-
return el.getAttribute(name) ?? fallback;
|
|
192
|
-
}
|
|
193
|
-
function intAttr(el, name, fallback) {
|
|
194
|
-
const raw = el.getAttribute(name);
|
|
195
|
-
const value = raw === null || raw === "" ? NaN : Number(raw);
|
|
196
|
-
return Number.isFinite(value) ? value : fallback;
|
|
197
|
-
}
|
|
198
|
-
function escapeHtml(value) {
|
|
199
|
-
return value.replace(/[&<>'"]/g, (c) => ({ "&": "&", "<": "<", ">": ">", "'": "'", '"': """ })[c] || c);
|
|
200
|
-
}
|
|
201
|
-
function csv(el, name, fallback) {
|
|
202
|
-
return attr(el, name, fallback).split(",").map((s) => s.trim()).filter(Boolean);
|
|
203
|
-
}
|
|
204
|
-
const deviceWidths = { web: 1440, ipad: 834, mobile: 390 };
|
|
205
|
-
function resolveWidth(el, fallback) {
|
|
206
|
-
const raw = el.getAttribute("width");
|
|
207
|
-
const width = raw === null || raw === "" ? NaN : Number(raw);
|
|
208
|
-
if (Number.isFinite(width)) return width;
|
|
209
|
-
return deviceWidths[attr(el, "device")] ?? fallback;
|
|
210
|
-
}
|
|
211
|
-
function hasExplicitNumericHeight(el) {
|
|
212
|
-
const raw = el.getAttribute("height");
|
|
213
|
-
return raw !== null && raw !== "" && Number.isFinite(Number(raw));
|
|
214
|
-
}
|
|
215
|
-
function usesAutoHeight(el) {
|
|
216
|
-
const raw = el.getAttribute("height");
|
|
217
|
-
return raw === "auto" || el.hasAttribute("auto-height") || !!el.getAttribute("device") && !hasExplicitNumericHeight(el);
|
|
218
|
-
}
|
|
219
|
-
function resolveHeight(el, fallback) {
|
|
220
|
-
const raw = el.getAttribute("height");
|
|
221
|
-
const height = raw === null || raw === "" ? NaN : Number(raw);
|
|
222
|
-
return Number.isFinite(height) ? height : fallback;
|
|
223
|
-
}
|
|
224
|
-
function isTopAnnotation(node) {
|
|
225
|
-
if (!(node instanceof HTMLElement)) return false;
|
|
226
|
-
const tag = node.tagName.toLowerCase();
|
|
227
|
-
return tag === "annotation-el" || tag === "annotation-el";
|
|
228
|
-
}
|
|
229
|
-
function isGlobalAnnotation(node) {
|
|
230
|
-
return node instanceof HTMLElement && node.tagName.toLowerCase() === "annotation-global-el";
|
|
231
|
-
}
|
|
232
|
-
function isViewportNode(node) {
|
|
233
|
-
if (!(node instanceof HTMLElement)) return false;
|
|
234
|
-
const tag = node.tagName.toLowerCase();
|
|
235
|
-
return tag === "viewport-el" || tag === "viewport-el";
|
|
236
|
-
}
|
|
237
|
-
function define(name, ctor) {
|
|
238
|
-
if (customElements.get(name)) return;
|
|
239
|
-
const Alias = class extends ctor {
|
|
240
|
-
};
|
|
241
|
-
customElements.define(name, Alias);
|
|
242
|
-
}
|
|
243
243
|
const RPUI_STYLE_ID = "rpui-runtime-style";
|
|
244
244
|
const style = `
|
|
245
245
|
:root { --rp-bg:#f0f2f5; --rp-surface:#fff; --rp-surface-soft:#f9fafb; --rp-text:#111827; --rp-muted:#6b7280; --rp-border:#e5e7eb; --rp-border-strong:#d1d5db; --rp-primary:#2563eb; --rp-success:#059669; --rp-warning:#d97706; --rp-danger:#dc2626; --rp-purple:#7c3aed; --rp-radius-sm:4px; --rp-radius-md:8px; --rp-radius-lg:12px; --rp-shadow:0 8px 28px rgba(15,23,42,.08); --rp-font:-apple-system,BlinkMacSystemFont,"Segoe UI",sans-serif; }
|
|
@@ -99584,6 +99584,30 @@ function registerAll() {
|
|
|
99584
99584
|
define(toComponentTag(suffix), ctor);
|
|
99585
99585
|
}
|
|
99586
99586
|
}
|
|
99587
|
+
function liveRender(host, source, opts = {}) {
|
|
99588
|
+
const { scroller, preserve = true, onError } = opts;
|
|
99589
|
+
const sc = scroller ?? document.scrollingElement ?? document.documentElement;
|
|
99590
|
+
const pane = preserve ? host.querySelector(".annotation-el-pane") : null;
|
|
99591
|
+
const pos = preserve ? { x: sc.scrollLeft, y: sc.scrollTop, px: (pane == null ? void 0 : pane.scrollLeft) ?? 0, py: (pane == null ? void 0 : pane.scrollTop) ?? 0 } : null;
|
|
99592
|
+
try {
|
|
99593
|
+
host.replaceChildren(parseToPage(source));
|
|
99594
|
+
onError == null ? void 0 : onError(null);
|
|
99595
|
+
} catch (e) {
|
|
99596
|
+
onError == null ? void 0 : onError(e.message ?? String(e));
|
|
99597
|
+
return;
|
|
99598
|
+
}
|
|
99599
|
+
if (pos) {
|
|
99600
|
+
requestAnimationFrame(() => requestAnimationFrame(() => {
|
|
99601
|
+
sc.scrollLeft = pos.x;
|
|
99602
|
+
sc.scrollTop = pos.y;
|
|
99603
|
+
const newPane = host.querySelector(".annotation-el-pane");
|
|
99604
|
+
if (newPane) {
|
|
99605
|
+
newPane.scrollLeft = pos.px;
|
|
99606
|
+
newPane.scrollTop = pos.py;
|
|
99607
|
+
}
|
|
99608
|
+
}));
|
|
99609
|
+
}
|
|
99610
|
+
}
|
|
99587
99611
|
registerAll();
|
|
99588
99612
|
const THEME_STYLE_ID = "rpml-theme-style";
|
|
99589
99613
|
const ATTR = "data-rpml-theme";
|
|
@@ -99721,14 +99745,13 @@ function resolveAnchorTarget(to, fromPath, paths) {
|
|
|
99721
99745
|
}
|
|
99722
99746
|
function mountGallery(docs, host = document.body) {
|
|
99723
99747
|
injectChrome();
|
|
99724
|
-
|
|
99725
|
-
|
|
99748
|
+
let byPath = new Map(docs.map((d) => [d.path, d]));
|
|
99749
|
+
let tree = buildTree(docs);
|
|
99726
99750
|
const root = document.createElement("div");
|
|
99727
99751
|
root.className = "rpml-gallery";
|
|
99728
99752
|
const side = document.createElement("aside");
|
|
99729
99753
|
side.className = "rpml-gx-side";
|
|
99730
|
-
|
|
99731
|
-
side.innerHTML = `<div class="rpml-gx-head"><span>RPML 文档<small>${count} 个文件</small></span><div class="rpml-gx-head-actions"><button class="rpml-gx-btn rpml-gx-theme" type="button" title="切换亮色/暗色" aria-label="切换亮色/暗色">◑</button><button class="rpml-gx-btn rpml-gx-toggle" type="button" title="收起侧边栏" aria-label="收起侧边栏">«</button></div></div>`;
|
|
99754
|
+
side.innerHTML = `<div class="rpml-gx-head"><span>RPML 文档<small>${docs.length} 个文件</small></span><div class="rpml-gx-head-actions"><button class="rpml-gx-btn rpml-gx-theme" type="button" title="切换亮色/暗色" aria-label="切换亮色/暗色">◑</button><button class="rpml-gx-btn rpml-gx-toggle" type="button" title="收起侧边栏" aria-label="收起侧边栏">«</button></div></div>`;
|
|
99732
99755
|
const nav = document.createElement("nav");
|
|
99733
99756
|
nav.className = "rpml-gx-nav";
|
|
99734
99757
|
side.appendChild(nav);
|
|
@@ -99781,25 +99804,34 @@ function mountGallery(docs, host = document.body) {
|
|
|
99781
99804
|
}
|
|
99782
99805
|
}
|
|
99783
99806
|
renderNav(tree, 0);
|
|
99807
|
+
function rebuildNav(newDocs) {
|
|
99808
|
+
nav.innerHTML = "";
|
|
99809
|
+
links.clear();
|
|
99810
|
+
tree = buildTree(newDocs);
|
|
99811
|
+
renderNav(tree, 0);
|
|
99812
|
+
side.querySelector(".rpml-gx-head small").textContent = `${newDocs.length} 个文件`;
|
|
99813
|
+
}
|
|
99784
99814
|
function pickDefault() {
|
|
99785
|
-
const
|
|
99786
|
-
|
|
99815
|
+
const cur = [...byPath.values()];
|
|
99816
|
+
const idx = cur.find((d) => basename(d.path).replace(/\.rpml$/i, "").toLowerCase() === "index");
|
|
99817
|
+
return (idx ?? cur[0]).path;
|
|
99787
99818
|
}
|
|
99788
99819
|
let currentPath = "";
|
|
99789
|
-
function show(path, section) {
|
|
99820
|
+
function show(path, section, preserve = false) {
|
|
99790
99821
|
const doc = byPath.get(path);
|
|
99791
99822
|
if (!doc) {
|
|
99792
99823
|
main.innerHTML = `<div class="rpml-gx-err">未找到文档:${path}</div>`;
|
|
99793
99824
|
return;
|
|
99794
99825
|
}
|
|
99795
|
-
|
|
99796
|
-
main
|
|
99797
|
-
|
|
99798
|
-
|
|
99799
|
-
|
|
99800
|
-
|
|
99801
|
-
}
|
|
99802
|
-
|
|
99826
|
+
liveRender(main, doc.source, {
|
|
99827
|
+
scroller: main,
|
|
99828
|
+
preserve,
|
|
99829
|
+
onError: (msg) => {
|
|
99830
|
+
if (msg) main.innerHTML = `<div class="rpml-gx-err">RPML 解析错误:${msg}</div>`;
|
|
99831
|
+
}
|
|
99832
|
+
});
|
|
99833
|
+
currentPath = path;
|
|
99834
|
+
links.forEach((row, p) => row.classList.toggle("active", p === path));
|
|
99803
99835
|
if (section) {
|
|
99804
99836
|
requestAnimationFrame(() => requestAnimationFrame(() => window.dispatchEvent(new CustomEvent("rp-section", { detail: section }))));
|
|
99805
99837
|
}
|
|
@@ -99843,11 +99875,46 @@ function mountGallery(docs, host = document.body) {
|
|
|
99843
99875
|
});
|
|
99844
99876
|
window.addEventListener("popstate", route);
|
|
99845
99877
|
route();
|
|
99878
|
+
const controller = {
|
|
99879
|
+
update(newDocs) {
|
|
99880
|
+
var _a2;
|
|
99881
|
+
const prevSource = (_a2 = byPath.get(currentPath)) == null ? void 0 : _a2.source;
|
|
99882
|
+
byPath = new Map(newDocs.map((d) => [d.path, d]));
|
|
99883
|
+
const newPaths = newDocs.map((d) => d.path).sort().join("\0");
|
|
99884
|
+
const oldPaths = [...links.keys()].sort().join("\0");
|
|
99885
|
+
if (newPaths !== oldPaths) rebuildNav(newDocs);
|
|
99886
|
+
const curr = byPath.get(currentPath);
|
|
99887
|
+
if (curr) {
|
|
99888
|
+
if (curr.source !== prevSource) show(currentPath, void 0, true);
|
|
99889
|
+
else links.forEach((row, p) => row.classList.toggle("active", p === currentPath));
|
|
99890
|
+
} else if (newDocs.length) {
|
|
99891
|
+
const def = pickDefault();
|
|
99892
|
+
history.replaceState(null, "", `#${def}`);
|
|
99893
|
+
show(def);
|
|
99894
|
+
}
|
|
99895
|
+
}
|
|
99896
|
+
};
|
|
99897
|
+
globalThis.__RPML_GALLERY__ = controller;
|
|
99898
|
+
return controller;
|
|
99846
99899
|
}
|
|
99847
99900
|
const inlined = globalThis.__RPML_DOCS__;
|
|
99848
99901
|
if (inlined && Array.isArray(inlined) && inlined.length) {
|
|
99849
|
-
|
|
99850
|
-
|
|
99902
|
+
const mount = () => {
|
|
99903
|
+
mountGallery(inlined);
|
|
99904
|
+
if (globalThis.__RPML_LIVE__) {
|
|
99905
|
+
const es = new EventSource("/~live");
|
|
99906
|
+
es.onmessage = (ev) => {
|
|
99907
|
+
var _a2;
|
|
99908
|
+
try {
|
|
99909
|
+
const docs = JSON.parse(ev.data);
|
|
99910
|
+
(_a2 = globalThis.__RPML_GALLERY__) == null ? void 0 : _a2.update(docs);
|
|
99911
|
+
} catch {
|
|
99912
|
+
}
|
|
99913
|
+
};
|
|
99914
|
+
}
|
|
99915
|
+
};
|
|
99916
|
+
if (document.readyState === "loading") document.addEventListener("DOMContentLoaded", mount);
|
|
99917
|
+
else mount();
|
|
99851
99918
|
}
|
|
99852
99919
|
export {
|
|
99853
99920
|
mountGallery
|