@bud.sh/app 0.5.0 → 0.6.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.
Files changed (115) hide show
  1. package/README.md +41 -31
  2. package/dist/client/assets/bud/design.js +1 -1
  3. package/dist/client/assets/canvas-Bih9EdKJ.js +1 -0
  4. package/dist/client/assets/difference-worker-Bzg-rizy.js +8 -0
  5. package/dist/client/assets/dist-CdE5wBkg.js +5 -0
  6. package/dist/client/assets/files-1dLuoM2f.js +1 -0
  7. package/dist/client/assets/i18n-CkO6VFI0.js +1 -0
  8. package/dist/client/assets/index-Cn2mxroU.css +2 -0
  9. package/dist/client/assets/{index-ChANGtl-.js → index-DtISWZp9.js} +2 -2
  10. package/dist/client/assets/pages-BJ-tNJ4J.js +1 -0
  11. package/dist/client/assets/{project-branches-DO897zM6.js → project-branches-Ce3rXrkc.js} +1 -1
  12. package/dist/client/assets/project-comments-CPUONfs8.js +1 -0
  13. package/dist/client/assets/project-thread-links-C-TGkq59.js +1 -0
  14. package/dist/client/assets/{project-threads-Lay351p4.js → project-threads-Bv7IDBgi.js} +105 -105
  15. package/dist/client/assets/project-work-DAE9-olg.js +1 -0
  16. package/dist/client/assets/{task-design-Avb2RO4w.js → task-design-CwySIAOl.js} +3 -3
  17. package/dist/client/assets/tasks-KWsCLi_h.js +3 -0
  18. package/dist/client/assets/wasm-inline-DSUyFn1L.js +1 -0
  19. package/dist/client/assets/workspace-CVdcfaaB.js +2 -0
  20. package/dist/client/index.html +3 -3
  21. package/dist/hosted/assets/{canvas-V36732ER.js → canvas-AII16n9i.js} +97 -6
  22. package/dist/hosted/assets/{comment-data-CF2ZV_3k.js → comment-data-BXfMElfx.js} +2004 -402
  23. package/dist/hosted/assets/dist-BCSTeNf4.js +4785 -0
  24. package/dist/hosted/assets/{files-DjSCjfU7.js → files-D_1yeAVO.js} +10 -5
  25. package/dist/hosted/assets/{pages-BzjzeuPu.js → pages-CN_SbKWA.js} +3 -3
  26. package/dist/hosted/assets/{project-branches-BT97J9i7.js → project-branches-Bxp0DCwg.js} +1 -1
  27. package/dist/hosted/assets/{project-thread-links-BRLgByEe.js → project-thread-links-KqQoKBLE.js} +76 -4
  28. package/dist/{node-host/assets/screen-CZXWJEds.js → hosted/assets/screen-DpAcDUKR.js} +29 -1
  29. package/dist/hosted/assets/tasks-D66LlwxM.js +1423 -0
  30. package/dist/hosted/assets/wasm-inline-Dl9tqabx.js +4 -0
  31. package/dist/hosted/hosted.js +7885 -6219
  32. package/dist/node/assets/Stream-CAm1eJ2n.js +16604 -0
  33. package/dist/{server/assets/bridge-B_Blt55E.js → node/assets/bridge-DQSBYHmw.js} +124 -290
  34. package/dist/node/assets/config-9_jWwNBh.js +1067 -0
  35. package/dist/node/assets/load-config.server-CMVtRVmO.js +261 -0
  36. package/dist/node/assets/module-3GgtT4Xs.js +308 -0
  37. package/dist/node/assets/server-DTQFuoX2.js +846 -0
  38. package/dist/node/assets/src-D-kG1GxB.js +2 -0
  39. package/dist/node/assets/{src-CerrKjID.js → src-Dwe9APUx.js} +93 -3
  40. package/dist/node/assets/src-DysjfbM8.js +8592 -0
  41. package/dist/node/bridge.js +1 -845
  42. package/dist/node/cli.js +206 -0
  43. package/dist/node/design.js +811 -13
  44. package/dist/node/index.js +2 -739
  45. package/dist/node/plugins.js +5711 -0
  46. package/dist/node/server.js +1 -6746
  47. package/dist/node/vite.js +121 -0
  48. package/dist/{server/assets/canvas-Dc1mYCwQ.js → node-host/assets/canvas-BeDoufy1.js} +97 -7
  49. package/dist/node-host/assets/{comment-data-DyIZNpfG.js → comment-data-DE2T9yTj.js} +1980 -376
  50. package/dist/node-host/assets/dist-BCSTeNf4.js +4785 -0
  51. package/dist/node-host/assets/{files-Dh2TiQZq.js → files-Dl-PTS09.js} +11 -6
  52. package/dist/node-host/assets/{pages-BxpjbYhs.js → pages-DL2sk6_U.js} +3 -3
  53. package/dist/node-host/assets/{project-branches-B7HUGiVK.js → project-branches-DGp5ELct.js} +1 -1
  54. package/dist/{server/assets/project-thread-links-CBOpf6zk.js → node-host/assets/project-thread-links-CgBV3Jcm.js} +76 -5
  55. package/dist/{hosted/assets/screen-CKp2C7kx.js → node-host/assets/screen-B55yyVfb.js} +29 -1
  56. package/dist/node-host/assets/tasks-DZRNkoxe.js +1425 -0
  57. package/dist/node-host/assets/wasm-inline-Dl9tqabx.js +4 -0
  58. package/dist/node-host/node-host.js +6127 -4438
  59. package/dist/server/assets/{branch-previews-ClkoJ0lM.js → branch-previews-DedrpnVR.js} +1555 -673
  60. package/dist/{node-host/assets/canvas-TRUfxfL5.js → server/assets/canvas-CJWQ-jjv.js} +98 -6
  61. package/dist/server/assets/{comment-data-CsjukwAW.js → comment-data-Rg42ToTW.js} +1666 -47
  62. package/dist/server/assets/dist-BCSTeNf4.js +4785 -0
  63. package/dist/server/assets/{events-iHpLGr3k.js → events-BH_rAu7O.js} +155 -20
  64. package/dist/server/assets/{files-E9mSFeoc.js → files-CPJqKeMo.js} +12 -7
  65. package/dist/server/assets/{listener-DN5TyOjJ.js → listener-D61O6PzF.js} +708 -12
  66. package/dist/server/assets/{pages-BBBXyJWV.js → pages-KJY_Ba92.js} +4 -4
  67. package/dist/server/assets/{project-branches-B0YIK6Ur.js → project-branches-qG9ACZvo.js} +2 -2
  68. package/dist/{node-host/assets/project-thread-links-CauJF0Cz.js → server/assets/project-thread-links-CqK0lqCF.js} +77 -4
  69. package/dist/{node-host/assets/tasks-request-ZWmbc8fE.js → server/assets/project-work-DoIwxWMm.js} +87 -2
  70. package/dist/server/assets/run-BJ8r5jSh.js +572 -0
  71. package/dist/server/assets/{screen-BIQA2mr4.js → screen-CBrHPFug.js} +30 -2
  72. package/dist/server/assets/{server-DxK-UB_Z.js → server-Dkbp5stG.js} +1521 -793
  73. package/dist/server/assets/{services-BRrgXYlT.js → services-BTfig8A8.js} +234 -997
  74. package/dist/server/assets/tasks-Bgu5Lg9Y.js +1427 -0
  75. package/dist/server/assets/wasm-inline-Dl9tqabx.js +4 -0
  76. package/dist/server/capture.js +1 -2
  77. package/dist/server/migration.js +569 -12
  78. package/dist/server/runtime.js +7 -5
  79. package/dist/server/server.js +3 -3
  80. package/dist/types/assets/{config-DIC2cf_S.d.ts → config-CvcYmE2s.d.ts} +188 -50
  81. package/dist/types/assets/{contract-CAT-XFNq.d.ts → contract-B7yuuqSn.d.ts} +44 -2
  82. package/dist/types/assets/{items-CaVkByHk.d.ts → items-BQdaVksf.d.ts} +12 -1
  83. package/dist/types/assets/memory-state-BBW-FAVA.d.ts +236 -0
  84. package/dist/types/assets/picker-Be5Gx4WR.d.ts +9 -0
  85. package/dist/types/assets/{task-design-xJOhRNWh.d.ts → task-design-BDHKFHpp.d.ts} +3 -1
  86. package/dist/types/bridge.d.ts +1 -1
  87. package/dist/types/companion.d.ts +3 -3
  88. package/dist/types/design.d.ts +2 -2
  89. package/dist/types/hosted.d.ts +3 -3
  90. package/dist/types/index.d.ts +2 -2
  91. package/dist/types/node-host.d.ts +2 -2
  92. package/dist/types/plugins.d.ts +445 -0
  93. package/dist/types/screen.d.ts +2 -2
  94. package/dist/types/server.d.ts +2 -228
  95. package/dist/types/vite.d.ts +16 -0
  96. package/package.json +19 -3
  97. package/dist/client/assets/canvas-Cu6R6xxT.js +0 -1
  98. package/dist/client/assets/difference-worker-jfTSn-Tw.js +0 -8
  99. package/dist/client/assets/files-js6ElfkU.js +0 -1
  100. package/dist/client/assets/i18n-DxqFr2mi.js +0 -1
  101. package/dist/client/assets/index-CFFxP0gS.css +0 -2
  102. package/dist/client/assets/pages-6_lhiQmz.js +0 -1
  103. package/dist/client/assets/project-comments-DFFKVpia.js +0 -1
  104. package/dist/client/assets/project-thread-links-NLFWQRD2.js +0 -1
  105. package/dist/client/assets/project-work-du0Y-L5Y.js +0 -1
  106. package/dist/client/assets/tasks-CA-E8bbK.js +0 -1
  107. package/dist/client/assets/tasks-request-C55IeuiP.js +0 -1
  108. package/dist/client/assets/workspace-Cw5HvX5d.js +0 -2
  109. package/dist/hosted/assets/tasks-Dj7AyBJB.js +0 -649
  110. package/dist/hosted/assets/tasks-request-DZob623r.js +0 -113
  111. package/dist/node-host/assets/tasks-Bs1IOpeU.js +0 -651
  112. package/dist/server/assets/project-work-qSKFO5yj.js +0 -88
  113. package/dist/server/assets/tasks-CiXodsLN.js +0 -652
  114. package/dist/server/assets/tasks-request-DhwCzpRi.js +0 -115
  115. package/dist/types/assets/picker-D1Bw3ndx.d.ts +0 -14
@@ -1,845 +1 @@
1
- //#region ../picker/src/lib/runtime.ts
2
- /**
3
- * The page side of every picker: Bud's DOM picker composed with a framework adapter. It runs in
4
- * the project's pages as module text, so it must not reference anything outside its own body.
5
- * @param adapter - The configured picker's page module, or null for the DOM picker alone.
6
- * @param name - The picker's name, recorded on every anchor it describes.
7
- * @returns The picker's page operations.
8
- */
9
- function pickerRuntime(adapter, name) {
10
- let blocks = "article, section, li, figure, form, header, footer, nav, aside, main, dialog, [data-block], [data-component], [role=\"listitem\"], [role=\"region\"], [role=\"dialog\"]";
11
- let ignored = "[data-react-grab], [data-bud-picker], script, style, link, meta, noscript";
12
- let active = null;
13
- function clip(text, length) {
14
- return text.length > length ? text.slice(0, length) : text;
15
- }
16
- function normalize(text) {
17
- return (text ?? "").replace(/\s+/g, " ").trim();
18
- }
19
- function textOf(element) {
20
- return clip(normalize(element instanceof HTMLElement ? element.innerText : element.textContent), 1e3);
21
- }
22
- function fingerprint(element) {
23
- let value = `${element.localName}\u0000${textOf(element)}`;
24
- let hash = 2166136261;
25
- for (let index = 0; index < value.length; index++) {
26
- hash ^= value.charCodeAt(index);
27
- hash = Math.imul(hash, 16777619) >>> 0;
28
- }
29
- return hash.toString(16).padStart(8, "0");
30
- }
31
- function stableId(element) {
32
- let id = element.id;
33
- if (!id || /[:\d]/.test(id) || id.length > 64) return null;
34
- return document.querySelectorAll(`#${CSS.escape(id)}`).length === 1 ? id : null;
35
- }
36
- function segment(element) {
37
- let id = stableId(element);
38
- if (id) return `#${CSS.escape(id)}`;
39
- let tag = element.localName;
40
- let parent = element.parentElement;
41
- if (!parent) return tag;
42
- let same = [...parent.children].filter((child) => child.localName === tag);
43
- return same.length > 1 ? `${tag}:nth-of-type(${same.indexOf(element) + 1})` : tag;
44
- }
45
- function selectorOf(element) {
46
- let parts = [];
47
- for (let node = element; node; node = node.parentElement) {
48
- if (node === document.documentElement) break;
49
- let part = segment(node);
50
- parts.unshift(part);
51
- if (part.startsWith("#") || node === document.body) break;
52
- }
53
- return clip(parts.join(" > "), 4096);
54
- }
55
- function breadcrumbOf(element) {
56
- let parts = [];
57
- for (let node = element; node && parts.length < 5; node = node.parentElement) {
58
- if (node === document.body || node === document.documentElement) break;
59
- parts.unshift(node.localName);
60
- }
61
- return clip(parts.join(" > ") || element.localName, 4096);
62
- }
63
- function labelOf(element) {
64
- return clip(normalize(element.getAttribute("aria-label") || element.getAttribute("alt") || element.getAttribute("title")) || clip(textOf(element), 80) || element.localName, 500);
65
- }
66
- function query(selector) {
67
- try {
68
- return document.querySelector(selector);
69
- } catch {
70
- return null;
71
- }
72
- }
73
- function box(element) {
74
- let rect = element.getBoundingClientRect();
75
- return {
76
- left: rect.left + scrollX,
77
- top: rect.top + scrollY,
78
- width: rect.width,
79
- height: rect.height
80
- };
81
- }
82
- function fraction(offset, size) {
83
- return size > 0 ? Math.min(1, Math.max(0, offset / size)) : .5;
84
- }
85
- function elementAt(clientX, clientY) {
86
- for (let element of document.elementsFromPoint(clientX, clientY)) {
87
- if (element === document.documentElement || element.closest(ignored)) continue;
88
- return element;
89
- }
90
- return null;
91
- }
92
- async function blockOf(element) {
93
- return (adapter?.block ? await Promise.resolve(adapter.block(element)).catch(() => null) : null) ?? element.closest(blocks);
94
- }
95
- async function anchor(element, x, y) {
96
- let rect = box(element);
97
- let around = await blockOf(element);
98
- let described = adapter?.describe ? await Promise.resolve(adapter.describe(element)).catch(() => null) : null;
99
- let block = null;
100
- if (around) {
101
- let outer = box(around);
102
- block = {
103
- selector: selectorOf(around),
104
- label: labelOf(around),
105
- tagName: around.localName,
106
- offsetX: fraction(x - outer.left, outer.width),
107
- offsetY: fraction(y - outer.top, outer.height)
108
- };
109
- }
110
- return {
111
- selector: selectorOf(element),
112
- breadcrumb: breadcrumbOf(element),
113
- contentHash: fingerprint(element),
114
- label: described?.label ? clip(described.label, 500) : labelOf(element),
115
- tagName: clip(element.localName, 100),
116
- text: textOf(element),
117
- offsetX: fraction(x - rect.left, rect.width),
118
- offsetY: fraction(y - rect.top, rect.height),
119
- block,
120
- source: described?.source ?? null,
121
- picker: name
122
- };
123
- }
124
- function alike(a, b) {
125
- let words = (text) => new Set(text.toLowerCase().split(/\s+/).filter(Boolean));
126
- let left = words(a);
127
- let right = words(b);
128
- let shared = [...left].filter((word) => right.has(word)).length;
129
- let all = (/* @__PURE__ */ new Set([...left, ...right])).size;
130
- return all === 0 || shared / all >= .5;
131
- }
132
- function find(stored) {
133
- let candidate = query(stored.selector);
134
- let same = (element) => element.localName === stored.tagName && (!stored.text || fingerprint(element) === stored.contentHash);
135
- if (candidate && same(candidate)) return {
136
- element: candidate,
137
- offsetX: stored.offsetX,
138
- offsetY: stored.offsetY
139
- };
140
- if (stored.text) {
141
- let moved = [...document.getElementsByTagName(stored.tagName)].filter((element) => !element.closest(ignored) && same(element));
142
- let container = stored.block ? query(stored.block.selector) : null;
143
- let inside = container ? moved.filter((element) => container.contains(element)) : [];
144
- let found = moved.length === 1 ? moved[0] : inside.length === 1 ? inside[0] : null;
145
- if (found) return {
146
- element: found,
147
- offsetX: stored.offsetX,
148
- offsetY: stored.offsetY
149
- };
150
- }
151
- let block = stored.block ? query(stored.block.selector) : null;
152
- if (block && block.localName === stored.block.tagName && alike(labelOf(block), stored.block.label)) return {
153
- element: block,
154
- offsetX: stored.block.offsetX,
155
- offsetY: stored.block.offsetY,
156
- block: true
157
- };
158
- return null;
159
- }
160
- return {
161
- async describe(x, y) {
162
- let from = {
163
- left: scrollX,
164
- top: scrollY
165
- };
166
- scrollTo({
167
- left: 0,
168
- top: Math.max(0, y - innerHeight / 2),
169
- behavior: "instant"
170
- });
171
- try {
172
- let element = elementAt(x - scrollX, y - scrollY);
173
- return element ? await anchor(element, x, y) : null;
174
- } finally {
175
- scrollTo({
176
- ...from,
177
- behavior: "instant"
178
- });
179
- }
180
- },
181
- async locate(anchors) {
182
- return anchors.map(({ id, element }) => {
183
- let found = find(element);
184
- if (!found) return {
185
- id,
186
- match: "missing",
187
- x: null,
188
- y: null
189
- };
190
- let rect = box(found.element);
191
- return {
192
- id,
193
- match: "block" in found ? "block" : "element",
194
- x: rect.left + found.offsetX * rect.width,
195
- y: rect.top + found.offsetY * rect.height
196
- };
197
- });
198
- },
199
- pick() {
200
- active?.abort();
201
- return new Promise((resolve) => {
202
- let controller = new AbortController();
203
- let outline = document.createElement("div");
204
- outline.setAttribute("data-bud-picker", "");
205
- outline.style.cssText = "position:fixed;z-index:2147483647;pointer-events:none;border:2px solid #7c3aed;border-radius:4px;background:rgb(124 58 237 / 0.08);display:none;box-sizing:border-box";
206
- let done = false;
207
- let finish = (value) => {
208
- if (done) return;
209
- done = true;
210
- controller.abort();
211
- outline.remove();
212
- if (active === session) active = null;
213
- resolve(value);
214
- };
215
- let session = { abort: () => finish(null) };
216
- active = session;
217
- let signal = controller.signal;
218
- if (adapter?.pick) {
219
- adapter.pick(signal).then(async (element) => {
220
- if (!element || done) return finish(null);
221
- let rect = box(element);
222
- finish(await anchor(element, rect.left + rect.width / 2, rect.top + rect.height / 2));
223
- }).catch(() => finish(null));
224
- return;
225
- }
226
- document.documentElement.append(outline);
227
- let hovered = null;
228
- let options = {
229
- capture: true,
230
- signal
231
- };
232
- addEventListener("pointermove", (event) => {
233
- hovered = elementAt(event.clientX, event.clientY);
234
- if (!hovered) return void (outline.style.display = "none");
235
- let rect = hovered.getBoundingClientRect();
236
- Object.assign(outline.style, {
237
- display: "block",
238
- left: `${rect.left}px`,
239
- top: `${rect.top}px`,
240
- width: `${rect.width}px`,
241
- height: `${rect.height}px`
242
- });
243
- }, options);
244
- for (let type of [
245
- "pointerdown",
246
- "mousedown",
247
- "pointerup",
248
- "mouseup"
249
- ]) addEventListener(type, (event) => event.preventDefault(), options);
250
- addEventListener("click", (event) => {
251
- event.preventDefault();
252
- event.stopPropagation();
253
- let element = elementAt(event.clientX, event.clientY);
254
- if (!element) return;
255
- anchor(element, event.clientX + scrollX, event.clientY + scrollY).then(finish);
256
- }, options);
257
- addEventListener("keydown", (event) => {
258
- if (event.key !== "Escape") return;
259
- event.preventDefault();
260
- finish(null);
261
- }, options);
262
- });
263
- },
264
- cancel() {
265
- active?.abort();
266
- },
267
- async index(options = {}) {
268
- let limit = options.maxElements ?? 2e4;
269
- let mark = options.mark ?? null;
270
- let page = globalThis;
271
- let from = {
272
- left: scrollX,
273
- top: scrollY
274
- };
275
- let priming = page.__budPriming;
276
- page.__budPriming = true;
277
- try {
278
- scrollTo({
279
- left: 0,
280
- top: 0,
281
- behavior: "instant"
282
- });
283
- let round = (value) => Math.round(value * 100) / 100;
284
- let intersect = (a, b) => {
285
- let left = Math.max(a[0], b[0]);
286
- let top = Math.max(a[1], b[1]);
287
- let right = Math.min(a[0] + a[2], b[0] + b[2]);
288
- let bottom = Math.min(a[1] + a[3], b[1] + b[3]);
289
- return [
290
- left,
291
- top,
292
- Math.max(0, right - left),
293
- Math.max(0, bottom - top)
294
- ];
295
- };
296
- let everywhere = [
297
- -1e6,
298
- -1e6,
299
- 2e6,
300
- 2e6
301
- ];
302
- let found = [];
303
- let indexes = /* @__PURE__ */ new Map();
304
- let clips = /* @__PURE__ */ new Map();
305
- for (let element of document.body?.querySelectorAll("*") ?? []) {
306
- if (found.length >= limit) break;
307
- if (element.closest(ignored)) continue;
308
- let style = getComputedStyle(element);
309
- let rect = element.getBoundingClientRect();
310
- let own = [
311
- rect.left + scrollX,
312
- rect.top + scrollY,
313
- rect.width,
314
- rect.height
315
- ];
316
- let container = element.parentElement;
317
- let clip = everywhere;
318
- if (style.position !== "fixed") for (let node = container; node; node = node.parentElement) {
319
- let known = clips.get(node);
320
- if (known) {
321
- clip = known;
322
- break;
323
- }
324
- }
325
- clips.set(element, style.overflowX !== "visible" || style.overflowY !== "visible" ? intersect(clip, own) : clip);
326
- if (rect.width <= 0 || rect.height <= 0) continue;
327
- let box = intersect(own, clip);
328
- let parent = -1;
329
- for (let node = container; node && parent < 0; node = node.parentElement) parent = indexes.get(node) ?? -1;
330
- indexes.set(element, found.length);
331
- found.push({
332
- element,
333
- box: [
334
- round(box[0]),
335
- round(box[1]),
336
- round(box[2]),
337
- round(box[3])
338
- ],
339
- parent,
340
- inert: style.pointerEvents === "none" || style.visibility !== "visible"
341
- });
342
- }
343
- let sources = [];
344
- let known = /* @__PURE__ */ new Map();
345
- let elements = [];
346
- for (let [index, { element, box, parent, inert }] of found.entries()) {
347
- let around = await blockOf(element);
348
- let described = adapter?.describe ? await Promise.resolve(adapter.describe(element)).catch(() => null) : null;
349
- let source = -1;
350
- if (described?.source) {
351
- let key = JSON.stringify(described.source);
352
- source = known.get(key) ?? -1;
353
- if (source < 0) {
354
- source = sources.push(described.source) - 1;
355
- known.set(key, source);
356
- }
357
- }
358
- if (mark) element.setAttribute(mark, String(index));
359
- elements.push({
360
- box,
361
- parent,
362
- rank: inert ? -1 : 0,
363
- selector: selectorOf(element),
364
- breadcrumb: breadcrumbOf(element),
365
- contentHash: fingerprint(element),
366
- label: described?.label ? clip(described.label, 500) : labelOf(element),
367
- tagName: clip(element.localName, 100),
368
- text: textOf(element),
369
- block: around ? indexes.get(around) ?? -1 : -1,
370
- source
371
- });
372
- }
373
- return {
374
- version: 2,
375
- picker: name,
376
- width: document.documentElement.clientWidth,
377
- height: Math.min(document.documentElement.scrollHeight, 1e5),
378
- elements,
379
- sources
380
- };
381
- } finally {
382
- scrollTo({
383
- ...from,
384
- behavior: "instant"
385
- });
386
- page.__budPriming = priming;
387
- }
388
- }
389
- };
390
- }
391
- //#endregion
392
- //#region ../picker/src/lib/module.ts
393
- /** The picker module's ID in the project's dev server, served by Bud's Vite plugin. */
394
- var PICKER_MODULE_ID = "\0bud-picker";
395
- /** Where pages import the picker module from. */
396
- var PICKER_MODULE_URL = "/@id/__x00__bud-picker";
397
- /** Where a picker script leaves the picker in a page that has no module to import it from. */
398
- var PICKER_GLOBAL = "__budPicker";
399
- /** A built-in picker's adapter module, which imports the framework from the project. */
400
- var PICKER_ADAPTER_MODULE_ID = "\0bud-picker-adapter";
401
- /**
402
- * The picker module's text: Bud's DOM picker composed with the configured adapter.
403
- * @param name - The picker's name, recorded on every anchor.
404
- * @param adapter - Where the adapter's page module is imported from, or null for the DOM picker.
405
- * @returns ES module text exporting describe, locate, pick and cancel.
406
- */
407
- function pickerModule(name, adapter) {
408
- return [
409
- adapter ? `import adapter from ${JSON.stringify(adapter)}` : "const adapter = null",
410
- `const picker = (${pickerRuntime.toString()})(adapter ?? null, ${JSON.stringify(name)})`,
411
- "export const describe = picker.describe",
412
- "export const locate = picker.locate",
413
- "export const pick = picker.pick",
414
- "export const cancel = picker.cancel",
415
- "export const index = picker.index"
416
- ].join("\n");
417
- }
418
- /**
419
- * The picker as a classic script, for pages no Bud Vite plugin serves, such as builds of a
420
- * branch: running it leaves the picker on `window.__budPicker` (once) and evaluates to it.
421
- * @param name - The picker's name, recorded on every anchor.
422
- * @param adapter - An expression evaluating to the adapter, needing nothing from the page's
423
- * modules; null for the DOM picker.
424
- * @returns Script text.
425
- */
426
- function pickerScript(name, adapter) {
427
- return `(globalThis.${PICKER_GLOBAL} ??= (${pickerRuntime.toString()})(${adapter ?? "null"}, ${JSON.stringify(name)}))`;
428
- }
429
- //#endregion
430
- //#region ../picker-react-grab/src/lib/adapter.ts
431
- /**
432
- * The page side of `bud:react` and `bud:react-grab`: an element's component and source come from
433
- * React's development build, its block is the component's outermost element, and with React Grab
434
- * its own selection picks. It runs in the project's pages as module or script text, so it must not
435
- * reference anything outside its own body. The line comes from React's own stack, mapped through
436
- * the module's source map, so it is exact whichever React Grab a project runs; React Grab's own
437
- * answer fills in what that can't find. Production builds keep no source, so only the DOM picker's
438
- * own description remains.
439
- * @param grab - The project's `react-grab` module, or null to read React alone. Importing it
440
- * starts React Grab if it isn't yet.
441
- * @param helpers - Resolves file names and source map positions.
442
- * @returns The picker adapter.
443
- */
444
- function reactGrabAdapter(grab, helpers) {
445
- let { sourceFile, projectFrames, sourceMapLookup } = helpers;
446
- let plugin = "bud:picker";
447
- let maps = /* @__PURE__ */ new Map();
448
- let host = 5;
449
- function fiberOf(element) {
450
- let key = Object.keys(element).find((name) => name.startsWith("__reactFiber$"));
451
- return key ? element[key] ?? null : null;
452
- }
453
- function outermost(component) {
454
- let node = component.child;
455
- while (node && node.tag !== host) node = node.child;
456
- return node?.stateNode instanceof Element ? node.stateNode : null;
457
- }
458
- function sourceMap(url) {
459
- let cached = maps.get(url);
460
- if (cached) return cached;
461
- cached = fetch(url).then((response) => response.ok ? response.text() : "").then(async (text) => {
462
- let reference = /\/\/[#@] sourceMappingURL=(\S+)\s*$/.exec(text)?.[1];
463
- let address = new URL(reference ?? `${url.replace(/[?#].*$/, "")}.map`, url);
464
- if (address.protocol !== "data:" && address.origin !== location.origin) return null;
465
- let response = await fetch(address);
466
- let map = response.ok ? await response.json() : null;
467
- let lookup = map && typeof map === "object" ? sourceMapLookup(map) : null;
468
- return lookup ? {
469
- lookup,
470
- base: address.protocol === "data:" ? url : address.href
471
- } : null;
472
- }).catch(() => null);
473
- maps.set(url, cached);
474
- if (maps.size > 50) maps.delete(maps.keys().next().value);
475
- return cached;
476
- }
477
- function servedPath(source, base, stack) {
478
- if (source.startsWith("/") && !source.startsWith("//")) return sourceFile(source, stack, location.origin);
479
- let url = new URL(source, base);
480
- return url.origin === location.origin && !url.pathname.startsWith("/@") && !url.pathname.includes("/node_modules/") ? url.pathname : null;
481
- }
482
- async function written(stack) {
483
- let frames = projectFrames(stack, location.origin);
484
- for (let frame of frames) {
485
- let map = await sourceMap(frame.url);
486
- let position = map ? map.lookup(frame.line, frame.column) : {
487
- source: frame.url,
488
- line: frame.line,
489
- column: frame.column
490
- };
491
- if (!position) continue;
492
- let file = servedPath(position.source, map?.base ?? frame.url, stack);
493
- if (file) return {
494
- name: frame.name,
495
- file,
496
- line: position.line,
497
- column: position.column
498
- };
499
- }
500
- return frames[0] ? {
501
- name: frames[0].name,
502
- file: null,
503
- line: null,
504
- column: null
505
- } : null;
506
- }
507
- function ownerName(element) {
508
- let type = fiberOf(element)?._debugOwner?.type;
509
- let name = type && typeof type === "object" ? type.displayName ?? type.name : null;
510
- return typeof name === "string" && name ? name : null;
511
- }
512
- let adapter = {
513
- async describe(element) {
514
- let api = grab?.getGlobalApi() ?? null;
515
- let stack = fiberOf(element)?._debugStack?.stack ?? "";
516
- let mapped = stack ? await written(stack).catch(() => null) : null;
517
- let found = !mapped?.file && api ? await api.getSource(element).catch(() => null) : null;
518
- let component = mapped?.name ?? found?.componentName ?? api?.getDisplayName(element) ?? ownerName(element);
519
- if (!mapped?.file && !found && !component) return null;
520
- if (mapped?.file) return { source: {
521
- component: component || null,
522
- file: mapped.file,
523
- line: mapped.line,
524
- column: mapped.column
525
- } };
526
- let file = found?.filePath ? sourceFile(found.filePath, stack, location.origin) : null;
527
- let line = found?.lineNumber && found.lineNumber > 0 ? found.lineNumber : null;
528
- let column = found?.columnNumber != null && found.columnNumber >= 0 ? found.columnNumber + 1 : null;
529
- return { source: {
530
- component: component || null,
531
- file,
532
- line,
533
- column
534
- } };
535
- },
536
- block(element) {
537
- for (let owner = fiberOf(element)?._debugOwner; owner; owner = owner._debugOwner) {
538
- let outer = outermost(owner);
539
- if (outer && outer !== document.body && outer.contains(element)) return outer;
540
- }
541
- return null;
542
- }
543
- };
544
- if (!grab) return adapter;
545
- return {
546
- ...adapter,
547
- pick(signal) {
548
- let api = grab.getGlobalApi();
549
- if (!api || signal.aborted) return Promise.resolve(null);
550
- return new Promise((resolve) => {
551
- let settled = false;
552
- let tidy = () => {
553
- api.unregisterPlugin(plugin);
554
- if (api.isActive()) api.deactivate();
555
- };
556
- let finish = (element, during) => {
557
- if (settled) return;
558
- settled = true;
559
- signal.removeEventListener("abort", cancel);
560
- resolve(element);
561
- if (during) setTimeout(tidy, 1e3);
562
- else tidy();
563
- };
564
- let cancel = () => finish(null, false);
565
- signal.addEventListener("abort", cancel, { once: true });
566
- api.unregisterPlugin(plugin);
567
- api.registerPlugin({
568
- name: plugin,
569
- theme: { grabbedBoxes: { enabled: false } },
570
- hooks: {
571
- onElementSelect(element) {
572
- finish(element, true);
573
- return true;
574
- },
575
- onDeactivate: () => finish(null, true)
576
- }
577
- });
578
- api.activate();
579
- });
580
- }
581
- };
582
- }
583
- //#endregion
584
- //#region ../picker-react-grab/src/lib/source-map.ts
585
- /**
586
- * The frames of React's stack for an element that may have run in the project's own code, in
587
- * order: the first one whose source is the project's is the component that rendered it.
588
- * Dependencies the dev server serves apart, Vite's own modules and other origins are left out; a
589
- * build bundles dependencies with the project, so their frames stay for their source maps to
590
- * tell apart. It runs in the project's pages as module text, so it must not reference anything
591
- * outside its own body.
592
- * @param stack - React's stack for the element, as `Error.stack` text.
593
- * @param origin - The page's origin.
594
- * @returns The frames, possibly none.
595
- */
596
- function projectFrames(stack, origin) {
597
- let frames = [];
598
- for (let text of stack.split("\n")) {
599
- let match = /^\s*at (?:(.+?) \()?(https?:\/\/[^\s()]+?):(\d+):(\d+)\)?\s*$/.exec(text);
600
- if (!match) continue;
601
- let url = new URL(match[2]);
602
- if (url.origin !== origin || url.pathname.startsWith("/@") || url.pathname.includes("/node_modules/")) continue;
603
- let name = match[1]?.replace(/^Object\./, "") ?? null;
604
- frames.push({
605
- name,
606
- url: url.href,
607
- line: Number(match[3]),
608
- column: Number(match[4])
609
- });
610
- }
611
- return frames;
612
- }
613
- /**
614
- * Decodes a module's source map once, for looking up many positions in it. It runs in the
615
- * project's pages as module text, so it must not reference anything outside its own body.
616
- * @param map - The source map, as parsed JSON.
617
- * @returns Maps a generated line and column, counted from one, to the original position; null
618
- * for a map that can't be read.
619
- */
620
- function sourceMapLookup(map) {
621
- if (typeof map.mappings !== "string" || !Array.isArray(map.sources)) return null;
622
- let sources = map.sources;
623
- let root = typeof map.sourceRoot === "string" && map.sourceRoot ? map.sourceRoot : "";
624
- let digits = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
625
- let lines = [];
626
- let source = 0;
627
- let sourceLine = 0;
628
- let sourceColumn = 0;
629
- for (let text of map.mappings.split(";")) {
630
- let generated = 0;
631
- let segments = [];
632
- for (let segment of text.split(",")) {
633
- if (!segment) continue;
634
- let values = [];
635
- let value = 0;
636
- let shift = 0;
637
- for (let character of segment) {
638
- let digit = digits.indexOf(character);
639
- if (digit < 0) return null;
640
- value += (digit & 31) << shift;
641
- if (digit & 32) shift += 5;
642
- else {
643
- values.push(value & 1 ? -(value >>> 1) : value >>> 1);
644
- value = 0;
645
- shift = 0;
646
- }
647
- }
648
- generated += values[0] ?? 0;
649
- if (values.length < 4) continue;
650
- source += values[1];
651
- sourceLine += values[2];
652
- sourceColumn += values[3];
653
- segments.push([
654
- generated,
655
- source,
656
- sourceLine,
657
- sourceColumn
658
- ]);
659
- }
660
- lines.push(segments);
661
- }
662
- return (line, column) => {
663
- let found = null;
664
- for (let segment of lines[line - 1] ?? []) if (segment[0] <= column - 1) found = segment;
665
- let name = found ? sources[found[1]] : null;
666
- if (!found || typeof name !== "string") return null;
667
- return {
668
- source: root ? `${root.replace(/\/$/, "")}/${name}` : name,
669
- line: found[2] + 1,
670
- column: found[3] + 1
671
- };
672
- };
673
- }
674
- //#endregion
675
- //#region ../picker-react-grab/src/lib/source.ts
676
- /**
677
- * The project path of a file React Grab names. React Grab maps React's stack through the dev
678
- * server's source maps, whose sources are relative to the module that names them (Vite writes
679
- * `card.tsx` for `/src/components/card.tsx`). The module's address is still in React's own stack,
680
- * so the file resolves against the first frame from the page's origin that shares its name. It runs
681
- * in the project's pages as module text, so it must not reference anything outside its own body.
682
- * @param file - The file React Grab reported: a name, a relative or absolute path, or a URL.
683
- * @param stack - React's stack for the element, as `Error.stack` text.
684
- * @param origin - The page's origin; frames from elsewhere are never the project's.
685
- * @returns A path as the dev server serves it, such as `/src/components/card.tsx`, or null.
686
- */
687
- function sourceFile(file, stack, origin) {
688
- let served = (url) => url.origin === origin && !url.pathname.startsWith("/@") && !url.pathname.includes("/node_modules/") && !/[\\\u0000-\u001f\u007f]/.test(url.pathname);
689
- if (/^https?:\/\//.test(file)) {
690
- let url = new URL(file);
691
- return served(url) ? url.pathname : null;
692
- }
693
- let name = file.split("/").pop();
694
- for (let line of stack.split("\n")) {
695
- let match = /(https?:\/\/[^\s()]+?)(?::\d+){1,2}\)?\s*$/.exec(line);
696
- if (!match) continue;
697
- let frame = new URL(match[1]);
698
- if (!served(frame) || frame.pathname.split("/").pop() !== name) continue;
699
- if (file.startsWith("/")) return file.endsWith(frame.pathname) ? frame.pathname : null;
700
- let resolved = new URL(file, frame);
701
- return served(resolved) ? resolved.pathname : null;
702
- }
703
- return null;
704
- }
705
- function helpers() {
706
- return [
707
- "{",
708
- ` sourceFile: ${sourceFile.toString()},`,
709
- ` projectFrames: ${projectFrames.toString()},`,
710
- ` sourceMapLookup: ${sourceMapLookup.toString()},`,
711
- "}"
712
- ].join("\n");
713
- }
714
- /**
715
- * The adapter's page module text. It imports `react-grab` from the project, so React Grab must be
716
- * installed there; the dev server serves the same instance the project's pages use.
717
- * @returns ES module text whose default export is the picker adapter.
718
- */
719
- function reactGrabAdapterModule() {
720
- return ["import * as grab from 'react-grab'", `export default (${reactGrabAdapter.toString()})(grab, ${helpers()})`].join("\n");
721
- }
722
- /**
723
- * An expression that builds the React adapter without React Grab, for module or script text.
724
- * It needs nothing from the project, so pages without a dev server can run it too.
725
- * @returns JavaScript expression text evaluating to the picker adapter.
726
- */
727
- function reactAdapterExpression() {
728
- return `(${reactGrabAdapter.toString()})(null, ${helpers()})`;
729
- }
730
- //#endregion
731
- //#region src/bridge.ts
732
- /**
733
- * Hosts add this to the project's own pages during development, so Bud's Pages browser can follow
734
- * a page it shows in a cross-origin frame. It does nothing outside a frame, answers only its
735
- * parent, and reports where the page is. It receives nothing but back, forward, reload and the
736
- * picker's requests: `bud:pick` runs the project's picker and answers `bud:picked` with the
737
- * element, where it is on the page and the page's width; `bud:pick-cancel` ends a pick.
738
- */
739
- var bridgeScript = `(() => {
740
- if (window.parent === window || window.__budBridge) return
741
- window.__budBridge = true
742
- let parentOrigin = null
743
- let send = () => {
744
- if (!parentOrigin) return
745
- window.parent.postMessage(
746
- {
747
- type: 'bud:location',
748
- path: location.pathname + location.search + location.hash,
749
- title: document.title,
750
- },
751
- parentOrigin,
752
- )
753
- }
754
- addEventListener('message', (event) => {
755
- if (event.source !== window.parent) return
756
- let type = event.data && event.data.type
757
- if (type === 'bud:hello') {
758
- parentOrigin = event.origin
759
- send()
760
- } else if (event.origin !== parentOrigin) return
761
- else if (type === 'bud:back') history.back()
762
- else if (type === 'bud:forward') history.forward()
763
- else if (type === 'bud:reload') location.reload()
764
- else if (type === 'bud:pick') pick(event.data.id, event.origin)
765
- else if (type === 'bud:pick-cancel') picker().then((module) => module.cancel(), () => {})
766
- })
767
- let picker = () => import(${JSON.stringify(PICKER_MODULE_URL)})
768
- // The element a person picks, its point in page pixels and where it shows in the viewport, for
769
- // the parent that asked.
770
- let pick = async (id, origin) => {
771
- if (typeof id !== 'string' || id.length > 64) return
772
- let anchor = null
773
- let point = null
774
- let view = null
775
- try {
776
- anchor = await (await picker()).pick()
777
- } catch {}
778
- try {
779
- let element = anchor && document.querySelector(anchor.selector)
780
- if (element) {
781
- let rect = element.getBoundingClientRect()
782
- point = {
783
- x: rect.left + scrollX + anchor.offsetX * rect.width,
784
- y: rect.top + scrollY + anchor.offsetY * rect.height,
785
- width: document.documentElement.clientWidth,
786
- }
787
- view = {
788
- x: rect.left + anchor.offsetX * rect.width,
789
- y: rect.top + anchor.offsetY * rect.height,
790
- }
791
- }
792
- } catch {}
793
- window.parent.postMessage(
794
- {
795
- type: 'bud:picked',
796
- id,
797
- path: location.pathname + location.search + location.hash,
798
- anchor,
799
- point,
800
- view,
801
- },
802
- origin,
803
- )
804
- }
805
- for (let method of ['pushState', 'replaceState']) {
806
- let original = history[method]
807
- history[method] = function (...args) {
808
- let result = original.apply(this, args)
809
- queueMicrotask(send)
810
- return result
811
- }
812
- }
813
- addEventListener('popstate', send)
814
- addEventListener('hashchange', send)
815
- addEventListener('load', send)
816
- new MutationObserver(send).observe(document.head || document.documentElement, {
817
- subtree: true,
818
- childList: true,
819
- characterData: true,
820
- })
821
- })()`;
822
- /**
823
- * The page modules a project's picker runs as, by module ID. Hosts serve them to the project's
824
- * own pages during development; they hold no Bud state, only the picker's page code.
825
- * @param picker - The project's configured picker.
826
- * @returns Module text by ID, the picker module first.
827
- */
828
- function pickerModules(picker) {
829
- if (picker.name === "bud:react-grab" || picker.name === "bud:react") return /* @__PURE__ */ new Map([[PICKER_MODULE_ID, pickerModule(picker.name, PICKER_ADAPTER_MODULE_ID)], [PICKER_ADAPTER_MODULE_ID, picker.name === "bud:react-grab" ? reactGrabAdapterModule() : `export default ${reactAdapterExpression()}`]]);
830
- let adapter = picker.module ? `/${picker.module.slice(2)}` : null;
831
- return /* @__PURE__ */ new Map([[PICKER_MODULE_ID, pickerModule(picker.name, adapter)]]);
832
- }
833
- /**
834
- * The picker as a classic script, for pages no Bud Vite plugin serves, such as a branch's build.
835
- * React pickers read React's development build without React Grab, which such pages can't import;
836
- * a project's own picker module needs its dev server, so the DOM picker stands in for it.
837
- * @param picker - The project's configured picker.
838
- * @returns Script text that leaves the picker on `window.__budPicker`.
839
- */
840
- function pickerPageScript(picker) {
841
- if (picker.name === "bud:react-grab" || picker.name === "bud:react") return pickerScript(picker.name, reactAdapterExpression());
842
- return pickerScript(picker.module ? "bud:dom" : picker.name, null);
843
- }
844
- //#endregion
845
- export { PICKER_MODULE_ID, PICKER_MODULE_URL, bridgeScript, pickerModules, pickerPageScript };
1
+ export { i as PICKER_MODULE_ID, a as PICKER_MODULE_URL, t as bridgeScript, n as pickerModules, r as pickerPageScript } from "./assets/bridge-DQSBYHmw.js";