mockpit 2.0.0 → 3.0.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 +60 -212
- package/bin/demoData.js +2 -2
- package/bin/initDesign.js +6 -6
- package/bin/mockpit.js +407 -187
- package/bin/poster.js +377 -0
- package/dist/mcp/server.js +80 -24
- package/dist/server/answerAdditions.d.ts +7 -0
- package/dist/server/answerAdditions.js +76 -0
- package/dist/server/apiViews.d.ts +289 -52
- package/dist/server/apiViews.js +189 -81
- package/dist/server/app.d.ts +7 -2
- package/dist/server/app.js +2845 -832
- package/dist/server/appIcon.js +15 -5
- package/dist/server/appIconPng.js +3 -3
- package/dist/server/askNudges.js +1 -1
- package/dist/server/cdnInline.d.ts +8 -0
- package/dist/server/cdnInline.js +638 -0
- package/dist/server/codeWorker.js +1 -1
- package/dist/server/decisionList.d.ts +45 -0
- package/dist/server/decisionList.js +302 -0
- package/dist/server/decisions.d.ts +4 -4
- package/dist/server/decisions.js +9 -9
- package/dist/server/designGuide.d.ts +5 -5
- package/dist/server/designGuide.js +128 -67
- package/dist/server/embeds.d.ts +3 -1
- package/dist/server/embeds.js +31 -6
- package/dist/server/eventLog.d.ts +2 -2
- package/dist/server/eventLog.js +11 -11
- package/dist/server/events.d.ts +9 -6
- package/dist/server/feedbackBatch.d.ts +35 -13
- package/dist/server/feedbackBatch.js +111 -47
- package/dist/server/fills.d.ts +4 -0
- package/dist/server/fills.js +55 -1
- package/dist/server/handoff.d.ts +4 -1
- package/dist/server/handoff.js +8 -2
- package/dist/server/icons.js +1 -1
- package/dist/server/index.js +39 -10
- package/dist/server/jump.d.ts +21 -0
- package/dist/server/jump.js +175 -0
- package/dist/server/knobs.d.ts +3 -3
- package/dist/server/knobs.js +6 -6
- package/dist/server/mcpHttp.d.ts +5 -1
- package/dist/server/mcpHttp.js +16 -11
- package/dist/server/mcpSpec.js +118 -46
- package/dist/server/parts.js +9 -1
- package/dist/server/run.d.ts +1 -1
- package/dist/server/run.js +25 -16
- package/dist/server/runApi.d.ts +3 -3
- package/dist/server/runApi.js +25 -19
- package/dist/server/sqlStore.d.ts +112 -96
- package/dist/server/sqlStore.js +906 -172
- package/dist/server/standings.d.ts +25 -0
- package/dist/server/standings.js +113 -0
- package/dist/server/surfacePage.d.ts +6 -9
- package/dist/server/surfacePage.js +361 -86
- package/dist/server/types.d.ts +226 -72
- package/dist/server/types.js +73 -78
- package/extensions/mockpit.js +89 -72
- package/guide/AGENT_SETUP.md +13 -1
- package/guide/packs/design-craft.md +2 -3
- package/guide/topics/asks.md +106 -62
- package/guide/topics/feedback.md +126 -119
- package/guide/topics/html.md +17 -24
- package/guide/topics/http.md +41 -41
- package/guide/topics/knobs.md +7 -10
- package/guide/topics/scripts.md +22 -33
- package/guide/topics/surfaces.md +39 -48
- package/opencode/mockpit.js +120 -0
- package/opencode/package.json +8 -0
- package/package.json +4 -3
- package/skills/launch-video/SKILL.md +11 -11
- package/skills/mockpit/SKILL.md +26 -22
- package/viewer/dist/index.html +9 -9
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { type AnswerStanding, type Ask, type AskOption, type Design, type HiddenAnswer, type Post } from "./types.ts";
|
|
2
|
+
export declare const MAX_WHY = 300;
|
|
3
|
+
export declare const MAX_SETS = 12;
|
|
4
|
+
export type StandingKind = "kept" | "hidden" | "open";
|
|
5
|
+
export declare const standingOf: (design: Pick<Design, "standings">, askId: string) => AnswerStanding;
|
|
6
|
+
export declare const isEmptyStanding: (s: AnswerStanding) => boolean;
|
|
7
|
+
export declare const hiddenAnswer: (s: AnswerStanding, id: string) => HiddenAnswer | undefined;
|
|
8
|
+
export declare function withStanding(s: AnswerStanding, option: Pick<AskOption, "id" | "label">, to: StandingKind, why?: string): AnswerStanding;
|
|
9
|
+
export declare function remapStanding(s: AnswerStanding, before: Ask | undefined, after: Ask): AnswerStanding;
|
|
10
|
+
export declare function reoffered(s: AnswerStanding, ask: Ask): HiddenAnswer[];
|
|
11
|
+
export declare function optionStates(ask: Ask, option: AskOption, design: Pick<Design, "states">): (string | null)[];
|
|
12
|
+
export declare function keptVariants(design: Design, posts: Pick<Post, "state" | "variant">[]): Set<string>;
|
|
13
|
+
export declare const isKeptVariant: (kept: Set<string>, p: Pick<Post, "state" | "variant">) => boolean;
|
|
14
|
+
export interface StandingView {
|
|
15
|
+
kept?: {
|
|
16
|
+
id: string;
|
|
17
|
+
label: string;
|
|
18
|
+
}[];
|
|
19
|
+
hidden?: HiddenAnswer[];
|
|
20
|
+
carried?: {
|
|
21
|
+
id: string;
|
|
22
|
+
label: string;
|
|
23
|
+
}[];
|
|
24
|
+
}
|
|
25
|
+
export declare function standingView(ask: Ask, s: AnswerStanding): StandingView | undefined;
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
// Kept and hidden answers: the rules the server and the viewer share. A standing
|
|
2
|
+
// belongs to a question by id, so it outlives the agent asking that question again,
|
|
3
|
+
// and to an answer by id, remapped when a re-ask renames it. Runtime-agnostic.
|
|
4
|
+
import { builtinAsk, optionState, } from "./types.js";
|
|
5
|
+
export const MAX_WHY = 300;
|
|
6
|
+
export const MAX_SETS = 12;
|
|
7
|
+
const EMPTY = { kept: [], hidden: [] };
|
|
8
|
+
export const standingOf = (design, askId) => design.standings[askId] ?? EMPTY;
|
|
9
|
+
export const isEmptyStanding = (s) => !s.kept.length && !s.hidden.length && !s.carried?.length;
|
|
10
|
+
export const hiddenAnswer = (s, id) => s.hidden.find((h) => h.id === id);
|
|
11
|
+
// One answer moved to kept, hidden or neither. Kept and hidden exclude each other, and
|
|
12
|
+
// an answer that stops being kept stops being carried.
|
|
13
|
+
export function withStanding(s, option, to, why) {
|
|
14
|
+
const kept = s.kept.filter((id) => id !== option.id);
|
|
15
|
+
const hidden = s.hidden.filter((h) => h.id !== option.id);
|
|
16
|
+
const carried = (s.carried ?? []).filter((id) => id !== option.id || to === "kept");
|
|
17
|
+
const since = { ...s.since };
|
|
18
|
+
if (to !== "kept")
|
|
19
|
+
delete since[option.id];
|
|
20
|
+
if (to === "kept")
|
|
21
|
+
kept.push(option.id);
|
|
22
|
+
if (to === "hidden")
|
|
23
|
+
hidden.push({ id: option.id, label: option.label, ...(why ? { why } : {}) });
|
|
24
|
+
return {
|
|
25
|
+
kept,
|
|
26
|
+
hidden,
|
|
27
|
+
...(carried.length ? { carried } : {}),
|
|
28
|
+
...(Object.keys(since).length ? { since } : {}),
|
|
29
|
+
unsent: true,
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
const sameSet = (a, b) => !!a.set && !!b.set && JSON.stringify(a.set) === JSON.stringify(b.set);
|
|
33
|
+
// The answer in a re-asked question that is the same one under another id: the same
|
|
34
|
+
// variant and version, the same values, else the same words.
|
|
35
|
+
function sameAnswer(old, next) {
|
|
36
|
+
return (next.find((o) => o.id === old.id) ??
|
|
37
|
+
next.find((o) => !!old.variant && o.variant === old.variant && o.version === old.version) ??
|
|
38
|
+
next.find((o) => sameSet(o, old)) ??
|
|
39
|
+
next.find((o) => o.label.trim().toLowerCase() === old.label.trim().toLowerCase()));
|
|
40
|
+
}
|
|
41
|
+
// A standing carried across a re-ask. A kept answer the agent dropped can't be shown
|
|
42
|
+
// any more, so it goes; a hidden one stays, by its label, so it is still not offered.
|
|
43
|
+
export function remapStanding(s, before, after) {
|
|
44
|
+
const move = (id) => {
|
|
45
|
+
const was = before?.options.find((o) => o.id === id);
|
|
46
|
+
return was
|
|
47
|
+
? sameAnswer(was, after.options)?.id
|
|
48
|
+
: after.options.some((o) => o.id === id)
|
|
49
|
+
? id
|
|
50
|
+
: undefined;
|
|
51
|
+
};
|
|
52
|
+
const kept = s.kept.flatMap((id) => move(id) ?? []);
|
|
53
|
+
const carried = (s.carried ?? []).flatMap((id) => move(id) ?? []);
|
|
54
|
+
const hidden = s.hidden.map((h) => ({ ...h, id: move(h.id) ?? h.id }));
|
|
55
|
+
const since = Object.fromEntries(Object.entries(s.since ?? {}).flatMap(([id, at]) => (move(id) ? [[move(id), at]] : [])));
|
|
56
|
+
return {
|
|
57
|
+
kept: [...new Set(kept)],
|
|
58
|
+
hidden,
|
|
59
|
+
...(carried.length ? { carried: [...new Set(carried)] } : {}),
|
|
60
|
+
...(Object.keys(since).length ? { since } : {}),
|
|
61
|
+
...(s.unsent ? { unsent: true } : {}),
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
// The answers a re-ask offers again that the user hid: they stay folded away.
|
|
65
|
+
export function reoffered(s, ask) {
|
|
66
|
+
return s.hidden.filter((h) => ask.options.some((o) => o.id === h.id));
|
|
67
|
+
}
|
|
68
|
+
// The states a variant answer of this question puts in use.
|
|
69
|
+
export function optionStates(ask, option, design) {
|
|
70
|
+
if (option.version !== undefined)
|
|
71
|
+
return [optionState(ask, design)];
|
|
72
|
+
if (ask.scope === "state")
|
|
73
|
+
return [ask.state ?? null];
|
|
74
|
+
return design.states.length ? design.states : [null];
|
|
75
|
+
}
|
|
76
|
+
const variantKey = (state, variant) => `${state ?? ""}\n${variant}`;
|
|
77
|
+
// Every variant some question keeps, by state and name: Send leaves them out of the
|
|
78
|
+
// archive and `read` marks them kept.
|
|
79
|
+
export function keptVariants(design, posts) {
|
|
80
|
+
const out = new Set();
|
|
81
|
+
for (const [askId, s] of Object.entries(design.standings)) {
|
|
82
|
+
if (!s.kept.length)
|
|
83
|
+
continue;
|
|
84
|
+
const ask = design.asks.find((a) => a.id === askId) ?? builtinAsk(design, posts, askId);
|
|
85
|
+
if (!ask || ask.scope === "part")
|
|
86
|
+
continue;
|
|
87
|
+
for (const id of s.kept) {
|
|
88
|
+
const o = ask.options.find((x) => x.id === id);
|
|
89
|
+
if (!o?.variant)
|
|
90
|
+
continue;
|
|
91
|
+
for (const state of optionStates(ask, o, design))
|
|
92
|
+
out.add(variantKey(state, o.variant));
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
return out;
|
|
96
|
+
}
|
|
97
|
+
export const isKeptVariant = (kept, p) => kept.has(variantKey(p.state, p.variant));
|
|
98
|
+
export function standingView(ask, s) {
|
|
99
|
+
const named = (ids) => ids.flatMap((id) => {
|
|
100
|
+
const o = ask.options.find((x) => x.id === id);
|
|
101
|
+
return o ? [{ id, label: o.label }] : [];
|
|
102
|
+
});
|
|
103
|
+
const kept = named(s.kept.filter((id) => !answered(ask).includes(id)));
|
|
104
|
+
const carried = named(s.carried ?? []);
|
|
105
|
+
if (!kept.length && !s.hidden.length && !carried.length)
|
|
106
|
+
return undefined;
|
|
107
|
+
return {
|
|
108
|
+
...(kept.length ? { kept } : {}),
|
|
109
|
+
...(s.hidden.length ? { hidden: s.hidden } : {}),
|
|
110
|
+
...(carried.length ? { carried } : {}),
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
const answered = (ask) => ask.answer === undefined ? [] : Array.isArray(ask.answer) ? ask.answer : [ask.answer];
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import { type IconResolver } from "./icons.ts";
|
|
2
|
-
import type
|
|
2
|
+
import { type DesignSystem } from "./types.ts";
|
|
3
3
|
import { type Mode, type Theme } from "./themes.ts";
|
|
4
4
|
export declare const BRIDGE_JS = "\nwindow.sendPrompt = function (text) {\n parent.postMessage({ __mockpit: true, type: 'send-prompt', text: String(text) }, '*');\n};\nwindow.openLink = function (url) {\n parent.postMessage({ __mockpit: true, type: 'open-link', url: String(url) }, '*');\n};\nwindow.copyToClipboard = function (text) {\n parent.postMessage({ __mockpit: true, type: 'copy', text: String(text) }, '*');\n};\ndocument.addEventListener('click', function (e) {\n var a = e.target && e.target.closest ? e.target.closest('a[href]') : null;\n if (a && /^https?:/.test(a.href)) { e.preventDefault(); window.openLink(a.href); }\n});\n// Cmd+Option+Up/Down switches sessions in the sidebar, but keydowns fire in\n// whichever document holds focus \u2014 once the user clicks into a surface, this\n// sandboxed iframe swallows them. Forward just that combo to the host.\ndocument.addEventListener('keydown', function (e) {\n if (!e.metaKey || !e.altKey || e.ctrlKey || e.shiftKey) return;\n if (e.key !== 'ArrowUp' && e.key !== 'ArrowDown') return;\n e.preventDefault();\n parent.postMessage({ __mockpit: true, type: 'switch-session', key: e.key }, '*');\n});\n// Report content height to the parent so it can size this iframe, while\n// breaking a feedback loop that can peg a CPU core.\n//\n// The loop: the parent sets the iframe's height to whatever we report, but some\n// content's height *inverts* with the frame's height \u2014 a scrollbar that appears\n// at height A reflows the content to height B, then disappears at B and reflows\n// back to A (or any 100vh / percentage-derived layout). The ResizeObserver then\n// fires on every flip, so reported heights alternate A, B, A, B... forever. With\n// a cheap surface that's a brief blip; with a heavy one (a big syntax-highlighted\n// diff/markdown surface) each relayout is expensive and the tab sits at 100% CPU\n// until the surface unmounts.\n//\n// A plain h !== __lastH guard can't stop this: in a 2-cycle every value differs\n// from the one immediately before it. So we remember the previous height too and\n// defer a return to it *if it recurs faster than a human could* (< 250ms) \u2014 that's\n// the runaway. The deferred pass keeps one trailing re-measure and reports the\n// taller height in the pair, so an ordinary font/image reflow can't leave the\n// frame permanently clipped.\nvar __lastH = 0;\nvar __prevH = 0;\nvar __lastT = 0;\nvar __seenH = 0;\nvar __trailTimer = 0;\nvar __trailH = 0;\nvar __FLIP_MS = 250;\nvar __TRAIL_MS = 350;\nfunction __now() {\n return typeof performance !== 'undefined' && performance.now ? performance.now() : Date.now();\n}\nfunction __measureHeight() {\n return document.body\n ? document.body.scrollHeight\n : document.documentElement.scrollHeight;\n}\nfunction __postHeight(h, t) {\n __prevH = __lastH;\n __lastH = h;\n __lastT = t;\n parent.postMessage({ __mockpit: true, type: 'resize', height: h }, '*');\n}\nfunction __clearTrailing() {\n if (__trailTimer && typeof clearTimeout !== 'undefined') clearTimeout(__trailTimer);\n __trailTimer = 0;\n __trailH = 0;\n}\nfunction __flushTrailing() {\n __trailTimer = 0;\n var measured = __measureHeight();\n if (measured > 0) __seenH = measured;\n var target = Math.max(__trailH || 0, measured || 0);\n __trailH = 0;\n if (target <= 0 || target === __lastH) return;\n __postHeight(target, __now());\n}\nfunction __scheduleTrailing(h, reset) {\n __trailH = Math.max(__trailH || 0, h || 0, __lastH || 0);\n if (__trailTimer) {\n if (!reset) return;\n if (typeof clearTimeout !== 'undefined') clearTimeout(__trailTimer);\n }\n __trailTimer = setTimeout(__flushTrailing, __TRAIL_MS);\n}\nfunction __report() {\n var h = __measureHeight();\n if (h <= 0) return; // no content yet\n var changed = h !== __seenH;\n __seenH = h;\n if (h === __lastH) return; // unchanged\n var t = __now();\n if (h === __prevH && (__trailTimer || t - __lastT < __FLIP_MS)) {\n __scheduleTrailing(h, true); // rapid A<->B flip: defer one settled report\n return;\n }\n __clearTrailing();\n __postHeight(h, t);\n}\nif (document.readyState === 'complete') __report();\nelse window.addEventListener('load', function () { requestAnimationFrame(__report); });\nsetTimeout(__report, 60);\nsetTimeout(__report, 350);\nsetTimeout(__report, 1500);\nsetTimeout(__report, 3000);\nsetTimeout(__report, 6000);\nsetTimeout(__report, 10000);\nif (document.fonts && document.fonts.ready && document.fonts.ready.then) {\n document.fonts.ready.then(function () { __report(); });\n}\nif (window.ResizeObserver) {\n window.__ssRO = new ResizeObserver(__report);\n window.__ssRO.observe(document.documentElement);\n if (document.body) window.__ssRO.observe(document.body);\n}\n";
|
|
5
|
+
export declare const FREEZE_JS = "\n(function () {\n if (location.hash !== '#small' || !document.getAnimations) return;\n var QUIET_MS = 800, CAP_MS = 10000, LOAD_CAP_MS = 15000, MAX_STEP_MS = 100, RUN_MAX_MS = 30000;\n var HELD_MAX = 32;\n var raf = window.requestAnimationFrame.bind(window);\n var caf = window.cancelAnimationFrame.bind(window);\n var asked = new Map(), nextId = 0;\n var frozen = false, loaded = false;\n var run = 0, last = 0, settleFrom = 0, active = 0, runUntil = RUN_MAX_MS;\n var paused = [], sweepQueued = false;\n window.addEventListener('load', function () { loaded = true; settleFrom = run; active = run; });\n\n function fire(id, t) {\n var entry = asked.get(id);\n if (!entry) return;\n entry.native = 0;\n if (frozen) return;\n asked.delete(id);\n entry.cb(t);\n }\n function queue(id, entry) {\n entry.native = raf(function (t) { fire(id, t); });\n }\n window.requestAnimationFrame = function (cb) {\n if (frozen && run < runUntil) thaw();\n var id = ++nextId, entry = { cb: cb, native: 0 };\n if (frozen && asked.size >= HELD_MAX) return id;\n asked.set(id, entry);\n active = run;\n if (!frozen) queue(id, entry);\n return id;\n };\n window.cancelAnimationFrame = function (id) {\n var entry = asked.get(id);\n if (!entry) return;\n if (entry.native) caf(entry.native);\n asked.delete(id);\n };\n if (window.webkitRequestAnimationFrame) {\n window.webkitRequestAnimationFrame = window.requestAnimationFrame;\n window.webkitCancelAnimationFrame = window.cancelAnimationFrame;\n }\n\n function own(a) { return a.timeline === document.timeline && a.effect; }\n function ends(a) { return isFinite(a.effect.getComputedTiming().endTime); }\n function stillDrawing() {\n return document.getAnimations().some(function (a) {\n return own(a) && a.playState === 'running' && ends(a);\n });\n }\n function sweep() {\n sweepQueued = false;\n if (!frozen) return;\n document.getAnimations().forEach(function (a) {\n if (!own(a)) return;\n try {\n if (ends(a)) a.finish();\n else if (a.playState !== 'paused') { a.pause(); a.currentTime = 0; paused.push(a); }\n } catch (e) {}\n });\n Array.prototype.forEach.call(document.querySelectorAll('svg'), function (svg) {\n if (svg.pauseAnimations) svg.pauseAnimations();\n });\n }\n function queueSweep() {\n if (frozen && !sweepQueued) { sweepQueued = true; setTimeout(sweep, 0); }\n }\n function freeze() { frozen = true; sweep(); }\n function thaw() {\n frozen = false;\n active = settleFrom = run;\n paused.splice(0).forEach(function (a) { try { a.play(); } catch (e) {} });\n Array.prototype.forEach.call(document.querySelectorAll('svg'), function (svg) {\n if (svg.unpauseAnimations) svg.unpauseAnimations();\n });\n asked.forEach(function (entry, id) { if (!entry.native) queue(id, entry); });\n last = 0;\n raf(tick);\n }\n function settled() {\n return run - active >= QUIET_MS && !stillDrawing();\n }\n function tick(t) {\n if (frozen) return;\n run += last ? Math.min(t - last, MAX_STEP_MS) : 0;\n last = t;\n if (loaded ? settled() || run - settleFrom >= CAP_MS : run >= LOAD_CAP_MS) freeze();\n else raf(tick);\n }\n new MutationObserver(function () {\n active = run;\n queueSweep();\n }).observe(document, { subtree: true, childList: true, attributes: true, characterData: true });\n document.addEventListener('animationstart', queueSweep, true);\n document.addEventListener('transitionstart', queueSweep, true);\n window.addEventListener('message', function (e) {\n var d = e.data;\n if (e.source !== window.parent || !d || d.__mockpit !== true || d.type !== 'knobs') return;\n runUntil = run + RUN_MAX_MS;\n if (frozen) thaw();\n });\n raf(tick);\n})();\n";
|
|
5
6
|
export declare const HIT_TEST_JS = "\n(function () {\n var MAX_DEPTH = 6;\n var MAX_TEXT = 60;\n function docBox() {\n var w = document.documentElement.clientWidth || 1;\n var h = (document.body && document.body.scrollHeight) || document.documentElement.scrollHeight || 1;\n return { w: w, h: h };\n }\n function ident(v) { return typeof v === 'string' && /^[A-Za-z][\\w-]*$/.test(v); }\n function cssPath(el) {\n var parts = [];\n while (el && el.nodeType === 1 && el !== document.body && el !== document.documentElement) {\n var tag = el.tagName.toLowerCase();\n if (ident(el.id)) { parts.unshift(tag + '#' + el.id); break; }\n var sel = tag;\n var cls = (el.getAttribute('class') || '').split(/\\s+/).filter(ident).slice(0, 2);\n if (cls.length) sel += '.' + cls.join('.');\n var p = el.parentElement;\n if (p) {\n var sibs = [];\n for (var i = 0; i < p.children.length; i++) {\n if (p.children[i].tagName === el.tagName) sibs.push(p.children[i]);\n }\n if (sibs.length > 1) sel += ':nth-of-type(' + (sibs.indexOf(el) + 1) + ')';\n }\n parts.unshift(sel);\n if (parts.length >= MAX_DEPTH) break;\n el = p;\n }\n return parts.join(' > ');\n }\n function firstLine(el) {\n var t = (el.innerText || el.textContent || '').replace(/\\s+/g, ' ').trim();\n var line = t.split('\\n')[0].trim();\n return line.length > MAX_TEXT ? line.slice(0, MAX_TEXT - 1) + '\\u2026' : line;\n }\n window.addEventListener('message', function (e) {\n if (e.source !== parent || parent === window) return;\n var d = e.data;\n if (!d || d.__mockpit !== true || d.type !== 'hit-test') return;\n var box = docBox();\n var px = Math.max(0, Math.min(1, Number(d.x) || 0)) * box.w;\n var py = Math.max(0, Math.min(1, Number(d.y) || 0)) * box.h;\n var el = document.elementFromPoint(px - (window.scrollX || 0), py - (window.scrollY || 0));\n var reply = { __mockpit: true, type: 'hit-test-result', ref: d.ref, path: '', text: '', rect: [0, 0, 0, 0] };\n if (el && el.nodeType === 1) {\n var r = el.getBoundingClientRect();\n reply.path = cssPath(el);\n reply.text = firstLine(el);\n reply.rect = [\n (r.left + (window.scrollX || 0)) / box.w,\n (r.top + (window.scrollY || 0)) / box.h,\n r.width / box.w,\n r.height / box.h,\n ];\n }\n parent.postMessage(reply, '*');\n });\n})();\n";
|
|
6
7
|
export declare const PARTS_JS = "\n(function () {\n if (window.parent === window) return;\n var HL = 'mockpit-part-hl';\n var MAX_PARTS = 200;\n var MAX_TEXT = 200;\n var doc = window.__mockpitDoc || {};\n var version = typeof doc.version === 'number' ? doc.version : null;\n function text(v) { return v == null ? null : String(v).slice(0, MAX_TEXT); }\n function isFixed(el) {\n for (var n = el; n && n.nodeType === 1; n = n.parentElement) {\n if (getComputedStyle(n).position === 'fixed') return true;\n }\n return false;\n }\n function collect() {\n var sx = window.scrollX || 0, sy = window.scrollY || 0;\n var els = document.querySelectorAll('[data-part]');\n var parts = [];\n for (var i = 0; i < els.length && parts.length < MAX_PARTS; i++) {\n var el = els[i];\n var name = text(el.getAttribute('data-part'));\n if (!name) continue;\n var r = el.getBoundingClientRect();\n var depth = 0;\n for (var p = el.parentElement; p; p = p.parentElement) if (p.hasAttribute('data-part')) depth++;\n var outer = el.parentElement && el.parentElement.closest('[data-part]');\n parts.push({\n name: name,\n label: text(el.getAttribute('data-part-label')) || name,\n key: text(el.getAttribute('data-part-key')),\n box: { x: r.left + sx, y: r.top + sy, w: r.width, h: r.height },\n visible: (r.width > 0 || r.height > 0) && getComputedStyle(el).visibility !== 'hidden',\n fixed: isFixed(el),\n depth: depth,\n parent: outer ? text(outer.getAttribute('data-part')) : null,\n order: i,\n });\n }\n return {\n version: version,\n parts: parts,\n height: document.body ? document.body.scrollHeight : document.documentElement.scrollHeight,\n scroll: { x: sx, y: sy },\n // scrollWidth past innerWidth: the design is wider than the frame.\n viewport: { w: innerWidth, h: innerHeight, scrollW: document.documentElement.scrollWidth },\n };\n }\n var last = '';\n var timer = 0;\n // setTimeout, not rAF: a hidden cross-origin frame may have rendering (and\n // with it rAF and ResizeObserver) throttled, but timers still run.\n function schedule() {\n if (timer) return;\n timer = setTimeout(function () {\n timer = 0;\n var m = collect();\n var key = JSON.stringify(m);\n if (key === last) return;\n last = key;\n m.__mockpit = true;\n m.type = 'parts';\n parent.postMessage(m, '*');\n }, 0);\n }\n\n var ro = typeof ResizeObserver !== 'undefined' ? new ResizeObserver(schedule) : null;\n var observed = typeof WeakSet !== 'undefined' ? new WeakSet() : null;\n function observeAll() {\n if (!ro || !observed) return;\n // html/body too: a non-part sibling growing moves parts without resizing them.\n var els = [document.documentElement, document.body].concat([].slice.call(document.querySelectorAll('[data-part]')));\n for (var i = 0; i < els.length; i++) {\n var el = els[i];\n if (el && !observed.has(el)) { observed.add(el); ro.observe(el); }\n }\n }\n var moTimer = 0;\n var mo = new MutationObserver(function () {\n clearTimeout(moTimer);\n moTimer = setTimeout(function () { observeAll(); schedule(); }, 40);\n });\n mo.observe(document.documentElement, { subtree: true, childList: true, attributes: true, characterData: true });\n\n // Transforms and transitions move boxes without resizing or mutating anything.\n document.addEventListener('animationend', schedule, true);\n document.addEventListener('transitionend', schedule, true);\n window.addEventListener('scroll', schedule, { passive: true });\n window.addEventListener('resize', schedule);\n if (document.fonts && document.fonts.ready) document.fonts.ready.then(schedule);\n observeAll();\n schedule();\n // WebKit: RO's initial callback may never fire in a sandboxed frame.\n function settle() {\n schedule();\n [50, 150, 400, 1000].forEach(function (ms) { setTimeout(schedule, ms); });\n }\n if (document.readyState === 'complete') settle();\n else window.addEventListener('load', settle);\n\n function setHighlight(names) {\n var on = document.querySelectorAll('.' + HL);\n for (var i = 0; i < on.length; i++) on[i].classList.remove(HL);\n if (names && names.length) {\n var want = {};\n for (var k = 0; k < names.length && k < MAX_PARTS; k++) want[String(names[k])] = true;\n var els = document.querySelectorAll('[data-part]');\n for (var j = 0; j < els.length; j++) {\n if (want[els[j].getAttribute('data-part')] === true) els[j].classList.add(HL);\n }\n }\n // Our own class flip must not look like the agent's page changing.\n mo.takeRecords();\n }\n\n // Try: the host lets the user click through the design; an element marked\n // data-goto moves them to another screen. Only the host knows what that\n // names, so the frame just reports it, and the click goes no further.\n var trying = false;\n function setTrying(on) {\n trying = on;\n document.documentElement.classList.toggle('mockpit-try', on);\n mo.takeRecords();\n }\n window.addEventListener('click', function (e) {\n if (!trying) return;\n var t = e.target && e.target.closest ? e.target.closest('[data-goto]') : null;\n if (!t) return;\n e.preventDefault();\n e.stopPropagation();\n parent.postMessage({\n __mockpit: true,\n type: 'goto',\n version: version,\n to: text(t.getAttribute('data-goto')),\n }, '*');\n }, true);\n\n // A finger's tap, in document px, for a host that lets touches through to the\n // page (its canvas, where the page scrolls natively). A drag is a scroll: the\n // browser cancels the pointer or it moves too far. A mouse clicks the host's\n // own overlay instead, so it never reports here.\n var tapAt = null;\n window.addEventListener('pointerdown', function (e) {\n tapAt = e.isPrimary && e.pointerType !== 'mouse' ? { x: e.clientX, y: e.clientY, t: Date.now() } : null;\n }, true);\n window.addEventListener('pointercancel', function () { tapAt = null; }, true);\n window.addEventListener('pointerup', function (e) {\n var a = tapAt;\n tapAt = null;\n if (!a || !e.isPrimary) return;\n if (Math.abs(e.clientX - a.x) > 10 || Math.abs(e.clientY - a.y) > 10 || Date.now() - a.t > 600) return;\n parent.postMessage({\n __mockpit: true,\n type: 'tap',\n x: e.clientX + (window.scrollX || 0),\n y: e.clientY + (window.scrollY || 0),\n }, '*');\n }, true);\n\n // Two fingers are the host's: a page laid on its canvas takes one-finger\n // scrolls itself, but a pinch zooms the canvas, not this page or the browser.\n var pinching = false;\n function pinch(phase, e) {\n var t = e.touches;\n parent.postMessage({\n __mockpit: true,\n type: 'pinch',\n phase: phase,\n a: t[0] ? { x: t[0].clientX, y: t[0].clientY } : null,\n b: t[1] ? { x: t[1].clientX, y: t[1].clientY } : null,\n }, '*');\n }\n window.addEventListener('touchstart', function (e) {\n if (e.touches.length !== 2) return;\n e.preventDefault();\n pinching = true;\n pinch('start', e);\n }, { capture: true, passive: false });\n window.addEventListener('touchmove', function (e) {\n if (!pinching || e.touches.length < 2) return;\n e.preventDefault();\n pinch('move', e);\n }, { capture: true, passive: false });\n function release(e) {\n if (!pinching || e.touches.length >= 2) return;\n pinching = false;\n pinch('end', e);\n }\n window.addEventListener('touchend', release, true);\n window.addEventListener('touchcancel', release, true);\n // \u2318/Ctrl+scroll and a trackpad pinch (ctrl+wheel) are the host's too: they\n // zoom the canvas around the pointer, never this page or the browser.\n window.addEventListener('wheel', function (e) {\n if (!e.ctrlKey && !e.metaKey) return;\n e.preventDefault();\n parent.postMessage({ __mockpit: true, type: 'zoom', x: e.clientX, y: e.clientY, dy: e.deltaY }, '*');\n }, { capture: true, passive: false });\n\n window.addEventListener('message', function (e) {\n if (e.source !== parent) return;\n var d = e.data;\n if (!d || d.__mockpit !== true) return;\n if (d.type === 'highlight') setHighlight(Array.isArray(d.parts) ? d.parts : []);\n else if (d.type === 'clear') setHighlight(null);\n else if (d.type === 'try') setTrying(d.on === true);\n else if (d.type === 'scroll') window.scrollBy(Number(d.dx) || 0, Number(d.dy) || 0);\n else if (d.type === 'hit') {\n var el = document.elementFromPoint(\n (Number(d.x) || 0) - (window.scrollX || 0),\n (Number(d.y) || 0) - (window.scrollY || 0)\n );\n var part = el && el.closest ? el.closest('[data-part]') : null;\n parent.postMessage({\n __mockpit: true,\n type: 'hit',\n ref: d.ref,\n part: part ? text(part.getAttribute('data-part')) : null,\n key: part ? text(part.getAttribute('data-part-key')) : null,\n }, '*');\n }\n });\n})();\n";
|
|
8
|
+
export declare const PARAGRAPHS_JS: string;
|
|
7
9
|
export declare const KNOBS_JS = "\n(function () {\n\nvar __kPathRe = /^[A-Za-z_][\\w-]{0,63}(\\.[A-Za-z_][\\w-]{0,63}){0,3}$/;\nvar __kTokenRe = /^[#\\w(),.%/+-][#\\w\\s(),.%/+-]*$/;\nfunction __kName(path) { return path.replace(/\\./g, '-'); }\nfunction __kCssString(s) {\n return '\"' + s.replace(/[\\\\\"]/g, function (c) { return '\\\\' + c; })\n .replace(/[\\u0000-\\u001f\\u007f]/g, function (c) { return '\\\\' + c.charCodeAt(0).toString(16) + ' '; }) + '\"';\n}\nfunction __kCss(v) {\n if (typeof v === 'number') return isFinite(v) ? String(v) : null;\n if (typeof v === 'boolean') return v ? '1' : '0';\n if (typeof v === 'string') return __kTokenRe.test(v) ? v : __kCssString(v);\n return null;\n}\nfunction __kVars(path, v) {\n var name = __kName(path);\n if (v && typeof v === 'object' && !Array.isArray(v)) {\n var out = [];\n for (var f in v) {\n if (!Object.prototype.hasOwnProperty.call(v, f) || !/^[A-Za-z_][\\w-]{0,63}$/.test(f)) continue;\n var c = __kCss(v[f]);\n if (c !== null) out.push([name + '-' + f, c]);\n }\n return out;\n }\n var css = __kCss(v);\n return css === null ? [] : [[name, css]];\n}\nfunction __kAttr(v) {\n if (typeof v === 'number') return isFinite(v) ? String(v) : null;\n if (typeof v === 'boolean') return v ? 'true' : 'false';\n if (typeof v === 'string') return v;\n return null;\n}\n\n var doc = window.__mockpitDoc || {};\n var current = {};\n function own(o, k) { return Object.prototype.hasOwnProperty.call(o, k); }\n function bind(path, v) {\n var els = document.querySelectorAll('[data-k-bind]');\n for (var i = 0; i < els.length; i++) {\n if (els[i].getAttribute('data-k-bind') !== path) continue;\n els[i].textContent = v && typeof v === 'object' ? JSON.stringify(v) : String(v);\n }\n }\n function apply(values, live) {\n var root = document.documentElement;\n for (var path in values) {\n if (!own(values, path) || !__kPathRe.test(path)) continue;\n var v = values[path];\n if (v === null || v === undefined) continue;\n current[path] = v;\n if (live) {\n var vars = __kVars(path, v);\n if (!vars.length) root.style.removeProperty('--k-' + __kName(path));\n for (var i = 0; i < vars.length; i++) root.style.setProperty('--k-' + vars[i][0], vars[i][1]);\n var attr = __kAttr(v);\n if (attr === null) root.removeAttribute('data-k-' + __kName(path));\n else root.setAttribute('data-k-' + __kName(path), attr);\n }\n bind(path, v);\n }\n window.dispatchEvent(new CustomEvent('mockpit:knobs', {\n detail: { values: JSON.parse(JSON.stringify(current)) },\n }));\n }\n // The URL's values are already on <html>; a live command may also have come\n // in before the body existed, so both are bound once it does.\n function initial() {\n var start = doc.knobs && typeof doc.knobs === 'object' ? doc.knobs : {};\n for (var k in start) if (own(start, k) && !own(current, k)) current[k] = start[k];\n apply(current, false);\n }\n if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', initial);\n else initial();\n // Runs from <head>, before the page's own markup and anything slow it loads\n // (a web font, a CDN stylesheet), so the host can send values at once rather\n // than wait for the first parts report, which those can hold back.\n if (parent !== window) parent.postMessage({ __mockpit: true, type: 'ready', version: doc.version }, '*');\n window.addEventListener('message', function (e) {\n if (e.source !== parent || parent === window) return;\n var d = e.data;\n if (!d || d.__mockpit !== true || d.type !== 'knobs') return;\n if (d.values && typeof d.values === 'object' && !Array.isArray(d.values)) apply(d.values, true);\n });\n})();\n";
|
|
8
10
|
export declare function knobCss(v: unknown): string | null;
|
|
9
11
|
export declare function knobVars(path: string, v: unknown): [string, string][];
|
|
@@ -17,13 +19,6 @@ export declare function knobAttributes(knobs: Record<string, unknown> | undefine
|
|
|
17
19
|
attrs: string;
|
|
18
20
|
values: Record<string, unknown>;
|
|
19
21
|
};
|
|
20
|
-
export interface StaticAsset {
|
|
21
|
-
path: string;
|
|
22
|
-
contentType: string;
|
|
23
|
-
body: string;
|
|
24
|
-
}
|
|
25
|
-
export declare const STATIC_ASSET_PREFIX = "/asset/";
|
|
26
|
-
export declare const staticAsset: (path: string) => StaticAsset | null;
|
|
27
22
|
export declare const escapeHtml: (s: string) => string;
|
|
28
23
|
export declare function renderSandboxedPart(doc: {
|
|
29
24
|
body: string;
|
|
@@ -31,12 +26,14 @@ export declare function renderSandboxedPart(doc: {
|
|
|
31
26
|
origin: string;
|
|
32
27
|
theme?: Theme | string;
|
|
33
28
|
mode?: Mode;
|
|
29
|
+
version?: number;
|
|
34
30
|
}): string;
|
|
35
31
|
export declare function renderMermaidPage(doc: {
|
|
36
32
|
mermaid: string;
|
|
37
33
|
origin: string;
|
|
38
34
|
theme?: Theme | string;
|
|
39
35
|
mode?: Mode;
|
|
36
|
+
version?: number;
|
|
40
37
|
}): string;
|
|
41
38
|
export declare function renderHtmlPage(doc: {
|
|
42
39
|
title: string;
|
|
@@ -45,7 +42,7 @@ export declare function renderHtmlPage(doc: {
|
|
|
45
42
|
theme?: Theme | string;
|
|
46
43
|
mode?: Mode;
|
|
47
44
|
kits?: string[];
|
|
48
|
-
|
|
45
|
+
designSystem?: DesignSystem | null;
|
|
49
46
|
version?: number;
|
|
50
47
|
knobs?: Record<string, unknown>;
|
|
51
48
|
resolveIcon?: IconResolver;
|