vitral 0.1.0 → 0.2.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/README.md +250 -217
- package/dist/angular.d.ts +15 -4
- package/dist/angular.js +25 -5
- package/dist/auto.d.ts +2 -0
- package/dist/auto.js +12 -0
- package/dist/chunk-2XF5BKV3.js +190 -0
- package/dist/chunk-6Y3VMWHH.js +181 -0
- package/dist/chunk-DXORSF4X.js +42 -0
- package/dist/chunk-GNPFWISJ.js +80 -0
- package/dist/chunk-HP6QWU6K.js +51 -0
- package/dist/chunk-NCONW6WS.js +606 -0
- package/dist/chunk-PX7PBCCT.js +89 -0
- package/dist/chunk-S5MZT5IT.js +20 -0
- package/dist/chunk-SFL6LTP3.js +56 -0
- package/dist/chunk-UTYAX6MU.js +152 -0
- package/dist/cli.d.ts +1 -0
- package/dist/cli.js +88 -0
- package/dist/dedupe-IWFIXRWG.js +81 -0
- package/dist/devtools.d.ts +12 -0
- package/dist/devtools.js +86 -0
- package/dist/element.d.ts +60 -2
- package/dist/element.js +9 -2
- package/dist/errors-KKB8FGCz.d.ts +11 -0
- package/dist/events-DUdjhfps.d.ts +6 -0
- package/dist/expose-53BEJB34.js +14 -0
- package/dist/host-slot-Cz6EiGsB.d.ts +6 -0
- package/dist/iframe.d.ts +28 -0
- package/dist/iframe.js +236 -0
- package/dist/index.d.ts +142 -147
- package/dist/index.js +39 -10
- package/dist/navigate-BRG1WJUM.d.ts +9 -0
- package/dist/overrides-NZAIUGK5.js +15 -0
- package/dist/preact.d.ts +30 -7
- package/dist/preact.js +37 -9
- package/dist/react.d.ts +38 -7
- package/dist/react.js +92 -42
- package/dist/routes.d.ts +56 -0
- package/dist/routes.js +143 -0
- package/dist/shadow-MYRJQLLY.js +72 -0
- package/dist/slot-pB276oPt.d.ts +36 -0
- package/dist/solid.d.ts +29 -6
- package/dist/solid.js +31 -8
- package/dist/sri-BVKZNX5Q.js +114 -0
- package/dist/state-BDdCwc21.d.ts +4 -0
- package/dist/svelte.d.ts +19 -3
- package/dist/svelte.js +10 -4
- package/dist/testing.d.ts +2 -2
- package/dist/testing.js +8 -3
- package/dist/types-BV-hUrms.d.ts +265 -0
- package/dist/vite.d.ts +58 -4
- package/dist/vite.js +714 -24
- package/dist/vue.d.ts +79 -7
- package/dist/vue.js +69 -46
- package/package.json +144 -8
- package/dist/chunk-IZK6ITIJ.js +0 -96
- package/dist/chunk-TTL52BF2.js +0 -547
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import {
|
|
2
|
+
addLink
|
|
3
|
+
} from "./chunk-PX7PBCCT.js";
|
|
4
|
+
import {
|
|
5
|
+
protocol
|
|
6
|
+
} from "./chunk-GNPFWISJ.js";
|
|
7
|
+
|
|
8
|
+
// src/core/css.ts
|
|
9
|
+
var loadedCss = /* @__PURE__ */ new WeakMap();
|
|
10
|
+
var cssText = /* @__PURE__ */ new Map();
|
|
11
|
+
var noop = () => {
|
|
12
|
+
};
|
|
13
|
+
var adopts = () => typeof CSSStyleSheet !== "undefined" && "replaceSync" in CSSStyleSheet.prototype;
|
|
14
|
+
function fetchCssText(href, integrity, priority) {
|
|
15
|
+
let p = cssText.get(href);
|
|
16
|
+
if (!p) {
|
|
17
|
+
p = fetch(href, { credentials: "omit", integrity, priority }).then((r) => r.ok ? r.text() : "").catch(() => "");
|
|
18
|
+
cssText.set(href, p);
|
|
19
|
+
}
|
|
20
|
+
return p;
|
|
21
|
+
}
|
|
22
|
+
function prefetchCss(urls, shadow, sri = {}, priority = "auto") {
|
|
23
|
+
for (const href of urls) {
|
|
24
|
+
if (shadow && adopts()) void fetchCssText(href, sri[href], priority);
|
|
25
|
+
else if (!document.querySelector(`link[href="${href}"]`)) addLink("preload", href, { as: "style", integrity: sri[href] ?? "", fetchPriority: priority });
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
function injectStyles(urls, root, el, styles, sri = {}) {
|
|
29
|
+
return root ? import("./shadow-MYRJQLLY.js").then((m) => m.attachStyles(root, el, urls, protocol().settings().styles, styles, sri)) : injectCss(urls, null, sri).then(() => noop);
|
|
30
|
+
}
|
|
31
|
+
function injectCss(urls, root, sri = {}) {
|
|
32
|
+
const owner = root ?? document;
|
|
33
|
+
let seen = loadedCss.get(owner);
|
|
34
|
+
if (!seen) loadedCss.set(owner, seen = /* @__PURE__ */ new Map());
|
|
35
|
+
const parent = root ?? document.head;
|
|
36
|
+
return Promise.all(
|
|
37
|
+
urls.map((href) => {
|
|
38
|
+
let p = seen.get(href);
|
|
39
|
+
if (!p) {
|
|
40
|
+
p = new Promise((resolve) => {
|
|
41
|
+
const link = addLink("stylesheet", href, { integrity: sri[href] ?? "" }, parent);
|
|
42
|
+
link.onload = link.onerror = () => resolve();
|
|
43
|
+
});
|
|
44
|
+
seen.set(href, p);
|
|
45
|
+
}
|
|
46
|
+
return p;
|
|
47
|
+
})
|
|
48
|
+
);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export {
|
|
52
|
+
fetchCssText,
|
|
53
|
+
prefetchCss,
|
|
54
|
+
injectStyles,
|
|
55
|
+
injectCss
|
|
56
|
+
};
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
import {
|
|
2
|
+
createSlot
|
|
3
|
+
} from "./chunk-NCONW6WS.js";
|
|
4
|
+
import {
|
|
5
|
+
preload,
|
|
6
|
+
registerSrc
|
|
7
|
+
} from "./chunk-2XF5BKV3.js";
|
|
8
|
+
|
|
9
|
+
// src/core/host-slot.ts
|
|
10
|
+
var noop = () => {
|
|
11
|
+
};
|
|
12
|
+
function timings(name) {
|
|
13
|
+
const out = {};
|
|
14
|
+
if (typeof performance === "undefined" || !performance.getEntriesByName) return out;
|
|
15
|
+
for (const stage of ["manifest", "js", "css", "mount"]) {
|
|
16
|
+
const m = performance.getEntriesByName(`vitral:${name}:${stage}`, "measure").pop();
|
|
17
|
+
if (m) out[stage] = Math.round(m.duration * 10) / 10;
|
|
18
|
+
}
|
|
19
|
+
return out;
|
|
20
|
+
}
|
|
21
|
+
function when(el, mode, fn) {
|
|
22
|
+
if (mode === "lazy" || mode === "visible") {
|
|
23
|
+
if (typeof IntersectionObserver === "undefined") return fn(), noop;
|
|
24
|
+
const io = new IntersectionObserver(
|
|
25
|
+
(entries) => {
|
|
26
|
+
if (entries.some((e) => e.isIntersecting)) io.disconnect(), fn();
|
|
27
|
+
},
|
|
28
|
+
{ rootMargin: "200px" }
|
|
29
|
+
);
|
|
30
|
+
io.observe(el);
|
|
31
|
+
return () => io.disconnect();
|
|
32
|
+
}
|
|
33
|
+
if (mode === "idle") {
|
|
34
|
+
if (typeof requestIdleCallback === "undefined") {
|
|
35
|
+
const t = setTimeout(fn, 1);
|
|
36
|
+
return () => clearTimeout(t);
|
|
37
|
+
}
|
|
38
|
+
const id = requestIdleCallback(fn, { timeout: 2e3 });
|
|
39
|
+
return () => cancelIdleCallback(id);
|
|
40
|
+
}
|
|
41
|
+
if (mode === "hover") {
|
|
42
|
+
const go = () => (off(), fn());
|
|
43
|
+
const off = () => {
|
|
44
|
+
el.removeEventListener("pointerenter", go);
|
|
45
|
+
el.removeEventListener("focusin", go);
|
|
46
|
+
};
|
|
47
|
+
el.addEventListener("pointerenter", go);
|
|
48
|
+
el.addEventListener("focusin", go);
|
|
49
|
+
return off;
|
|
50
|
+
}
|
|
51
|
+
fn();
|
|
52
|
+
return noop;
|
|
53
|
+
}
|
|
54
|
+
var kept = /* @__PURE__ */ new Map();
|
|
55
|
+
var shelf = null;
|
|
56
|
+
function move(parent, node) {
|
|
57
|
+
try {
|
|
58
|
+
;
|
|
59
|
+
parent.moveBefore(node, null);
|
|
60
|
+
} catch {
|
|
61
|
+
parent.appendChild(node);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
function signal(node, type) {
|
|
65
|
+
for (const el of node.querySelectorAll("*")) {
|
|
66
|
+
if (el.hasAttribute("data-vitral-root")) el.dispatchEvent(new Event(type));
|
|
67
|
+
if (el.shadowRoot) signal(el.shadowRoot, type);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
function park(key, item, max) {
|
|
71
|
+
kept.get(key)?.slot.destroy();
|
|
72
|
+
kept.delete(key);
|
|
73
|
+
if (!shelf?.isConnected) {
|
|
74
|
+
shelf = document.createElement("div");
|
|
75
|
+
shelf.hidden = true;
|
|
76
|
+
shelf.setAttribute("data-vitral-keep-alive", "");
|
|
77
|
+
document.body.appendChild(shelf);
|
|
78
|
+
}
|
|
79
|
+
move(shelf, item.box);
|
|
80
|
+
signal(item.box, "vitral:deactivate");
|
|
81
|
+
kept.set(key, item);
|
|
82
|
+
for (const [k, old] of kept) {
|
|
83
|
+
if (kept.size <= max) break;
|
|
84
|
+
kept.delete(k);
|
|
85
|
+
old.slot.destroy();
|
|
86
|
+
old.box.remove();
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
function hostSlot(target, options) {
|
|
90
|
+
let { props = {}, keepAlive } = options;
|
|
91
|
+
const key = (o) => o.src ? registerSrc(o.src, o.name) : o.name ?? "";
|
|
92
|
+
let name = key(options);
|
|
93
|
+
let status = "loading";
|
|
94
|
+
let item = null;
|
|
95
|
+
const onStatus = (s, e) => {
|
|
96
|
+
status = s;
|
|
97
|
+
options.onStatus?.(s, e);
|
|
98
|
+
};
|
|
99
|
+
const cancelPrefetch = options.prefetch ? when(target, options.prefetch, () => preload(name)) : noop;
|
|
100
|
+
const cancel = when(target, options.loading, () => {
|
|
101
|
+
cancelPrefetch();
|
|
102
|
+
const found = keepAlive ? kept.get(name) : void 0;
|
|
103
|
+
if (found) {
|
|
104
|
+
kept.delete(name);
|
|
105
|
+
item = found;
|
|
106
|
+
item.on = onStatus;
|
|
107
|
+
move(target, item.box);
|
|
108
|
+
item.slot.update(props);
|
|
109
|
+
signal(item.box, "vitral:activate");
|
|
110
|
+
onStatus(item.slot.status, null);
|
|
111
|
+
return;
|
|
112
|
+
}
|
|
113
|
+
let box = target;
|
|
114
|
+
if (keepAlive) {
|
|
115
|
+
box = target.appendChild(document.createElement("div"));
|
|
116
|
+
box.style.display = "contents";
|
|
117
|
+
}
|
|
118
|
+
const it = { box, on: onStatus, slot: null };
|
|
119
|
+
it.slot = createSlot(box, { ...options, name, src: void 0, props, onStatus: (s, e) => it.on(s, e) });
|
|
120
|
+
item = it;
|
|
121
|
+
});
|
|
122
|
+
return {
|
|
123
|
+
update(next) {
|
|
124
|
+
props = next;
|
|
125
|
+
item?.slot.update(next);
|
|
126
|
+
},
|
|
127
|
+
set(next) {
|
|
128
|
+
if (next.src || next.name !== void 0) name = key(next);
|
|
129
|
+
item?.slot.set({ ...next, src: void 0, name });
|
|
130
|
+
},
|
|
131
|
+
retry: () => item?.slot.retry(),
|
|
132
|
+
destroy() {
|
|
133
|
+
cancel();
|
|
134
|
+
cancelPrefetch();
|
|
135
|
+
if (!item) return;
|
|
136
|
+
if (keepAlive && status === "ready") park(name, item, keepAlive === true ? 5 : keepAlive);
|
|
137
|
+
else {
|
|
138
|
+
item.slot.destroy();
|
|
139
|
+
if (item.box !== target) item.box.remove();
|
|
140
|
+
}
|
|
141
|
+
item = null;
|
|
142
|
+
},
|
|
143
|
+
get status() {
|
|
144
|
+
return status;
|
|
145
|
+
}
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
export {
|
|
150
|
+
timings,
|
|
151
|
+
hostSlot
|
|
152
|
+
};
|
package/dist/cli.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
package/dist/cli.js
ADDED
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
// src/cli/types.ts
|
|
4
|
+
import { existsSync, readFileSync, writeFileSync } from "fs";
|
|
5
|
+
import { resolve } from "path";
|
|
6
|
+
var PROPS = /export type Props =\s*([\s\S]*?)\s*$/;
|
|
7
|
+
function parseProps(dts) {
|
|
8
|
+
return PROPS.exec(dts.replace(/^\s*\/\/.*$/gm, "").trim())?.[1]?.replace(/;$/, "") || null;
|
|
9
|
+
}
|
|
10
|
+
function envFile(props) {
|
|
11
|
+
const lines = Object.entries(props).map(([name, type]) => ` ${JSON.stringify(name)}: ${type}`);
|
|
12
|
+
return `// Gerado por \`npx vitral types\`. N\xE3o edite.
|
|
13
|
+
import 'vitral'
|
|
14
|
+
|
|
15
|
+
declare module 'vitral' {
|
|
16
|
+
interface Remotes {
|
|
17
|
+
${lines.join("\n")}
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
`;
|
|
21
|
+
}
|
|
22
|
+
function readRemotes(cwd, args2, base) {
|
|
23
|
+
const pairs = args2.filter((a) => a.includes("="));
|
|
24
|
+
if (pairs.length) return Object.fromEntries(pairs.map((p) => [p.slice(0, p.indexOf("=")), p.slice(p.indexOf("=") + 1)]));
|
|
25
|
+
const file = [args2[0], "public/remotes.json", "remotes.json"].find((f) => f && existsSync(resolve(cwd, f)));
|
|
26
|
+
if (!file) throw new Error("[vitral] remotes.json n\xE3o encontrado. Passe o caminho ou pares nome=url.");
|
|
27
|
+
const map = JSON.parse(readFileSync(resolve(cwd, file), "utf8"));
|
|
28
|
+
return Object.fromEntries(
|
|
29
|
+
Object.entries(map).map(([name, v]) => {
|
|
30
|
+
const url = typeof v === "string" ? v : v.url;
|
|
31
|
+
return [name, base ? new URL(url, base).href : url];
|
|
32
|
+
})
|
|
33
|
+
);
|
|
34
|
+
}
|
|
35
|
+
async function types(options = {}) {
|
|
36
|
+
const cwd = options.cwd ?? process.cwd();
|
|
37
|
+
const get = options.fetch ?? fetch;
|
|
38
|
+
const log = options.log ?? console.log;
|
|
39
|
+
const remotes = readRemotes(cwd, options.args ?? [], options.base);
|
|
40
|
+
const props = {};
|
|
41
|
+
let falhas = 0;
|
|
42
|
+
for (const [name, url] of Object.entries(remotes)) {
|
|
43
|
+
let dts;
|
|
44
|
+
try {
|
|
45
|
+
const res = await get(new URL("vitral.d.ts", url).href);
|
|
46
|
+
if (!res.ok) throw new Error(`HTTP ${res.status}`);
|
|
47
|
+
dts = await res.text();
|
|
48
|
+
} catch (err) {
|
|
49
|
+
log(`[vitral] ${name}: sem tipos (${err.message}).`);
|
|
50
|
+
falhas++;
|
|
51
|
+
continue;
|
|
52
|
+
}
|
|
53
|
+
const type = parseProps(dts);
|
|
54
|
+
if (type) props[name] = type;
|
|
55
|
+
else log(`[vitral] ${name}: vitral.d.ts sem "export type Props".`);
|
|
56
|
+
}
|
|
57
|
+
const out = resolve(cwd, options.out ?? "vitral-env.d.ts");
|
|
58
|
+
writeFileSync(out, envFile(props));
|
|
59
|
+
log(`[vitral] ${Object.keys(props).length} remote(s) em ${out}`);
|
|
60
|
+
return falhas;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// src/cli.ts
|
|
64
|
+
var AJUDA = `Uso: vitral types [remotes.json | nome=url ...] [--base url] [--out arquivo]
|
|
65
|
+
|
|
66
|
+
Baixa o vitral.d.ts de cada remote e gera vitral-env.d.ts.`;
|
|
67
|
+
function flag(args2, name) {
|
|
68
|
+
const i = args2.indexOf(name);
|
|
69
|
+
if (i < 0) return void 0;
|
|
70
|
+
const value = args2[i + 1];
|
|
71
|
+
args2.splice(i, 2);
|
|
72
|
+
return value;
|
|
73
|
+
}
|
|
74
|
+
var [command, ...args] = process.argv.slice(2);
|
|
75
|
+
if (command === "types") {
|
|
76
|
+
const base = flag(args, "--base");
|
|
77
|
+
const out = flag(args, "--out");
|
|
78
|
+
types({ args, base, out }).then(
|
|
79
|
+
(falhas) => process.exitCode = falhas ? 1 : 0,
|
|
80
|
+
(err) => {
|
|
81
|
+
console.error(err.message);
|
|
82
|
+
process.exitCode = 1;
|
|
83
|
+
}
|
|
84
|
+
);
|
|
85
|
+
} else {
|
|
86
|
+
console.log(AJUDA);
|
|
87
|
+
process.exitCode = command && command !== "--help" ? 1 : 0;
|
|
88
|
+
}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
// src/core/semver.ts
|
|
2
|
+
function satisfies(version, range) {
|
|
3
|
+
if (range === "*") return true;
|
|
4
|
+
const [, op = "", want = ""] = /^(\^|~|>=|=)?(.*)$/.exec(range.trim());
|
|
5
|
+
if (!op || op === "=" || version.includes("-")) return version === want;
|
|
6
|
+
const v = version.split(".").map(Number);
|
|
7
|
+
const w = want.split(".").map(Number);
|
|
8
|
+
for (let i = 0; i < 3; i++) if (v[i] !== w[i]) {
|
|
9
|
+
if (!(v[i] > w[i])) return false;
|
|
10
|
+
break;
|
|
11
|
+
}
|
|
12
|
+
if (op === ">=") return true;
|
|
13
|
+
const fixed = op === "~" ? 2 : w[0] ? 1 : w[1] ? 2 : 3;
|
|
14
|
+
return v.slice(0, fixed).join(".") === w.slice(0, fixed).join(".");
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
// src/core/dedupe.ts
|
|
18
|
+
var KEY = "vitral:dedupe:";
|
|
19
|
+
var remembered = (k) => {
|
|
20
|
+
try {
|
|
21
|
+
return localStorage.getItem(KEY + k);
|
|
22
|
+
} catch {
|
|
23
|
+
return null;
|
|
24
|
+
}
|
|
25
|
+
};
|
|
26
|
+
var remember = (k, url) => {
|
|
27
|
+
try {
|
|
28
|
+
localStorage.setItem(KEY + k, url);
|
|
29
|
+
} catch {
|
|
30
|
+
}
|
|
31
|
+
};
|
|
32
|
+
function shared(p) {
|
|
33
|
+
if (!p.dedupe) {
|
|
34
|
+
const offers = /* @__PURE__ */ new Map();
|
|
35
|
+
const waiting = /* @__PURE__ */ new Map();
|
|
36
|
+
const drop = (list, o) => list.includes(o) && list.splice(list.indexOf(o), 1);
|
|
37
|
+
const start = (name, list, o) => {
|
|
38
|
+
if (!o.p) {
|
|
39
|
+
;
|
|
40
|
+
(o.p = o.load()).catch(() => drop(list, o));
|
|
41
|
+
if (o.url) o.p.then(() => remember(`${name}@${o.version}`, o.url), () => {
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
return o.p;
|
|
45
|
+
};
|
|
46
|
+
p.dedupe = (name, range, offer2) => {
|
|
47
|
+
const own = offer2;
|
|
48
|
+
const list = offers.get(name) ?? [];
|
|
49
|
+
offers.set(name, list);
|
|
50
|
+
if (own?.url) waiting.get(name + own.url)?.(own);
|
|
51
|
+
let hit = list.find((o) => satisfies(o.version, range));
|
|
52
|
+
if (!hit && own) {
|
|
53
|
+
hit = list[list.push(own) - 1];
|
|
54
|
+
const want = own.url && remembered(`${name}@${own.version}`);
|
|
55
|
+
if (want && want !== own.url) {
|
|
56
|
+
own.p = new Promise((resolve) => {
|
|
57
|
+
waiting.set(name + want, resolve);
|
|
58
|
+
setTimeout(resolve, 300, own);
|
|
59
|
+
}).then((o) => {
|
|
60
|
+
waiting.delete(name + want);
|
|
61
|
+
if (o === own) own.p = void 0;
|
|
62
|
+
return start(name, list, o);
|
|
63
|
+
});
|
|
64
|
+
own.p.catch(() => drop(list, own));
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
return hit && start(name, list, hit);
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
return p.dedupe;
|
|
71
|
+
}
|
|
72
|
+
function offer(p, groups) {
|
|
73
|
+
for (const name in groups) {
|
|
74
|
+
const { version, modules } = groups[name];
|
|
75
|
+
shared(p)(name, version, { version, load: async () => modules });
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
export {
|
|
79
|
+
offer,
|
|
80
|
+
shared
|
|
81
|
+
};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/** Overrides salvos neste navegador: `{ nome: url }`. */
|
|
2
|
+
declare function getOverrides(): Record<string, string>;
|
|
3
|
+
/** Salva (ou remove, com `null`) o override de um remote. Vale a partir do próximo carregamento. */
|
|
4
|
+
declare function setOverride(name: string, url: string | null): void;
|
|
5
|
+
interface DevtoolsOptions {
|
|
6
|
+
/** Recarrega a página depois de mudar um override. Padrão: true. */
|
|
7
|
+
reload?: boolean;
|
|
8
|
+
}
|
|
9
|
+
/** Mostra o painel no canto da página. Devolve uma função que o remove. */
|
|
10
|
+
declare function devtools(options?: DevtoolsOptions): () => void;
|
|
11
|
+
|
|
12
|
+
export { type DevtoolsOptions, devtools, getOverrides, setOverride };
|
package/dist/devtools.js
ADDED
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import {
|
|
2
|
+
OVERRIDES_KEY,
|
|
3
|
+
manifestUrl,
|
|
4
|
+
overridesEnabled,
|
|
5
|
+
storedOverrides
|
|
6
|
+
} from "./chunk-DXORSF4X.js";
|
|
7
|
+
import "./chunk-GNPFWISJ.js";
|
|
8
|
+
|
|
9
|
+
// src/devtools.ts
|
|
10
|
+
function getOverrides() {
|
|
11
|
+
return storedOverrides();
|
|
12
|
+
}
|
|
13
|
+
function setOverride(name, url) {
|
|
14
|
+
const all = storedOverrides();
|
|
15
|
+
if (url) all[name] = manifestUrl(url);
|
|
16
|
+
else delete all[name];
|
|
17
|
+
if (Object.keys(all).length) localStorage.setItem(OVERRIDES_KEY, JSON.stringify(all));
|
|
18
|
+
else localStorage.removeItem(OVERRIDES_KEY);
|
|
19
|
+
}
|
|
20
|
+
var STYLE = `
|
|
21
|
+
:host { position: fixed; right: 12px; bottom: 12px; z-index: 2147483647; font: 13px/1.4 system-ui, sans-serif; color: #111 }
|
|
22
|
+
button { font: inherit; cursor: pointer }
|
|
23
|
+
.toggle { border: 1px solid #888; border-radius: 6px; background: #fff; padding: 4px 10px }
|
|
24
|
+
.panel { margin-bottom: 8px; padding: 10px; width: 320px; background: #fff; border: 1px solid #888; border-radius: 8px; box-shadow: 0 4px 16px #0003 }
|
|
25
|
+
ul { list-style: none; margin: 0 0 8px; padding: 0 }
|
|
26
|
+
li { display: flex; gap: 6px; align-items: center; margin-bottom: 4px; word-break: break-all }
|
|
27
|
+
form { display: grid; gap: 4px }
|
|
28
|
+
input { font: inherit; padding: 3px 6px }
|
|
29
|
+
.aviso { color: #a40000; margin: 0 0 8px }
|
|
30
|
+
`;
|
|
31
|
+
function devtools(options = {}) {
|
|
32
|
+
const host = document.createElement("div");
|
|
33
|
+
host.setAttribute("data-vitral-devtools", "");
|
|
34
|
+
const root = host.attachShadow({ mode: "open" });
|
|
35
|
+
const style = document.createElement("style");
|
|
36
|
+
style.textContent = STYLE;
|
|
37
|
+
const panel = document.createElement("div");
|
|
38
|
+
panel.className = "panel";
|
|
39
|
+
panel.hidden = true;
|
|
40
|
+
const toggle = document.createElement("button");
|
|
41
|
+
toggle.className = "toggle";
|
|
42
|
+
toggle.type = "button";
|
|
43
|
+
toggle.textContent = "vitral";
|
|
44
|
+
toggle.onclick = () => panel.hidden = !panel.hidden;
|
|
45
|
+
root.append(style, panel, toggle);
|
|
46
|
+
const changed = () => options.reload === false ? draw() : location.reload();
|
|
47
|
+
function draw() {
|
|
48
|
+
panel.replaceChildren();
|
|
49
|
+
if (!overridesEnabled()) {
|
|
50
|
+
const p = document.createElement("p");
|
|
51
|
+
p.className = "aviso";
|
|
52
|
+
p.textContent = "Overrides desligados: use configure({ devOverrides: true }) ou rode em localhost.";
|
|
53
|
+
panel.append(p);
|
|
54
|
+
}
|
|
55
|
+
const list = document.createElement("ul");
|
|
56
|
+
for (const [name2, url2] of Object.entries(storedOverrides())) {
|
|
57
|
+
const item = document.createElement("li");
|
|
58
|
+
const remove = document.createElement("button");
|
|
59
|
+
remove.type = "button";
|
|
60
|
+
remove.textContent = "remover";
|
|
61
|
+
remove.setAttribute("aria-label", `remover override de ${name2}`);
|
|
62
|
+
remove.onclick = () => (setOverride(name2, null), changed());
|
|
63
|
+
item.append(`${name2} \u2192 ${url2}`, remove);
|
|
64
|
+
list.append(item);
|
|
65
|
+
}
|
|
66
|
+
const form = document.createElement("form");
|
|
67
|
+
const name = Object.assign(document.createElement("input"), { placeholder: "nome (ex.: carrinho)", required: true, name: "name" });
|
|
68
|
+
const url = Object.assign(document.createElement("input"), { placeholder: "http://localhost:5174", required: true, name: "url" });
|
|
69
|
+
const save = Object.assign(document.createElement("button"), { type: "submit", textContent: "Salvar" });
|
|
70
|
+
form.append(name, url, save);
|
|
71
|
+
form.onsubmit = (e) => {
|
|
72
|
+
e.preventDefault();
|
|
73
|
+
setOverride(name.value.trim(), url.value.trim());
|
|
74
|
+
changed();
|
|
75
|
+
};
|
|
76
|
+
panel.append(list, form);
|
|
77
|
+
}
|
|
78
|
+
draw();
|
|
79
|
+
document.body.append(host);
|
|
80
|
+
return () => host.remove();
|
|
81
|
+
}
|
|
82
|
+
export {
|
|
83
|
+
devtools,
|
|
84
|
+
getOverrides,
|
|
85
|
+
setOverride
|
|
86
|
+
};
|
package/dist/element.d.ts
CHANGED
|
@@ -1,4 +1,38 @@
|
|
|
1
|
-
import { Props,
|
|
1
|
+
import { P as Props, S as Shared, a as RemoteModule } from './types-BV-hUrms.js';
|
|
2
|
+
import { S as SlotStatus } from './slot-pB276oPt.js';
|
|
3
|
+
import './errors-KKB8FGCz.js';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Host universal: `<vitral-remote>` funciona em qualquer lugar que renderize
|
|
7
|
+
* HTML (JS/TS puro, Angular, Svelte, Solid, Lit, Astro, Qwik, jQuery, server
|
|
8
|
+
* templates…).
|
|
9
|
+
*
|
|
10
|
+
* import { defineVitralElement } from 'vitral/element'
|
|
11
|
+
* defineVitralElement()
|
|
12
|
+
*
|
|
13
|
+
* <vitral-remote name="carrinho" props='{"userId": 42}' isolate="shadow"
|
|
14
|
+
* inherit-styles="/assets/base.css">
|
|
15
|
+
* <p slot="fallback">Carregando…</p>
|
|
16
|
+
* <p slot="error">Indisponível</p>
|
|
17
|
+
* </vitral-remote>
|
|
18
|
+
*
|
|
19
|
+
* <vitral-remote src="https://cdn.exemplo.com/carrinho/vitral.json"></vitral-remote>
|
|
20
|
+
*
|
|
21
|
+
* Sem os slots, mostra um carregando acessível e um erro com "Tentar de novo".
|
|
22
|
+
*
|
|
23
|
+
* el.props = { userId: 43 } // atualiza sem remontar
|
|
24
|
+
* el.addEventListener('vitral-error', (e) => e.detail.error)
|
|
25
|
+
* el.addEventListener('vitral-ready', (e) => e.detail.timings) // { manifest, js, css, mount } em ms
|
|
26
|
+
* el.retry()
|
|
27
|
+
*
|
|
28
|
+
* Atributos de performance: `loading="lazy|idle"` (monta perto de aparecer ou
|
|
29
|
+
* com o navegador ocioso; reserve o espaço com `min-height`),
|
|
30
|
+
* `prefetch="hover|visible|idle"` (baixa antes de montar), `priority="high"`
|
|
31
|
+
* e `keep-alive` (ou `keep-alive="3"`: máximo de remotes guardados).
|
|
32
|
+
*
|
|
33
|
+
* Também exporta `elementRemote()` para publicar um Web Component (Lit,
|
|
34
|
+
* Stencil, vanilla) como remote.
|
|
35
|
+
*/
|
|
2
36
|
|
|
3
37
|
declare const Base: typeof HTMLElement;
|
|
4
38
|
declare class VitralRemoteElement extends Base {
|
|
@@ -21,10 +55,34 @@ declare function defineVitralElement(tag?: string): void;
|
|
|
21
55
|
* export default elementRemote('meu-widget')
|
|
22
56
|
*/
|
|
23
57
|
declare function elementRemote<P extends Props = Props>(tag: string, setup?: () => void): RemoteModule<P>;
|
|
58
|
+
/** O que o `SharedController` precisa do elemento (o `ReactiveControllerHost` do Lit). */
|
|
59
|
+
interface SharedControllerHost {
|
|
60
|
+
addController(controller: {
|
|
61
|
+
hostConnected?(): void;
|
|
62
|
+
hostDisconnected?(): void;
|
|
63
|
+
}): void;
|
|
64
|
+
requestUpdate(): void;
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Controller do Lit para uma chave compartilhada (`provide`/`shared`). Assina
|
|
68
|
+
* enquanto o elemento está conectado e pede um novo render quando o valor
|
|
69
|
+
* (ou o resultado do seletor) muda.
|
|
70
|
+
*
|
|
71
|
+
* usuario = new SharedController(this, 'usuario')
|
|
72
|
+
* render() { return html`${this.usuario.value?.nome}` }
|
|
73
|
+
*/
|
|
74
|
+
declare class SharedController<T = unknown, S = T | undefined> {
|
|
75
|
+
#private;
|
|
76
|
+
/** Valor atual (ou o resultado do seletor). */
|
|
77
|
+
value: S;
|
|
78
|
+
constructor(host: SharedControllerHost, key: keyof Shared | (string & {}), select?: (value: T | undefined) => S);
|
|
79
|
+
hostConnected(): void;
|
|
80
|
+
hostDisconnected(): void;
|
|
81
|
+
}
|
|
24
82
|
declare global {
|
|
25
83
|
interface HTMLElementTagNameMap {
|
|
26
84
|
'vitral-remote': VitralRemoteElement;
|
|
27
85
|
}
|
|
28
86
|
}
|
|
29
87
|
|
|
30
|
-
export { VitralRemoteElement, defineVitralElement, elementRemote };
|
|
88
|
+
export { SharedController, type SharedControllerHost, VitralRemoteElement, defineVitralElement, elementRemote };
|
package/dist/element.js
CHANGED
|
@@ -1,10 +1,17 @@
|
|
|
1
1
|
import {
|
|
2
|
+
SharedController,
|
|
2
3
|
VitralRemoteElement,
|
|
3
4
|
defineVitralElement,
|
|
4
5
|
elementRemote
|
|
5
|
-
} from "./chunk-
|
|
6
|
-
import "./chunk-
|
|
6
|
+
} from "./chunk-6Y3VMWHH.js";
|
|
7
|
+
import "./chunk-UTYAX6MU.js";
|
|
8
|
+
import "./chunk-NCONW6WS.js";
|
|
9
|
+
import "./chunk-2XF5BKV3.js";
|
|
10
|
+
import "./chunk-SFL6LTP3.js";
|
|
11
|
+
import "./chunk-PX7PBCCT.js";
|
|
12
|
+
import "./chunk-GNPFWISJ.js";
|
|
7
13
|
export {
|
|
14
|
+
SharedController,
|
|
8
15
|
VitralRemoteElement,
|
|
9
16
|
defineVitralElement,
|
|
10
17
|
elementRemote
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
type RemoteErrorCode = 'NOT_REGISTERED' | 'NOT_EXPOSED' | 'ORIGIN_BLOCKED' | 'TIMEOUT' | 'INTEGRITY' | 'INVALID_MODULE' | 'LOAD_FAILED' | 'MOUNT_FAILED' | 'RENDER_FAILED' | 'SHARED_READONLY';
|
|
2
|
+
declare class RemoteError extends Error {
|
|
3
|
+
code: RemoteErrorCode;
|
|
4
|
+
remote: string;
|
|
5
|
+
cause?: unknown | undefined;
|
|
6
|
+
/** Link da página deste erro na documentação. */
|
|
7
|
+
docs: string;
|
|
8
|
+
constructor(code: RemoteErrorCode, remote: string, message: string, cause?: unknown | undefined);
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export { RemoteError as R, type RemoteErrorCode as a };
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import {
|
|
2
|
+
resolveModule,
|
|
3
|
+
resolveTarget,
|
|
4
|
+
splitName
|
|
5
|
+
} from "./chunk-HP6QWU6K.js";
|
|
6
|
+
import "./chunk-2XF5BKV3.js";
|
|
7
|
+
import "./chunk-SFL6LTP3.js";
|
|
8
|
+
import "./chunk-PX7PBCCT.js";
|
|
9
|
+
import "./chunk-GNPFWISJ.js";
|
|
10
|
+
export {
|
|
11
|
+
resolveModule,
|
|
12
|
+
resolveTarget,
|
|
13
|
+
splitName
|
|
14
|
+
};
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/** Quando montar: já (`eager`, padrão), perto de aparecer na tela (`lazy`) ou com o navegador ocioso (`idle`). */
|
|
2
|
+
type Loading = 'eager' | 'lazy' | 'idle';
|
|
3
|
+
/** Quando baixar antes de montar: no hover ou foco (`hover`), perto de aparecer (`visible`) ou com o navegador ocioso (`idle`). */
|
|
4
|
+
type Prefetch = 'hover' | 'visible' | 'idle';
|
|
5
|
+
|
|
6
|
+
export type { Loading as L, Prefetch as P };
|
package/dist/iframe.d.ts
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/** Script inline do iframe. Libere o hash dele no CSP (`script-src 'sha256-…'`). */
|
|
2
|
+
declare const FRAME_SCRIPT = "(function (w, load) {\n var parent = w.parent, doc = w.document, handlers = {}, last = {}, channel = {}, mounted = null, stage = 'LOAD_FAILED'\n function post(type, data) { parent.postMessage({ vitral: 1, type: type, data: data }, '*') }\n function call(fn, arg) { try { fn(arg) } catch (e) { w.console.error(e) } }\n var events = {\n emit: function (type, payload) { post('emit', { type: type, payload: payload }) },\n on: function (type, fn) {\n if (!handlers[type]) { handlers[type] = []; post('on', { type: type }) }\n handlers[type].push(fn)\n return function () { handlers[type] = handlers[type].filter(function (h) { return h !== fn }) }\n },\n last: function (type) { return last[type] }\n }\n function start(d) {\n var root = doc.createElement('div')\n root.setAttribute('data-vitral-root', d.name)\n if (d.scope) root.setAttribute('data-vitral-scope', d.scope)\n doc.body.appendChild(root)\n // Ponto de extens\u00E3o: uma ponte nova registra handlers em channel[tipo] e\n // acrescenta campos aqui (a Fase 2 acrescenta ctx.shared).\n var ctx = {\n name: d.name, baseUrl: d.baseUrl, events: events, shadowRoot: null, protocol: 1,\n reportError: function (e) { post('report', { message: String((e && e.message) || e) }) },\n navigate: function (url, o) { post('navigate', { url: String(url), replace: !!(o && o.replace) }) }\n }\n Promise.all(d.css.map(function (href) {\n return new Promise(function (done) {\n var link = doc.createElement('link')\n link.rel = 'stylesheet'; link.href = href; link.crossOrigin = 'anonymous'\n link.onload = link.onerror = done\n doc.head.appendChild(link)\n })\n })).then(function () {\n return load(d.code ? w.URL.createObjectURL(new w.Blob([d.code], { type: 'text/javascript' })) : d.url)\n }).then(function (ns) {\n if (!d.key) return ns\n var table = ns.exposes, part = table && table[d.key]\n if (!part) { stage = 'NOT_EXPOSED'; throw new Error(d.name + ' n\u00E3o exp\u00F5e ' + d.key) }\n return typeof part === 'function' ? part() : part\n }).then(function (ns) {\n var mod = (ns && ns.default) || ns\n if (!mod || typeof mod.mount !== 'function') { stage = 'INVALID_MODULE'; throw new Error('o m\u00F3dulo n\u00E3o exporta mount()') }\n stage = 'MOUNT_FAILED'\n return mod.mount(root, d.props, ctx)\n }).then(function (handle) {\n mounted = handle\n post('mounted')\n var size = function () { post('size', { height: Math.ceil(doc.body.getBoundingClientRect().height) }) }\n size()\n if (w.ResizeObserver) new w.ResizeObserver(size).observe(doc.body)\n }, function (e) {\n post('error', { code: stage, message: String((e && e.message) || e) })\n })\n }\n w.addEventListener('message', function (e) {\n var m = e.data\n if (e.source !== parent || !m || m.vitral !== 1) return\n var d = m.data\n if (m.type === 'mount') start(d)\n else if (m.type === 'update') { if (mounted && mounted.update) mounted.update(d) }\n else if (m.type === 'unmount') { if (mounted) mounted.unmount(); mounted = null }\n else if (m.type === 'last') last[d.type] = d.payload\n else if (m.type === 'event') {\n last[d.type] = d.payload\n ;(handlers[d.type] || []).slice().forEach(function (h) { call(h, d.payload) })\n } else (channel[m.type] || []).forEach(function (h) { call(h, d) })\n })\n post('ready')\n})(window, function (u) { return import(u) })";
|
|
3
|
+
|
|
4
|
+
/** Canal com um iframe montado, para pontes novas (ex.: estado compartilhado). */
|
|
5
|
+
interface FramePort {
|
|
6
|
+
/** Manda `data` (serializável) para o iframe com o tipo `type`. */
|
|
7
|
+
post(type: string, data?: unknown): void;
|
|
8
|
+
/** Recebe as mensagens do iframe com o tipo `type`. */
|
|
9
|
+
on(type: string, handler: (data: unknown) => void): () => void;
|
|
10
|
+
}
|
|
11
|
+
/** Chamada a cada iframe montado. Devolve a limpeza. */
|
|
12
|
+
type FrameBridge = (port: FramePort, info: {
|
|
13
|
+
name: string;
|
|
14
|
+
}) => void | (() => void);
|
|
15
|
+
interface IframeOptions {
|
|
16
|
+
/**
|
|
17
|
+
* Valor do atributo `sandbox`. Padrão `'allow-scripts'`. Acrescente o que o
|
|
18
|
+
* remote precisa (`'allow-scripts allow-forms allow-popups'`). Com
|
|
19
|
+
* `allow-same-origin` o iframe ganha a origem da página e deixa de isolar.
|
|
20
|
+
*/
|
|
21
|
+
sandbox?: string;
|
|
22
|
+
/** Pontes extras, além de props e eventos. */
|
|
23
|
+
bridges?: FrameBridge[];
|
|
24
|
+
}
|
|
25
|
+
/** Liga `isolate="iframe"` em todos os componentes de host e em `mountRemote`. */
|
|
26
|
+
declare function enableIframe(options?: IframeOptions): void;
|
|
27
|
+
|
|
28
|
+
export { FRAME_SCRIPT, type FrameBridge, type FramePort, type IframeOptions, enableIframe };
|