@valbuild/shared 0.150.10 → 0.150.12

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 (51) hide show
  1. package/CHANGELOG.md +33 -0
  2. package/client/dist/valbuild-shared-client.cjs.dev.js +16 -2
  3. package/client/dist/valbuild-shared-client.cjs.prod.js +16 -2
  4. package/client/dist/valbuild-shared-client.esm.js +2 -2
  5. package/dist/{acquireTypes-dd976839.cjs.prod.js → acquireTypes-6250a305.cjs.prod.js} +46 -46
  6. package/dist/{acquireTypes-6e2f7961.esm.js → acquireTypes-c2227b23.esm.js} +2 -2
  7. package/dist/{acquireTypes-84a4077a.cjs.dev.js → acquireTypes-c9e757a1.cjs.dev.js} +46 -46
  8. package/dist/{slicedToArray-22567815.esm.js → createForOfIteratorHelper-9b80f1a2.esm.js} +136 -106
  9. package/dist/{slicedToArray-d99b4e2e.cjs.prod.js → createForOfIteratorHelper-9ca2078d.cjs.prod.js} +142 -111
  10. package/dist/{slicedToArray-c8a29f6b.cjs.dev.js → createForOfIteratorHelper-f2d7ac6d.cjs.dev.js} +142 -111
  11. package/dist/declarations/src/client/index.d.ts +2 -0
  12. package/dist/declarations/src/internal/ApiRoutes.d.ts +35 -0
  13. package/dist/declarations/src/internal/index.d.ts +2 -0
  14. package/dist/declarations/src/internal/pageInspection.d.ts +117 -0
  15. package/dist/declarations/src/internal/quickPreview.d.ts +91 -0
  16. package/dist/declarations/src/internal/valCanvasProtocol.d.ts +53 -0
  17. package/dist/declarations/src/publish/buildProposal.d.ts +16 -1
  18. package/dist/declarations/src/publish/buildQuickPreview.d.ts +46 -0
  19. package/dist/declarations/src/publish/index.d.ts +3 -2
  20. package/dist/declarations/src/publish/runStudioDeploy.d.ts +10 -0
  21. package/dist/getSitemapTree-5354ce90.cjs.prod.js +1421 -0
  22. package/dist/getSitemapTree-97b3166f.esm.js +1381 -0
  23. package/dist/getSitemapTree-d934ff9c.cjs.dev.js +1421 -0
  24. package/dist/{proposalProject-689c24cc.esm.js → proposalProject-5da177d5.esm.js} +1 -2
  25. package/dist/{proposalProject-926f2c68.cjs.dev.js → proposalProject-76caa377.cjs.prod.js} +2 -3
  26. package/dist/{proposalProject-fab0c026.cjs.prod.js → proposalProject-81fee08f.cjs.dev.js} +2 -3
  27. package/dist/{protocol-7ddc1a71.esm.js → protocol-55cfa3cf.esm.js} +1 -1
  28. package/dist/{protocol-4e2a455b.cjs.prod.js → protocol-b1055ef0.cjs.prod.js} +6 -6
  29. package/dist/{protocol-ac1c3ec7.cjs.dev.js → protocol-d0efb8cd.cjs.dev.js} +6 -6
  30. package/dist/wrapNativeSuper-639b12b7.esm.js +107 -0
  31. package/dist/wrapNativeSuper-8673414f.cjs.prod.js +113 -0
  32. package/dist/wrapNativeSuper-933f991e.cjs.dev.js +113 -0
  33. package/internal/dist/valbuild-shared-internal.cjs.dev.js +94 -34
  34. package/internal/dist/valbuild-shared-internal.cjs.prod.js +94 -34
  35. package/internal/dist/valbuild-shared-internal.esm.js +52 -6
  36. package/package.json +2 -2
  37. package/publish/dist/valbuild-shared-publish.cjs.dev.js +589 -237
  38. package/publish/dist/valbuild-shared-publish.cjs.prod.js +589 -237
  39. package/publish/dist/valbuild-shared-publish.esm.js +504 -155
  40. package/typecheck/dist/valbuild-shared-typecheck.cjs.dev.js +34 -34
  41. package/typecheck/dist/valbuild-shared-typecheck.cjs.prod.js +34 -34
  42. package/typecheck/dist/valbuild-shared-typecheck.esm.js +5 -5
  43. package/typecheck/testing/dist/valbuild-shared-typecheck-testing.cjs.dev.js +7 -7
  44. package/typecheck/testing/dist/valbuild-shared-typecheck-testing.cjs.prod.js +7 -7
  45. package/typecheck/testing/dist/valbuild-shared-typecheck-testing.esm.js +3 -3
  46. package/dist/createForOfIteratorHelper-666a6d17.esm.js +0 -137
  47. package/dist/createForOfIteratorHelper-87a33eff.cjs.dev.js +0 -145
  48. package/dist/createForOfIteratorHelper-fef4fa7d.cjs.prod.js +0 -145
  49. package/dist/getSitemapTree-873f7266.cjs.prod.js +0 -743
  50. package/dist/getSitemapTree-b6161fd8.esm.js +0 -717
  51. package/dist/getSitemapTree-be70d9fc.cjs.dev.js +0 -743
@@ -1,717 +0,0 @@
1
- import { _ as _typeof, a as _objectSpread2, b as _toConsumableArray, c as _createForOfIteratorHelper } from './createForOfIteratorHelper-666a6d17.esm.js';
2
- import { Internal, tanStackSegmentsOfRoutePath } from '@valbuild/core';
3
-
4
- var VAL_CONFIG_SESSION_STORAGE_KEY = "val-config";
5
- var VAL_THEME_SESSION_STORAGE_KEY = "val-theme";
6
- var VAL_AI_SESSION_STORAGE_KEY = "val-ai-session";
7
-
8
- /**
9
- * The protocol between the studio's canvas and the page inside it.
10
- *
11
- * The canvas shows the running site in a frame. That frame is a different
12
- * document — the customer's app, rendered by their components — so the studio
13
- * cannot reach into it, and it cannot reach out. Everything they say to each
14
- * other goes through `postMessage`, and this is the vocabulary.
15
- *
16
- * It lives in `shared` because both halves have to agree on it: the page half
17
- * ships in `@valbuild/next`, the studio half in `@valbuild/ui`, and a message
18
- * shape defined twice is a message shape that will differ once.
19
- *
20
- * ## Why a query parameter turns it on
21
- *
22
- * The frame has to render the page as Val sees it — draft content, with
23
- * `data-val-path` on every element Val tracks — while *not* showing Val's own
24
- * overlay, because the studio is already the UI. Nothing about the cookies can
25
- * express that: they are per-origin, and the studio and the page share an
26
- * origin, so a cookie would change the customer's own tabs too. A parameter on
27
- * the frame's URL is scoped to exactly the one document that needs it.
28
- */
29
-
30
- /** Marks a page load as the studio's canvas frame. */
31
- var VAL_CANVAS_PARAM = "val_canvas";
32
-
33
- /**
34
- * Every message is tagged with this, and the tag is checked on receipt.
35
- *
36
- * A window receives messages from anything that has a handle on it —
37
- * extensions, embeds, other frames — and `event.data` is whatever they chose to
38
- * send. Checking a discriminator before reading anything else is what keeps a
39
- * stray message from being read as a canvas instruction.
40
- */
41
- var VAL_CANVAS_MESSAGE = "val-canvas";
42
-
43
- /** One element on the page that Val has a path for. */
44
-
45
- /**
46
- * The colours Val outlines the page's content in, when nobody has said
47
- * otherwise.
48
- *
49
- * They mirror `--bg-page-selection` and `--bg-page-selection-soft` in
50
- * `packages/ui/spa/index.css`, and they are literals here because the page the
51
- * bridge runs in has none of Val's stylesheet — no `:host`, no tokens, nothing
52
- * to inherit. A CSS custom property genuinely cannot reach across that
53
- * boundary, which is why the colours are SENT (see the `theme` message below)
54
- * rather than derived.
55
- *
56
- * They live beside the protocol rather than with the theme code on purpose:
57
- * `@valbuild/shared/client` is what the bridge imports, and it exists to keep
58
- * production bundles small (see the docblock on that entrypoint). Two strings
59
- * cost nothing; the accent generator that produces the non-default values is
60
- * ~350 lines of colour maths that no visitor to a Val site should download.
61
- *
62
- * `canvasSelectionDefaults.test.ts` holds them equal to the stylesheet.
63
- */
64
- var DEFAULT_CANVAS_SELECTION = "#079455";
65
- var DEFAULT_CANVAS_SELECTION_SOFT = "rgba(7, 148, 85, 0.4)";
66
-
67
- /** What the page tells the studio. */
68
-
69
- /** What the studio tells the page. */
70
-
71
- /** Narrow an unknown `event.data` to a message from the page. */
72
- function isValCanvasPageMessage(data) {
73
- if (_typeof(data) !== "object" || data === null) return false;
74
- var message = data;
75
- if (message.val !== VAL_CANVAS_MESSAGE) return false;
76
- return message.type === "ready" || message.type === "elements" || message.type === "clicked" || message.type === "pinch" || message.type === "zoom" || message.type === "refreshing" || message.type === "elementPickingStopped" || message.type === "elementPicked" && isPickedElement(data.element);
77
- }
78
- function isPickedElement(value) {
79
- if (_typeof(value) !== "object" || value === null) return false;
80
- var element = value;
81
- return typeof element.tag === "string" && typeof element.text === "string" && typeof element.selector === "string" && Array.isArray(element.classes) && element.classes.every(function (item) {
82
- return typeof item === "string";
83
- }) && (element.valPath === undefined || typeof element.valPath === "string");
84
- }
85
- var PICK_MODIFIERS = ["alt", "meta", "shift", "ctrl"];
86
-
87
- /**
88
- * Whether a value is a colour a `theme` message may carry.
89
- *
90
- * A whitelist rather than an escape, and the reason is where these two strings
91
- * end up: the bridge writes them into a `<style>` element in the CUSTOMER's
92
- * document with `dangerouslySetInnerHTML`, so a value containing `</style>` is
93
- * a script tag away from running in someone else's page. A page can be
94
- * `postMessage`d by any window holding a handle on it, and this guard is the
95
- * only thing between such a message and that sink.
96
- *
97
- * The two shapes are exactly what `themeCustomProperties` produces — a hex, and
98
- * the `rgba()` it derives the soft outline as. Narrowing the contract is easier
99
- * to keep true than sanitising an open one, and a forged message that passes
100
- * this can do no more than pick a different colour.
101
- */
102
- var CANVAS_SELECTION_COLOR = /^(?:#[0-9a-f]{3,8}|rgba?\(\s*\d{1,3}\s*,\s*\d{1,3}\s*,\s*\d{1,3}\s*(?:,\s*(?:0|1|0?\.\d+)\s*)?\))$/i;
103
- function isCanvasSelectionColor(value) {
104
- return typeof value === "string" && CANVAS_SELECTION_COLOR.test(value);
105
- }
106
-
107
- /** Narrow an unknown `event.data` to a message from the studio. */
108
- function isValCanvasStudioMessage(data) {
109
- if (_typeof(data) !== "object" || data === null) return false;
110
- var message = data;
111
- if (message.val !== VAL_CANVAS_MESSAGE) return false;
112
- if (message.type === "theme") {
113
- // Checked here and not in the bridge: a rejected message is never applied
114
- // at all, and there is one guard rather than one per framework binding.
115
- return isCanvasSelectionColor(message.selection) && isCanvasSelectionColor(message.selectionSoft);
116
- }
117
- if (message.type === "pickElements") {
118
- var pick = data;
119
- return typeof pick.enabled === "boolean" && typeof pick.active === "boolean" && typeof pick.keepPicked === "boolean" && PICK_MODIFIERS.includes(pick.modifier);
120
- }
121
- return message.type === "rescan" || message.type === "highlight" || message.type === "setPicking" || message.type === "sourceUpdate" || message.type === "sourcesSynced";
122
- }
123
-
124
- /**
125
- * Whether this document is showing in the studio's canvas frame.
126
- *
127
- * The parameter marks the document the studio LOADED, and that is not always
128
- * the document the frame ends up holding. A frame navigates on its own: a site
129
- * with a login of its own redirects a signed-out canvas to its sign-in page,
130
- * and the sign-in sends it back to wherever the site chooses. Each of those is
131
- * a new document without the parameter, and it used to render Val's whole
132
- * overlay inside the canvas — a studio in the studio, which never told the
133
- * canvas it was there, so the canvas never went live again until reloaded.
134
- *
135
- * So where the frame SITS answers too: a document whose parent is the studio
136
- * is in the canvas, whatever its own address says. `parentPathname` is that
137
- * parent's path: `null` for a top-level document, and for a parent on another
138
- * origin, whose `location` cannot be read and which is not the studio anyway.
139
- */
140
- function isValCanvasFrame(search) {
141
- var parentPathname = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null;
142
- if (parentPathname !== null && isValStudioPathname(parentPathname)) {
143
- return true;
144
- }
145
- try {
146
- return new URLSearchParams(search).get(VAL_CANVAS_PARAM) !== null;
147
- } catch (_unused) {
148
- return false;
149
- }
150
- }
151
-
152
- /** Whether a path is the studio's own route, where the canvas lives. */
153
- function isValStudioPathname(pathname) {
154
- return pathname === "/val" || pathname.startsWith("/val/");
155
- }
156
-
157
- /** Add the canvas marker to a page URL. */
158
- function withValCanvasParam(url) {
159
- var separator = url.includes("?") ? "&" : "?";
160
- return "".concat(url).concat(separator).concat(VAL_CANVAS_PARAM, "=1");
161
- }
162
-
163
- /**
164
- * Pointing at anything on a page, as Lovable's picker does: hover outlines
165
- * the element under the pointer, a click picks it, and the assistant is told
166
- * which (valbuild/home `docs/design-tab.md`).
167
- *
168
- * ANY element, not only what Val marks. The design tab changes code, and the
169
- * thing a person wants changed is as often a wrapper, a gap or a button as a
170
- * field -- so a field's path is extra information when there is one
171
- * (`valPath`), never the condition for picking.
172
- *
173
- * Picking is on while a MODIFIER is held, so the page stays a page: links
174
- * follow, menus open, and nothing has to be switched back off. `active`
175
- * turns it on without one, for a Select button or a touch screen.
176
- *
177
- * Plain DOM, nothing of React's or the Studio's, and in `shared` because
178
- * both halves need it: the canvas bridge (`@valbuild/next`,
179
- * `@valbuild/tanstack`) runs it inside the proposal's page, which is another
180
- * origin than the design tab and the only place the page's elements can be
181
- * reached; the Studio's stories run it on a page of their own. Only the
182
- * `PickedElement` crosses the frame (`valCanvasProtocol.ts`).
183
- */
184
-
185
- var TEXT_LENGTH = 80;
186
- var CLASSES = 6;
187
- function describeElement(element, root) {
188
- var _element$textContent, _element$closest$getA, _element$closest;
189
- var text = ((_element$textContent = element.textContent) !== null && _element$textContent !== void 0 ? _element$textContent : "").replace(/\s+/g, " ").trim();
190
- var valPath = (_element$closest$getA = (_element$closest = element.closest("[data-val-path]")) === null || _element$closest === void 0 ? void 0 : _element$closest.getAttribute("data-val-path")) !== null && _element$closest$getA !== void 0 ? _element$closest$getA : undefined;
191
- return _objectSpread2({
192
- tag: element.tagName.toLowerCase(),
193
- text: text.length > TEXT_LENGTH ? "".concat(text.slice(0, TEXT_LENGTH - 1), "\u2026") : text,
194
- classes: Array.from(element.classList).slice(0, CLASSES),
195
- selector: selectorOf(element, root)
196
- }, valPath !== undefined ? {
197
- valPath: valPath
198
- } : {});
199
- }
200
- function selectorOf(element, root) {
201
- var parts = [];
202
- var at = element;
203
- while (at !== null && at !== root) {
204
- var tag = at.tagName.toLowerCase();
205
- if (at.id !== "") {
206
- parts.unshift("".concat(tag, "#").concat(at.id));
207
- break;
208
- }
209
- var parent = at.parentElement;
210
- var same = parent === null ? [] : Array.from(parent.children).filter(function (sibling) {
211
- var _at;
212
- return sibling.tagName === ((_at = at) === null || _at === void 0 ? void 0 : _at.tagName);
213
- });
214
- parts.unshift(same.length > 1 ? "".concat(tag, ":nth-of-type(").concat(same.indexOf(at) + 1, ")") : tag);
215
- at = parent;
216
- }
217
- return parts.join(" > ");
218
- }
219
-
220
- /** What a person is told to hold, on their own keyboard. */
221
- function modifierLabel(modifier, mac) {
222
- switch (modifier) {
223
- case "alt":
224
- return mac ? "⌥" : "Alt";
225
- case "meta":
226
- return mac ? "⌘" : "Win";
227
- case "shift":
228
- return mac ? "⇧" : "Shift";
229
- case "ctrl":
230
- return mac ? "⌃" : "Ctrl";
231
- }
232
- }
233
- function held(event, modifier) {
234
- switch (modifier) {
235
- case "alt":
236
- return event.altKey;
237
- case "meta":
238
- return event.metaKey;
239
- case "shift":
240
- return event.shiftKey;
241
- case "ctrl":
242
- return event.ctrlKey;
243
- }
244
- }
245
- /**
246
- * Listens on `root` (capturing, so the page's own handlers never see a pick)
247
- * and returns what stops it.
248
- */
249
- function attachElementPicker(root, options) {
250
- var win = root.ownerDocument.defaultView;
251
- var last = null;
252
- var picking = function picking(event) {
253
- return options.active() || held(event, options.modifier);
254
- };
255
- var target = function target(event) {
256
- return event.target instanceof Element && root.contains(event.target) ? event.target : null;
257
- };
258
- var onMove = function onMove(event) {
259
- last = {
260
- x: event.clientX,
261
- y: event.clientY
262
- };
263
- options.onHover(picking(event) ? target(event) : null);
264
- };
265
- var onClick = function onClick(event) {
266
- if (!picking(event)) return;
267
- var element = target(event);
268
- if (element === null) return;
269
- event.preventDefault();
270
- event.stopPropagation();
271
- options.onPick(element);
272
- };
273
- // Pressing the modifier with the pointer still: outline what is under it
274
- // now, rather than after the next move.
275
- var onKey = function onKey(event) {
276
- if (!picking(event)) {
277
- options.onHover(null);
278
- return;
279
- }
280
- if (last === null) return;
281
- var under = root.ownerDocument.elementFromPoint(last.x, last.y);
282
- options.onHover(under !== null && root.contains(under) ? under : null);
283
- };
284
- var onLeave = function onLeave() {
285
- last = null;
286
- options.onHover(null);
287
- };
288
- root.addEventListener("mousemove", onMove, true);
289
- root.addEventListener("click", onClick, true);
290
- root.addEventListener("mouseleave", onLeave);
291
- win === null || win === void 0 || win.addEventListener("keydown", onKey, true);
292
- win === null || win === void 0 || win.addEventListener("keyup", onKey, true);
293
- return function () {
294
- root.removeEventListener("mousemove", onMove, true);
295
- root.removeEventListener("click", onClick, true);
296
- root.removeEventListener("mouseleave", onLeave);
297
- win === null || win === void 0 || win.removeEventListener("keydown", onKey, true);
298
- win === null || win === void 0 || win.removeEventListener("keyup", onKey, true);
299
- };
300
- }
301
-
302
- /**
303
- * The outlines over the page while picking: the element under the pointer,
304
- * named, and the one picked.
305
- *
306
- * Boxes `position: fixed` on top of everything, with `pointer-events: none`,
307
- * appended to the page's body -- not outlines on the elements themselves.
308
- * The canvas's field outlines are a stylesheet so they cannot disturb the
309
- * page's layout (`ValCanvasBridge`); a fixed box is out of the flow, so it
310
- * cannot either, and it is the one way to put a NAME beside any element, which
311
- * a selector cannot reach.
312
- *
313
- * In a shadow root of one host element: the bridge re-measures the page on
314
- * every `style` change under `body`, and a box that follows the pointer
315
- * changes its style every frame. Inside a shadow root those changes are not
316
- * the page's, so the host's one insertion is all the bridge sees.
317
- */
318
-
319
- var TOP = "2147483647";
320
- function createPickerOverlay(doc, initialColor) {
321
- var color = initialColor;
322
- var shown = {
323
- hover: null,
324
- picked: null
325
- };
326
- var host = doc.createElement("div");
327
- host.setAttribute("data-val-picker", "");
328
- var shadow = host.attachShadow({
329
- mode: "open"
330
- });
331
- doc.body.appendChild(host);
332
- var box = function box(kind) {
333
- var el = doc.createElement("div");
334
- el.setAttribute("data-kind", kind);
335
- Object.assign(el.style, {
336
- position: "fixed",
337
- pointerEvents: "none",
338
- zIndex: TOP,
339
- boxSizing: "border-box",
340
- display: "none"
341
- });
342
- shadow.appendChild(el);
343
- return el;
344
- };
345
- var boxes = {
346
- hover: box("hover"),
347
- picked: box("picked")
348
- };
349
- var label = doc.createElement("span");
350
- Object.assign(label.style, {
351
- position: "absolute",
352
- left: "-2px",
353
- padding: "1px 4px",
354
- borderRadius: "2px",
355
- font: "500 10px/1.4 ui-monospace, SFMono-Regular, Menlo, monospace",
356
- color: "#fff",
357
- whiteSpace: "nowrap"
358
- });
359
- boxes.hover.appendChild(label);
360
- // The pointer says it is picking, and a link under it is not a link.
361
- var cursor = doc.createElement("style");
362
- cursor.textContent = "[data-val-picking] * { cursor: crosshair !important; }";
363
- doc.head.appendChild(cursor);
364
- var place = function place(kind) {
365
- var element = shown[kind];
366
- var el = boxes[kind];
367
- if (element === null || !element.isConnected) {
368
- el.style.display = "none";
369
- return;
370
- }
371
- var rect = element.getBoundingClientRect();
372
- Object.assign(el.style, {
373
- display: "block",
374
- top: "".concat(rect.top - 2, "px"),
375
- left: "".concat(rect.left - 2, "px"),
376
- width: "".concat(rect.width + 4, "px"),
377
- height: "".concat(rect.height + 4, "px"),
378
- border: "2px ".concat(kind === "hover" ? "solid" : "dashed", " ").concat(color)
379
- });
380
- if (kind === "hover") {
381
- label.textContent = elementLabel(element);
382
- label.style.background = color;
383
- // Above the box, unless that is off the top of the window.
384
- if (rect.top >= 18) {
385
- label.style.top = "";
386
- label.style.bottom = "100%";
387
- } else {
388
- label.style.bottom = "";
389
- label.style.top = "100%";
390
- }
391
- }
392
- };
393
- var frame = null;
394
- var win = doc.defaultView;
395
- var reposition = function reposition() {
396
- if (frame !== null || win === null) return;
397
- frame = win.requestAnimationFrame(function () {
398
- frame = null;
399
- place("hover");
400
- place("picked");
401
- });
402
- };
403
- win === null || win === void 0 || win.addEventListener("scroll", reposition, true);
404
- win === null || win === void 0 || win.addEventListener("resize", reposition);
405
- return {
406
- show: function show(kind, element) {
407
- shown[kind] = element;
408
- if (kind === "hover") {
409
- if (element !== null) {
410
- doc.documentElement.setAttribute("data-val-picking", "");
411
- } else {
412
- doc.documentElement.removeAttribute("data-val-picking");
413
- }
414
- }
415
- place(kind);
416
- },
417
- setColor: function setColor(next) {
418
- color = next;
419
- place("hover");
420
- place("picked");
421
- },
422
- destroy: function destroy() {
423
- if (frame !== null) win === null || win === void 0 || win.cancelAnimationFrame(frame);
424
- win === null || win === void 0 || win.removeEventListener("scroll", reposition, true);
425
- win === null || win === void 0 || win.removeEventListener("resize", reposition);
426
- host.remove();
427
- cursor.remove();
428
- doc.documentElement.removeAttribute("data-val-picking");
429
- }
430
- };
431
- }
432
-
433
- /** `h2.mb-6.text-2xl`: what the hover box is named. */
434
- function elementLabel(element) {
435
- var classes = Array.from(element.classList).slice(0, 2);
436
- return [element.tagName.toLowerCase()].concat(_toConsumableArray(classes)).join(".");
437
- }
438
- /**
439
- * Picking on a page, whole: the listeners, the outlines, and Esc to stop
440
- * picking without the modifier. What a canvas bridge mounts.
441
- */
442
- function startElementPicking(root, options) {
443
- var _doc$defaultView;
444
- var doc = root.ownerDocument;
445
- var overlay = createPickerOverlay(doc, options.color);
446
- var detach = attachElementPicker(root, {
447
- modifier: options.modifier,
448
- active: options.active,
449
- onHover: function onHover(element) {
450
- return overlay.show("hover", element);
451
- },
452
- onPick: function onPick(element) {
453
- overlay.show("hover", null);
454
- overlay.show("picked", element);
455
- options.onPick(describeElement(element, root));
456
- }
457
- });
458
- var onKey = function onKey(event) {
459
- if (event.key === "Escape" && options.active()) options.onStop();
460
- };
461
- (_doc$defaultView = doc.defaultView) === null || _doc$defaultView === void 0 || _doc$defaultView.addEventListener("keydown", onKey);
462
- return {
463
- clearPicked: function clearPicked() {
464
- return overlay.show("picked", null);
465
- },
466
- setColor: overlay.setColor,
467
- stop: function stop() {
468
- var _doc$defaultView2;
469
- (_doc$defaultView2 = doc.defaultView) === null || _doc$defaultView2 === void 0 || _doc$defaultView2.removeEventListener("keydown", onKey);
470
- detach();
471
- overlay.destroy();
472
- }
473
- };
474
- }
475
-
476
- function parseRoutePattern(pattern) {
477
- if (pattern === "" || pattern === "/") {
478
- return [];
479
- }
480
- var p = pattern.startsWith("/") ? pattern.slice(1) : pattern;
481
- return p.split("/").map(function (part) {
482
- var isOptionalParam = part.startsWith("[[") && part.endsWith("]]");
483
- var isNonOptionalParam = part.startsWith("[") && part.endsWith("]");
484
- var nameStart = isOptionalParam ? 2 : isNonOptionalParam ? 1 : 0;
485
- var nameEnd = part.indexOf("]", nameStart);
486
- var isArrayParam = part.slice(nameStart, nameStart + 3) === "...";
487
- var paramName = part.slice(nameStart + (isArrayParam ? 3 : 0), nameEnd);
488
- if (isOptionalParam || isNonOptionalParam) {
489
- if (isArrayParam) {
490
- return {
491
- type: "array-param",
492
- paramName: paramName,
493
- optional: isOptionalParam
494
- };
495
- } else {
496
- return {
497
- type: "string-param",
498
- paramName: paramName,
499
- optional: isOptionalParam
500
- };
501
- }
502
- }
503
- return {
504
- type: "literal",
505
- name: part
506
- };
507
- });
508
- }
509
-
510
- /**
511
- * A parsed pattern written back as segments: the inverse of
512
- * {@link parseRoutePattern}, in the vocabulary core's `matchRoutePattern`
513
- * reads.
514
- */
515
- function formatRoutePattern(pattern) {
516
- return pattern.map(function (part) {
517
- if (part.type === "literal") {
518
- return part.name;
519
- }
520
- var inner = part.type === "string-param" ? part.paramName : "...".concat(part.paramName);
521
- return part.optional ? "[[".concat(inner, "]]") : "[".concat(inner, "]");
522
- });
523
- }
524
-
525
- function getNextAppRouterSourceFolder(moduleFilePath) {
526
- if (moduleFilePath.startsWith("/app")) {
527
- return "/app";
528
- } else if (moduleFilePath.startsWith("/src/app")) {
529
- return "/src/app";
530
- }
531
- return null;
532
- }
533
-
534
- /**
535
- * The folder a TanStack Router app keeps its route files in.
536
- *
537
- * The same question as above for the other convention: `routes/` at the project
538
- * root, or under `src/`. A Val module for a route lives beside the route file
539
- * and is named the same way, so this is the prefix to strip before reading the
540
- * route pattern out of the rest.
541
- */
542
- function getTanStackRouterSourceFolder(moduleFilePath) {
543
- if (moduleFilePath.startsWith("/routes/")) {
544
- return "/routes";
545
- } else if (moduleFilePath.startsWith("/src/routes/")) {
546
- return "/src/routes";
547
- }
548
- return null;
549
- }
550
-
551
- /**
552
- * The route folder of whichever page router this module belongs to.
553
- *
554
- * The two conventions have disjoint prefixes — `app/` versus `routes/` — so a
555
- * module file path answers this on its own, which is what the Studio needs: it
556
- * walks every schema in the project and has no framework to ask.
557
- */
558
- function getPageRouterSourceFolder(moduleFilePath) {
559
- var _getNextAppRouterSour;
560
- return (_getNextAppRouterSour = getNextAppRouterSourceFolder(moduleFilePath)) !== null && _getNextAppRouterSour !== void 0 ? _getNextAppRouterSour : getTanStackRouterSourceFolder(moduleFilePath);
561
- }
562
-
563
- /**
564
- * Whether a route folder is a TanStack Router one.
565
- *
566
- * Exported so the pattern derivation and the source-folder detection cannot
567
- * drift apart about what `/src/routes` means.
568
- */
569
- function isTanStackRoutesFolder(srcFolder) {
570
- return srcFolder === "/routes" || srcFolder === "/src/routes";
571
- }
572
-
573
- // Strictly speaking this should be in the framework packages but it's shared,
574
- // because we want to use it in the ui package. We want to resolve that somehow.
575
- //
576
- // It is one function for both page routers because the tree it builds is made
577
- // of URL paths, which is the same thing in either: only `srcFolder` and the
578
- // pattern derivation differ, and both of those are arguments (or the one call
579
- // below).
580
- function getPageRouterSitemapTree(srcFolder, paths) {
581
- var root = {
582
- type: "node",
583
- name: "/",
584
- children: []
585
- };
586
- var _iterator = _createForOfIteratorHelper(paths),
587
- _step;
588
- try {
589
- var _loop = function _loop() {
590
- var path = _step.value;
591
- var urlPath = path.urlPath,
592
- moduleFilePathS = path.moduleFilePath;
593
- var moduleFilePath = moduleFilePathS;
594
- if (!urlPath.startsWith("/")) {
595
- Internal.log.error("urlPath must start with /: ".concat(urlPath));
596
- return 0; // continue
597
- }
598
- var pattern = getPatternFromModuleFilePath(moduleFilePath, srcFolder);
599
- if (urlPath === "/") {
600
- var fullPath = "/";
601
- root.pattern = getPatternFromModuleFilePath(moduleFilePath, srcFolder);
602
- root.page = {
603
- fullPath: fullPath
604
- };
605
- root.sourcePath = Internal.joinModuleFilePathAndModulePath(moduleFilePath, "\"".concat(fullPath, "\""));
606
- root.moduleFilePath = moduleFilePath;
607
- return 0; // continue
608
- }
609
- var pathParts = urlPath.split("/").slice(1).filter(Boolean);
610
- var currentNode = root;
611
- pathParts.forEach(function (part, index) {
612
- var hasChildren = index < pathParts.length - 1;
613
- var isLast = index === pathParts.length - 1;
614
- var fullPath = "/" + pathParts.slice(0, index + 1).join("/");
615
- var sourcePath = Internal.joinModuleFilePathAndModulePath(moduleFilePath, "\"".concat(fullPath, "\""));
616
- var node = hasChildren ? _objectSpread2(_objectSpread2({
617
- type: "node",
618
- name: part,
619
- pattern: pattern,
620
- moduleFilePath: moduleFilePath
621
- }, isLast ? {
622
- page: {
623
- fullPath: fullPath
624
- },
625
- sourcePath: sourcePath
626
- } : {}), {}, {
627
- children: []
628
- }) : {
629
- type: "leaf",
630
- name: part,
631
- pattern: pattern,
632
- fullPath: fullPath,
633
- moduleFilePath: moduleFilePath,
634
- sourcePath: sourcePath,
635
- children: []
636
- };
637
- var existingNodeIndex = currentNode.children.findIndex(function (node) {
638
- return node.name === part;
639
- });
640
- if (existingNodeIndex === -1) {
641
- currentNode.children.push(node);
642
- if (currentNode.type === "node") {
643
- currentNode.isLinear = true;
644
- if (currentNode.children.length > 1) {
645
- delete currentNode.isLinear;
646
- }
647
- }
648
- currentNode = node;
649
- } else {
650
- var existingNode = currentNode.children[existingNodeIndex];
651
- if (existingNode.type === "leaf" && hasChildren) {
652
- var _sourcePath = existingNode.sourcePath;
653
- // convert leaf to node
654
- currentNode.children[existingNodeIndex] = {
655
- type: "node",
656
- name: part,
657
- pattern: pattern,
658
- page: {
659
- fullPath: fullPath
660
- },
661
- sourcePath: _sourcePath,
662
- children: existingNode.children,
663
- moduleFilePath: moduleFilePath
664
- };
665
- currentNode = currentNode.children[existingNodeIndex];
666
- } else if (existingNode.type === "node" && isLast) {
667
- // add page, source path and module file path
668
- existingNode.page = {
669
- fullPath: fullPath
670
- };
671
- existingNode.sourcePath = sourcePath;
672
- existingNode.moduleFilePath = moduleFilePath;
673
- existingNode.pattern = pattern;
674
- } else {
675
- currentNode = currentNode.children[existingNodeIndex];
676
- }
677
- }
678
- });
679
- },
680
- _ret;
681
- for (_iterator.s(); !(_step = _iterator.n()).done;) {
682
- _ret = _loop();
683
- if (_ret === 0) continue;
684
- }
685
- } catch (err) {
686
- _iterator.e(err);
687
- } finally {
688
- _iterator.f();
689
- }
690
- return root;
691
- }
692
-
693
- /**
694
- * The route pattern a page-router module serves, e.g. `/blogs/[blog]`.
695
- *
696
- * Written in Next's vocabulary for both routers on purpose: the pattern is read
697
- * by `parseRoutePattern`, the sitemap and the Studio's key inputs, none of which
698
- * should have to know which framework the project uses. The TanStack branch
699
- * translates that framework's conventions into it; see
700
- * `tanStackSegmentsOfRoutePath` in `@valbuild/core` for the rules.
701
- */
702
- function getPatternFromModuleFilePath(moduleFilePath, srcFolder) {
703
- if (isTanStackRoutesFolder(srcFolder)) {
704
- var routePath = moduleFilePath.slice(srcFolder.length).replace(/\.val\.[tj]sx?$/, "");
705
- var segments = tanStackSegmentsOfRoutePath(routePath);
706
- // "" rather than "/" for the root, so it matches what the Next branch
707
- // returns for `/app/page.val.ts` — `parseRoutePattern` reads both as [].
708
- return segments.length === 0 ? "" : "/".concat(segments.join("/"));
709
- }
710
- return moduleFilePath.replace(srcFolder, "")
711
- // TODO: hacky!
712
- // remove route groups
713
- .replace(/\/\([^/]+\)/g, "") // not sure we want to do this?
714
- .replace("/page.val.ts", "").replace("/page.val.js", "");
715
- }
716
-
717
- export { DEFAULT_CANVAS_SELECTION as D, VAL_CONFIG_SESSION_STORAGE_KEY as V, VAL_THEME_SESSION_STORAGE_KEY as a, VAL_AI_SESSION_STORAGE_KEY as b, VAL_CANVAS_PARAM as c, VAL_CANVAS_MESSAGE as d, DEFAULT_CANVAS_SELECTION_SOFT as e, isValCanvasStudioMessage as f, isValCanvasFrame as g, describeElement as h, isValCanvasPageMessage as i, attachElementPicker as j, createPickerOverlay as k, elementLabel as l, modifierLabel as m, formatRoutePattern as n, getNextAppRouterSourceFolder as o, parseRoutePattern as p, getTanStackRouterSourceFolder as q, getPageRouterSourceFolder as r, startElementPicking as s, isTanStackRoutesFolder as t, getPageRouterSitemapTree as u, getPatternFromModuleFilePath as v, withValCanvasParam as w };