@valbuild/shared 0.150.3 → 0.150.8

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 (40) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/client/dist/valbuild-shared-client.cjs.dev.js +8 -2
  3. package/client/dist/valbuild-shared-client.cjs.prod.js +8 -2
  4. package/client/dist/valbuild-shared-client.esm.js +2 -2
  5. package/dist/{acquireTypes-50960f2c.esm.js → acquireTypes-6e2f7961.esm.js} +2 -2
  6. package/dist/{acquireTypes-de10005d.cjs.dev.js → acquireTypes-84a4077a.cjs.dev.js} +6 -6
  7. package/dist/{acquireTypes-e9467a2a.cjs.prod.js → acquireTypes-dd976839.cjs.prod.js} +6 -6
  8. package/dist/{createForOfIteratorHelper-3db5d737.esm.js → createForOfIteratorHelper-666a6d17.esm.js} +31 -15
  9. package/dist/{createForOfIteratorHelper-90e6a8b6.cjs.prod.js → createForOfIteratorHelper-87a33eff.cjs.dev.js} +31 -15
  10. package/dist/{createForOfIteratorHelper-d86bb352.cjs.dev.js → createForOfIteratorHelper-fef4fa7d.cjs.prod.js} +31 -15
  11. package/dist/declarations/src/client/index.d.ts +1 -0
  12. package/dist/declarations/src/internal/ApiRoutes.d.ts +8 -0
  13. package/dist/declarations/src/internal/elementPicker.d.ts +96 -0
  14. package/dist/declarations/src/internal/index.d.ts +1 -0
  15. package/dist/declarations/src/internal/valCanvasProtocol.d.ts +36 -0
  16. package/dist/{getSitemapTree-667bcb3c.cjs.prod.js → getSitemapTree-873f7266.cjs.prod.js} +333 -2
  17. package/dist/{getSitemapTree-5afbc3ac.esm.js → getSitemapTree-b6161fd8.esm.js} +328 -3
  18. package/dist/{getSitemapTree-0fa0569c.cjs.dev.js → getSitemapTree-be70d9fc.cjs.dev.js} +333 -2
  19. package/dist/{proposalProject-a3d3ad76.esm.js → proposalProject-689c24cc.esm.js} +2 -2
  20. package/dist/{proposalProject-cdc53711.cjs.dev.js → proposalProject-926f2c68.cjs.dev.js} +2 -2
  21. package/dist/{proposalProject-28550146.cjs.prod.js → proposalProject-fab0c026.cjs.prod.js} +2 -2
  22. package/dist/{protocol-1c13de0d.cjs.prod.js → protocol-4e2a455b.cjs.prod.js} +1 -1
  23. package/dist/{protocol-3b9ef786.esm.js → protocol-7ddc1a71.esm.js} +1 -1
  24. package/dist/{protocol-d8a6efda.cjs.dev.js → protocol-ac1c3ec7.cjs.dev.js} +1 -1
  25. package/dist/{slicedToArray-6cd80315.esm.js → slicedToArray-22567815.esm.js} +2 -18
  26. package/dist/{slicedToArray-62e428df.cjs.dev.js → slicedToArray-c8a29f6b.cjs.dev.js} +1 -18
  27. package/dist/{slicedToArray-af50e684.cjs.prod.js → slicedToArray-d99b4e2e.cjs.prod.js} +1 -18
  28. package/internal/dist/valbuild-shared-internal.cjs.dev.js +25 -9
  29. package/internal/dist/valbuild-shared-internal.cjs.prod.js +25 -9
  30. package/internal/dist/valbuild-shared-internal.esm.js +17 -7
  31. package/package.json +1 -1
  32. package/publish/dist/valbuild-shared-publish.cjs.dev.js +6 -6
  33. package/publish/dist/valbuild-shared-publish.cjs.prod.js +6 -6
  34. package/publish/dist/valbuild-shared-publish.esm.js +4 -4
  35. package/typecheck/dist/valbuild-shared-typecheck.cjs.dev.js +7 -7
  36. package/typecheck/dist/valbuild-shared-typecheck.cjs.prod.js +7 -7
  37. package/typecheck/dist/valbuild-shared-typecheck.esm.js +5 -5
  38. package/typecheck/testing/dist/valbuild-shared-typecheck-testing.cjs.dev.js +4 -4
  39. package/typecheck/testing/dist/valbuild-shared-typecheck-testing.cjs.prod.js +4 -4
  40. package/typecheck/testing/dist/valbuild-shared-typecheck-testing.esm.js +3 -3
@@ -1,4 +1,4 @@
1
- import { _ as _typeof, a as _createForOfIteratorHelper, b as _objectSpread2 } from './createForOfIteratorHelper-3db5d737.esm.js';
1
+ import { _ as _typeof, a as _objectSpread2, b as _toConsumableArray, c as _createForOfIteratorHelper } from './createForOfIteratorHelper-666a6d17.esm.js';
2
2
  import { Internal, tanStackSegmentsOfRoutePath } from '@valbuild/core';
3
3
 
4
4
  var VAL_CONFIG_SESSION_STORAGE_KEY = "val-config";
@@ -73,8 +73,16 @@ function isValCanvasPageMessage(data) {
73
73
  if (_typeof(data) !== "object" || data === null) return false;
74
74
  var message = data;
75
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";
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
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"];
78
86
 
79
87
  /**
80
88
  * Whether a value is a colour a `theme` message may carry.
@@ -106,6 +114,10 @@ function isValCanvasStudioMessage(data) {
106
114
  // at all, and there is one guard rather than one per framework binding.
107
115
  return isCanvasSelectionColor(message.selection) && isCanvasSelectionColor(message.selectionSoft);
108
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
+ }
109
121
  return message.type === "rescan" || message.type === "highlight" || message.type === "setPicking" || message.type === "sourceUpdate" || message.type === "sourcesSynced";
110
122
  }
111
123
 
@@ -148,6 +160,319 @@ function withValCanvasParam(url) {
148
160
  return "".concat(url).concat(separator).concat(VAL_CANVAS_PARAM, "=1");
149
161
  }
150
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
+
151
476
  function parseRoutePattern(pattern) {
152
477
  if (pattern === "" || pattern === "/") {
153
478
  return [];
@@ -389,4 +714,4 @@ function getPatternFromModuleFilePath(moduleFilePath, srcFolder) {
389
714
  .replace("/page.val.ts", "").replace("/page.val.js", "");
390
715
  }
391
716
 
392
- 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, formatRoutePattern as h, isValCanvasPageMessage as i, getNextAppRouterSourceFolder as j, getTanStackRouterSourceFolder as k, getPageRouterSourceFolder as l, isTanStackRoutesFolder as m, getPageRouterSitemapTree as n, getPatternFromModuleFilePath as o, parseRoutePattern as p, withValCanvasParam as w };
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 };