@popcraft/cli 0.16.0 → 0.17.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 (2) hide show
  1. package/dist/popcraft.mjs +1918 -1947
  2. package/package.json +2 -2
package/dist/popcraft.mjs CHANGED
@@ -1186,7 +1186,7 @@ function operations(spec = openapi) {
1186
1186
  }
1187
1187
  async function call(target2, method, path, opts = {}) {
1188
1188
  const qs = new URLSearchParams(opts.query ?? {}).toString();
1189
- const headers = { "user-agent": `popcraft-cli/${"0.16.0"}`, ...opts.headers };
1189
+ const headers = { "user-agent": `popcraft-cli/${"0.17.0"}`, ...opts.headers };
1190
1190
  if (target2.token) headers.authorization = `Bearer ${target2.token}`;
1191
1191
  if (opts.contentType) headers["content-type"] = opts.contentType;
1192
1192
  try {
@@ -32554,14 +32554,12 @@ var init_en2 = __esm({
32554
32554
  "command:export.storefront": "Export storefront\u2026",
32555
32555
  "command:export.storefront#next-commerce": "Export storefront as Next.js Commerce components",
32556
32556
  "command:export.storefront#next-commerce-store": "Export storefront as a Next.js Commerce store",
32557
- "command:export.storefront#shopify-theme": "Export storefront as a Shopify theme",
32558
32557
  "command:export.web": "Export as web code\u2026",
32559
32558
  "command:export.webm": "Export animation as WebM",
32560
32559
  "command:file.duplicate": "Duplicate file",
32561
32560
  "command:generate.video": "Generate video",
32562
32561
  "command:history.redo": "Redo",
32563
32562
  "command:history.undo": "Undo",
32564
- "command:integration.pullProducts": "Draw with my store's products",
32565
32563
  "command:media.download": "Download",
32566
32564
  "command:motion.addAudio": "Add audio",
32567
32565
  "command:motion.applyPreset": "Animate",
@@ -32684,6 +32682,7 @@ var init_en2 = __esm({
32684
32682
  "command:show.setAdvance": "Set how the show advances",
32685
32683
  "command:site.setBreakpoints": "Breakpoints",
32686
32684
  "command:site.setBreakpoints#defaults": "Reset breakpoints to Desktop, Tablet and Phone",
32685
+ "command:site.setEnvironment": "Site environment",
32687
32686
  "command:site.setGpuTransitions": "Draw 3D transitions with WebGPU",
32688
32687
  "command:site.setGpuTransitions#off": "Draw 3D transitions in CSS only",
32689
32688
  "command:site.setGpuTransitions#on": "Draw 3D transitions with WebGPU",
@@ -33809,7 +33808,6 @@ var init_en2 = __esm({
33809
33808
  "integrationsDialog.adminsOnly": "Only owners and admins of this team connect and disconnect accounts.",
33810
33809
  "integrationsDialog.cancel": "Cancel",
33811
33810
  "integrationsDialog.capabilityAuth": "Sign-in",
33812
- "integrationsDialog.capabilityCommerce": "Store",
33813
33811
  "integrationsDialog.capabilityDatabase": "Database",
33814
33812
  "integrationsDialog.capabilityDeploy": "Hosting",
33815
33813
  "integrationsDialog.capabilityRepo": "Code",
@@ -35658,7 +35656,7 @@ var init_en2 = __esm({
35658
35656
  "stateMachine.wholeFrame": "The whole frame",
35659
35657
  "storeSection.about": "Deploy it as a store that sells: a Next.js Commerce store on Vercel, with your Shopify store's products, cart and checkout.",
35660
35658
  "storeSection.building": "Building:",
35661
- "storeSection.connect": "Connect Shopify and Vercel\u2026",
35659
+ "storeSection.connect": "Connect Vercel\u2026",
35662
35660
  "storeSection.deploy": "Deploy store",
35663
35661
  "storeSection.deployAgain": "Deploy store again",
35664
35662
  "storeSection.deploying": "Deploying store\u2026",
@@ -35667,6 +35665,7 @@ var init_en2 = __esm({
35667
35665
  "storeSection.noHost": "Not connected",
35668
35666
  "storeSection.noShop": "Not connected",
35669
35667
  "storeSection.sellsFrom": "Sells from Shopify",
35668
+ "storeSection.setUpShop": "Choose the Shopify store it sells from in the Ecommerce plugin (Marketplace \u203A Plugins).",
35670
35669
  "storeSection.title": "Store",
35671
35670
  "strokeEndpointDropdown.circle": "Circle",
35672
35671
  "strokeEndpointDropdown.diamond": "Diamond",
@@ -241678,6 +241677,7 @@ function resyncText(doc2, ids2) {
241678
241677
  var isVirtualId;
241679
241678
  var init_invariants2 = __esm({
241680
241679
  "lib/document/invariants.ts"() {
241680
+ "use strict";
241681
241681
  init_auto_layout();
241682
241682
  init_scene_graph();
241683
241683
  init_text_bounds();
@@ -254786,35 +254786,6 @@ var init_contract = __esm({
254786
254786
  });
254787
254787
 
254788
254788
  // lib/document/collections.ts
254789
- var collections_exports = {};
254790
- __export(collections_exports, {
254791
- COLLECTION_LIMITS: () => COLLECTION_LIMITS,
254792
- ITEM_RECORD: () => ITEM_RECORD,
254793
- copyRecord: () => copyRecord,
254794
- copySuffix: () => copySuffix,
254795
- exprData: () => exprData,
254796
- fieldKey: () => fieldKey,
254797
- fieldText: () => fieldText,
254798
- hasItemToken: () => hasItemToken,
254799
- itemMark: () => itemMark,
254800
- itemMarks: () => itemMarks,
254801
- itemNode: () => itemNode,
254802
- itemScope: () => itemScope,
254803
- itemText: () => itemText,
254804
- itemValues: () => itemValues,
254805
- layerId: () => layerId,
254806
- recordSlugs: () => recordSlugs,
254807
- recordsIn: () => recordsIn,
254808
- removeCollection: () => removeCollection,
254809
- removeRecords: () => removeRecords,
254810
- repeatRecords: () => repeatRecords,
254811
- setCollection: () => setCollection,
254812
- shownRecordOf: () => shownRecordOf,
254813
- slugify: () => slugify2,
254814
- templateRecord: () => templateRecord,
254815
- upsertRecords: () => upsertRecords,
254816
- withData: () => withData
254817
- });
254818
254789
  function recordsIn(doc2, collectionId) {
254819
254790
  const c2 = doc2.collections?.[collectionId];
254820
254791
  if (!c2) return [];
@@ -264657,7 +264628,7 @@ var init_ydoc = __esm({
264657
264628
  "use strict";
264658
264629
  init_yjs();
264659
264630
  LOCAL_ORIGIN = "popcraft-local";
264660
- RECORD_FIELDS = ["styles", "variables", "variableCollections", "libraries", "compositions", "collections", "records", "codeModules"];
264631
+ RECORD_FIELDS = ["styles", "variables", "variableCollections", "libraries", "compositions", "collections", "records", "codeModules", "pluginData"];
264661
264632
  META_FIELDS = ["name", "thumbnailNodeId", "voteResults", "settings", "site"];
264662
264633
  yRecordMaps = (ydoc) => RECORD_FIELDS.map((f2) => ydoc.getMap(f2));
264663
264634
  TRACK_PREFIX = "motion.tracks/";
@@ -304658,6 +304629,7 @@ function downloadBlob(blob, filename) {
304658
304629
  }
304659
304630
  var init_download = __esm({
304660
304631
  "lib/io/download.ts"() {
304632
+ "use strict";
304661
304633
  }
304662
304634
  });
304663
304635
 
@@ -304875,6 +304847,7 @@ function creditLine(c2) {
304875
304847
  var MAX_PHOTO_PAGE, MAX_PHOTO_QUERY, UUID, isPhotoId, photoImagePath;
304876
304848
  var init_stock = __esm({
304877
304849
  "lib/photos/stock.ts"() {
304850
+ "use strict";
304878
304851
  MAX_PHOTO_PAGE = 12;
304879
304852
  MAX_PHOTO_QUERY = 200;
304880
304853
  UUID = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
@@ -305536,6 +305509,7 @@ function applyTextPath(layout2, path, tp, rebase = true) {
305536
305509
  var defaultCircleRadius, ownsPath, mapPoint;
305537
305510
  var init_text_path = __esm({
305538
305511
  "lib/engine/text/text-path.ts"() {
305512
+ "use strict";
305539
305513
  init_scene_graph();
305540
305514
  init_transform();
305541
305515
  init_shape_to_path();
@@ -305653,6 +305627,7 @@ function areaBounds(rings) {
305653
305627
  }
305654
305628
  var init_text_area = __esm({
305655
305629
  "lib/engine/text/text-area.ts"() {
305630
+ "use strict";
305656
305631
  }
305657
305632
  });
305658
305633
 
@@ -309977,7 +309952,6 @@ async function selectionReferenceImages(doc2, selection, opts = {}) {
309977
309952
  var FIT_QUALITIES, FIT_SCALES, blobToDataUrl;
309978
309953
  var init_reference_images = __esm({
309979
309954
  "lib/ai/reference-images.ts"() {
309980
- "use strict";
309981
309955
  init_export();
309982
309956
  init_selection_bounds();
309983
309957
  init_renderer_registry();
@@ -310809,7 +310783,6 @@ function agentToolList() {
310809
310783
  var AGENT_CAPABILITIES, legacyCommandId, legacyTools, blobToDataUrl3, provided, legacyTool, legacyToolList;
310810
310784
  var init_agent = __esm({
310811
310785
  "lib/commands/agent.ts"() {
310812
- "use strict";
310813
310786
  init_types5();
310814
310787
  init_registry();
310815
310788
  init_errors();
@@ -315221,6 +315194,1674 @@ var init_formats = __esm({
315221
315194
  }
315222
315195
  });
315223
315196
 
315197
+ // packages/runtime/src/commerce.ts
315198
+ var COMMERCE_SCHEMAS, COMMERCE_FIELDS, COMMERCE_PROP, COMMERCE_ACTIONS, COMMERCE_ACTION_PROP, isCommerceAction;
315199
+ var init_commerce = __esm({
315200
+ "packages/runtime/src/commerce.ts"() {
315201
+ "use strict";
315202
+ COMMERCE_SCHEMAS = ["commerce.product", "commerce.collection", "commerce.cart", "commerce.cartLine", "commerce.menu"];
315203
+ COMMERCE_FIELDS = {
315204
+ "commerce.product": [
315205
+ { name: "Title", type: "TEXT" },
315206
+ { name: "Handle", type: "TEXT" },
315207
+ { name: "URL", type: "URL" },
315208
+ { name: "Description", type: "TEXT" },
315209
+ { name: "Price", type: "TEXT" },
315210
+ { name: "Max price", type: "TEXT" },
315211
+ { name: "Image", type: "MEDIA" },
315212
+ { name: "Image alt", type: "TEXT" },
315213
+ { name: "Available", type: "BOOLEAN" },
315214
+ { name: "Variant ID", type: "TEXT" },
315215
+ { name: "Tags", type: "TEXT" }
315216
+ ],
315217
+ "commerce.collection": [{ name: "Title", type: "TEXT" }, { name: "Handle", type: "TEXT" }, { name: "URL", type: "URL" }, { name: "Description", type: "TEXT" }],
315218
+ "commerce.cart": [
315219
+ { name: "Count", type: "NUMBER" },
315220
+ { name: "Subtotal", type: "TEXT" },
315221
+ { name: "Taxes", type: "TEXT" },
315222
+ { name: "Total", type: "TEXT" },
315223
+ { name: "Checkout URL", type: "URL" }
315224
+ ],
315225
+ "commerce.cartLine": [
315226
+ { name: "Title", type: "TEXT" },
315227
+ { name: "Variant", type: "TEXT" },
315228
+ { name: "URL", type: "URL" },
315229
+ { name: "Image", type: "MEDIA" },
315230
+ { name: "Quantity", type: "NUMBER" },
315231
+ { name: "Price", type: "TEXT" },
315232
+ { name: "Merchandise ID", type: "TEXT" }
315233
+ ],
315234
+ "commerce.menu": [{ name: "Title", type: "TEXT" }, { name: "URL", type: "URL" }]
315235
+ };
315236
+ COMMERCE_PROP = {
315237
+ "commerce.product": { name: "products", type: "Product" },
315238
+ "commerce.collection": { name: "collections", type: "Collection" },
315239
+ "commerce.cart": { name: "cart", type: "Cart", one: true },
315240
+ "commerce.cartLine": { name: "lines", type: "CartItem" },
315241
+ "commerce.menu": { name: "menu", type: "Menu" }
315242
+ };
315243
+ COMMERCE_ACTIONS = ["addToCart", "updateCartLine", "removeCartLine", "checkout", "search"];
315244
+ COMMERCE_ACTION_PROP = {
315245
+ addToCart: "onAddToCart",
315246
+ updateCartLine: "onUpdateCartLine",
315247
+ removeCartLine: "onRemoveCartLine",
315248
+ checkout: "onCheckout",
315249
+ search: "onSearch"
315250
+ };
315251
+ isCommerceAction = (a) => typeof a === "string" && COMMERCE_ACTIONS.includes(a);
315252
+ }
315253
+ });
315254
+
315255
+ // lib/code/props.ts
315256
+ function propName(key5) {
315257
+ const words = key5.split("#")[0].trim().split(/[^A-Za-z0-9]+/).filter(Boolean);
315258
+ const name2 = words.map((w, i2) => i2 === 0 ? w.charAt(0).toLowerCase() + w.slice(1) : w.charAt(0).toUpperCase() + w.slice(1)).join("");
315259
+ return /^[A-Za-z_$]/.test(name2) ? name2 : `p${name2}`;
315260
+ }
315261
+ function componentOf(nodes, node2) {
315262
+ const c2 = node2.type === "COMPONENT" ? node2 : node2.type === "INSTANCE" ? nodes[node2.mainComponentId] : void 0;
315263
+ return c2?.type === "COMPONENT" ? c2 : void 0;
315264
+ }
315265
+ function codeOf(nodes, node2) {
315266
+ if (node2.type !== "COMPONENT" && node2.type !== "INSTANCE") return null;
315267
+ return componentOf(nodes, node2)?.code ?? null;
315268
+ }
315269
+ function codeProps(nodes, node2) {
315270
+ const component = componentOf(nodes, node2);
315271
+ const out = {};
315272
+ if (!component) return out;
315273
+ const set4 = component.parentId ? nodes[component.parentId] : void 0;
315274
+ const defs = (set4?.type === "COMPONENT_SET" ? set4.componentPropertyDefinitions : component.componentPropertyDefinitions) ?? {};
315275
+ const given = node2.type === "INSTANCE" ? node2.componentProperties ?? {} : {};
315276
+ for (const key5 of Object.keys(defs).sort()) {
315277
+ const v = value(key5 in given ? given[key5] : defs[key5].defaultValue);
315278
+ if (v !== void 0) out[propName(key5)] = v;
315279
+ }
315280
+ out.width = Math.round(node2.width);
315281
+ out.height = Math.round(node2.height);
315282
+ return out;
315283
+ }
315284
+ var value;
315285
+ var init_props = __esm({
315286
+ "lib/code/props.ts"() {
315287
+ "use strict";
315288
+ init_color();
315289
+ value = (v) => typeof v === "string" || typeof v === "number" || typeof v === "boolean" ? v : v && typeof v === "object" && "r" in v ? colorToHex8(v) : void 0;
315290
+ }
315291
+ });
315292
+
315293
+ // lib/document/controls.ts
315294
+ function fieldPart(nodes, id3) {
315295
+ const n = nodes[id3];
315296
+ if (!n) return null;
315297
+ if (n.type === "TEXT") return id3;
315298
+ for (const c2 of n.childIds ?? []) {
315299
+ const hit = fieldPart(nodes, c2);
315300
+ if (hit) return hit;
315301
+ }
315302
+ return null;
315303
+ }
315304
+ var cleanName;
315305
+ var init_controls = __esm({
315306
+ "lib/document/controls.ts"() {
315307
+ "use strict";
315308
+ cleanName = (raw) => raw.trim().replace(/[^A-Za-z0-9_-]+/g, "-").replace(/^-+|-+$/g, "");
315309
+ }
315310
+ });
315311
+
315312
+ // lib/io/web/paint.ts
315313
+ function toRgba(c2, a) {
315314
+ const alpha2 = a !== void 0 ? a : c2.a;
315315
+ const [r, g, b] = [c2.r, c2.g, c2.b].map((v) => Math.round(v * 255));
315316
+ return alpha2 < 1 ? `rgba(${r}, ${g}, ${b}, ${Math.round(alpha2 * 100) / 100})` : `rgb(${r}, ${g}, ${b})`;
315317
+ }
315318
+ function gradientAngleDeg(paint) {
315319
+ const h = paint.gradientHandlePositions;
315320
+ const p0 = h?.[0] ?? { x: 0, y: 0.5 };
315321
+ const p1 = h?.[1] ?? { x: 1, y: 0.5 };
315322
+ return Math.round(Math.atan2(p1.x - p0.x, -(p1.y - p0.y)) * 180 / Math.PI);
315323
+ }
315324
+ function paintToBackground(paint, opts = {}) {
315325
+ if (paint.type === "SOLID" && paint.color) {
315326
+ const alpha2 = (paint.opacity ?? 1) * paint.color.a;
315327
+ return alpha2 < 1 ? toRgba(paint.color, alpha2) : toHex(paint.color);
315328
+ }
315329
+ if (paint.type === "GRADIENT_LINEAR") return `linear-gradient(${gradientAngleDeg(paint)}deg, ${gradientStopsCSS(paint)})`;
315330
+ if (paint.type === "GRADIENT_RADIAL") return `radial-gradient(circle, ${gradientStopsCSS(paint)})`;
315331
+ if (paint.type === "GRADIENT_ANGULAR") return `conic-gradient(${gradientStopsCSS(paint)})`;
315332
+ if (paint.type === "GRADIENT_DIAMOND") return `radial-gradient(closest-side, ${gradientStopsCSS(paint)})`;
315333
+ if (paint.type === "IMAGE") {
315334
+ const src = paint.imageUrl || paint.imageHash;
315335
+ if (!src) return null;
315336
+ return `url('${opts.fullImageUrl || src.length <= 64 ? src : src.slice(0, 64)}') ${IMAGE_FIT[paint.scaleMode ?? "FILL"]}`;
315337
+ }
315338
+ return null;
315339
+ }
315340
+ function parseCssColor(css) {
315341
+ if (!css) return null;
315342
+ const hex10 = /^#([0-9a-f]{6})$/i.exec(css.trim());
315343
+ if (hex10) {
315344
+ const n = parseInt(hex10[1], 16);
315345
+ return { r: (n >> 16 & 255) / 255, g: (n >> 8 & 255) / 255, b: (n & 255) / 255, a: 1 };
315346
+ }
315347
+ const rgb = /^rgba?\(([^)]+)\)$/i.exec(css.trim());
315348
+ if (!rgb) return null;
315349
+ const parts = rgb[1].split(",").map((v) => Number(v.trim()));
315350
+ if (parts.length < 3 || parts.some((v) => Number.isNaN(v))) return null;
315351
+ return { r: parts[0] / 255, g: parts[1] / 255, b: parts[2] / 255, a: parts[3] ?? 1 };
315352
+ }
315353
+ var hex23, toHex, gradientStopsCSS, IMAGE_FIT, swiftColor, composeColor;
315354
+ var init_paint2 = __esm({
315355
+ "lib/io/web/paint.ts"() {
315356
+ "use strict";
315357
+ hex23 = (v) => Math.round(v * 255).toString(16).padStart(2, "0");
315358
+ toHex = (c2) => `#${hex23(c2.r)}${hex23(c2.g)}${hex23(c2.b)}`.toUpperCase();
315359
+ gradientStopsCSS = (paint) => (paint.gradientStops ?? []).map((s) => `${toRgba(s.color)} ${Math.round((s.position ?? 0) * 100)}%`).join(", ");
315360
+ IMAGE_FIT = {
315361
+ FILL: "center / cover no-repeat",
315362
+ CROP: "center / cover no-repeat",
315363
+ FIT: "center / contain no-repeat",
315364
+ TILE: "top left / auto repeat"
315365
+ };
315366
+ swiftColor = (c2) => {
315367
+ const n = (v) => Math.round(v * 1e3) / 1e3;
315368
+ return `Color(red: ${n(c2.r)}, green: ${n(c2.g)}, blue: ${n(c2.b)}${(c2.a ?? 1) < 1 ? `, opacity: ${Math.round((c2.a ?? 1) * 100) / 100}` : ""})`;
315369
+ };
315370
+ composeColor = (c2) => `Color(0x${[c2.a ?? 1, c2.r, c2.g, c2.b].map((v) => Math.round(v * 255).toString(16).padStart(2, "0")).join("").toUpperCase()})`;
315371
+ }
315372
+ });
315373
+
315374
+ // lib/io/web/css.ts
315375
+ function stylePaints(styleId, styles) {
315376
+ const s = styleId ? styles?.[styleId] : void 0;
315377
+ return s?.type === "PAINT" ? s.paints ?? [] : null;
315378
+ }
315379
+ function transformParts(node2, dx = 0, dy = 0) {
315380
+ return [
315381
+ dx + restValue(node2, "translateX"),
315382
+ dy + restValue(node2, "translateY"),
315383
+ restValue(node2, "z"),
315384
+ node2.rotation || 0,
315385
+ restValue(node2, "rotateY"),
315386
+ restValue(node2, "rotateX"),
315387
+ restValue(node2, "scaleX") * (node2.flipHorizontal ? -1 : 1),
315388
+ restValue(node2, "scaleY") * (node2.flipVertical ? -1 : 1)
315389
+ ];
315390
+ }
315391
+ function transformFromParts(p2, orbit) {
315392
+ const [tx2, ty, z2, r, ry0, rx0, sx, sy] = p2;
315393
+ const ry = ry0 + (orbit?.rotateY ?? 0), rx = rx0 + (orbit?.rotateX ?? 0);
315394
+ const parts = [];
315395
+ if (tx2 || ty || z2) parts.push(z2 ? `translate3d(${round(tx2)}px, ${round(ty)}px, ${round(z2)}px)` : `translate(${round(tx2)}px, ${round(ty)}px)`);
315396
+ if (r) parts.push(`rotate(${round(r)}deg)`);
315397
+ if (ry) parts.push(`rotateY(${round(ry)}deg)`);
315398
+ if (rx) parts.push(`rotateX(${round(rx)}deg)`);
315399
+ if (sx !== 1 || sy !== 1) parts.push(`scale(${round(sx)}, ${round(sy)})`);
315400
+ return parts.length ? parts.join(" ") : void 0;
315401
+ }
315402
+ function styleMapFor(node2, styles, opts = {}) {
315403
+ const scene2 = node2;
315404
+ const out = {};
315405
+ out.width = `${Math.round(node2.width)}px`;
315406
+ out.height = `${Math.round(node2.height)}px`;
315407
+ const transform3 = transformCss(node2);
315408
+ if (transform3) out.transform = transform3;
315409
+ const ax = restValue(node2, "anchorX"), ay = restValue(node2, "anchorY");
315410
+ if (transform3 && (ax !== 0.5 || ay !== 0.5)) out["transform-origin"] = `${round(ax * 100)}% ${round(ay * 100)}%`;
315411
+ const scene3d = scene3dOf(node2);
315412
+ if (scene3d) {
315413
+ out.perspective = `${round(zoomPx(scene3d.camera.focalLength, node2.width))}px`;
315414
+ out["perspective-origin"] = `${round((scene3d.originX ?? 0.5) * 100)}% ${round((scene3d.originY ?? 0.5) * 100)}%`;
315415
+ out["transform-style"] = "preserve-3d";
315416
+ } else if (has3DPlacement(node2) && passesThrough(node2)) out["transform-style"] = "preserve-3d";
315417
+ if ((node2.opacity ?? 1) !== 1) out.opacity = String(round(node2.opacity ?? 1));
315418
+ const bm = node2.blendMode;
315419
+ if (bm && bm !== "NORMAL" && bm !== "PASS_THROUGH") out["mix-blend-mode"] = bm.toLowerCase().replace(/_/g, "-");
315420
+ const fills = visibleFills(node2, styles);
315421
+ const own2 = node2.type === "IMAGE" && node2.imageUrl ? [{ type: "IMAGE", imageUrl: node2.imageUrl, scaleMode: node2.scaleMode, visible: true }] : [];
315422
+ const painted = [...fills, ...own2];
315423
+ if (node2.type !== "TEXT" && painted.length) {
315424
+ const layers2 = painted.map((f2) => paintToBackground(f2, opts)).filter((l) => !!l);
315425
+ const over2 = (l) => /^(#|rgb)/.test(l) ? `linear-gradient(${l}, ${l})` : l;
315426
+ if (layers2.length) out.background = layers2.map((l, i2) => i2 === layers2.length - 1 ? l : over2(l)).join(", ");
315427
+ }
315428
+ const cr = scene2.cornerRadius;
315429
+ if (typeof cr === "number" && cr > 0) out["border-radius"] = `${cr}px`;
315430
+ else if (Array.isArray(cr) && cr.some((r) => r > 0)) out["border-radius"] = cr.map((r) => `${r}px`).join(" ");
315431
+ if (node2.type === "ELLIPSE") out["border-radius"] = "50%";
315432
+ const stroke3 = scene2.strokes?.[0];
315433
+ if (stroke3) {
315434
+ const color4 = toHex(stroke3.color);
315435
+ if (Array.isArray(stroke3.width)) {
315436
+ out["border-style"] = "solid";
315437
+ out["border-color"] = color4;
315438
+ out["border-width"] = stroke3.width.map((w) => `${w}px`).join(" ");
315439
+ } else if (stroke3.alignment === "OUTSIDE") {
315440
+ out.outline = `${stroke3.width}px solid ${color4}`;
315441
+ } else {
315442
+ out.border = `${stroke3.width}px ${stroke3.dashPattern?.length ? "dashed" : "solid"} ${color4}`;
315443
+ if (stroke3.alignment === "INSIDE") out["box-sizing"] = "border-box";
315444
+ }
315445
+ }
315446
+ const shadows = shadowsOf(node2, styles).filter((s) => s.visible);
315447
+ if (node2.type === "TEXT") {
315448
+ const drops = shadows.filter((s) => s.type === "DROP_SHADOW");
315449
+ if (drops.length) out["text-shadow"] = drops.map((s) => `${s.offset.x}px ${s.offset.y}px ${s.blur}px ${toRgba(s.color)}`).join(", ");
315450
+ } else if (shadows.length) {
315451
+ out["box-shadow"] = shadows.map((s) => `${s.type === "INNER_SHADOW" ? "inset " : ""}${s.offset.x}px ${s.offset.y}px ${s.blur}px ${s.spread}px ${toRgba(s.color)}`).join(", ");
315452
+ }
315453
+ const blurs = blursOf(node2, styles);
315454
+ const layer2 = blurs.find((b) => b.type === "LAYER");
315455
+ const backdrop = blurs.find((b) => b.type === "BACKGROUND");
315456
+ if (layer2) out.filter = `blur(${layer2.radius}px)`;
315457
+ if (backdrop) out["backdrop-filter"] = `blur(${backdrop.radius}px)`;
315458
+ if (node2.type === "FRAME" || node2.type === "COMPONENT" || node2.type === "INSTANCE") {
315459
+ const f2 = node2;
315460
+ Object.assign(out, flexDeclarations(f2));
315461
+ if (f2.clipsContent) out.overflow = "hidden";
315462
+ }
315463
+ if (node2.type === "TEXT") {
315464
+ const t3 = node2;
315465
+ const tFills = visibleFills(t3, styles);
315466
+ out.margin = "0";
315467
+ if (t3.textAutoResize === "WIDTH_AND_HEIGHT") {
315468
+ out.width = "max-content";
315469
+ out.height = "auto";
315470
+ out["white-space"] = "pre";
315471
+ } else if (t3.textAutoResize === "HEIGHT") out.height = "auto";
315472
+ out["font-family"] = `"${t3.fontFamily}", system-ui, sans-serif`;
315473
+ out["font-size"] = `${t3.fontSize}px`;
315474
+ out["font-weight"] = String(t3.fontWeight);
315475
+ if (t3.fontStyle === "italic") out["font-style"] = "italic";
315476
+ out["line-height"] = t3.lineHeight === "AUTO" ? "normal" : `${t3.lineHeight}px`;
315477
+ if (t3.letterSpacing) out["letter-spacing"] = `${t3.letterSpacing}px`;
315478
+ out["text-align"] = t3.textAlign.toLowerCase();
315479
+ if (t3.textDecoration === "UNDERLINE") out["text-decoration"] = "underline";
315480
+ else if (t3.textDecoration === "STRIKETHROUGH") out["text-decoration"] = "line-through";
315481
+ const tc = t3.textCase;
315482
+ if (tc === "UPPER") out["text-transform"] = "uppercase";
315483
+ else if (tc === "LOWER") out["text-transform"] = "lowercase";
315484
+ else if (tc === "TITLE") out["text-transform"] = "capitalize";
315485
+ const solid5 = tFills.find((f2) => f2.type === "SOLID" && f2.color);
315486
+ if (solid5?.color) out.color = toHex(solid5.color);
315487
+ const grad = tFills.find((f2) => f2.type !== "SOLID");
315488
+ const g = grad ? paintToBackground(grad) : null;
315489
+ if (g) {
315490
+ out.background = g;
315491
+ out["-webkit-background-clip"] = "text";
315492
+ out.color = "transparent";
315493
+ }
315494
+ }
315495
+ return out;
315496
+ }
315497
+ function flexDeclarations(f2) {
315498
+ const out = {};
315499
+ if (f2.layoutMode !== "HORIZONTAL" && f2.layoutMode !== "VERTICAL") return out;
315500
+ out.display = "flex";
315501
+ out["flex-direction"] = f2.layoutMode === "HORIZONTAL" ? "row" : "column";
315502
+ const justify = JUSTIFY[f2.primaryAxisAlignItems ?? "MIN"];
315503
+ const align4 = ALIGN2[f2.counterAxisAlignItems ?? "MIN"];
315504
+ if (justify !== "flex-start") out["justify-content"] = justify;
315505
+ if (align4 !== "flex-start") out["align-items"] = align4;
315506
+ out.gap = `${f2.itemSpacing ?? 0}px`;
315507
+ if (f2.padding) {
315508
+ out.padding = `${f2.padding.top}px ${f2.padding.right}px ${f2.padding.bottom}px ${f2.padding.left}px`;
315509
+ if (f2.padding.top || f2.padding.right || f2.padding.bottom || f2.padding.left) out["box-sizing"] = "border-box";
315510
+ }
315511
+ return out;
315512
+ }
315513
+ var visibleFills, round, transformCss, JUSTIFY, ALIGN2, styleMapToCSSText, styleMapToInline, camel2, styleMapToJSX;
315514
+ var init_css = __esm({
315515
+ "lib/io/web/css.ts"() {
315516
+ "use strict";
315517
+ init_effects();
315518
+ init_paint2();
315519
+ init_scene3d();
315520
+ init_transform3d();
315521
+ init_transform();
315522
+ visibleFills = (node2, styles) => (stylePaints(node2.fillStyleId, styles) ?? node2.fills ?? []).filter((f2) => f2.visible !== false);
315523
+ round = (v) => Math.round(v * 100) / 100;
315524
+ transformCss = (node2) => transformFromParts(transformParts(node2));
315525
+ JUSTIFY = { MIN: "flex-start", MAX: "flex-end", CENTER: "center", SPACE_BETWEEN: "space-between" };
315526
+ ALIGN2 = { MIN: "flex-start", MAX: "flex-end", CENTER: "center", BASELINE: "baseline" };
315527
+ styleMapToCSSText = (m, indent = "") => Object.entries(m).map(([k2, v]) => `${indent}${k2}: ${v};`).join("\n");
315528
+ styleMapToInline = (m) => Object.entries(m).map(([k2, v]) => `${k2}:${v}`).join(";");
315529
+ camel2 = (k2) => k2.startsWith("--") ? k2 : (k2.startsWith("-") ? k2.replace(/^-/, "Webkit").replace(/-webkit-/i, "") : k2).replace(/-([a-z])/g, (_, c2) => c2.toUpperCase());
315530
+ styleMapToJSX = (m) => Object.entries(m).map(([k2, v]) => [camel2(k2), v.replace(/'/g, "\\'")]);
315531
+ }
315532
+ });
315533
+
315534
+ // lib/io/web/expressible.ts
315535
+ function expressibility(node2, styles) {
315536
+ const c2 = capability(node2, "css", styles);
315537
+ return { css: c2.reason === "", reason: c2.reason, needsRaster: c2.verdict === "raster" };
315538
+ }
315539
+ var init_expressible = __esm({
315540
+ "lib/io/web/expressible.ts"() {
315541
+ "use strict";
315542
+ init_capability();
315543
+ }
315544
+ });
315545
+
315546
+ // lib/io/web/keyframes.ts
315547
+ function transformOf(n, rest) {
315548
+ return transformFromParts(transformParts(n, n.x - rest.x, n.y - rest.y)) ?? "none";
315549
+ }
315550
+ function declarationsOf(node2, rest, style) {
315551
+ return { ...style(node2), transform: transformOf(node2, rest), opacity: String(round2(node2.visible === false ? 0 : node2.opacity ?? 1)) };
315552
+ }
315553
+ function vectorOf(style, keys4) {
315554
+ const text = keys4.map((k2) => `${k2}:${style[k2] ?? ""}`).join(";");
315555
+ return { shape: text.replace(NUMBER2, "#"), v: (text.match(NUMBER2) ?? []).map(Number) };
315556
+ }
315557
+ function thinSamples(times2, samples, tol, pinned = []) {
315558
+ const n = samples.length;
315559
+ if (n <= 2) return samples.map((_, i2) => i2);
315560
+ const keep = /* @__PURE__ */ new Set([0, n - 1, ...pinned]);
315561
+ for (let i2 = 1; i2 < n; i2++) if (samples[i2].shape !== samples[i2 - 1].shape) {
315562
+ keep.add(i2 - 1);
315563
+ keep.add(i2);
315564
+ }
315565
+ const sorted = () => [...keep].sort((a, b) => a - b);
315566
+ const stack = [];
315567
+ const kept = sorted();
315568
+ for (let i2 = 1; i2 < kept.length; i2++) stack.push([kept[i2 - 1], kept[i2]]);
315569
+ while (stack.length) {
315570
+ const [a, b] = stack.pop();
315571
+ if (b - a < 2 || samples[a].shape !== samples[b].shape) continue;
315572
+ let worst2 = -1, at3 = -1;
315573
+ for (let i2 = a + 1; i2 < b; i2++) {
315574
+ const k2 = (times2[i2] - times2[a]) / (times2[b] - times2[a] || 1);
315575
+ let err2 = 0;
315576
+ samples[i2].v.forEach((x2, d) => {
315577
+ const want = samples[a].v[d] + (samples[b].v[d] - samples[a].v[d]) * k2;
315578
+ err2 = Math.max(err2, Math.abs(x2 - want) / tol[d]);
315579
+ });
315580
+ if (err2 > worst2) {
315581
+ worst2 = err2;
315582
+ at3 = i2;
315583
+ }
315584
+ }
315585
+ if (worst2 > 1) {
315586
+ keep.add(at3);
315587
+ stack.push([a, at3], [at3, b]);
315588
+ }
315589
+ }
315590
+ return sorted();
315591
+ }
315592
+ function keyframesOf(times2, samples, length2) {
315593
+ const keys4 = [...new Set(samples.flatMap((s) => Object.keys(s)))].filter((k2) => !FIXED.has(k2));
315594
+ const moving = keys4.filter((k2) => samples.some((s) => s[k2] !== samples[0][k2]));
315595
+ if (!moving.length) return null;
315596
+ const vectors = samples.map((s) => vectorOf(s, moving));
315597
+ const dims = Math.max(...vectors.map((v) => v.v.length));
315598
+ const range3 = Array.from({ length: dims }, (_, d) => {
315599
+ let lo = Infinity, hi = -Infinity;
315600
+ for (const v of vectors) if (d < v.v.length) {
315601
+ lo = Math.min(lo, v.v[d]);
315602
+ hi = Math.max(hi, v.v[d]);
315603
+ }
315604
+ return hi > lo ? hi - lo : 0;
315605
+ });
315606
+ const tol = range3.map((r) => Math.max(1e-3, r * 3e-3));
315607
+ const same5 = (a, b) => vectors[a].shape === vectors[b].shape && vectors[a].v.every((x2, d) => Math.abs(x2 - vectors[b].v[d]) <= tol[d]);
315608
+ const jumps = /* @__PURE__ */ new Set();
315609
+ for (let i2 = 1; i2 < samples.length; i2++) {
315610
+ if (same5(i2 - 1, i2)) continue;
315611
+ const stillBefore = i2 >= 2 && same5(i2 - 2, i2 - 1);
315612
+ if (!stillBefore) continue;
315613
+ const words = vectors[i2].shape !== vectors[i2 - 1].shape;
315614
+ const far = !words && vectors[i2].v.some((x2, d) => range3[d] > 0 && Math.abs(x2 - vectors[i2 - 1].v[d]) > range3[d] * 0.2);
315615
+ if (words || far) jumps.add(i2);
315616
+ }
315617
+ const kept = thinSamples(times2, vectors, tol, [...jumps].flatMap((i2) => [i2 - 1, i2]));
315618
+ return kept.map((i2) => {
315619
+ const style = {};
315620
+ for (const k2 of moving) if (samples[i2][k2] !== void 0) style[k2] = samples[i2][k2];
315621
+ return { offset: pct(times2[i2] / (length2 || 1)), style, ...jumps.has(i2 + 1) ? { step: true } : {} };
315622
+ });
315623
+ }
315624
+ var SAMPLE_RATE, round2, pct, FIXED, NUMBER2;
315625
+ var init_keyframes = __esm({
315626
+ "lib/io/web/keyframes.ts"() {
315627
+ "use strict";
315628
+ init_css();
315629
+ SAMPLE_RATE = 30;
315630
+ round2 = (v) => Math.round(v * 1e3) / 1e3;
315631
+ pct = (k2) => Math.round(k2 * 1e5) / 1e3;
315632
+ FIXED = /* @__PURE__ */ new Set(["position", "display", "left", "top", "right", "bottom", "inset", "animation", "animation-play-state", "transform-origin", "transform-style", "box-sizing", "isolation", "z-index"]);
315633
+ NUMBER2 = /-?\d+(?:\.\d+)?(?:e-?\d+)?/g;
315634
+ }
315635
+ });
315636
+
315637
+ // lib/io/web/element.ts
315638
+ function placementStyle(node2, isRoot) {
315639
+ if (node2.place) return { ...node2.place, ...node2.place.position ? {} : node2.layered || node2.children.some((c2) => c2.positioning === "absolute") ? { position: "relative" } : {} };
315640
+ const out = {};
315641
+ if (node2.positioning === "absolute" && !isRoot) {
315642
+ out.position = "absolute";
315643
+ out.left = `${node2.x}px`;
315644
+ out.top = `${node2.y}px`;
315645
+ } else if (node2.layered || node2.children.some((c2) => c2.positioning === "absolute") || isRoot) {
315646
+ out.position = "relative";
315647
+ }
315648
+ return out;
315649
+ }
315650
+ function imageRole(node2) {
315651
+ if (node2.asset || node2.text) return null;
315652
+ if (node2.type !== "IMAGE" && node2.alt === void 0) return null;
315653
+ return roleOf(node2);
315654
+ }
315655
+ function pictureOf(node2) {
315656
+ const a = node2.asset;
315657
+ if (!a) return null;
315658
+ if (a.src) return { kind: "img", src: a.src };
315659
+ if (a.svg) return { kind: "svg", svg: a.svg };
315660
+ if (a.pngDataUrl) return { kind: "img", src: a.pngDataUrl };
315661
+ return { kind: "missing", reason: a.reason, format: a.kind };
315662
+ }
315663
+ function elementOf(node2, ctx2) {
315664
+ const motion = ctx2.still ? void 0 : node2.motion;
315665
+ const spec = ctx2.spec ?? null;
315666
+ const tag = node2.input ? node2.input.tag : node2.link ? "a" : node2.tag ?? (node2.text ? "p" : "div");
315667
+ const attrs = { ...node2.attrs };
315668
+ if (node2.input) Object.assign(attrs, node2.input.attrs);
315669
+ if (node2.link && !node2.input) {
315670
+ attrs.href = node2.link.href;
315671
+ if (node2.link.newTab) {
315672
+ attrs.target = "_blank";
315673
+ attrs.rel = "noopener noreferrer";
315674
+ }
315675
+ }
315676
+ return {
315677
+ tag,
315678
+ attrs,
315679
+ // A tag's own look (a button's border, a link's underline, a list's bullets) is not the layer's: under its declarations.
315680
+ style: { ...node2.link || node2.tag || node2.input ? TAG_RESET[tag] : void 0, ...placementStyle(node2, ctx2.isRoot), ...node2.style, ...motion ? motion.style : {}, ...hiddenAtStart(spec, node2) ? HIDDEN_AT_START : {} },
315681
+ // A field's words are its placeholder (an attribute), not its content.
315682
+ ...node2.text && !node2.input ? { text: node2.text.characters } : {},
315683
+ ...node2.text && node2.runs && !node2.input ? { runs: node2.runs } : {},
315684
+ ...node2.input ? { input: node2.input } : {},
315685
+ ...node2.html !== void 0 ? { html: node2.html } : {},
315686
+ ...node2.check ? { check: node2.check } : {},
315687
+ picture: pictureOf(node2),
315688
+ role: imageRole(node2),
315689
+ ...motion ? { keyframes: motion.keyframes } : {},
315690
+ ...node2.motionTrigger ? { motionTrigger: node2.motionTrigger } : {},
315691
+ ...spec && node2.uid !== void 0 ? { pc: { uid: node2.uid, layer: node2.name } } : {},
315692
+ ...ctx2.listened?.has(node2.id) ? { sm: node2.id } : {}
315693
+ };
315694
+ }
315695
+ var escapeHTML, altFor, roleOf, roleAttrs, labelSVG, imageRoleAttrs, hiddenAtStart, HIDDEN_AT_START, FIELD, HEADING, TAG_RESET, MOTION_PLAY_RULE, CHECK_STYLE;
315696
+ var init_element = __esm({
315697
+ "lib/io/web/element.ts"() {
315698
+ "use strict";
315699
+ escapeHTML = (s) => s.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;");
315700
+ altFor = (node2) => node2.alt ?? node2.name;
315701
+ roleOf = (node2) => {
315702
+ const alt = altFor(node2);
315703
+ return alt === "" ? { hidden: true } : { label: alt };
315704
+ };
315705
+ roleAttrs = (role) => "hidden" in role ? ' aria-hidden="true"' : ` role="img" aria-label="${escapeHTML(role.label)}"`;
315706
+ labelSVG = (svg, node2) => svg.replace(/^<svg\b/, `<svg${roleAttrs(roleOf(node2))}`);
315707
+ imageRoleAttrs = (node2) => {
315708
+ const role = imageRole(node2);
315709
+ return role ? roleAttrs(role) : "";
315710
+ };
315711
+ hiddenAtStart = (spec, node2) => {
315712
+ const e = spec && node2.uid !== void 0 ? spec.e[node2.uid] : void 0;
315713
+ return !!e && e[1][spec.m[e[0]]] === -1;
315714
+ };
315715
+ HIDDEN_AT_START = { opacity: "0", visibility: "hidden", "pointer-events": "none", position: "absolute" };
315716
+ FIELD = { display: "block", border: "0", padding: "0", margin: "0", background: "none", outline: "none", font: "inherit", color: "inherit", "min-width": "0" };
315717
+ HEADING = { margin: "0", "font-size": "inherit", "font-weight": "inherit" };
315718
+ TAG_RESET = {
315719
+ a: { display: "block", color: "inherit", "text-decoration": "none" },
315720
+ button: { display: "block", border: "0", padding: "0", background: "none", font: "inherit", color: "inherit", "text-align": "inherit", cursor: "pointer" },
315721
+ ul: { "list-style": "none", margin: "0", padding: "0" },
315722
+ ol: { "list-style": "none", margin: "0", padding: "0" },
315723
+ h1: HEADING,
315724
+ h2: HEADING,
315725
+ h3: HEADING,
315726
+ h4: HEADING,
315727
+ h5: HEADING,
315728
+ h6: HEADING,
315729
+ p: { margin: "0" },
315730
+ figure: { margin: "0" },
315731
+ span: { display: "block" },
315732
+ label: { display: "block" },
315733
+ form: { margin: "0" },
315734
+ input: FIELD,
315735
+ textarea: { ...FIELD, resize: "none" },
315736
+ select: { ...FIELD, appearance: "none" }
315737
+ };
315738
+ MOTION_PLAY_RULE = "[data-motion-play] [data-motion-child] { animation-play-state: running; }";
315739
+ CHECK_STYLE = "position:absolute;inset:0;width:100%;height:100%;margin:0;opacity:0;cursor:pointer";
315740
+ }
315741
+ });
315742
+
315743
+ // lib/io/web/motion.ts
315744
+ function instanceWebMotion(doc2, instance, style) {
315745
+ const comp = instance.mainComponentId;
315746
+ if (!comp || !isMotionComponent(doc2.nodes, comp)) return null;
315747
+ const m = playbackOf(doc2.nodes, instance, comp);
315748
+ const [a, b] = m.range;
315749
+ const len3 = b - a;
315750
+ if (len3 <= 0) return null;
315751
+ const steps = Math.max(1, Math.ceil(len3 / 1e3 * SAMPLE_RATE));
315752
+ const times2 = Array.from({ length: steps + 1 }, (_, i2) => len3 * i2 / steps);
315753
+ const samples = [];
315754
+ for (let i2 = 0; i2 <= steps; i2++) samples.push(instancePoseAt(doc2.nodes, instance.id, a + len3 * i2 / steps));
315755
+ const ids2 = /* @__PURE__ */ new Set();
315756
+ for (const s of samples) for (const id3 in s) if (id3.includes("::")) ids2.add(id3);
315757
+ const children = /* @__PURE__ */ new Map();
315758
+ const tag = instance.id.replace(/[^a-zA-Z0-9]/g, "").slice(-6);
315759
+ let n = 0;
315760
+ for (const id3 of ids2) {
315761
+ const restNode = resolveVirtualNode2(doc2.nodes, id3);
315762
+ if (!restNode) continue;
315763
+ const frames = keyframesOf(times2, samples.map((s) => declarationsOf(s[id3] ?? restNode, restNode, style)), len3);
315764
+ if (!frames) continue;
315765
+ children.set(id3, {
315766
+ name: `motion-${tag}-${n++}`,
315767
+ frames,
315768
+ durationMs: m.speed > 0 ? Math.round(len3 / m.speed) : 0,
315769
+ delayMs: Math.round(m.start),
315770
+ iterations: m.loop === "none" ? 1 : "infinite",
315771
+ direction: m.loop === "pingpong" ? "alternate" : "normal",
315772
+ fill: m.hold === "first" ? "backwards" : "both"
315773
+ });
315774
+ }
315775
+ return children.size ? { trigger: m.trigger, children } : null;
315776
+ }
315777
+ function animationStyle(mo, trigger) {
315778
+ const out = { animation: `${mo.name} ${mo.durationMs}ms linear ${mo.delayMs}ms ${mo.iterations} ${mo.direction} ${mo.fill}` };
315779
+ if (trigger !== "load") out["animation-play-state"] = "paused";
315780
+ return out;
315781
+ }
315782
+ var keyframesCSS, MOTION_SCRIPT;
315783
+ var init_motion = __esm({
315784
+ "lib/io/web/motion.ts"() {
315785
+ "use strict";
315786
+ init_scene_graph();
315787
+ init_instances2();
315788
+ init_keyframes();
315789
+ init_keyframes();
315790
+ init_element();
315791
+ keyframesCSS = (mo) => `@keyframes ${mo.name} {
315792
+ ${mo.frames.map((f2) => ` ${f2.offset}% { ${Object.entries(f2.style).map(([k2, v]) => `${k2}: ${v};`).join(" ")}${f2.step ? " animation-timing-function: step-end;" : ""} }`).join("\n")}
315793
+ }`;
315794
+ MOTION_SCRIPT = `(function () {
315795
+ var play = function (el) { el.setAttribute('data-motion-play', '') };
315796
+ document.querySelectorAll('[data-motion="click"]').forEach(function (el) { el.addEventListener('click', function () { play(el) }) });
315797
+ document.querySelectorAll('[data-motion="hover"]').forEach(function (el) { el.addEventListener('mouseenter', function () { play(el) }) });
315798
+ var seen = document.querySelectorAll('[data-motion="inView"]');
315799
+ if (!('IntersectionObserver' in window)) { seen.forEach(play); return }
315800
+ var io = new IntersectionObserver(function (entries) { entries.forEach(function (e) { if (e.isIntersecting) { play(e.target); io.unobserve(e.target) } }) }, { threshold: 0.25 });
315801
+ seen.forEach(function (el) { io.observe(el) });
315802
+ })();`;
315803
+ }
315804
+ });
315805
+
315806
+ // lib/io/web/responsive.ts
315807
+ function containerStyle(f2) {
315808
+ const out = {};
315809
+ if (isStack(f2) && f2.layoutWrap === "WRAP") {
315810
+ out["flex-wrap"] = "wrap";
315811
+ const cross2 = f2.counterAxisSpacing ?? f2.itemSpacing ?? 0;
315812
+ const main2 = f2.itemSpacing ?? 0;
315813
+ if (cross2 !== main2) out.gap = f2.layoutMode === "HORIZONTAL" ? `${cross2}px ${main2}px` : `${main2}px ${cross2}px`;
315814
+ out["align-content"] = "flex-start";
315815
+ }
315816
+ if (isGrid(f2)) {
315817
+ out.display = "grid";
315818
+ const cols = f2.layoutGridColumns ?? "AUTO";
315819
+ out["grid-template-columns"] = cols === "AUTO" ? `repeat(auto-fill, minmax(${f2.layoutGridMinColumnWidth ?? 100}px, 1fr))` : Array.from({ length: Math.max(1, cols) }, (_, i2) => track(f2.layoutGridColumnSizes?.[i2])).join(" ");
315820
+ const rows = f2.layoutGridRows ?? "AUTO";
315821
+ if (rows === "AUTO") out["grid-auto-rows"] = `minmax(${f2.layoutGridMinRowHeight ?? 100}px, auto)`;
315822
+ else out["grid-template-rows"] = Array.from({ length: Math.max(1, rows) }, (_, i2) => track(f2.layoutGridRowSizes?.[i2])).join(" ");
315823
+ const colGap = f2.itemSpacing ?? 0, rowGap = f2.counterAxisSpacing ?? colGap;
315824
+ out.gap = rowGap === colGap ? `${colGap}px` : `${rowGap}px ${colGap}px`;
315825
+ if (f2.padding) {
315826
+ out.padding = `${f2.padding.top}px ${f2.padding.right}px ${f2.padding.bottom}px ${f2.padding.left}px`;
315827
+ if (f2.padding.top || f2.padding.right || f2.padding.bottom || f2.padding.left) out["box-sizing"] = "border-box";
315828
+ }
315829
+ }
315830
+ const scroll = f2.overflowScrolling;
315831
+ if (scroll && scroll !== "NONE") {
315832
+ out["overflow-x"] = scroll === "HORIZONTAL" || scroll === "BOTH" ? "auto" : "hidden";
315833
+ out["overflow-y"] = scroll === "VERTICAL" || scroll === "BOTH" ? "auto" : "hidden";
315834
+ }
315835
+ return out;
315836
+ }
315837
+ function flowChild(node2, parent) {
315838
+ const style = { ...limits(node2) };
315839
+ const h = node2.layoutSizingHorizontal ?? "FIXED", v = node2.layoutSizingVertical ?? "FIXED";
315840
+ if (isGrid(parent)) {
315841
+ if (h !== "FIXED") style.width = h === "FILL" ? null : "fit-content";
315842
+ if (v !== "FIXED") style.height = null;
315843
+ return { style };
315844
+ }
315845
+ if (h === "FIXED" && style["max-width"] === void 0) style["max-width"] = "100%";
315846
+ const row2 = parent.layoutMode === "HORIZONTAL";
315847
+ const main2 = row2 ? h : v, cross2 = row2 ? v : h;
315848
+ const mainProp = row2 ? "width" : "height", crossProp = row2 ? "height" : "width";
315849
+ if (main2 === "FILL") {
315850
+ style[mainProp] = null;
315851
+ style.flex = "1 1 0";
315852
+ if (style[`min-${mainProp}`] === void 0) style[`min-${mainProp}`] = "0";
315853
+ } else {
315854
+ if (main2 === "HUG") style[mainProp] = null;
315855
+ style["flex-shrink"] = "0";
315856
+ }
315857
+ if (cross2 === "FILL") {
315858
+ style[crossProp] = null;
315859
+ style["align-self"] = "stretch";
315860
+ } else {
315861
+ if (cross2 === "HUG") style[crossProp] = null;
315862
+ if ((parent.counterAxisAlignItems ?? "MIN") === "MIN") style["align-self"] = "flex-start";
315863
+ }
315864
+ return { style };
315865
+ }
315866
+ function constrained(kind, pos, size6, parentSize, start2, end, sizeProp) {
315867
+ const far = parentSize - pos - size6;
315868
+ switch (kind) {
315869
+ case "MAX":
315870
+ return { place: { [end]: px2(far) }, style: {} };
315871
+ case "STRETCH":
315872
+ return { place: { [start2]: px2(pos), [end]: px2(far) }, style: { [sizeProp]: null } };
315873
+ // Its centre keeps its distance from the parent's centre.
315874
+ case "CENTER":
315875
+ return { place: { [start2]: `calc(50% + ${px2(pos - parentSize / 2)})` }, style: {} };
315876
+ case "SCALE":
315877
+ return parentSize > 0 ? { place: { [start2]: pct2(pos / parentSize) }, style: { [sizeProp]: pct2(size6 / parentSize) } } : { place: { [start2]: px2(pos) }, style: {} };
315878
+ default:
315879
+ return { place: { [start2]: px2(pos) }, style: {} };
315880
+ }
315881
+ }
315882
+ function placedChild(node2, parent, frame2 = parent) {
315883
+ const c2 = node2.constraints ?? { horizontal: "MIN", vertical: "MIN" };
315884
+ const x2 = constrained(c2.horizontal, node2.x, node2.width, frame2.width, "left", "right", "width");
315885
+ const y = constrained(c2.vertical, node2.y, node2.height, frame2.height, "top", "bottom", "height");
315886
+ return { style: { ...limits(node2), ...x2.style, ...y.style }, place: { position: "absolute", ...x2.place, ...y.place } };
315887
+ }
315888
+ function siteLayout(node2, parent, layout2) {
315889
+ const own2 = node2.type === "FRAME" || node2.type === "COMPONENT" || node2.type === "INSTANCE" ? node2 : null;
315890
+ if (!parent) {
315891
+ const grows = !own2 || laysOut(own2) || own2.overflowScrolling === "NONE" || !own2.overflowScrolling;
315892
+ return { style: { ...limits(node2), width: "100%", ...grows ? { height: null, "min-height": `max(${px2(node2.height)}, 100dvh)` } : {} }, place: { position: "relative" } };
315893
+ }
315894
+ const s = node2;
315895
+ return layout2 && laysOut(layout2) && s.layoutPositioning !== "ABSOLUTE" ? flowChild(s, layout2) : placedChild(s, parent, parent.type === "INSTANCE" && layout2 ? layout2 : parent);
315896
+ }
315897
+ var px2, pct2, isStack, isGrid, laysOut, track, limits;
315898
+ var init_responsive = __esm({
315899
+ "lib/io/web/responsive.ts"() {
315900
+ "use strict";
315901
+ px2 = (v) => `${Math.round(v * 100) / 100}px`;
315902
+ pct2 = (v) => `${Math.round(v * 1e4) / 100}%`;
315903
+ isStack = (f2) => f2?.layoutMode === "HORIZONTAL" || f2?.layoutMode === "VERTICAL";
315904
+ isGrid = (f2) => f2?.layoutMode === "GRID";
315905
+ laysOut = (f2) => isStack(f2) || isGrid(f2);
315906
+ track = (t3) => {
315907
+ if (!t3 || t3.sizing === "FILL") return t3?.value && /fr$/.test(t3.value) ? t3.value : "1fr";
315908
+ if (t3.sizing === "HUG") return "auto";
315909
+ return /^[\d.]+$/.test(t3.value) ? `${t3.value}px` : t3.value;
315910
+ };
315911
+ limits = (n) => {
315912
+ const out = {};
315913
+ if (n.minWidth !== void 0) out["min-width"] = px2(n.minWidth);
315914
+ if (n.maxWidth !== void 0) out["max-width"] = px2(n.maxWidth);
315915
+ if (n.minHeight !== void 0) out["min-height"] = px2(n.minHeight);
315916
+ if (n.maxHeight !== void 0) out["max-height"] = px2(n.maxHeight);
315917
+ return out;
315918
+ };
315919
+ }
315920
+ });
315921
+
315922
+ // lib/io/web/richtext.ts
315923
+ function runStyle(seg) {
315924
+ const out = {};
315925
+ if (seg.fontFamily) out["font-family"] = `"${seg.fontFamily}", system-ui, sans-serif`;
315926
+ if (seg.fontSize) out["font-size"] = `${seg.fontSize}px`;
315927
+ if (seg.fontWeight) out["font-weight"] = String(seg.fontWeight);
315928
+ if (seg.fontStyle) out["font-style"] = seg.fontStyle;
315929
+ if (seg.lineHeight !== void 0 && seg.lineHeight !== "AUTO") out["line-height"] = `${seg.lineHeight}px`;
315930
+ if (seg.textDecoration === "UNDERLINE") out["text-decoration"] = "underline";
315931
+ else if (seg.textDecoration === "STRIKETHROUGH") out["text-decoration"] = "line-through";
315932
+ else if (seg.textDecoration === "NONE") out["text-decoration"] = "none";
315933
+ if (seg.textCase === "UPPER") out["text-transform"] = "uppercase";
315934
+ else if (seg.textCase === "LOWER") out["text-transform"] = "lowercase";
315935
+ else if (seg.textCase === "TITLE") out["text-transform"] = "capitalize";
315936
+ else if (seg.textCase === "ORIGINAL") out["text-transform"] = "none";
315937
+ const solid5 = seg.fills?.find((f2) => f2.visible !== false && f2.type === "SOLID" && f2.color);
315938
+ if (solid5?.color) out.color = toHex(solid5.color);
315939
+ return out;
315940
+ }
315941
+ function textRuns(t3) {
315942
+ const text = t3.characters ?? "";
315943
+ const segs = [...t3.styledSegments ?? []].filter((s) => s.end > s.start).sort((a, b) => a.start - b.start);
315944
+ if (!segs.length && !t3.link) return void 0;
315945
+ const runs = [];
315946
+ const push2 = (from2, to, seg) => {
315947
+ if (to <= from2) return;
315948
+ const link2 = seg?.link ?? t3.link;
315949
+ runs.push({ text: text.slice(from2, to), style: seg ? runStyle(seg) : {}, ...link2 ? { link: link2 } : {} });
315950
+ };
315951
+ let at3 = 0;
315952
+ for (const s of segs) {
315953
+ const start2 = Math.max(at3, Math.min(text.length, s.start)), end = Math.min(text.length, s.end);
315954
+ push2(at3, start2);
315955
+ push2(start2, end, s);
315956
+ at3 = Math.max(at3, end);
315957
+ }
315958
+ push2(at3, text.length);
315959
+ return runs;
315960
+ }
315961
+ var init_richtext = __esm({
315962
+ "lib/io/web/richtext.ts"() {
315963
+ "use strict";
315964
+ init_paint2();
315965
+ }
315966
+ });
315967
+
315968
+ // lib/document/dev-mode.ts
315969
+ function codeSyntaxFor(v, platform4) {
315970
+ const explicit = v.codeSyntax?.[platform4];
315971
+ if (explicit) return explicit;
315972
+ const parts = v.name.split("/").map((p2) => p2.trim()).filter(Boolean);
315973
+ if (platform4 === "WEB") return `--${parts.join("-").toLowerCase().replace(/[^a-z0-9-]+/g, "-")}`;
315974
+ const camel4 = parts.map((p2, i2) => {
315975
+ const w = p2.replace(/[^A-Za-z0-9]+/g, " ").trim().split(/\s+/);
315976
+ return w.map((x2, j) => i2 === 0 && j === 0 ? x2.toLowerCase() : x2[0].toUpperCase() + x2.slice(1).toLowerCase()).join("");
315977
+ }).join("");
315978
+ return platform4 === "iOS" ? `Tokens.${camel4}` : `Tokens.${camel4}`;
315979
+ }
315980
+ var init_dev_mode = __esm({
315981
+ "lib/document/dev-mode.ts"() {
315982
+ "use strict";
315983
+ }
315984
+ });
315985
+
315986
+ // lib/io/web/tokens.ts
315987
+ function cssValue(v, value3) {
315988
+ if (v.type === "COLOR") return isColor3(value3) ? (value3.a ?? 1) < 1 ? toRgba(value3) : toHex(value3) : null;
315989
+ if (v.type === "FLOAT") return typeof value3 === "number" && Number.isFinite(value3) ? String(Math.round(value3 * 1e3) / 1e3) : null;
315990
+ if (v.type === "STRING") return typeof value3 === "string" ? JSON.stringify(value3) : null;
315991
+ return null;
315992
+ }
315993
+ function siteTokens(doc2) {
315994
+ const collections = Object.values(doc2.variableCollections ?? {}).map((c2) => ({
315995
+ id: c2.id,
315996
+ name: c2.name,
315997
+ defaultMode: c2.defaultModeId,
315998
+ modes: c2.modes.map((m) => ({ id: m.id, name: m.name, className: modeClass(c2, m) }))
315999
+ }));
316000
+ const taken = /* @__PURE__ */ new Set();
316001
+ const vars = [];
316002
+ for (const v of Object.values(doc2.variables ?? {}).sort((a, b) => a.name.localeCompare(b.name) || a.id.localeCompare(b.id))) {
316003
+ const values3 = {};
316004
+ for (const [mode, value3] of Object.entries(v.valuesByMode ?? {})) {
316005
+ const css = cssValue(v, value3);
316006
+ if (css !== null) values3[mode] = css;
316007
+ }
316008
+ if (!Object.keys(values3).length) continue;
316009
+ let name2 = codeSyntaxFor(v, "WEB");
316010
+ if (!name2.startsWith("--")) name2 = `--${slug(name2)}`;
316011
+ if (taken.has(name2)) name2 = `${name2}-${v.id.replace(/[^a-zA-Z0-9]/g, "").slice(-4)}`;
316012
+ taken.add(name2);
316013
+ vars.push({ id: v.id, name: name2, type: v.type, collection: v.variableCollectionId, values: values3 });
316014
+ }
316015
+ const active3 = Object.entries(doc2.activeVariableModes ?? {}).flatMap(([cid, mid]) => {
316016
+ const c2 = collections.find((x2) => x2.id === cid);
316017
+ const m = c2 && mid !== c2.defaultMode ? c2.modes.find((x2) => x2.id === mid) : void 0;
316018
+ return m ? [m.className] : [];
316019
+ });
316020
+ return { collections, vars, active: active3 };
316021
+ }
316022
+ function tokensCSS(tokens) {
316023
+ const rules = [];
316024
+ const defaults3 = [];
316025
+ const byMode = /* @__PURE__ */ new Map();
316026
+ for (const v of tokens.vars) {
316027
+ const c2 = tokens.collections.find((x2) => x2.id === v.collection);
316028
+ const base = v.values[c2?.defaultMode ?? ""] ?? Object.values(v.values)[0];
316029
+ defaults3.push(` ${v.name}: ${base};`);
316030
+ if (v.type === "FLOAT") rules.push(`@property ${v.name} { syntax: '<number>'; inherits: true; initial-value: ${base}; }`);
316031
+ for (const m of c2?.modes ?? []) {
316032
+ if (m.id === c2.defaultMode || v.values[m.id] === void 0 || v.values[m.id] === base) continue;
316033
+ (byMode.get(m.className) ?? byMode.set(m.className, []).get(m.className)).push(` ${v.name}: ${v.values[m.id]};`);
316034
+ }
316035
+ }
316036
+ if (defaults3.length) rules.push(`:root {
316037
+ ${defaults3.join("\n")}
316038
+ }`);
316039
+ for (const [cls, lines2] of byMode) rules.push(`.${cls} {
316040
+ ${lines2.join("\n")}
316041
+ }`);
316042
+ return rules;
316043
+ }
316044
+ function tokenStyle(raw, style, tokens) {
316045
+ const name2 = (id3) => id3 ? tokens.vars.find((v) => v.id === id3)?.name : void 0;
316046
+ const out = {};
316047
+ const fills = (raw.fills ?? []).filter((f2) => f2.visible !== false);
316048
+ const fill = fills.length === 1 && fills[0].type === "SOLID" && (fills[0].opacity ?? 1) === 1 ? name2(fills[0].boundVariables?.color) : void 0;
316049
+ if (fill) {
316050
+ if (raw.type === "TEXT") {
316051
+ if (style.color) out.color = `var(${fill})`;
316052
+ } else if (style.background) out.background = `var(${fill})`;
316053
+ }
316054
+ const stroke3 = raw.strokes?.[0];
316055
+ const strokeVar = name2(stroke3?.boundVariables?.color);
316056
+ if (strokeVar) {
316057
+ if (style["border-color"]) out["border-color"] = `var(${strokeVar})`;
316058
+ for (const p2 of ["border", "outline"]) if (style[p2]) out[p2] = style[p2].replace(/(#[0-9A-Fa-f]{3,8}|rgba?\([^)]*\))$/, `var(${strokeVar})`);
316059
+ }
316060
+ for (const [prop, id3] of Object.entries(raw.boundVariables ?? {})) {
316061
+ const rule2 = NUMBER_PROPS[prop];
316062
+ const token = tokens.vars.find((v) => v.id === id3);
316063
+ if (!rule2 || !token || token.type !== "FLOAT" || style[rule2[0]] === void 0) continue;
316064
+ out[rule2[0]] = rule2[1](token.name);
316065
+ }
316066
+ return out;
316067
+ }
316068
+ var slug, modeClass, isColor3, px3, NUMBER_PROPS;
316069
+ var init_tokens2 = __esm({
316070
+ "lib/io/web/tokens.ts"() {
316071
+ "use strict";
316072
+ init_dev_mode();
316073
+ init_paint2();
316074
+ slug = (s) => s.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "") || "x";
316075
+ modeClass = (collection, mode) => `pc-${slug(collection.name)}-${slug(mode.name)}`;
316076
+ isColor3 = (v) => !!v && typeof v === "object" && "r" in v && "g" in v && "b" in v;
316077
+ px3 = (name2) => `calc(var(${name2}) * 1px)`;
316078
+ NUMBER_PROPS = {
316079
+ width: ["width", px3],
316080
+ height: ["height", px3],
316081
+ opacity: ["opacity", (n) => `var(${n})`],
316082
+ cornerRadius: ["border-radius", px3],
316083
+ itemSpacing: ["gap", px3],
316084
+ fontSize: ["font-size", px3],
316085
+ letterSpacing: ["letter-spacing", px3]
316086
+ };
316087
+ }
316088
+ });
316089
+
316090
+ // lib/io/web/timeline.ts
316091
+ function frameWebMotion(doc2, frameId, style) {
316092
+ const nodes = doc2.nodes;
316093
+ const frame2 = nodes[frameId];
316094
+ if (!frame2 || !hasFrameMotion(nodes, frameId)) return null;
316095
+ const len3 = timelineDuration(nodes, frameId);
316096
+ if (!(len3 > 0)) return null;
316097
+ const steps = Math.max(1, Math.ceil(len3 / 1e3 * SAMPLE_RATE));
316098
+ const times2 = [];
316099
+ const poses = [];
316100
+ for (let i2 = 0; i2 <= steps; i2++) {
316101
+ const t3 = len3 * i2 / steps;
316102
+ times2.push(t3);
316103
+ poses.push(evaluatePose(nodes, { kind: "frame", frameId }, t3).nodes);
316104
+ }
316105
+ const ids2 = /* @__PURE__ */ new Set();
316106
+ for (const p2 of poses) for (const id3 in p2) if (id3 !== frameId && p2[id3] !== nodes[id3]) ids2.add(id3);
316107
+ const loops = frameRunsOn(nodes, frameId);
316108
+ const out = /* @__PURE__ */ new Map();
316109
+ const tag = frameId.replace(/[^a-zA-Z0-9]/g, "").slice(-6);
316110
+ let n = 0;
316111
+ for (const id3 of ids2) {
316112
+ const rest = id3.includes("::") ? resolveVirtualNode2(nodes, id3) : nodes[id3];
316113
+ if (!rest || !underFrame(nodes, id3, frameId)) continue;
316114
+ const frames = keyframesOf(times2, poses.map((p2) => declarationsOf(p2[id3] ?? rest, rest, style)), len3);
316115
+ if (!frames) continue;
316116
+ out.set(id3, {
316117
+ name: `timeline-${tag}-${n++}`,
316118
+ frames,
316119
+ durationMs: Math.round(len3),
316120
+ delayMs: 0,
316121
+ iterations: loops ? "infinite" : 1,
316122
+ direction: "normal",
316123
+ fill: "both"
316124
+ });
316125
+ }
316126
+ return out.size ? out : null;
316127
+ }
316128
+ function underFrame(nodes, id3, frameId) {
316129
+ const real = id3.split("::")[0];
316130
+ for (let n = nodes[real]; n; n = n.parentId ? nodes[n.parentId] : void 0) if (n.id === frameId) return true;
316131
+ return false;
316132
+ }
316133
+ var init_timeline = __esm({
316134
+ "lib/io/web/timeline.ts"() {
316135
+ "use strict";
316136
+ init_scene_graph();
316137
+ init_pose();
316138
+ init_instances2();
316139
+ init_keyframes();
316140
+ }
316141
+ });
316142
+
316143
+ // lib/io/web/generated/runtimes.ts
316144
+ var PROTOTYPE_JS, MACHINE_JS;
316145
+ var init_runtimes = __esm({
316146
+ "lib/io/web/generated/runtimes.ts"() {
316147
+ "use strict";
316148
+ PROTOTYPE_JS = 'function popcraftMount(root, spec) {\n var els = {}, state = {}, owned = {}, orbit = {}, last = {}, holds = {}, hist = [], timers = [];\n var nodes = [root].concat(Array.prototype.slice.call(root.querySelectorAll("[data-pc]")));\n nodes.forEach(function(el) {\n els[el.getAttribute("data-pc")] = el;\n });\n for (var m in spec.m) state[m] = spec.m[m];\n for (var u in spec.e) (owned[spec.e[u][0]] = owned[spec.e[u][0]] || []).push(u);\n var drags = {}, clicks = {};\n spec.on.forEach(function(o) {\n if (o[3] === "drag") drags[o[0]] = 1;\n if (o[3] === "click" || o[3] === "press") clicks[o[0]] = 1;\n });\n function lookIn(u2, st) {\n var e = spec.e[u2];\n if (!e) return -2;\n var i = e[1][st === void 0 ? state[e[0]] : st];\n return i === void 0 ? -1 : i;\n }\n function tf(f, o) {\n var ry = f[4] + (o ? o.ry : 0), rx = f[5] + (o ? o.rx : 0), p = [];\n if (f[0] || f[1] || f[2]) p.push(f[2] ? "translate3d(" + f[0] + "px, " + f[1] + "px, " + f[2] + "px)" : "translate(" + f[0] + "px, " + f[1] + "px)");\n if (f[3]) p.push("rotate(" + f[3] + "deg)");\n if (ry) p.push("rotateY(" + ry + "deg)");\n if (rx) p.push("rotateX(" + rx + "deg)");\n if (f[6] !== 1 || f[7] !== 1) p.push("scale(" + f[6] + ", " + f[7] + ")");\n return p.length ? p.join(" ") : "none";\n }\n function css(u2, i) {\n var L = spec.L[i], c = L[0];\n if (orbit[u2] && L[2]) c += ";transform:" + tf(L[2], orbit[u2]);\n if (drags[u2]) c += ";touch-action:none;user-select:none;-webkit-user-select:none";\n if (clicks[u2]) c += ";cursor:pointer";\n return c;\n }\n var HIDE = ";opacity:0;visibility:hidden;pointer-events:none;position:absolute";\n function set(u2, ms, ez) {\n var el = els[u2], i = lookIn(u2, void 0);\n if (!el || i === -2) return;\n var tr = ms ? ";transition:all " + ms + "ms " + ez : ";transition:none";\n if (i < 0) {\n el.style.cssText = (last[u2] || "") + HIDE + tr;\n return;\n }\n var c = css(u2, i), text = spec.L[i][1];\n if (text !== null && el.textContent !== text) el.textContent = text;\n if (ms && el.style.visibility === "hidden") {\n el.style.cssText = c + ";opacity:0;transition:none";\n void el.offsetWidth;\n }\n el.style.cssText = c + tr;\n last[u2] = c;\n }\n var ANIM = /(?:^|;)animation:[^;]*/;\n function anim(i) {\n var m2 = i >= 0 ? ANIM.exec(spec.L[i][0]) : null;\n return m2 ? m2[0] : "";\n }\n function go(m2, to, ms, ez, fromHistory) {\n if (!(m2 in state) || state[m2] === to) return;\n var list = owned[m2] || [];\n list.forEach(function(u2) {\n var a = lookIn(u2, void 0), b = lookIn(u2, to), el = els[u2];\n if (!el || a < 0 || !anim(a) || anim(a) === anim(b)) return;\n var cs = getComputedStyle(el);\n el.style.cssText = css(u2, a) + ";animation:none;transition:none;transform:" + cs.transform + ";opacity:" + cs.opacity;\n });\n void root.offsetWidth;\n if (m2 === "flow" && !fromHistory) hist.push(state[m2]);\n state[m2] = to;\n list.forEach(function(u2) {\n set(u2, ms, ez);\n });\n arm();\n }\n function active(u2, trig) {\n return spec.on.filter(function(o) {\n return String(o[0]) === String(u2) && o[3] === trig && state[o[1]] === o[2];\n });\n }\n function run(o, u2) {\n var a = o[4];\n if (a.k === "go") {\n if (a.hold) {\n if (!holds[u2]) holds[u2] = { m: a.m, back: state[a.m], ms: a.ms, ez: a.ez };\n }\n go(a.m, a.to, a.ms, a.ez, false);\n } else if (a.k === "back" && hist.length) {\n go(a.m, hist.pop(), 300, "ease-in-out", true);\n }\n }\n function release(u2) {\n var h = holds[u2];\n if (!h) return;\n delete holds[u2];\n go(h.m, h.back, h.ms, h.ez, true);\n }\n function chain(el) {\n var out = [];\n for (var n = el; n && n !== root.parentNode; n = n.parentNode) {\n var id2 = n.getAttribute && n.getAttribute("data-pc");\n if (id2 !== null && id2 !== void 0) out.push(id2);\n if (n === root) break;\n }\n return out;\n }\n function first(ids, trig) {\n for (var i = 0; i < ids.length; i++) {\n var a = active(ids[i], trig);\n if (a.length) return { u: ids[i], list: a };\n }\n return null;\n }\n function arm() {\n timers.forEach(clearTimeout);\n timers = [];\n spec.on.forEach(function(o) {\n if (o[3] === "timeout" && state[o[1]] === o[2]) timers.push(setTimeout(function() {\n if (state[o[1]] === o[2]) run(o, o[0]);\n }, o[5]));\n });\n }\n var over = [];\n function hover(ids) {\n var left = over.filter(function(u2) {\n return ids.indexOf(u2) < 0;\n }), entered = ids.filter(function(u2) {\n return over.indexOf(u2) < 0;\n });\n over = ids;\n left.forEach(function(u2) {\n release(u2);\n active(u2, "leave").forEach(function(o) {\n run(o, u2);\n });\n });\n entered.slice().reverse().forEach(function(u2) {\n active(u2, "hover").concat(active(u2, "enter")).forEach(function(o) {\n run(o, u2);\n });\n });\n }\n var press = null;\n function onMove(e) {\n if (press) {\n var dx = e.clientX - press.x, dy = e.clientY - press.y;\n if (!press.dragged && Math.abs(dx) + Math.abs(dy) > 5) {\n press.dragged = true;\n var d = first(press.ids, "drag");\n if (d) {\n var du = d.u;\n press.drag = d;\n d.list.forEach(function(o) {\n if (o[4].k !== "orbit") run(o, du);\n });\n }\n if (press.held) {\n release(press.held);\n press.held = null;\n }\n }\n if (press.drag) {\n var k = root.getBoundingClientRect().width / (root.offsetWidth || 1) || 1;\n press.drag.list.forEach(function(o) {\n var a = o[4];\n if (a.k !== "orbit") return;\n var cur = orbit[a.t] || { rx: 0, ry: 0 };\n orbit[a.t] = { rx: cur.rx, ry: cur.ry + (e.clientX - press.lx) / k * a.d };\n if (a.tilt) {\n var tc = orbit[a.tt] || { rx: 0, ry: 0 };\n orbit[a.tt] = { ry: tc.ry, rx: Math.max(a.lo, Math.min(a.hi, tc.rx - (e.clientY - press.ly) / k * a.d)) };\n }\n set(a.t, 0, "linear");\n if (a.tt !== a.t) set(a.tt, 0, "linear");\n });\n press.lx = e.clientX;\n press.ly = e.clientY;\n return;\n }\n }\n hover(chain(e.target));\n }\n function onDown(e) {\n var ids = chain(e.target);\n press = { x: e.clientX, y: e.clientY, lx: e.clientX, ly: e.clientY, ids, dragged: false, drag: null, held: null };\n if (first(ids, "drag") && root.setPointerCapture) {\n try {\n root.setPointerCapture(e.pointerId);\n } catch (err) {\n }\n }\n var p = first(ids, "press");\n if (p) {\n var pu = p.u;\n press.held = pu;\n p.list.forEach(function(o) {\n run(o, pu);\n });\n }\n }\n function onUp(e) {\n var p = press;\n press = null;\n if (!p) return;\n if (p.held) release(p.held);\n if (p.dragged) return;\n var c = first(p.ids, "click");\n if (c) {\n var cu = c.u;\n c.list.forEach(function(o) {\n run(o, cu);\n });\n }\n void e;\n }\n function onLeave() {\n if (!press) hover([]);\n }\n function onKey(e) {\n spec.on.forEach(function(o) {\n if (o[3] === "key" && state[o[1]] === o[2] && (!o[6] || o[6].toLowerCase() === String(e.key).toLowerCase())) run(o, o[0]);\n });\n }\n for (var id in els) set(id, 0, "linear");\n root.addEventListener("pointermove", onMove);\n root.addEventListener("pointerdown", onDown);\n root.addEventListener("pointerup", onUp);\n root.addEventListener("pointercancel", onUp);\n root.addEventListener("pointerleave", onLeave);\n window.addEventListener("keydown", onKey);\n arm();\n return function() {\n timers.forEach(clearTimeout);\n root.removeEventListener("pointermove", onMove);\n root.removeEventListener("pointerdown", onDown);\n root.removeEventListener("pointerup", onUp);\n root.removeEventListener("pointercancel", onUp);\n root.removeEventListener("pointerleave", onLeave);\n window.removeEventListener("keydown", onKey);\n };\n}';
316149
+ MACHINE_JS = 'function popcraftMachineCore(spec) {\n function start(id) {\n var t = spec.in[id];\n return !t || t[0] === "event" ? void 0 : t[1];\n }\n function holds(g, values, fired) {\n var t = spec.in[g[0]];\n if (!t) return false;\n if (t[0] === "event") return !!fired[g[0]];\n var v = g[0] in values ? values[g[0]] : start(g[0]), w = g[2];\n switch (g[1]) {\n case "eq":\n return v === w;\n case "neq":\n return v !== w;\n case "gt":\n return typeof v === "number" && typeof w === "number" && v > w;\n case "gte":\n return typeof v === "number" && typeof w === "number" && v >= w;\n case "lt":\n return typeof v === "number" && typeof w === "number" && v < w;\n case "lte":\n return typeof v === "number" && typeof w === "number" && v <= w;\n }\n return false;\n }\n function apply(values, actions) {\n var out = {}, fired = {};\n for (var k in values) out[k] = values[k];\n actions.forEach(function(a) {\n var t = spec.in[a[1]];\n if (!t) return;\n var cur = a[1] in out ? out[a[1]] : start(a[1]), by = typeof a[2] === "number" ? a[2] : 1;\n if (a[0] === "set") {\n if (t[0] === "event") fired[a[1]] = 1;\n else if (a.length > 2 && typeof a[2] === typeof cur) out[a[1]] = a[2];\n } else if (a[0] === "toggle") {\n if (typeof cur === "boolean") out[a[1]] = !cur;\n } else if (a[0] === "increment") {\n if (typeof cur === "number") out[a[1]] = cur + by;\n } else if (a[0] === "decrement") {\n if (typeof cur === "number") out[a[1]] = cur - by;\n } else if (a[0] === "fire") {\n if (t[0] === "event") fired[a[1]] = 1;\n } else if (a[0] === "reset") {\n var s = start(a[1]);\n if (s === void 0) delete out[a[1]];\n else out[a[1]] = s;\n }\n });\n return { values: out, fired };\n }\n function next(r, fired) {\n var own = spec.t.filter(function(t2) {\n return t2[0] === r.state;\n });\n var any = spec.t.filter(function(t2) {\n return t2[0] === "*" && t2[1] !== r.state;\n });\n var all = own.concat(any);\n for (var i = 0; i < all.length; i++) {\n var t = all[i];\n if (spec.s[t[1]] && t[2].every(function(g) {\n return holds(g, r.values, fired);\n })) return t;\n }\n return null;\n }\n function enter(r, id) {\n var res = apply(r.values, spec.s[id] ? spec.s[id][4] : []);\n return { run: { state: id, values: res.values }, fired: res.fired };\n }\n function settle(r, fired) {\n var cur = r, ev = fired || {};\n for (var i = 0; i < 16; i++) {\n var t = next(cur, ev);\n if (!t) break;\n var n = enter(cur, t[1]);\n cur = n.run;\n ev = n.fired;\n }\n return cur;\n }\n function begin() {\n var first = spec.s[spec.i] ? spec.i : Object.keys(spec.s)[0], values = {};\n if (first === void 0) return null;\n for (var k in spec.in) {\n var s = start(k);\n if (s !== void 0) values[k] = s;\n }\n var e = enter({ state: first, values }, first);\n return settle(e.run, e.fired);\n }\n function hears(l, type, chain, key) {\n if (l[0] !== type) return false;\n if (type === "complete") return true;\n if (type === "keyDown" || type === "keyUp") return !l[3] || String(l[3]).toLowerCase() === String(key).toLowerCase();\n return l[1] === null || chain.indexOf(l[1]) >= 0;\n }\n function dispatch(r, type, chain, key) {\n var heard = spec.l.filter(function(l) {\n return hears(l, type, chain, key);\n });\n if (!heard.length) return r;\n var res = apply(r.values, [].concat.apply([], heard.map(function(l) {\n return l[2];\n })));\n return settle({ state: r.state, values: res.values }, res.fired);\n }\n function set(r, id, value) {\n var t = spec.in[id];\n if (!t) return r;\n var res = apply(r.values, [t[0] === "event" ? ["fire", id] : ["set", id, value]]);\n return settle({ state: r.state, values: res.values }, res.fired);\n }\n return { begin, dispatch, set };\n}\nfunction popcraftMachine(root, spec) {\n var core = popcraftMachineCore(spec), run = core.begin(), anims = [], t0 = 0, done = false, raf = 0, over = [];\n if (!run) return function() {\n };\n function chain(el) {\n var out = [];\n for (var n = el; n && n !== root.parentNode; n = n.parentNode) {\n var id = n.getAttribute && n.getAttribute("data-sm");\n if (id) out.push(id);\n if (n === root) break;\n }\n return out;\n }\n function update(r) {\n if (r === run) return;\n var changed = r.state !== run.state;\n run = r;\n if (!changed) return;\n t0 = performance.now();\n done = false;\n root.dispatchEvent(new CustomEvent("popcraft:state", { detail: { state: r.state, name: spec.s[r.state] ? spec.s[r.state][5] : r.state, values: r.values } }));\n }\n function tick(now) {\n var s = spec.s[run.state];\n if (s) {\n var a = s[0], b = s[1], played = Math.max(0, now - t0) * s[3], t;\n if (s[2] && b > a) t = a + played % (b - a);\n else {\n t = Math.min(b, a + played);\n if (!done && a + played >= b) {\n done = true;\n update(core.dispatch(run, "complete", []));\n }\n }\n anims.forEach(function(x) {\n x.currentTime = t;\n });\n }\n raf = requestAnimationFrame(tick);\n }\n function on(type) {\n return function(e) {\n update(core.dispatch(run, type, chain(e.target)));\n };\n }\n function onMove(e) {\n var ids = chain(e.target);\n var left = over.filter(function(u) {\n return ids.indexOf(u) < 0;\n }), entered = ids.filter(function(u) {\n return over.indexOf(u) < 0;\n });\n over = ids;\n if (left.length) update(core.dispatch(run, "pointerExit", left));\n if (entered.length) update(core.dispatch(run, "pointerEnter", entered));\n }\n function onLeave() {\n if (over.length) {\n var left = over;\n over = [];\n update(core.dispatch(run, "pointerExit", left));\n }\n }\n function onKey(type) {\n return function(e) {\n var t = e.target;\n if (e.repeat || e.metaKey || e.ctrlKey || t && (t.tagName === "INPUT" || t.tagName === "TEXTAREA" || t.isContentEditable)) return;\n var r = core.dispatch(run, type, [], e.key);\n if (r !== run) {\n e.preventDefault();\n update(r);\n }\n };\n }\n var down = on("pointerDown"), up = on("pointerUp"), click = on("click"), keyDown = onKey("keyDown"), keyUp = onKey("keyUp");\n anims = root.getAnimations ? root.getAnimations({ subtree: true }) : [];\n anims.forEach(function(x) {\n x.pause();\n });\n t0 = performance.now();\n root.addEventListener("pointerdown", down);\n root.addEventListener("pointerup", up);\n root.addEventListener("click", click);\n root.addEventListener("pointermove", onMove);\n root.addEventListener("pointerleave", onLeave);\n window.addEventListener("keydown", keyDown);\n window.addEventListener("keyup", keyUp);\n raf = requestAnimationFrame(tick);\n function byName(k) {\n if (spec.in[k]) return k;\n for (var id in spec.in) if (spec.in[id][2] === k) return id;\n return k;\n }\n var api = {\n state: function() {\n return run.state;\n },\n values: function() {\n return run.values;\n },\n set: function(input, value) {\n update(core.set(run, byName(input), value));\n },\n fire: function(input) {\n update(core.set(run, byName(input), void 0));\n },\n destroy: function() {\n cancelAnimationFrame(raf);\n root.removeEventListener("pointerdown", down);\n root.removeEventListener("pointerup", up);\n root.removeEventListener("click", click);\n root.removeEventListener("pointermove", onMove);\n root.removeEventListener("pointerleave", onLeave);\n window.removeEventListener("keydown", keyDown);\n window.removeEventListener("keyup", keyUp);\n }\n };\n root.popcraftMachine = api;\n return api.destroy;\n}';
316150
+ }
316151
+ });
316152
+
316153
+ // lib/io/web/machine-runtime.ts
316154
+ var init_machine_runtime = __esm({
316155
+ "lib/io/web/machine-runtime.ts"() {
316156
+ "use strict";
316157
+ init_runtimes();
316158
+ }
316159
+ });
316160
+
316161
+ // lib/io/web/state-machine.ts
316162
+ function webStateMachine(doc2, frameId) {
316163
+ const sm = machineOf(doc2.nodes[frameId]);
316164
+ if (!sm || !doc2.nodes[frameId]?.timeline) return null;
316165
+ const timeline = frameTimeline(doc2.nodes, frameId);
316166
+ const duration3 = timelineDuration(doc2.nodes, frameId);
316167
+ const action3 = (a) => a.value === void 0 ? [a.type, a.input] : [a.type, a.input, a.value];
316168
+ const spec = { i: sm.initial, s: {}, t: [], in: {}, l: [] };
316169
+ for (const i2 of sortedValues(sm.inputs)) spec.in[i2.id] = [i2.type, i2.type === "event" ? null : i2.value ?? defaultOf2(i2.type), i2.name];
316170
+ for (const s of sortedValues(sm.states)) {
316171
+ const [a, b] = stateStretch(s, timeline, duration3);
316172
+ spec.s[s.id] = [a, b, s.loop ? 1 : 0, s.speed ?? 1, (s.entry ?? []).map(action3), s.name];
316173
+ }
316174
+ for (const t3 of sortedValues(sm.transitions)) {
316175
+ spec.t.push([t3.from, t3.to, (t3.guards ?? []).map((g) => {
316176
+ const type = sm.inputs[g.input]?.type;
316177
+ const value3 = type === "event" ? null : g.value ?? (type === "boolean" ? true : type === "number" ? 0 : "");
316178
+ return [g.input, g.op ?? "eq", value3];
316179
+ })]);
316180
+ }
316181
+ for (const l of sortedValues(sm.listeners)) {
316182
+ if (!isKeyListener(l.type)) spec.l.push([l.type, l.layer ?? null, l.actions.map(action3)]);
316183
+ else spec.l.push(l.key ? [l.type, null, l.actions.map(action3), l.key] : [l.type, null, l.actions.map(action3)]);
316184
+ }
316185
+ return spec;
316186
+ }
316187
+ var defaultOf2, machineLayers, machineScript;
316188
+ var init_state_machine2 = __esm({
316189
+ "lib/io/web/state-machine.ts"() {
316190
+ "use strict";
316191
+ init_instances2();
316192
+ init_state_machine();
316193
+ init_machine_runtime();
316194
+ init_machine_runtime();
316195
+ defaultOf2 = (type) => type === "boolean" ? false : type === "number" ? 0 : type === "string" ? "" : null;
316196
+ machineLayers = (spec) => new Set((spec?.l ?? []).map((l) => l[1]).filter((id3) => !!id3));
316197
+ machineScript = (spec) => `${MACHINE_JS}
316198
+ popcraftMachine(document.querySelector('[data-sm-root]'), ${JSON.stringify(spec)});`;
316199
+ }
316200
+ });
316201
+
316202
+ // lib/io/web/interactive.ts
316203
+ function subtreeIds(doc2, id3, out = /* @__PURE__ */ new Set()) {
316204
+ if (out.has(id3)) return out;
316205
+ const n = doc2.nodes[id3];
316206
+ if (!n) return out;
316207
+ out.add(id3);
316208
+ if (n.type === "INSTANCE") subtreeIds(doc2, n.mainComponentId, out);
316209
+ for (const c2 of n.childIds ?? []) subtreeIds(doc2, c2, out);
316210
+ return out;
316211
+ }
316212
+ function flowScreens(doc2, startId) {
316213
+ const start2 = doc2.nodes[startId];
316214
+ if (!start2 || start2.type !== "FRAME" || doc2.nodes[start2.parentId ?? ""]?.type !== "PAGE") return [startId];
316215
+ const out = [startId];
316216
+ for (let i2 = 0; i2 < out.length; i2++) {
316217
+ for (const id3 of subtreeIds(doc2, out[i2])) {
316218
+ for (const ix of interactionsOf(doc2.nodes[id3])) {
316219
+ const to = ix.action.navigationType === "NAVIGATE" ? ix.action.destinationId : null;
316220
+ const dest = to ? doc2.nodes[to] : void 0;
316221
+ if (!dest || out.includes(dest.id) || dest.type !== "FRAME" || doc2.nodes[dest.parentId ?? ""]?.type !== "PAGE") continue;
316222
+ if (Math.round(dest.width) !== Math.round(start2.width) || Math.round(dest.height) !== Math.round(start2.height)) continue;
316223
+ out.push(dest.id);
316224
+ }
316225
+ }
316226
+ }
316227
+ return out;
316228
+ }
316229
+ function variantStates(doc2, mainId) {
316230
+ const out = [mainId];
316231
+ for (let i2 = 0; i2 < out.length; i2++) {
316232
+ for (const id3 of subtreeIds(doc2, out[i2])) {
316233
+ for (const ix of interactionsOf(doc2.nodes[id3])) {
316234
+ const to = ix.action.navigationType === "CHANGE_TO" ? ix.action.destinationId : null;
316235
+ if (to && !out.includes(to) && doc2.nodes[to]?.type === "COMPONENT") out.push(to);
316236
+ }
316237
+ }
316238
+ }
316239
+ return out;
316240
+ }
316241
+ function buildState(ctx2, doc2, id3, machine, state, start2, variantOf2) {
316242
+ const expand = /* @__PURE__ */ new Map();
316243
+ const tree = buildPlainTree(doc2, id3, ctx2.opts, start2, { built: (web, _node, at3) => {
316244
+ if (web.type === "INSTANCE") expand.set(web, at3);
316245
+ } });
316246
+ for (const r of tree.rules ?? []) ctx2.rules.add(r);
316247
+ if (tree.truncated) ctx2.truncated = true;
316248
+ const ids2 = /* @__PURE__ */ new Map();
316249
+ const index2 = (w) => {
316250
+ ids2.set(w.id, w);
316251
+ w.children.forEach(index2);
316252
+ };
316253
+ index2(tree.root);
316254
+ const visit2 = (w, owner, st, isRoot) => {
316255
+ w.owner = owner;
316256
+ w.looks = { [st]: lookOf(w, isRoot) };
316257
+ if (w.motion) ctx2.keyframes.add(w.motion.keyframes);
316258
+ const node2 = nodeOf(doc2, w.id);
316259
+ note(ctx2, w, interactionsOf(doc2.nodes[realId(w.id)]), owner, st, ids2);
316260
+ const at3 = expand.get(w);
316261
+ const inst = node2?.type === "INSTANCE" ? node2 : void 0;
316262
+ const states = inst && at3 && ctx2.depth < 4 ? variantStates(doc2, inst.mainComponentId) : [];
316263
+ if (inst && at3 && states.length > 1 && w.id !== variantOf2) {
316264
+ const m = { id: `m${ctx2.machines.length}`, initial: inst.mainComponentId, states: states.map((s) => ({ id: s, name: stateName(doc2, s) })) };
316265
+ ctx2.machines.push(m);
316266
+ w.machine = m;
316267
+ const perState = [];
316268
+ for (const s of states) {
316269
+ let kids;
316270
+ if (s === inst.mainComponentId) {
316271
+ kids = w.children;
316272
+ kids.forEach((c2) => visit2(c2, m.id, s, false));
316273
+ } else {
316274
+ const shown2 = { ...doc2, nodes: { ...doc2.nodes, [inst.id]: { ...inst, mainComponentId: s } } };
316275
+ ctx2.depth++;
316276
+ try {
316277
+ kids = buildState(ctx2, shown2, inst.id, m.id, s, at3, inst.id).children;
316278
+ } finally {
316279
+ ctx2.depth--;
316280
+ }
316281
+ }
316282
+ note(ctx2, w, interactionsOf(doc2.nodes[s]), m.id, s, ids2, m.id);
316283
+ perState.push([s, kids]);
316284
+ }
316285
+ w.children = mergeChildren(perState, m.id, m.states.map((s) => s.id), ctx2);
316286
+ } else if (w.id === variantOf2) {
316287
+ w.children.forEach((c2) => visit2(c2, owner, st, false));
316288
+ } else {
316289
+ if (inst) note(ctx2, w, interactionsOf(doc2.nodes[inst.mainComponentId]), owner, st, ids2);
316290
+ w.children.forEach((c2) => visit2(c2, owner, st, false));
316291
+ }
316292
+ };
316293
+ visit2(tree.root, machine, state, !start2);
316294
+ return tree.root;
316295
+ }
316296
+ function note(ctx2, w, list2, machine, state, ids2, hostMachine) {
316297
+ if (!list2.length) return;
316298
+ const at3 = ctx2.pending.get(w) ?? [];
316299
+ for (const ix of list2) at3.push({ machine, state, ix, hostMachine: hostMachine ?? (machine !== FLOW ? machine : void 0), ids: ids2 });
316300
+ ctx2.pending.set(w, at3);
316301
+ }
316302
+ function lookOf(w, isRoot) {
316303
+ return {
316304
+ style: { ...placementStyle(w, isRoot), ...w.style, ...w.motion?.style ?? {} },
316305
+ ...w.text ? { text: w.text.characters } : {},
316306
+ ...w.tf ? { tf: w.tf } : {}
316307
+ };
316308
+ }
316309
+ function keyed(kids) {
316310
+ const seen = /* @__PURE__ */ new Map();
316311
+ return kids.map((k2) => {
316312
+ const base = `${k2.name}\0${k2.type}`;
316313
+ const i2 = seen.get(base) ?? 0;
316314
+ seen.set(base, i2 + 1);
316315
+ return [`${base}\0${i2}`, k2];
316316
+ });
316317
+ }
316318
+ function mergeChildren(perState, machine, states, ctx2) {
316319
+ const order2 = [];
316320
+ const groups = /* @__PURE__ */ new Map();
316321
+ for (const [state, kids] of perState) {
316322
+ let after = -1;
316323
+ for (const [k2, node2] of keyed(kids)) {
316324
+ let at3 = order2.indexOf(k2);
316325
+ if (at3 < 0) {
316326
+ order2.splice(after + 1, 0, k2);
316327
+ at3 = after + 1;
316328
+ }
316329
+ after = at3;
316330
+ (groups.get(k2) ?? groups.set(k2, []).get(k2)).push([state, node2]);
316331
+ }
316332
+ }
316333
+ return order2.map((k2) => mergeNode(groups.get(k2), machine, states, ctx2));
316334
+ }
316335
+ function mergeNode(items, machine, states, ctx2) {
316336
+ const [, first2] = items[0];
316337
+ if (first2.owner !== machine) {
316338
+ for (const [, w] of items.slice(1)) alias(ctx2, w, first2);
316339
+ return first2;
316340
+ }
316341
+ const looks = {};
316342
+ for (const s of states) looks[s] = null;
316343
+ for (const [s, w] of items) looks[s] = w.looks?.[s] ?? null;
316344
+ const merged = { ...first2, looks };
316345
+ const pend = items.flatMap(([, w]) => ctx2.pending.get(w) ?? []);
316346
+ if (pend.length) ctx2.pending.set(merged, pend);
316347
+ for (const [, w] of items) if (w !== merged) alias(ctx2, w, merged);
316348
+ if (first2.machine) {
316349
+ for (const [, w] of items) if (w.machine && w.machine !== first2.machine) ctx2.renamed.set(w.machine.id, first2.machine.id);
316350
+ }
316351
+ merged.children = first2.machine ? first2.children : mergeChildren(items.map(([s, w]) => [s, w.children]), machine, states, ctx2);
316352
+ return merged;
316353
+ }
316354
+ function alias(ctx2, from2, to) {
316355
+ const a = ctx2.alias ??= /* @__PURE__ */ new Map();
316356
+ a.set(from2, to);
316357
+ }
316358
+ function mergedOf(ctx2, w) {
316359
+ const a = ctx2.alias;
316360
+ let cur = w;
316361
+ for (let i2 = 0; i2 < 16 && a?.has(cur); i2++) cur = a.get(cur);
316362
+ return cur;
316363
+ }
316364
+ function actionOf(ctx2, p2) {
316365
+ const a = p2.ix.action;
316366
+ const glide2 = glideOf2(a.transition);
316367
+ const hold = p2.ix.trigger === "ON_HOVER" || p2.ix.trigger === "ON_PRESS";
316368
+ switch (a.navigationType) {
316369
+ case "NAVIGATE":
316370
+ return a.destinationId && ctx2.screens.has(a.destinationId) ? { kind: "go", machine: FLOW, to: a.destinationId, ...glide2, ...hold ? { hold } : {} } : null;
316371
+ case "BACK":
316372
+ return ctx2.screens.size > 1 ? { kind: "back", machine: FLOW } : null;
316373
+ case "CHANGE_TO":
316374
+ return p2.hostMachine && a.destinationId ? { kind: "go", machine: p2.hostMachine, to: a.destinationId, ...glide2, ...hold ? { hold } : {} } : null;
316375
+ case "ORBIT_3D": {
316376
+ const o = a.orbit ?? {};
316377
+ const uidOf = (id3) => {
316378
+ const w = id3 ? p2.ids.get(id3) : void 0;
316379
+ return w ? mergedOf(ctx2, w).uid : void 0;
316380
+ };
316381
+ const uid2 = uidOf(a.destinationId);
316382
+ const tiltUid = uidOf(o.tiltLayerId) ?? uid2;
316383
+ return uid2 === void 0 || tiltUid === void 0 ? null : { kind: "orbit", target: uid2, tiltTarget: tiltUid, degreesPerPx: o.degreesPerPx ?? 0.4, tilt: !!o.tilt, tiltRange: o.tiltRange ?? [-30, 30] };
316384
+ }
316385
+ default:
316386
+ return null;
316387
+ }
316388
+ }
316389
+ function buildWebTree(doc2, nodeId2, opts = {}) {
316390
+ const tree = buildTree(doc2, nodeId2, opts);
316391
+ const machine = opts.static || opts.stateMachine === false ? null : webStateMachine(doc2, nodeId2);
316392
+ return machine ? { ...tree, stateMachine: machine } : tree;
316393
+ }
316394
+ function buildTree(doc2, nodeId2, opts = {}) {
316395
+ if (opts.static || opts.target === "site") return buildPlainTree(doc2, nodeId2, opts);
316396
+ const screens = flowScreens(doc2, nodeId2);
316397
+ const anything = screens.length > 1 || [...subtreeIds(doc2, nodeId2)].some((id3) => interactionsOf(doc2.nodes[id3]).some((ix) => ix.action.navigationType === "CHANGE_TO" || ix.action.navigationType === "ORBIT_3D"));
316398
+ if (!anything) return buildPlainTree(doc2, nodeId2, opts);
316399
+ const flow = { id: FLOW, initial: nodeId2, states: screens.map((s) => ({ id: s, name: doc2.nodes[s]?.name ?? s })) };
316400
+ const ctx2 = { doc: doc2, opts, screens: new Set(screens), machines: [flow], keyframes: /* @__PURE__ */ new Set(), rules: /* @__PURE__ */ new Set(), pending: /* @__PURE__ */ new Map(), depth: 0, renamed: /* @__PURE__ */ new Map() };
316401
+ const roots = screens.map((s) => [s, buildState(ctx2, doc2, s, FLOW, s)]);
316402
+ const truncated = !!ctx2.truncated;
316403
+ const root2 = mergeNode(roots, FLOW, screens, ctx2);
316404
+ let uid2 = 0;
316405
+ const number4 = (w) => {
316406
+ w.uid = uid2++;
316407
+ w.children.forEach(number4);
316408
+ };
316409
+ number4(root2);
316410
+ const place4 = (w) => {
316411
+ const pend = ctx2.pending.get(w);
316412
+ if (pend) {
316413
+ const seen = /* @__PURE__ */ new Set();
316414
+ const on = [];
316415
+ for (const raw of pend) {
316416
+ const p2 = { ...raw, machine: ctx2.renamed.get(raw.machine) ?? raw.machine, ...raw.hostMachine ? { hostMachine: ctx2.renamed.get(raw.hostMachine) ?? raw.hostMachine } : {} };
316417
+ const trigger = TRIGGERS[p2.ix.trigger];
316418
+ const action3 = trigger ? actionOf(ctx2, p2) : null;
316419
+ if (!trigger || !action3) continue;
316420
+ const ix = { machine: p2.machine, state: p2.state, trigger, ...p2.ix.triggerDelay ? { delay: p2.ix.triggerDelay } : {}, ...p2.ix.triggerKey ? { key: p2.ix.triggerKey } : {}, action: action3 };
316421
+ const sig = JSON.stringify(ix);
316422
+ if (!seen.has(sig)) {
316423
+ seen.add(sig);
316424
+ on.push(ix);
316425
+ }
316426
+ }
316427
+ if (on.length) w.on = on;
316428
+ }
316429
+ w.children.forEach(place4);
316430
+ };
316431
+ place4(root2);
316432
+ return { root: root2, truncated, ...ctx2.rules.size ? { rules: [...ctx2.rules].sort() } : {}, interactive: { machines: ctx2.machines.filter((m) => !ctx2.renamed.has(m.id)), keyframes: [...ctx2.keyframes] } };
316433
+ }
316434
+ var FLOW, interactionsOf, realId, nodeOf, stateName, TRIGGERS, EASINGS2, glideOf2;
316435
+ var init_interactive = __esm({
316436
+ "lib/io/web/interactive.ts"() {
316437
+ "use strict";
316438
+ init_scene_graph();
316439
+ init_tree();
316440
+ init_state_machine2();
316441
+ init_element();
316442
+ FLOW = "flow";
316443
+ interactionsOf = (n) => n?.interactions ?? [];
316444
+ realId = (id3) => id3.includes("::") ? id3.slice(id3.lastIndexOf("::") + 2) : id3;
316445
+ nodeOf = (doc2, id3) => doc2.nodes[id3] ?? (id3.includes("::") ? resolveVirtualNode2(doc2.nodes, id3) ?? void 0 : void 0);
316446
+ stateName = (doc2, id3) => {
316447
+ const n = doc2.nodes[id3];
316448
+ const v = n?.variantProperties;
316449
+ return v ? Object.values(v).join(", ") : n?.name ?? id3;
316450
+ };
316451
+ TRIGGERS = {
316452
+ ON_CLICK: "click",
316453
+ ON_HOVER: "hover",
316454
+ ON_PRESS: "press",
316455
+ ON_DRAG: "drag",
316456
+ MOUSE_ENTER: "enter",
316457
+ MOUSE_LEAVE: "leave",
316458
+ AFTER_TIMEOUT: "timeout",
316459
+ KEY_DOWN: "key"
316460
+ };
316461
+ EASINGS2 = { EASE_IN: "ease-in", EASE_OUT: "ease-out", EASE_IN_OUT: "ease-in-out", LINEAR: "linear", SPRING: "cubic-bezier(0.34, 1.56, 0.64, 1)" };
316462
+ glideOf2 = (t3) => !t3 || t3.type === "INSTANT" || t3.type === "CUT" ? { ms: 0, easing: "linear" } : { ms: Math.max(0, Math.round(t3.duration)), easing: EASINGS2[t3.easing] ?? "ease-in-out" };
316463
+ }
316464
+ });
316465
+
316466
+ // lib/io/web/tree.ts
316467
+ var tree_exports = {};
316468
+ __export(tree_exports, {
316469
+ DEFAULT_NODE_CAP: () => DEFAULT_NODE_CAP,
316470
+ EXPORT_NODE_CAP: () => EXPORT_NODE_CAP,
316471
+ buildPlainTree: () => buildPlainTree,
316472
+ buildWebTree: () => buildWebTree,
316473
+ flatten: () => flatten2,
316474
+ foldRules: () => foldRules,
316475
+ foldVar: () => foldVar,
316476
+ prepared: () => prepared
316477
+ });
316478
+ function anchorTargets(doc2) {
316479
+ const hit = anchorMemo.get(doc2.nodes);
316480
+ if (hit) return hit;
316481
+ const out = /* @__PURE__ */ new Set();
316482
+ for (const id3 in doc2.nodes) {
316483
+ const n = doc2.nodes[id3];
316484
+ if (n.semantics?.link?.kind === "anchor") out.add(n.semantics.link.nodeId);
316485
+ for (const ix of n.interactions ?? []) if (ix.action.link?.kind === "anchor" && ix.action.link.nodeId) out.add(ix.action.link.nodeId);
316486
+ }
316487
+ anchorMemo.set(doc2.nodes, out);
316488
+ return out;
316489
+ }
316490
+ function spriteOnly(nodes, id3) {
316491
+ let leaves = 0;
316492
+ const visit2 = (nid, depth2) => {
316493
+ const n = nodes[nid];
316494
+ if (!n || n.visible === false) return true;
316495
+ if (n.type === "PIXEL_GRID") {
316496
+ leaves++;
316497
+ return true;
316498
+ }
316499
+ if (depth2 > 8 || n.type !== "INSTANCE" && n.type !== "COMPONENT" && n.type !== "FRAME" && n.type !== "GROUP") return false;
316500
+ const main2 = n.mainComponentId;
316501
+ const kids = n.childIds?.length ? n.childIds : main2 ? [main2] : [];
316502
+ return kids.every((k2) => visit2(k2, depth2 + 1));
316503
+ };
316504
+ return visit2(id3, 0) && leaves > 0;
316505
+ }
316506
+ function prepared(node2, doc2) {
316507
+ let n = node2;
316508
+ if (n.id.includes("::")) n = withInstanceBox(n, doc2.nodes);
316509
+ n = resolveNodeVariables(n, doc2.variables, doc2.variableCollections, doc2.activeVariableModes, exprData(doc2));
316510
+ n = resolveTextNodeStyles(n, doc2.styles ?? {});
316511
+ return n;
316512
+ }
316513
+ function layoutOf2(node2, nodes) {
316514
+ if (!node2) return null;
316515
+ if (node2.type === "INSTANCE") {
316516
+ const mainId = node2.mainComponentId;
316517
+ const main2 = mainId ? nodes[mainId] : void 0;
316518
+ return main2 ?? null;
316519
+ }
316520
+ if (node2.id.includes("::")) {
316521
+ const real = nodes[node2.id.split("::").pop()];
316522
+ return real ?? node2;
316523
+ }
316524
+ return node2;
316525
+ }
316526
+ function buildPlainTree(doc2, nodeId2, opts = {}, start2, hooks = {}) {
316527
+ const cap2 = opts.nodeCap ?? DEFAULT_NODE_CAP;
316528
+ const first2 = doc2.nodes[nodeId2] ?? (nodeId2.includes("::") ? childLookup(doc2, nodeId2) : void 0);
316529
+ if (!first2) throw new Error(`No node ${nodeId2}`);
316530
+ let emitted = 0;
316531
+ let truncated = false;
316532
+ let folds = 0;
316533
+ const tokens = opts.target === "site" && Object.keys(doc2.variables ?? {}).length ? siteTokens(doc2) : null;
316534
+ const anchored = anchorTargets(doc2);
316535
+ const pageItem = () => {
316536
+ const c2 = opts.item && doc2.collections?.[opts.item.collectionId];
316537
+ if (c2 && opts.item.recordId === ITEM_RECORD) return { collection: c2, record: templateRecord(c2), suffix: `~${ITEM_RECORD}` };
316538
+ const r = opts.item && doc2.records?.[opts.item.recordId];
316539
+ return c2 && r ? { collection: c2, record: r, suffix: "" } : null;
316540
+ };
316541
+ let item = pageItem();
316542
+ const scopeOf2 = (it) => itemScope(it.collection, it.record, withData(variablesScope(doc2.variables, doc2.variableCollections, doc2.activeVariableModes), doc2));
316543
+ const itemised = (node2, raw, it) => itemNode(node2, raw, it.collection, it.record, scopeOf2(it));
316544
+ const itemLink = (link2, it) => {
316545
+ const filled2 = it && link2.kind === "url" ? { ...link2, url: itemText(link2.url, it.collection, it.record) } : it && (link2.kind === "email" || link2.kind === "tel") ? { ...link2, value: itemText(link2.value, it.collection, it.record) } : link2;
316546
+ if (filled2.kind === "screen") {
316547
+ const dest = doc2.nodes[filled2.frameId];
316548
+ const base = opts.routes?.[filled2.frameId];
316549
+ const of = dest?.route?.collectionId;
316550
+ if (of && base !== void 0) {
316551
+ const slugField = it?.record.id === ITEM_RECORD && it.collection.id === of ? it.collection.fields.find((f2) => f2.id === it.collection.slugFieldId) ?? it.collection.fields.find((f2) => f2.type === "SLUG" || f2.type === "TEXT") : void 0;
316552
+ if (slugField) return { link: filled2, href: `${base === "/" ? "" : base}/${itemMark(fieldKey(slugField.name))}`, screen: filled2.frameId };
316553
+ const slugs = recordSlugs(doc2, of);
316554
+ const rec = it?.collection.id === of ? it.record.id : slugs.keys().next().value;
316555
+ const slug3 = rec ? slugs.get(rec) : void 0;
316556
+ return slug3 ? { link: filled2, href: `${base === "/" ? "" : base}/${slug3}`, screen: `${filled2.frameId}~${rec}` } : { link: filled2, href: null };
316557
+ }
316558
+ return { link: filled2, href: base ?? null, screen: filled2.frameId };
316559
+ }
316560
+ if (filled2.kind === "url" && it?.record.id === ITEM_RECORD && itemMarks(filled2.url)) return { link: filled2, href: filled2.url.trim() };
316561
+ return { link: filled2, href: hrefOf(filled2, doc2.nodes, opts.routes) };
316562
+ };
316563
+ const fields = /* @__PURE__ */ new Map();
316564
+ const styleOpts = { fullImageUrl: opts.fullImageUrls ?? opts.target === "site" };
316565
+ const stylesOf = (n) => styleMapFor(n, doc2.styles, styleOpts);
316566
+ let motion = null;
316567
+ const timeline = !opts.static && !start2 && first2.type === "FRAME" ? frameWebMotion(doc2, first2.id, (n) => stylesOf(prepared(n, doc2))) : null;
316568
+ const build3 = (raw, parent, in3D2, fold) => {
316569
+ if (emitted >= cap2) {
316570
+ truncated = true;
316571
+ return null;
316572
+ }
316573
+ emitted++;
316574
+ const node2 = item ? itemised(prepared(raw, doc2), raw, item) : prepared(raw, doc2);
316575
+ const waits = node2.visible === false && parent !== null;
316576
+ if (waits && !(opts.target === "site" && followsVisibility(raw))) return null;
316577
+ const exp = expressibility(node2, doc2.styles);
316578
+ const f2 = layoutOf2(node2, doc2.nodes) ?? node2;
316579
+ const style = stylesOf(node2);
316580
+ if (f2 !== node2 && !style.display) Object.assign(style, flexDeclarations(f2));
316581
+ const through = in3D2 && passesThrough(raw, doc2.nodes);
316582
+ const own2 = typeof node2.opacity === "number" ? node2.opacity : 1;
316583
+ if (through) {
316584
+ style["transform-style"] = "preserve-3d";
316585
+ delete style.opacity;
316586
+ style[foldVar(fold + 1)] = fold ? `calc(var(${foldVar(fold)}) * ${round3(own2)})` : String(round3(own2));
316587
+ folds = Math.max(folds, fold + 1);
316588
+ } else if (fold) style.opacity = own2 === 1 ? `var(${foldVar(fold)})` : `calc(var(${foldVar(fold)}) * ${round3(own2)})`;
316589
+ if (own2 === 0) style["pointer-events"] = "none";
316590
+ if (clickable(raw) && !style.cursor) style.cursor = "pointer";
316591
+ const web = {
316592
+ id: item?.suffix ? `${node2.id}${item.suffix}` : node2.id,
316593
+ name: node2.name || node2.type,
316594
+ type: node2.type,
316595
+ x: Math.round(node2.x),
316596
+ y: Math.round(node2.y),
316597
+ width: Math.round(node2.width),
316598
+ height: Math.round(node2.height),
316599
+ // Absolutely-positioned auto-layout children are taken out of the flow, exactly as the canvas does.
316600
+ // A grid's children are in its flow too: its tracks place them.
316601
+ positioning: (isFlex(layoutOf2(parent, doc2.nodes)) || layoutOf2(parent, doc2.nodes)?.layoutMode === "GRID") && node2.layoutPositioning !== "ABSOLUTE" ? "flow" : "absolute",
316602
+ style,
316603
+ children: []
316604
+ };
316605
+ if (tokens) Object.assign(style, tokenStyle(raw, style, tokens));
316606
+ if (opts.target === "site") {
316607
+ const lay = siteLayout(node2, parent, layoutOf2(parent, doc2.nodes));
316608
+ for (const [k2, v] of Object.entries(lay.style)) {
316609
+ if (v === null) delete style[k2];
316610
+ else style[k2] = v;
316611
+ }
316612
+ if (laysOut(f2) || f2.overflowScrolling) Object.assign(style, containerStyle(f2));
316613
+ if (node2.type === "TEXT") {
316614
+ if (style["white-space"] === "pre") {
316615
+ style["white-space"] = "pre-wrap";
316616
+ style.width = "fit-content";
316617
+ }
316618
+ if (style["max-width"] === void 0) style["max-width"] = "100%";
316619
+ if (style.height && style.height !== "auto") {
316620
+ style["min-height"] = style.height;
316621
+ delete style.height;
316622
+ }
316623
+ }
316624
+ if (lay.place && (parent !== null || !start2?.parent)) web.place = lay.place;
316625
+ }
316626
+ if (waits) web.hidden = true;
316627
+ const sem = node2.semantics;
316628
+ if (sem) {
316629
+ if (sem.tag && sem.tag !== "div") web.tag = sem.tag;
316630
+ const attrs = {};
316631
+ if (sem.label) attrs["aria-label"] = sem.label;
316632
+ if (sem.hidden) attrs["aria-hidden"] = "true";
316633
+ if (Object.keys(attrs).length) web.attrs = attrs;
316634
+ const to = sem.link ? itemLink(sem.link, item) : null;
316635
+ if (to?.href) web.link = { href: to.href, ...opensNewTab(to.link) ? { newTab: true } : {}, ...to.screen ? { screen: to.screen } : {} };
316636
+ }
316637
+ const control = node2.control;
316638
+ if (control) {
316639
+ const named = control.name ? { name: control.name } : {};
316640
+ if (control.kind === "FORM") {
316641
+ web.tag = "form";
316642
+ if (isCommerceAction(control.formAction)) web.action = control.formAction;
316643
+ } else if (control.kind === "BUTTON") {
316644
+ web.tag = "button";
316645
+ web.attrs = { ...web.attrs, type: control.buttonType ?? "submit", ...named, ...control.name && control.value !== void 0 ? { value: item && hasItemToken(control.value) ? itemText(control.value, item.collection, item.record) : control.value } : {} };
316646
+ } else if (control.kind === "CHECKBOX" || control.kind === "RADIO") {
316647
+ web.check = { attrs: { type: control.kind === "RADIO" ? "radio" : "checkbox", ...named, ...control.value !== void 0 ? { value: control.value } : {}, ...control.checked ? { checked: "" } : {}, ...control.required ? { required: "" } : {} }, ...control.variableId ? { variable: control.variableId } : {} };
316648
+ } else fields.set(fieldPart(doc2.nodes, raw.id) ?? raw.id, control);
316649
+ }
316650
+ const control0 = fields.get(raw.id);
316651
+ const field = control0 && item && control0.value !== void 0 && hasItemToken(control0.value) ? { ...control0, value: itemText(control0.value, item.collection, item.record) } : control0;
316652
+ if (field) {
316653
+ const tag = field.kind === "TEXTAREA" ? "textarea" : field.kind === "SELECT" ? "select" : "input";
316654
+ const words = node2.characters;
316655
+ web.input = {
316656
+ tag,
316657
+ attrs: {
316658
+ ...tag === "input" ? { type: field.inputType ?? "text" } : {},
316659
+ ...field.name ? { name: field.name } : {},
316660
+ ...tag !== "select" && (field.placeholder ?? words) ? { placeholder: field.placeholder ?? words } : {},
316661
+ ...field.required ? { required: "" } : {},
316662
+ ...tag === "input" && field.value !== void 0 ? { value: field.value } : {},
316663
+ "aria-label": node2.semantics?.label ?? field.placeholder ?? field.name ?? web.name
316664
+ },
316665
+ ...tag === "select" ? { options: field.options ?? [] } : {},
316666
+ ...tag !== "input" && field.value !== void 0 ? { value: field.value } : {},
316667
+ ...field.variableId ? { variable: field.variableId } : {}
316668
+ };
316669
+ }
316670
+ if (sem?.anchor || anchored.has(node2.id)) web.attrs = { ...web.attrs, id: anchorOf(node2) };
316671
+ if (through) web.preserve3d = true;
316672
+ web.tf = transformParts(node2);
316673
+ if (typeof node2.altText === "string") web.alt = node2.altText;
316674
+ if (parent === null) web.positioning = start2?.parent ? web.positioning : "flow";
316675
+ if (f2.layoutMode === "HORIZONTAL" || f2.layoutMode === "VERTICAL") {
316676
+ web.layout = {
316677
+ direction: f2.layoutMode === "HORIZONTAL" ? "row" : "column",
316678
+ gap: f2.itemSpacing ?? 0,
316679
+ justify: JUSTIFY[f2.primaryAxisAlignItems ?? "MIN"],
316680
+ align: ALIGN2[f2.counterAxisAlignItems ?? "MIN"],
316681
+ padding: f2.padding ?? { top: 0, right: 0, bottom: 0, left: 0 }
316682
+ };
316683
+ }
316684
+ if (node2.type === "TEXT") {
316685
+ const t3 = node2;
316686
+ const solid5 = (t3.fills ?? []).find((p2) => p2.visible !== false && p2.type === "SOLID" && p2.color);
316687
+ web.text = {
316688
+ characters: t3.characters ?? "",
316689
+ align: t3.textAlign,
316690
+ fontFamily: t3.fontFamily,
316691
+ fontSize: t3.fontSize,
316692
+ fontWeight: t3.fontWeight,
316693
+ italic: t3.fontStyle === "italic",
316694
+ ...solid5?.color ? { color: toHex(solid5.color) } : {},
316695
+ ...t3.letterSpacing ? { letterSpacing: t3.letterSpacing } : {},
316696
+ ...t3.lineHeight !== "AUTO" ? { lineHeight: t3.lineHeight } : {}
316697
+ };
316698
+ const runs = textRuns(t3);
316699
+ if (runs) web.runs = runs;
316700
+ }
316701
+ const tl = timeline?.get(node2.id);
316702
+ const mo = tl ?? motion?.children.get(node2.id);
316703
+ if (mo) web.motion = { style: animationStyle(mo, tl ? "load" : motion.trigger), keyframes: keyframesCSS(mo) };
316704
+ const ext = getNativeExtension(raw.type);
316705
+ if (ext?.toWeb) {
316706
+ const said = ext.toWeb(node2, { escape: escapeHTML, color: (c2) => toRgba({ ...c2, a: c2.a ?? 1 }) });
316707
+ if (said.tag) web.tag = said.tag;
316708
+ Object.assign(style, said.style);
316709
+ web.html = said.html;
316710
+ hooks.built?.(web, node2, { parent, in3D: in3D2, fold });
316711
+ return web;
316712
+ }
316713
+ const code = opts.target === "site" ? codeOf(doc2.nodes, raw) : null;
316714
+ if (code && doc2.codeModules?.[code.moduleId]) {
316715
+ for (const k2 of PAINTED) delete style[k2];
316716
+ web.code = { module: code.moduleId, ...code.exportName ? { export: code.exportName } : {}, props: codeProps(doc2.nodes, node2) };
316717
+ hooks.built?.(web, node2, { parent, in3D: in3D2, fold });
316718
+ return web;
316719
+ }
316720
+ const sprite = opts.target === "site" && raw.type === "INSTANCE" && !raw.id.includes("::") && spriteOnly(doc2.nodes, raw.id) && isLive(doc2.nodes, raw.id);
316721
+ if (!exp.css || sprite) {
316722
+ for (const k2 of PAINTED) delete style[k2];
316723
+ web.asset = { kind: opts.assetKind ?? (exp.needsRaster ? "png" : "svg"), reason: exp.reason || (sprite ? "an animated sprite" : ""), ...item?.suffix ? { of: node2.id } : {} };
316724
+ if (isPixelArt(doc2, raw.id)) style["image-rendering"] = "pixelated";
316725
+ if (sprite || opts.target === "site" && renderMode(node2, { styles: doc2.styles, live: isLive(doc2.nodes, raw.id) }) === "island") web.island = true;
316726
+ hooks.built?.(web, node2, { parent, in3D: in3D2, fold });
316727
+ return web;
316728
+ }
316729
+ const lost = capability(node2, "css", doc2.styles).dropped.find((f3) => f3.startsWith("paint:"));
316730
+ if (lost && !node2.id.includes("::")) {
316731
+ const site = opts.target === "site";
316732
+ style.isolation = "isolate";
316733
+ web.children.push({
316734
+ id: `${node2.id}/backdrop${item?.suffix ?? ""}`,
316735
+ name: `${web.name} fill`,
316736
+ type: "BACKDROP",
316737
+ x: 0,
316738
+ y: 0,
316739
+ width: web.width,
316740
+ height: web.height,
316741
+ positioning: "absolute",
316742
+ ...site ? { place: { position: "absolute", inset: "0" } } : {},
316743
+ style: { ...site ? {} : { width: `${web.width}px`, height: `${web.height}px` }, "border-radius": "inherit", overflow: "hidden", "z-index": "-1", "pointer-events": "none" },
316744
+ alt: "",
316745
+ asset: { kind: "png", reason: featureName(lost), of: node2.id, self: true },
316746
+ ...site && movesItself(raw) ? { island: true } : {},
316747
+ children: []
316748
+ });
316749
+ }
316750
+ const outer = motion;
316751
+ if (!motion && node2.type === "INSTANCE" && !opts.static) {
316752
+ motion = instanceWebMotion(doc2, node2, (n) => stylesOf(prepared(n, doc2)));
316753
+ if (motion && (motion.trigger !== "load" || opts.target === "site")) web.motionTrigger = motion.trigger;
316754
+ }
316755
+ try {
316756
+ if (opts.includeChildren !== false) {
316757
+ const kids3D = in3D2 ? through : is3DContext(raw) && !raw.id.includes("::");
316758
+ const kidFold = through ? fold + 1 : 0;
316759
+ const repeat = raw.repeat;
316760
+ const collection = repeat && doc2.collections?.[repeat.collectionId];
316761
+ if (repeat && collection && opts.target === "site") {
316762
+ const outerItem = item;
316763
+ const under = outerItem ? scopeOf2(outerItem) : withData(variablesScope(doc2.variables, doc2.variableCollections, doc2.activeVariableModes), doc2);
316764
+ try {
316765
+ for (const record2 of repeatRecords(doc2, repeat, under)) {
316766
+ item = { collection, record: record2, suffix: `${outerItem?.suffix ?? ""}~${record2.id}` };
316767
+ for (const child of childrenOf(node2, doc2.nodes)) {
316768
+ const built = build3(child, node2, kids3D, kidFold);
316769
+ if (built) web.children.push(built);
316770
+ }
316771
+ }
316772
+ if (collection.perVisitor && !outerItem || collection.schema && opts.listTemplates) {
316773
+ item = { collection, record: templateRecord(collection), suffix: `~${ITEM_RECORD}` };
316774
+ const template2 = [];
316775
+ for (const child of childrenOf(node2, doc2.nodes)) {
316776
+ const built = build3(child, node2, kids3D, kidFold);
316777
+ if (built) template2.push(built);
316778
+ }
316779
+ const sortField = repeat.sort && collection.fields.find((f3) => f3.id === repeat.sort.fieldId);
316780
+ web.repeat = {
316781
+ collectionId: collection.id,
316782
+ template: template2,
316783
+ ...repeat.filter?.trim() ? { filter: repeat.filter } : {},
316784
+ ...sortField ? { sort: { key: fieldKey(sortField.name), dir: repeat.sort.dir } } : {},
316785
+ ...repeat.offset ? { offset: repeat.offset } : {},
316786
+ ...repeat.limit ? { limit: repeat.limit } : {}
316787
+ };
316788
+ }
316789
+ } finally {
316790
+ item = outerItem;
316791
+ }
316792
+ } else for (const child of childrenOf(node2, doc2.nodes)) {
316793
+ const built = build3(child, node2, kids3D, kidFold);
316794
+ if (built) web.children.push(built);
316795
+ }
316796
+ }
316797
+ } finally {
316798
+ motion = outer;
316799
+ }
316800
+ if (web.children.some((c2) => c2.positioning === "absolute")) {
316801
+ for (const c2 of web.children) if (c2.positioning === "flow") c2.layered = true;
316802
+ }
316803
+ hooks.built?.(web, node2, { parent, in3D: in3D2, fold });
316804
+ return web;
316805
+ };
316806
+ const root2 = build3(first2, start2?.parent ?? null, start2?.in3D ?? false, start2?.fold ?? 0);
316807
+ if (!root2) throw new Error("Node cap of 0");
316808
+ return { root: root2, truncated, ...folds ? { rules: foldRules(folds) } : {}, ...tokens?.vars.length ? { tokens } : {} };
316809
+ }
316810
+ function childLookup(doc2, id3) {
316811
+ const at3 = id3.lastIndexOf("::");
316812
+ const host = at3 > 0 ? id3.slice(0, at3) : "";
316813
+ const hostNode = doc2.nodes[host] ?? (host.includes("::") ? childLookup(doc2, host) : void 0);
316814
+ return hostNode ? childrenOf(hostNode, doc2.nodes).find((c2) => c2.id === id3) : void 0;
316815
+ }
316816
+ function flatten2(node2, out = []) {
316817
+ out.push(node2);
316818
+ for (const c2 of node2.children) flatten2(c2, out);
316819
+ return out;
316820
+ }
316821
+ var DEFAULT_NODE_CAP, EXPORT_NODE_CAP, PAINTED, anchorMemo, followsVisibility, isFlex, round3, foldVar, foldRules, clickable;
316822
+ var init_tree = __esm({
316823
+ "lib/io/web/tree.ts"() {
316824
+ "use strict";
316825
+ init_pixel_art();
316826
+ init_instance_layout();
316827
+ init_text_styles();
316828
+ init_variables();
316829
+ init_scene3d();
316830
+ init_semantics();
316831
+ init_commerce();
316832
+ init_collections();
316833
+ init_props();
316834
+ init_native_registry();
316835
+ init_controls();
316836
+ init_expressions2();
316837
+ init_children();
316838
+ init_css();
316839
+ init_capability();
316840
+ init_expressible();
316841
+ init_motion();
316842
+ init_element();
316843
+ init_paint2();
316844
+ init_responsive();
316845
+ init_richtext();
316846
+ init_tokens2();
316847
+ init_timeline();
316848
+ init_interactive();
316849
+ DEFAULT_NODE_CAP = 120;
316850
+ EXPORT_NODE_CAP = 2e4;
316851
+ PAINTED = ["background", "border", "border-style", "border-color", "border-width", "outline", "border-radius", "box-shadow", "box-sizing", "filter", "backdrop-filter"];
316852
+ anchorMemo = /* @__PURE__ */ new WeakMap();
316853
+ followsVisibility = (n) => !!n.boundVariables?.visible || !!n.boundExpressions?.visible || // Hidden in the design and shown at a breakpoint: on the page, for the media query that shows it.
316854
+ Object.values(n.responsive ?? {}).some((o) => o.visible === true) || // A game's win banner (LayerPhysics role 'win') and a player's run and jump poses: hidden in the design, shown by
316855
+ // the platformer on winning or as the player moves.
316856
+ n.physics?.role === "win" || n.physics?.role === "pose" || n.physics?.role === "reveal";
316857
+ isFlex = (f2) => f2?.layoutMode === "HORIZONTAL" || f2?.layoutMode === "VERTICAL";
316858
+ round3 = (v) => Math.round(v * 1e3) / 1e3;
316859
+ foldVar = (depth2) => `--pc-f${depth2}`;
316860
+ foldRules = (depth2) => Array.from({ length: depth2 }, (_, i2) => `@property ${foldVar(i2 + 1)} { syntax: '<number>'; inherits: true; initial-value: 1; }`);
316861
+ clickable = (n) => !!n.semantics?.link || (n.interactions ?? []).some((ix) => ix.trigger === "ON_CLICK" || ix.trigger === "ON_PRESS");
316862
+ }
316863
+ });
316864
+
315224
316865
  // lib/io/zip-export.ts
315225
316866
  var zip_export_exports = {};
315226
316867
  __export(zip_export_exports, {
@@ -316232,7 +317873,7 @@ function stateMachineFromDotLottie(input2, id3 = "sm1", name2 = "State machine")
316232
317873
  };
316233
317874
  }
316234
317875
  var INPUT_TYPES2, CONDITIONS, INTERACTIONS, invert2, isObj6, isValue2, DOT_INPUT_TYPES, DOT_CONDITIONS, DOT_INTERACTIONS;
316235
- var init_state_machine2 = __esm({
317876
+ var init_state_machine3 = __esm({
316236
317877
  "lib/io/lottie/state-machine.ts"() {
316237
317878
  "use strict";
316238
317879
  init_state_machine();
@@ -316439,7 +318080,7 @@ var init_build = __esm({
316439
318080
  init_channels();
316440
318081
  init_ease();
316441
318082
  init_shapes();
316442
- init_state_machine2();
318083
+ init_state_machine3();
316443
318084
  BLEND2 = {
316444
318085
  NORMAL: 0,
316445
318086
  MULTIPLY: 1,
@@ -317313,7 +318954,7 @@ var init_lottie = __esm({
317313
318954
  init_scene_graph();
317314
318955
  init_png();
317315
318956
  init_build();
317316
- init_state_machine2();
318957
+ init_state_machine3();
317317
318958
  init_build();
317318
318959
  init_support();
317319
318960
  RASTER_SCALE = 2;
@@ -317458,112 +319099,6 @@ var init_data = __esm({
317458
319099
  }
317459
319100
  });
317460
319101
 
317461
- // lib/io/web/element.ts
317462
- function placementStyle(node2, isRoot) {
317463
- if (node2.place) return { ...node2.place, ...node2.place.position ? {} : node2.layered || node2.children.some((c2) => c2.positioning === "absolute") ? { position: "relative" } : {} };
317464
- const out = {};
317465
- if (node2.positioning === "absolute" && !isRoot) {
317466
- out.position = "absolute";
317467
- out.left = `${node2.x}px`;
317468
- out.top = `${node2.y}px`;
317469
- } else if (node2.layered || node2.children.some((c2) => c2.positioning === "absolute") || isRoot) {
317470
- out.position = "relative";
317471
- }
317472
- return out;
317473
- }
317474
- function imageRole(node2) {
317475
- if (node2.asset || node2.text) return null;
317476
- if (node2.type !== "IMAGE" && node2.alt === void 0) return null;
317477
- return roleOf(node2);
317478
- }
317479
- function pictureOf(node2) {
317480
- const a = node2.asset;
317481
- if (!a) return null;
317482
- if (a.src) return { kind: "img", src: a.src };
317483
- if (a.svg) return { kind: "svg", svg: a.svg };
317484
- if (a.pngDataUrl) return { kind: "img", src: a.pngDataUrl };
317485
- return { kind: "missing", reason: a.reason, format: a.kind };
317486
- }
317487
- function elementOf(node2, ctx2) {
317488
- const motion = ctx2.still ? void 0 : node2.motion;
317489
- const spec = ctx2.spec ?? null;
317490
- const tag = node2.input ? node2.input.tag : node2.link ? "a" : node2.tag ?? (node2.text ? "p" : "div");
317491
- const attrs = { ...node2.attrs };
317492
- if (node2.input) Object.assign(attrs, node2.input.attrs);
317493
- if (node2.link && !node2.input) {
317494
- attrs.href = node2.link.href;
317495
- if (node2.link.newTab) {
317496
- attrs.target = "_blank";
317497
- attrs.rel = "noopener noreferrer";
317498
- }
317499
- }
317500
- return {
317501
- tag,
317502
- attrs,
317503
- // A tag's own look (a button's border, a link's underline, a list's bullets) is not the layer's: under its declarations.
317504
- style: { ...node2.link || node2.tag || node2.input ? TAG_RESET[tag] : void 0, ...placementStyle(node2, ctx2.isRoot), ...node2.style, ...motion ? motion.style : {}, ...hiddenAtStart(spec, node2) ? HIDDEN_AT_START : {} },
317505
- // A field's words are its placeholder (an attribute), not its content.
317506
- ...node2.text && !node2.input ? { text: node2.text.characters } : {},
317507
- ...node2.text && node2.runs && !node2.input ? { runs: node2.runs } : {},
317508
- ...node2.input ? { input: node2.input } : {},
317509
- ...node2.html !== void 0 ? { html: node2.html } : {},
317510
- ...node2.check ? { check: node2.check } : {},
317511
- picture: pictureOf(node2),
317512
- role: imageRole(node2),
317513
- ...motion ? { keyframes: motion.keyframes } : {},
317514
- ...node2.motionTrigger ? { motionTrigger: node2.motionTrigger } : {},
317515
- ...spec && node2.uid !== void 0 ? { pc: { uid: node2.uid, layer: node2.name } } : {},
317516
- ...ctx2.listened?.has(node2.id) ? { sm: node2.id } : {}
317517
- };
317518
- }
317519
- var escapeHTML, altFor, roleOf, roleAttrs, labelSVG, imageRoleAttrs, hiddenAtStart, HIDDEN_AT_START, FIELD, HEADING, TAG_RESET, MOTION_PLAY_RULE, CHECK_STYLE;
317520
- var init_element = __esm({
317521
- "lib/io/web/element.ts"() {
317522
- "use strict";
317523
- escapeHTML = (s) => s.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;");
317524
- altFor = (node2) => node2.alt ?? node2.name;
317525
- roleOf = (node2) => {
317526
- const alt = altFor(node2);
317527
- return alt === "" ? { hidden: true } : { label: alt };
317528
- };
317529
- roleAttrs = (role) => "hidden" in role ? ' aria-hidden="true"' : ` role="img" aria-label="${escapeHTML(role.label)}"`;
317530
- labelSVG = (svg, node2) => svg.replace(/^<svg\b/, `<svg${roleAttrs(roleOf(node2))}`);
317531
- imageRoleAttrs = (node2) => {
317532
- const role = imageRole(node2);
317533
- return role ? roleAttrs(role) : "";
317534
- };
317535
- hiddenAtStart = (spec, node2) => {
317536
- const e = spec && node2.uid !== void 0 ? spec.e[node2.uid] : void 0;
317537
- return !!e && e[1][spec.m[e[0]]] === -1;
317538
- };
317539
- HIDDEN_AT_START = { opacity: "0", visibility: "hidden", "pointer-events": "none", position: "absolute" };
317540
- FIELD = { display: "block", border: "0", padding: "0", margin: "0", background: "none", outline: "none", font: "inherit", color: "inherit", "min-width": "0" };
317541
- HEADING = { margin: "0", "font-size": "inherit", "font-weight": "inherit" };
317542
- TAG_RESET = {
317543
- a: { display: "block", color: "inherit", "text-decoration": "none" },
317544
- button: { display: "block", border: "0", padding: "0", background: "none", font: "inherit", color: "inherit", "text-align": "inherit", cursor: "pointer" },
317545
- ul: { "list-style": "none", margin: "0", padding: "0" },
317546
- ol: { "list-style": "none", margin: "0", padding: "0" },
317547
- h1: HEADING,
317548
- h2: HEADING,
317549
- h3: HEADING,
317550
- h4: HEADING,
317551
- h5: HEADING,
317552
- h6: HEADING,
317553
- p: { margin: "0" },
317554
- figure: { margin: "0" },
317555
- span: { display: "block" },
317556
- label: { display: "block" },
317557
- form: { margin: "0" },
317558
- input: FIELD,
317559
- textarea: { ...FIELD, resize: "none" },
317560
- select: { ...FIELD, appearance: "none" }
317561
- };
317562
- MOTION_PLAY_RULE = "[data-motion-play] [data-motion-child] { animation-play-state: running; }";
317563
- CHECK_STYLE = "position:absolute;inset:0;width:100%;height:100%;margin:0;opacity:0;cursor:pointer";
317564
- }
317565
- });
317566
-
317567
319102
  // lib/io/web/fonts.ts
317568
319103
  function fontFamilies(tree) {
317569
319104
  const families = /* @__PURE__ */ new Map();
@@ -317586,392 +319121,6 @@ var init_fonts3 = __esm({
317586
319121
  }
317587
319122
  });
317588
319123
 
317589
- // lib/io/web/paint.ts
317590
- function toRgba(c2, a) {
317591
- const alpha2 = a !== void 0 ? a : c2.a;
317592
- const [r, g, b] = [c2.r, c2.g, c2.b].map((v) => Math.round(v * 255));
317593
- return alpha2 < 1 ? `rgba(${r}, ${g}, ${b}, ${Math.round(alpha2 * 100) / 100})` : `rgb(${r}, ${g}, ${b})`;
317594
- }
317595
- function gradientAngleDeg(paint) {
317596
- const h = paint.gradientHandlePositions;
317597
- const p0 = h?.[0] ?? { x: 0, y: 0.5 };
317598
- const p1 = h?.[1] ?? { x: 1, y: 0.5 };
317599
- return Math.round(Math.atan2(p1.x - p0.x, -(p1.y - p0.y)) * 180 / Math.PI);
317600
- }
317601
- function paintToBackground(paint, opts = {}) {
317602
- if (paint.type === "SOLID" && paint.color) {
317603
- const alpha2 = (paint.opacity ?? 1) * paint.color.a;
317604
- return alpha2 < 1 ? toRgba(paint.color, alpha2) : toHex(paint.color);
317605
- }
317606
- if (paint.type === "GRADIENT_LINEAR") return `linear-gradient(${gradientAngleDeg(paint)}deg, ${gradientStopsCSS(paint)})`;
317607
- if (paint.type === "GRADIENT_RADIAL") return `radial-gradient(circle, ${gradientStopsCSS(paint)})`;
317608
- if (paint.type === "GRADIENT_ANGULAR") return `conic-gradient(${gradientStopsCSS(paint)})`;
317609
- if (paint.type === "GRADIENT_DIAMOND") return `radial-gradient(closest-side, ${gradientStopsCSS(paint)})`;
317610
- if (paint.type === "IMAGE") {
317611
- const src = paint.imageUrl || paint.imageHash;
317612
- if (!src) return null;
317613
- return `url('${opts.fullImageUrl || src.length <= 64 ? src : src.slice(0, 64)}') ${IMAGE_FIT[paint.scaleMode ?? "FILL"]}`;
317614
- }
317615
- return null;
317616
- }
317617
- function parseCssColor(css) {
317618
- if (!css) return null;
317619
- const hex10 = /^#([0-9a-f]{6})$/i.exec(css.trim());
317620
- if (hex10) {
317621
- const n = parseInt(hex10[1], 16);
317622
- return { r: (n >> 16 & 255) / 255, g: (n >> 8 & 255) / 255, b: (n & 255) / 255, a: 1 };
317623
- }
317624
- const rgb = /^rgba?\(([^)]+)\)$/i.exec(css.trim());
317625
- if (!rgb) return null;
317626
- const parts = rgb[1].split(",").map((v) => Number(v.trim()));
317627
- if (parts.length < 3 || parts.some((v) => Number.isNaN(v))) return null;
317628
- return { r: parts[0] / 255, g: parts[1] / 255, b: parts[2] / 255, a: parts[3] ?? 1 };
317629
- }
317630
- var hex23, toHex, gradientStopsCSS, IMAGE_FIT, swiftColor, composeColor;
317631
- var init_paint2 = __esm({
317632
- "lib/io/web/paint.ts"() {
317633
- "use strict";
317634
- hex23 = (v) => Math.round(v * 255).toString(16).padStart(2, "0");
317635
- toHex = (c2) => `#${hex23(c2.r)}${hex23(c2.g)}${hex23(c2.b)}`.toUpperCase();
317636
- gradientStopsCSS = (paint) => (paint.gradientStops ?? []).map((s) => `${toRgba(s.color)} ${Math.round((s.position ?? 0) * 100)}%`).join(", ");
317637
- IMAGE_FIT = {
317638
- FILL: "center / cover no-repeat",
317639
- CROP: "center / cover no-repeat",
317640
- FIT: "center / contain no-repeat",
317641
- TILE: "top left / auto repeat"
317642
- };
317643
- swiftColor = (c2) => {
317644
- const n = (v) => Math.round(v * 1e3) / 1e3;
317645
- return `Color(red: ${n(c2.r)}, green: ${n(c2.g)}, blue: ${n(c2.b)}${(c2.a ?? 1) < 1 ? `, opacity: ${Math.round((c2.a ?? 1) * 100) / 100}` : ""})`;
317646
- };
317647
- composeColor = (c2) => `Color(0x${[c2.a ?? 1, c2.r, c2.g, c2.b].map((v) => Math.round(v * 255).toString(16).padStart(2, "0")).join("").toUpperCase()})`;
317648
- }
317649
- });
317650
-
317651
- // lib/io/web/css.ts
317652
- function stylePaints(styleId, styles) {
317653
- const s = styleId ? styles?.[styleId] : void 0;
317654
- return s?.type === "PAINT" ? s.paints ?? [] : null;
317655
- }
317656
- function transformParts(node2, dx = 0, dy = 0) {
317657
- return [
317658
- dx + restValue(node2, "translateX"),
317659
- dy + restValue(node2, "translateY"),
317660
- restValue(node2, "z"),
317661
- node2.rotation || 0,
317662
- restValue(node2, "rotateY"),
317663
- restValue(node2, "rotateX"),
317664
- restValue(node2, "scaleX") * (node2.flipHorizontal ? -1 : 1),
317665
- restValue(node2, "scaleY") * (node2.flipVertical ? -1 : 1)
317666
- ];
317667
- }
317668
- function transformFromParts(p2, orbit) {
317669
- const [tx2, ty, z2, r, ry0, rx0, sx, sy] = p2;
317670
- const ry = ry0 + (orbit?.rotateY ?? 0), rx = rx0 + (orbit?.rotateX ?? 0);
317671
- const parts = [];
317672
- if (tx2 || ty || z2) parts.push(z2 ? `translate3d(${round(tx2)}px, ${round(ty)}px, ${round(z2)}px)` : `translate(${round(tx2)}px, ${round(ty)}px)`);
317673
- if (r) parts.push(`rotate(${round(r)}deg)`);
317674
- if (ry) parts.push(`rotateY(${round(ry)}deg)`);
317675
- if (rx) parts.push(`rotateX(${round(rx)}deg)`);
317676
- if (sx !== 1 || sy !== 1) parts.push(`scale(${round(sx)}, ${round(sy)})`);
317677
- return parts.length ? parts.join(" ") : void 0;
317678
- }
317679
- function styleMapFor(node2, styles, opts = {}) {
317680
- const scene2 = node2;
317681
- const out = {};
317682
- out.width = `${Math.round(node2.width)}px`;
317683
- out.height = `${Math.round(node2.height)}px`;
317684
- const transform3 = transformCss(node2);
317685
- if (transform3) out.transform = transform3;
317686
- const ax = restValue(node2, "anchorX"), ay = restValue(node2, "anchorY");
317687
- if (transform3 && (ax !== 0.5 || ay !== 0.5)) out["transform-origin"] = `${round(ax * 100)}% ${round(ay * 100)}%`;
317688
- const scene3d = scene3dOf(node2);
317689
- if (scene3d) {
317690
- out.perspective = `${round(zoomPx(scene3d.camera.focalLength, node2.width))}px`;
317691
- out["perspective-origin"] = `${round((scene3d.originX ?? 0.5) * 100)}% ${round((scene3d.originY ?? 0.5) * 100)}%`;
317692
- out["transform-style"] = "preserve-3d";
317693
- } else if (has3DPlacement(node2) && passesThrough(node2)) out["transform-style"] = "preserve-3d";
317694
- if ((node2.opacity ?? 1) !== 1) out.opacity = String(round(node2.opacity ?? 1));
317695
- const bm = node2.blendMode;
317696
- if (bm && bm !== "NORMAL" && bm !== "PASS_THROUGH") out["mix-blend-mode"] = bm.toLowerCase().replace(/_/g, "-");
317697
- const fills = visibleFills(node2, styles);
317698
- const own2 = node2.type === "IMAGE" && node2.imageUrl ? [{ type: "IMAGE", imageUrl: node2.imageUrl, scaleMode: node2.scaleMode, visible: true }] : [];
317699
- const painted = [...fills, ...own2];
317700
- if (node2.type !== "TEXT" && painted.length) {
317701
- const layers2 = painted.map((f2) => paintToBackground(f2, opts)).filter((l) => !!l);
317702
- const over2 = (l) => /^(#|rgb)/.test(l) ? `linear-gradient(${l}, ${l})` : l;
317703
- if (layers2.length) out.background = layers2.map((l, i2) => i2 === layers2.length - 1 ? l : over2(l)).join(", ");
317704
- }
317705
- const cr = scene2.cornerRadius;
317706
- if (typeof cr === "number" && cr > 0) out["border-radius"] = `${cr}px`;
317707
- else if (Array.isArray(cr) && cr.some((r) => r > 0)) out["border-radius"] = cr.map((r) => `${r}px`).join(" ");
317708
- if (node2.type === "ELLIPSE") out["border-radius"] = "50%";
317709
- const stroke3 = scene2.strokes?.[0];
317710
- if (stroke3) {
317711
- const color4 = toHex(stroke3.color);
317712
- if (Array.isArray(stroke3.width)) {
317713
- out["border-style"] = "solid";
317714
- out["border-color"] = color4;
317715
- out["border-width"] = stroke3.width.map((w) => `${w}px`).join(" ");
317716
- } else if (stroke3.alignment === "OUTSIDE") {
317717
- out.outline = `${stroke3.width}px solid ${color4}`;
317718
- } else {
317719
- out.border = `${stroke3.width}px ${stroke3.dashPattern?.length ? "dashed" : "solid"} ${color4}`;
317720
- if (stroke3.alignment === "INSIDE") out["box-sizing"] = "border-box";
317721
- }
317722
- }
317723
- const shadows = shadowsOf(node2, styles).filter((s) => s.visible);
317724
- if (node2.type === "TEXT") {
317725
- const drops = shadows.filter((s) => s.type === "DROP_SHADOW");
317726
- if (drops.length) out["text-shadow"] = drops.map((s) => `${s.offset.x}px ${s.offset.y}px ${s.blur}px ${toRgba(s.color)}`).join(", ");
317727
- } else if (shadows.length) {
317728
- out["box-shadow"] = shadows.map((s) => `${s.type === "INNER_SHADOW" ? "inset " : ""}${s.offset.x}px ${s.offset.y}px ${s.blur}px ${s.spread}px ${toRgba(s.color)}`).join(", ");
317729
- }
317730
- const blurs = blursOf(node2, styles);
317731
- const layer2 = blurs.find((b) => b.type === "LAYER");
317732
- const backdrop = blurs.find((b) => b.type === "BACKGROUND");
317733
- if (layer2) out.filter = `blur(${layer2.radius}px)`;
317734
- if (backdrop) out["backdrop-filter"] = `blur(${backdrop.radius}px)`;
317735
- if (node2.type === "FRAME" || node2.type === "COMPONENT" || node2.type === "INSTANCE") {
317736
- const f2 = node2;
317737
- Object.assign(out, flexDeclarations(f2));
317738
- if (f2.clipsContent) out.overflow = "hidden";
317739
- }
317740
- if (node2.type === "TEXT") {
317741
- const t3 = node2;
317742
- const tFills = visibleFills(t3, styles);
317743
- out.margin = "0";
317744
- if (t3.textAutoResize === "WIDTH_AND_HEIGHT") {
317745
- out.width = "max-content";
317746
- out.height = "auto";
317747
- out["white-space"] = "pre";
317748
- } else if (t3.textAutoResize === "HEIGHT") out.height = "auto";
317749
- out["font-family"] = `"${t3.fontFamily}", system-ui, sans-serif`;
317750
- out["font-size"] = `${t3.fontSize}px`;
317751
- out["font-weight"] = String(t3.fontWeight);
317752
- if (t3.fontStyle === "italic") out["font-style"] = "italic";
317753
- out["line-height"] = t3.lineHeight === "AUTO" ? "normal" : `${t3.lineHeight}px`;
317754
- if (t3.letterSpacing) out["letter-spacing"] = `${t3.letterSpacing}px`;
317755
- out["text-align"] = t3.textAlign.toLowerCase();
317756
- if (t3.textDecoration === "UNDERLINE") out["text-decoration"] = "underline";
317757
- else if (t3.textDecoration === "STRIKETHROUGH") out["text-decoration"] = "line-through";
317758
- const tc = t3.textCase;
317759
- if (tc === "UPPER") out["text-transform"] = "uppercase";
317760
- else if (tc === "LOWER") out["text-transform"] = "lowercase";
317761
- else if (tc === "TITLE") out["text-transform"] = "capitalize";
317762
- const solid5 = tFills.find((f2) => f2.type === "SOLID" && f2.color);
317763
- if (solid5?.color) out.color = toHex(solid5.color);
317764
- const grad = tFills.find((f2) => f2.type !== "SOLID");
317765
- const g = grad ? paintToBackground(grad) : null;
317766
- if (g) {
317767
- out.background = g;
317768
- out["-webkit-background-clip"] = "text";
317769
- out.color = "transparent";
317770
- }
317771
- }
317772
- return out;
317773
- }
317774
- function flexDeclarations(f2) {
317775
- const out = {};
317776
- if (f2.layoutMode !== "HORIZONTAL" && f2.layoutMode !== "VERTICAL") return out;
317777
- out.display = "flex";
317778
- out["flex-direction"] = f2.layoutMode === "HORIZONTAL" ? "row" : "column";
317779
- const justify = JUSTIFY[f2.primaryAxisAlignItems ?? "MIN"];
317780
- const align4 = ALIGN2[f2.counterAxisAlignItems ?? "MIN"];
317781
- if (justify !== "flex-start") out["justify-content"] = justify;
317782
- if (align4 !== "flex-start") out["align-items"] = align4;
317783
- out.gap = `${f2.itemSpacing ?? 0}px`;
317784
- if (f2.padding) {
317785
- out.padding = `${f2.padding.top}px ${f2.padding.right}px ${f2.padding.bottom}px ${f2.padding.left}px`;
317786
- if (f2.padding.top || f2.padding.right || f2.padding.bottom || f2.padding.left) out["box-sizing"] = "border-box";
317787
- }
317788
- return out;
317789
- }
317790
- var visibleFills, round, transformCss, JUSTIFY, ALIGN2, styleMapToCSSText, styleMapToInline, camel2, styleMapToJSX;
317791
- var init_css = __esm({
317792
- "lib/io/web/css.ts"() {
317793
- "use strict";
317794
- init_effects();
317795
- init_paint2();
317796
- init_scene3d();
317797
- init_transform3d();
317798
- init_transform();
317799
- visibleFills = (node2, styles) => (stylePaints(node2.fillStyleId, styles) ?? node2.fills ?? []).filter((f2) => f2.visible !== false);
317800
- round = (v) => Math.round(v * 100) / 100;
317801
- transformCss = (node2) => transformFromParts(transformParts(node2));
317802
- JUSTIFY = { MIN: "flex-start", MAX: "flex-end", CENTER: "center", SPACE_BETWEEN: "space-between" };
317803
- ALIGN2 = { MIN: "flex-start", MAX: "flex-end", CENTER: "center", BASELINE: "baseline" };
317804
- styleMapToCSSText = (m, indent = "") => Object.entries(m).map(([k2, v]) => `${indent}${k2}: ${v};`).join("\n");
317805
- styleMapToInline = (m) => Object.entries(m).map(([k2, v]) => `${k2}:${v}`).join(";");
317806
- camel2 = (k2) => k2.startsWith("--") ? k2 : (k2.startsWith("-") ? k2.replace(/^-/, "Webkit").replace(/-webkit-/i, "") : k2).replace(/-([a-z])/g, (_, c2) => c2.toUpperCase());
317807
- styleMapToJSX = (m) => Object.entries(m).map(([k2, v]) => [camel2(k2), v.replace(/'/g, "\\'")]);
317808
- }
317809
- });
317810
-
317811
- // lib/io/web/keyframes.ts
317812
- function transformOf(n, rest) {
317813
- return transformFromParts(transformParts(n, n.x - rest.x, n.y - rest.y)) ?? "none";
317814
- }
317815
- function declarationsOf(node2, rest, style) {
317816
- return { ...style(node2), transform: transformOf(node2, rest), opacity: String(round2(node2.visible === false ? 0 : node2.opacity ?? 1)) };
317817
- }
317818
- function vectorOf(style, keys4) {
317819
- const text = keys4.map((k2) => `${k2}:${style[k2] ?? ""}`).join(";");
317820
- return { shape: text.replace(NUMBER2, "#"), v: (text.match(NUMBER2) ?? []).map(Number) };
317821
- }
317822
- function thinSamples(times2, samples, tol, pinned = []) {
317823
- const n = samples.length;
317824
- if (n <= 2) return samples.map((_, i2) => i2);
317825
- const keep = /* @__PURE__ */ new Set([0, n - 1, ...pinned]);
317826
- for (let i2 = 1; i2 < n; i2++) if (samples[i2].shape !== samples[i2 - 1].shape) {
317827
- keep.add(i2 - 1);
317828
- keep.add(i2);
317829
- }
317830
- const sorted = () => [...keep].sort((a, b) => a - b);
317831
- const stack = [];
317832
- const kept = sorted();
317833
- for (let i2 = 1; i2 < kept.length; i2++) stack.push([kept[i2 - 1], kept[i2]]);
317834
- while (stack.length) {
317835
- const [a, b] = stack.pop();
317836
- if (b - a < 2 || samples[a].shape !== samples[b].shape) continue;
317837
- let worst2 = -1, at3 = -1;
317838
- for (let i2 = a + 1; i2 < b; i2++) {
317839
- const k2 = (times2[i2] - times2[a]) / (times2[b] - times2[a] || 1);
317840
- let err2 = 0;
317841
- samples[i2].v.forEach((x2, d) => {
317842
- const want = samples[a].v[d] + (samples[b].v[d] - samples[a].v[d]) * k2;
317843
- err2 = Math.max(err2, Math.abs(x2 - want) / tol[d]);
317844
- });
317845
- if (err2 > worst2) {
317846
- worst2 = err2;
317847
- at3 = i2;
317848
- }
317849
- }
317850
- if (worst2 > 1) {
317851
- keep.add(at3);
317852
- stack.push([a, at3], [at3, b]);
317853
- }
317854
- }
317855
- return sorted();
317856
- }
317857
- function keyframesOf(times2, samples, length2) {
317858
- const keys4 = [...new Set(samples.flatMap((s) => Object.keys(s)))].filter((k2) => !FIXED.has(k2));
317859
- const moving = keys4.filter((k2) => samples.some((s) => s[k2] !== samples[0][k2]));
317860
- if (!moving.length) return null;
317861
- const vectors = samples.map((s) => vectorOf(s, moving));
317862
- const dims = Math.max(...vectors.map((v) => v.v.length));
317863
- const range3 = Array.from({ length: dims }, (_, d) => {
317864
- let lo = Infinity, hi = -Infinity;
317865
- for (const v of vectors) if (d < v.v.length) {
317866
- lo = Math.min(lo, v.v[d]);
317867
- hi = Math.max(hi, v.v[d]);
317868
- }
317869
- return hi > lo ? hi - lo : 0;
317870
- });
317871
- const tol = range3.map((r) => Math.max(1e-3, r * 3e-3));
317872
- const same5 = (a, b) => vectors[a].shape === vectors[b].shape && vectors[a].v.every((x2, d) => Math.abs(x2 - vectors[b].v[d]) <= tol[d]);
317873
- const jumps = /* @__PURE__ */ new Set();
317874
- for (let i2 = 1; i2 < samples.length; i2++) {
317875
- if (same5(i2 - 1, i2)) continue;
317876
- const stillBefore = i2 >= 2 && same5(i2 - 2, i2 - 1);
317877
- if (!stillBefore) continue;
317878
- const words = vectors[i2].shape !== vectors[i2 - 1].shape;
317879
- const far = !words && vectors[i2].v.some((x2, d) => range3[d] > 0 && Math.abs(x2 - vectors[i2 - 1].v[d]) > range3[d] * 0.2);
317880
- if (words || far) jumps.add(i2);
317881
- }
317882
- const kept = thinSamples(times2, vectors, tol, [...jumps].flatMap((i2) => [i2 - 1, i2]));
317883
- return kept.map((i2) => {
317884
- const style = {};
317885
- for (const k2 of moving) if (samples[i2][k2] !== void 0) style[k2] = samples[i2][k2];
317886
- return { offset: pct(times2[i2] / (length2 || 1)), style, ...jumps.has(i2 + 1) ? { step: true } : {} };
317887
- });
317888
- }
317889
- var SAMPLE_RATE, round2, pct, FIXED, NUMBER2;
317890
- var init_keyframes = __esm({
317891
- "lib/io/web/keyframes.ts"() {
317892
- "use strict";
317893
- init_css();
317894
- SAMPLE_RATE = 30;
317895
- round2 = (v) => Math.round(v * 1e3) / 1e3;
317896
- pct = (k2) => Math.round(k2 * 1e5) / 1e3;
317897
- FIXED = /* @__PURE__ */ new Set(["position", "display", "left", "top", "right", "bottom", "inset", "animation", "animation-play-state", "transform-origin", "transform-style", "box-sizing", "isolation", "z-index"]);
317898
- NUMBER2 = /-?\d+(?:\.\d+)?(?:e-?\d+)?/g;
317899
- }
317900
- });
317901
-
317902
- // lib/io/web/motion.ts
317903
- function instanceWebMotion(doc2, instance, style) {
317904
- const comp = instance.mainComponentId;
317905
- if (!comp || !isMotionComponent(doc2.nodes, comp)) return null;
317906
- const m = playbackOf(doc2.nodes, instance, comp);
317907
- const [a, b] = m.range;
317908
- const len3 = b - a;
317909
- if (len3 <= 0) return null;
317910
- const steps = Math.max(1, Math.ceil(len3 / 1e3 * SAMPLE_RATE));
317911
- const times2 = Array.from({ length: steps + 1 }, (_, i2) => len3 * i2 / steps);
317912
- const samples = [];
317913
- for (let i2 = 0; i2 <= steps; i2++) samples.push(instancePoseAt(doc2.nodes, instance.id, a + len3 * i2 / steps));
317914
- const ids2 = /* @__PURE__ */ new Set();
317915
- for (const s of samples) for (const id3 in s) if (id3.includes("::")) ids2.add(id3);
317916
- const children = /* @__PURE__ */ new Map();
317917
- const tag = instance.id.replace(/[^a-zA-Z0-9]/g, "").slice(-6);
317918
- let n = 0;
317919
- for (const id3 of ids2) {
317920
- const restNode = resolveVirtualNode2(doc2.nodes, id3);
317921
- if (!restNode) continue;
317922
- const frames = keyframesOf(times2, samples.map((s) => declarationsOf(s[id3] ?? restNode, restNode, style)), len3);
317923
- if (!frames) continue;
317924
- children.set(id3, {
317925
- name: `motion-${tag}-${n++}`,
317926
- frames,
317927
- durationMs: m.speed > 0 ? Math.round(len3 / m.speed) : 0,
317928
- delayMs: Math.round(m.start),
317929
- iterations: m.loop === "none" ? 1 : "infinite",
317930
- direction: m.loop === "pingpong" ? "alternate" : "normal",
317931
- fill: m.hold === "first" ? "backwards" : "both"
317932
- });
317933
- }
317934
- return children.size ? { trigger: m.trigger, children } : null;
317935
- }
317936
- function animationStyle(mo, trigger) {
317937
- const out = { animation: `${mo.name} ${mo.durationMs}ms linear ${mo.delayMs}ms ${mo.iterations} ${mo.direction} ${mo.fill}` };
317938
- if (trigger !== "load") out["animation-play-state"] = "paused";
317939
- return out;
317940
- }
317941
- var keyframesCSS, MOTION_SCRIPT;
317942
- var init_motion = __esm({
317943
- "lib/io/web/motion.ts"() {
317944
- "use strict";
317945
- init_scene_graph();
317946
- init_instances2();
317947
- init_keyframes();
317948
- init_keyframes();
317949
- init_element();
317950
- keyframesCSS = (mo) => `@keyframes ${mo.name} {
317951
- ${mo.frames.map((f2) => ` ${f2.offset}% { ${Object.entries(f2.style).map(([k2, v]) => `${k2}: ${v};`).join(" ")}${f2.step ? " animation-timing-function: step-end;" : ""} }`).join("\n")}
317952
- }`;
317953
- MOTION_SCRIPT = `(function () {
317954
- var play = function (el) { el.setAttribute('data-motion-play', '') };
317955
- document.querySelectorAll('[data-motion="click"]').forEach(function (el) { el.addEventListener('click', function () { play(el) }) });
317956
- document.querySelectorAll('[data-motion="hover"]').forEach(function (el) { el.addEventListener('mouseenter', function () { play(el) }) });
317957
- var seen = document.querySelectorAll('[data-motion="inView"]');
317958
- if (!('IntersectionObserver' in window)) { seen.forEach(play); return }
317959
- var io = new IntersectionObserver(function (entries) { entries.forEach(function (e) { if (e.isIntersecting) { play(e.target); io.unobserve(e.target) } }) }, { threshold: 0.25 });
317960
- seen.forEach(function (el) { io.observe(el) });
317961
- })();`;
317962
- }
317963
- });
317964
-
317965
- // lib/io/web/generated/runtimes.ts
317966
- var PROTOTYPE_JS, MACHINE_JS;
317967
- var init_runtimes = __esm({
317968
- "lib/io/web/generated/runtimes.ts"() {
317969
- "use strict";
317970
- PROTOTYPE_JS = 'function popcraftMount(root, spec) {\n var els = {}, state = {}, owned = {}, orbit = {}, last = {}, holds = {}, hist = [], timers = [];\n var nodes = [root].concat(Array.prototype.slice.call(root.querySelectorAll("[data-pc]")));\n nodes.forEach(function(el) {\n els[el.getAttribute("data-pc")] = el;\n });\n for (var m in spec.m) state[m] = spec.m[m];\n for (var u in spec.e) (owned[spec.e[u][0]] = owned[spec.e[u][0]] || []).push(u);\n var drags = {}, clicks = {};\n spec.on.forEach(function(o) {\n if (o[3] === "drag") drags[o[0]] = 1;\n if (o[3] === "click" || o[3] === "press") clicks[o[0]] = 1;\n });\n function lookIn(u2, st) {\n var e = spec.e[u2];\n if (!e) return -2;\n var i = e[1][st === void 0 ? state[e[0]] : st];\n return i === void 0 ? -1 : i;\n }\n function tf(f, o) {\n var ry = f[4] + (o ? o.ry : 0), rx = f[5] + (o ? o.rx : 0), p = [];\n if (f[0] || f[1] || f[2]) p.push(f[2] ? "translate3d(" + f[0] + "px, " + f[1] + "px, " + f[2] + "px)" : "translate(" + f[0] + "px, " + f[1] + "px)");\n if (f[3]) p.push("rotate(" + f[3] + "deg)");\n if (ry) p.push("rotateY(" + ry + "deg)");\n if (rx) p.push("rotateX(" + rx + "deg)");\n if (f[6] !== 1 || f[7] !== 1) p.push("scale(" + f[6] + ", " + f[7] + ")");\n return p.length ? p.join(" ") : "none";\n }\n function css(u2, i) {\n var L = spec.L[i], c = L[0];\n if (orbit[u2] && L[2]) c += ";transform:" + tf(L[2], orbit[u2]);\n if (drags[u2]) c += ";touch-action:none;user-select:none;-webkit-user-select:none";\n if (clicks[u2]) c += ";cursor:pointer";\n return c;\n }\n var HIDE = ";opacity:0;visibility:hidden;pointer-events:none;position:absolute";\n function set(u2, ms, ez) {\n var el = els[u2], i = lookIn(u2, void 0);\n if (!el || i === -2) return;\n var tr = ms ? ";transition:all " + ms + "ms " + ez : ";transition:none";\n if (i < 0) {\n el.style.cssText = (last[u2] || "") + HIDE + tr;\n return;\n }\n var c = css(u2, i), text = spec.L[i][1];\n if (text !== null && el.textContent !== text) el.textContent = text;\n if (ms && el.style.visibility === "hidden") {\n el.style.cssText = c + ";opacity:0;transition:none";\n void el.offsetWidth;\n }\n el.style.cssText = c + tr;\n last[u2] = c;\n }\n var ANIM = /(?:^|;)animation:[^;]*/;\n function anim(i) {\n var m2 = i >= 0 ? ANIM.exec(spec.L[i][0]) : null;\n return m2 ? m2[0] : "";\n }\n function go(m2, to, ms, ez, fromHistory) {\n if (!(m2 in state) || state[m2] === to) return;\n var list = owned[m2] || [];\n list.forEach(function(u2) {\n var a = lookIn(u2, void 0), b = lookIn(u2, to), el = els[u2];\n if (!el || a < 0 || !anim(a) || anim(a) === anim(b)) return;\n var cs = getComputedStyle(el);\n el.style.cssText = css(u2, a) + ";animation:none;transition:none;transform:" + cs.transform + ";opacity:" + cs.opacity;\n });\n void root.offsetWidth;\n if (m2 === "flow" && !fromHistory) hist.push(state[m2]);\n state[m2] = to;\n list.forEach(function(u2) {\n set(u2, ms, ez);\n });\n arm();\n }\n function active(u2, trig) {\n return spec.on.filter(function(o) {\n return String(o[0]) === String(u2) && o[3] === trig && state[o[1]] === o[2];\n });\n }\n function run(o, u2) {\n var a = o[4];\n if (a.k === "go") {\n if (a.hold) {\n if (!holds[u2]) holds[u2] = { m: a.m, back: state[a.m], ms: a.ms, ez: a.ez };\n }\n go(a.m, a.to, a.ms, a.ez, false);\n } else if (a.k === "back" && hist.length) {\n go(a.m, hist.pop(), 300, "ease-in-out", true);\n }\n }\n function release(u2) {\n var h = holds[u2];\n if (!h) return;\n delete holds[u2];\n go(h.m, h.back, h.ms, h.ez, true);\n }\n function chain(el) {\n var out = [];\n for (var n = el; n && n !== root.parentNode; n = n.parentNode) {\n var id2 = n.getAttribute && n.getAttribute("data-pc");\n if (id2 !== null && id2 !== void 0) out.push(id2);\n if (n === root) break;\n }\n return out;\n }\n function first(ids, trig) {\n for (var i = 0; i < ids.length; i++) {\n var a = active(ids[i], trig);\n if (a.length) return { u: ids[i], list: a };\n }\n return null;\n }\n function arm() {\n timers.forEach(clearTimeout);\n timers = [];\n spec.on.forEach(function(o) {\n if (o[3] === "timeout" && state[o[1]] === o[2]) timers.push(setTimeout(function() {\n if (state[o[1]] === o[2]) run(o, o[0]);\n }, o[5]));\n });\n }\n var over = [];\n function hover(ids) {\n var left = over.filter(function(u2) {\n return ids.indexOf(u2) < 0;\n }), entered = ids.filter(function(u2) {\n return over.indexOf(u2) < 0;\n });\n over = ids;\n left.forEach(function(u2) {\n release(u2);\n active(u2, "leave").forEach(function(o) {\n run(o, u2);\n });\n });\n entered.slice().reverse().forEach(function(u2) {\n active(u2, "hover").concat(active(u2, "enter")).forEach(function(o) {\n run(o, u2);\n });\n });\n }\n var press = null;\n function onMove(e) {\n if (press) {\n var dx = e.clientX - press.x, dy = e.clientY - press.y;\n if (!press.dragged && Math.abs(dx) + Math.abs(dy) > 5) {\n press.dragged = true;\n var d = first(press.ids, "drag");\n if (d) {\n var du = d.u;\n press.drag = d;\n d.list.forEach(function(o) {\n if (o[4].k !== "orbit") run(o, du);\n });\n }\n if (press.held) {\n release(press.held);\n press.held = null;\n }\n }\n if (press.drag) {\n var k = root.getBoundingClientRect().width / (root.offsetWidth || 1) || 1;\n press.drag.list.forEach(function(o) {\n var a = o[4];\n if (a.k !== "orbit") return;\n var cur = orbit[a.t] || { rx: 0, ry: 0 };\n orbit[a.t] = { rx: cur.rx, ry: cur.ry + (e.clientX - press.lx) / k * a.d };\n if (a.tilt) {\n var tc = orbit[a.tt] || { rx: 0, ry: 0 };\n orbit[a.tt] = { ry: tc.ry, rx: Math.max(a.lo, Math.min(a.hi, tc.rx - (e.clientY - press.ly) / k * a.d)) };\n }\n set(a.t, 0, "linear");\n if (a.tt !== a.t) set(a.tt, 0, "linear");\n });\n press.lx = e.clientX;\n press.ly = e.clientY;\n return;\n }\n }\n hover(chain(e.target));\n }\n function onDown(e) {\n var ids = chain(e.target);\n press = { x: e.clientX, y: e.clientY, lx: e.clientX, ly: e.clientY, ids, dragged: false, drag: null, held: null };\n if (first(ids, "drag") && root.setPointerCapture) {\n try {\n root.setPointerCapture(e.pointerId);\n } catch (err) {\n }\n }\n var p = first(ids, "press");\n if (p) {\n var pu = p.u;\n press.held = pu;\n p.list.forEach(function(o) {\n run(o, pu);\n });\n }\n }\n function onUp(e) {\n var p = press;\n press = null;\n if (!p) return;\n if (p.held) release(p.held);\n if (p.dragged) return;\n var c = first(p.ids, "click");\n if (c) {\n var cu = c.u;\n c.list.forEach(function(o) {\n run(o, cu);\n });\n }\n void e;\n }\n function onLeave() {\n if (!press) hover([]);\n }\n function onKey(e) {\n spec.on.forEach(function(o) {\n if (o[3] === "key" && state[o[1]] === o[2] && (!o[6] || o[6].toLowerCase() === String(e.key).toLowerCase())) run(o, o[0]);\n });\n }\n for (var id in els) set(id, 0, "linear");\n root.addEventListener("pointermove", onMove);\n root.addEventListener("pointerdown", onDown);\n root.addEventListener("pointerup", onUp);\n root.addEventListener("pointercancel", onUp);\n root.addEventListener("pointerleave", onLeave);\n window.addEventListener("keydown", onKey);\n arm();\n return function() {\n timers.forEach(clearTimeout);\n root.removeEventListener("pointermove", onMove);\n root.removeEventListener("pointerdown", onDown);\n root.removeEventListener("pointerup", onUp);\n root.removeEventListener("pointercancel", onUp);\n root.removeEventListener("pointerleave", onLeave);\n window.removeEventListener("keydown", onKey);\n };\n}';
317971
- MACHINE_JS = 'function popcraftMachineCore(spec) {\n function start(id) {\n var t = spec.in[id];\n return !t || t[0] === "event" ? void 0 : t[1];\n }\n function holds(g, values, fired) {\n var t = spec.in[g[0]];\n if (!t) return false;\n if (t[0] === "event") return !!fired[g[0]];\n var v = g[0] in values ? values[g[0]] : start(g[0]), w = g[2];\n switch (g[1]) {\n case "eq":\n return v === w;\n case "neq":\n return v !== w;\n case "gt":\n return typeof v === "number" && typeof w === "number" && v > w;\n case "gte":\n return typeof v === "number" && typeof w === "number" && v >= w;\n case "lt":\n return typeof v === "number" && typeof w === "number" && v < w;\n case "lte":\n return typeof v === "number" && typeof w === "number" && v <= w;\n }\n return false;\n }\n function apply(values, actions) {\n var out = {}, fired = {};\n for (var k in values) out[k] = values[k];\n actions.forEach(function(a) {\n var t = spec.in[a[1]];\n if (!t) return;\n var cur = a[1] in out ? out[a[1]] : start(a[1]), by = typeof a[2] === "number" ? a[2] : 1;\n if (a[0] === "set") {\n if (t[0] === "event") fired[a[1]] = 1;\n else if (a.length > 2 && typeof a[2] === typeof cur) out[a[1]] = a[2];\n } else if (a[0] === "toggle") {\n if (typeof cur === "boolean") out[a[1]] = !cur;\n } else if (a[0] === "increment") {\n if (typeof cur === "number") out[a[1]] = cur + by;\n } else if (a[0] === "decrement") {\n if (typeof cur === "number") out[a[1]] = cur - by;\n } else if (a[0] === "fire") {\n if (t[0] === "event") fired[a[1]] = 1;\n } else if (a[0] === "reset") {\n var s = start(a[1]);\n if (s === void 0) delete out[a[1]];\n else out[a[1]] = s;\n }\n });\n return { values: out, fired };\n }\n function next(r, fired) {\n var own = spec.t.filter(function(t2) {\n return t2[0] === r.state;\n });\n var any = spec.t.filter(function(t2) {\n return t2[0] === "*" && t2[1] !== r.state;\n });\n var all = own.concat(any);\n for (var i = 0; i < all.length; i++) {\n var t = all[i];\n if (spec.s[t[1]] && t[2].every(function(g) {\n return holds(g, r.values, fired);\n })) return t;\n }\n return null;\n }\n function enter(r, id) {\n var res = apply(r.values, spec.s[id] ? spec.s[id][4] : []);\n return { run: { state: id, values: res.values }, fired: res.fired };\n }\n function settle(r, fired) {\n var cur = r, ev = fired || {};\n for (var i = 0; i < 16; i++) {\n var t = next(cur, ev);\n if (!t) break;\n var n = enter(cur, t[1]);\n cur = n.run;\n ev = n.fired;\n }\n return cur;\n }\n function begin() {\n var first = spec.s[spec.i] ? spec.i : Object.keys(spec.s)[0], values = {};\n if (first === void 0) return null;\n for (var k in spec.in) {\n var s = start(k);\n if (s !== void 0) values[k] = s;\n }\n var e = enter({ state: first, values }, first);\n return settle(e.run, e.fired);\n }\n function hears(l, type, chain, key) {\n if (l[0] !== type) return false;\n if (type === "complete") return true;\n if (type === "keyDown" || type === "keyUp") return !l[3] || String(l[3]).toLowerCase() === String(key).toLowerCase();\n return l[1] === null || chain.indexOf(l[1]) >= 0;\n }\n function dispatch(r, type, chain, key) {\n var heard = spec.l.filter(function(l) {\n return hears(l, type, chain, key);\n });\n if (!heard.length) return r;\n var res = apply(r.values, [].concat.apply([], heard.map(function(l) {\n return l[2];\n })));\n return settle({ state: r.state, values: res.values }, res.fired);\n }\n function set(r, id, value) {\n var t = spec.in[id];\n if (!t) return r;\n var res = apply(r.values, [t[0] === "event" ? ["fire", id] : ["set", id, value]]);\n return settle({ state: r.state, values: res.values }, res.fired);\n }\n return { begin, dispatch, set };\n}\nfunction popcraftMachine(root, spec) {\n var core = popcraftMachineCore(spec), run = core.begin(), anims = [], t0 = 0, done = false, raf = 0, over = [];\n if (!run) return function() {\n };\n function chain(el) {\n var out = [];\n for (var n = el; n && n !== root.parentNode; n = n.parentNode) {\n var id = n.getAttribute && n.getAttribute("data-sm");\n if (id) out.push(id);\n if (n === root) break;\n }\n return out;\n }\n function update(r) {\n if (r === run) return;\n var changed = r.state !== run.state;\n run = r;\n if (!changed) return;\n t0 = performance.now();\n done = false;\n root.dispatchEvent(new CustomEvent("popcraft:state", { detail: { state: r.state, name: spec.s[r.state] ? spec.s[r.state][5] : r.state, values: r.values } }));\n }\n function tick(now) {\n var s = spec.s[run.state];\n if (s) {\n var a = s[0], b = s[1], played = Math.max(0, now - t0) * s[3], t;\n if (s[2] && b > a) t = a + played % (b - a);\n else {\n t = Math.min(b, a + played);\n if (!done && a + played >= b) {\n done = true;\n update(core.dispatch(run, "complete", []));\n }\n }\n anims.forEach(function(x) {\n x.currentTime = t;\n });\n }\n raf = requestAnimationFrame(tick);\n }\n function on(type) {\n return function(e) {\n update(core.dispatch(run, type, chain(e.target)));\n };\n }\n function onMove(e) {\n var ids = chain(e.target);\n var left = over.filter(function(u) {\n return ids.indexOf(u) < 0;\n }), entered = ids.filter(function(u) {\n return over.indexOf(u) < 0;\n });\n over = ids;\n if (left.length) update(core.dispatch(run, "pointerExit", left));\n if (entered.length) update(core.dispatch(run, "pointerEnter", entered));\n }\n function onLeave() {\n if (over.length) {\n var left = over;\n over = [];\n update(core.dispatch(run, "pointerExit", left));\n }\n }\n function onKey(type) {\n return function(e) {\n var t = e.target;\n if (e.repeat || e.metaKey || e.ctrlKey || t && (t.tagName === "INPUT" || t.tagName === "TEXTAREA" || t.isContentEditable)) return;\n var r = core.dispatch(run, type, [], e.key);\n if (r !== run) {\n e.preventDefault();\n update(r);\n }\n };\n }\n var down = on("pointerDown"), up = on("pointerUp"), click = on("click"), keyDown = onKey("keyDown"), keyUp = onKey("keyUp");\n anims = root.getAnimations ? root.getAnimations({ subtree: true }) : [];\n anims.forEach(function(x) {\n x.pause();\n });\n t0 = performance.now();\n root.addEventListener("pointerdown", down);\n root.addEventListener("pointerup", up);\n root.addEventListener("click", click);\n root.addEventListener("pointermove", onMove);\n root.addEventListener("pointerleave", onLeave);\n window.addEventListener("keydown", keyDown);\n window.addEventListener("keyup", keyUp);\n raf = requestAnimationFrame(tick);\n function byName(k) {\n if (spec.in[k]) return k;\n for (var id in spec.in) if (spec.in[id][2] === k) return id;\n return k;\n }\n var api = {\n state: function() {\n return run.state;\n },\n values: function() {\n return run.values;\n },\n set: function(input, value) {\n update(core.set(run, byName(input), value));\n },\n fire: function(input) {\n update(core.set(run, byName(input), void 0));\n },\n destroy: function() {\n cancelAnimationFrame(raf);\n root.removeEventListener("pointerdown", down);\n root.removeEventListener("pointerup", up);\n root.removeEventListener("click", click);\n root.removeEventListener("pointermove", onMove);\n root.removeEventListener("pointerleave", onLeave);\n window.removeEventListener("keydown", keyDown);\n window.removeEventListener("keyup", keyUp);\n }\n };\n root.popcraftMachine = api;\n return api.destroy;\n}';
317972
- }
317973
- });
317974
-
317975
319124
  // lib/io/web/runtime.ts
317976
319125
  function interactiveSpec(tree) {
317977
319126
  if (!tree.interactive) return null;
@@ -318019,55 +319168,6 @@ var init_runtime3 = __esm({
318019
319168
  }
318020
319169
  });
318021
319170
 
318022
- // lib/io/web/machine-runtime.ts
318023
- var init_machine_runtime = __esm({
318024
- "lib/io/web/machine-runtime.ts"() {
318025
- "use strict";
318026
- init_runtimes();
318027
- }
318028
- });
318029
-
318030
- // lib/io/web/state-machine.ts
318031
- function webStateMachine(doc2, frameId) {
318032
- const sm = machineOf(doc2.nodes[frameId]);
318033
- if (!sm || !doc2.nodes[frameId]?.timeline) return null;
318034
- const timeline = frameTimeline(doc2.nodes, frameId);
318035
- const duration3 = timelineDuration(doc2.nodes, frameId);
318036
- const action3 = (a) => a.value === void 0 ? [a.type, a.input] : [a.type, a.input, a.value];
318037
- const spec = { i: sm.initial, s: {}, t: [], in: {}, l: [] };
318038
- for (const i2 of sortedValues(sm.inputs)) spec.in[i2.id] = [i2.type, i2.type === "event" ? null : i2.value ?? defaultOf2(i2.type), i2.name];
318039
- for (const s of sortedValues(sm.states)) {
318040
- const [a, b] = stateStretch(s, timeline, duration3);
318041
- spec.s[s.id] = [a, b, s.loop ? 1 : 0, s.speed ?? 1, (s.entry ?? []).map(action3), s.name];
318042
- }
318043
- for (const t3 of sortedValues(sm.transitions)) {
318044
- spec.t.push([t3.from, t3.to, (t3.guards ?? []).map((g) => {
318045
- const type = sm.inputs[g.input]?.type;
318046
- const value3 = type === "event" ? null : g.value ?? (type === "boolean" ? true : type === "number" ? 0 : "");
318047
- return [g.input, g.op ?? "eq", value3];
318048
- })]);
318049
- }
318050
- for (const l of sortedValues(sm.listeners)) {
318051
- if (!isKeyListener(l.type)) spec.l.push([l.type, l.layer ?? null, l.actions.map(action3)]);
318052
- else spec.l.push(l.key ? [l.type, null, l.actions.map(action3), l.key] : [l.type, null, l.actions.map(action3)]);
318053
- }
318054
- return spec;
318055
- }
318056
- var defaultOf2, machineLayers, machineScript;
318057
- var init_state_machine3 = __esm({
318058
- "lib/io/web/state-machine.ts"() {
318059
- "use strict";
318060
- init_instances2();
318061
- init_state_machine();
318062
- init_machine_runtime();
318063
- init_machine_runtime();
318064
- defaultOf2 = (type) => type === "boolean" ? false : type === "number" ? 0 : type === "string" ? "" : null;
318065
- machineLayers = (spec) => new Set((spec?.l ?? []).map((l) => l[1]).filter((id3) => !!id3));
318066
- machineScript = (spec) => `${MACHINE_JS}
318067
- popcraftMachine(document.querySelector('[data-sm-root]'), ${JSON.stringify(spec)});`;
318068
- }
318069
- });
318070
-
318071
319171
  // lib/io/web/naming.ts
318072
319172
  var classNameFor, componentName, fileBase;
318073
319173
  var init_naming = __esm({
@@ -318083,128 +319183,6 @@ var init_naming = __esm({
318083
319183
  }
318084
319184
  });
318085
319185
 
318086
- // lib/document/dev-mode.ts
318087
- function codeSyntaxFor(v, platform4) {
318088
- const explicit = v.codeSyntax?.[platform4];
318089
- if (explicit) return explicit;
318090
- const parts = v.name.split("/").map((p2) => p2.trim()).filter(Boolean);
318091
- if (platform4 === "WEB") return `--${parts.join("-").toLowerCase().replace(/[^a-z0-9-]+/g, "-")}`;
318092
- const camel4 = parts.map((p2, i2) => {
318093
- const w = p2.replace(/[^A-Za-z0-9]+/g, " ").trim().split(/\s+/);
318094
- return w.map((x2, j) => i2 === 0 && j === 0 ? x2.toLowerCase() : x2[0].toUpperCase() + x2.slice(1).toLowerCase()).join("");
318095
- }).join("");
318096
- return platform4 === "iOS" ? `Tokens.${camel4}` : `Tokens.${camel4}`;
318097
- }
318098
- var init_dev_mode = __esm({
318099
- "lib/document/dev-mode.ts"() {
318100
- "use strict";
318101
- }
318102
- });
318103
-
318104
- // lib/io/web/tokens.ts
318105
- function cssValue(v, value3) {
318106
- if (v.type === "COLOR") return isColor3(value3) ? (value3.a ?? 1) < 1 ? toRgba(value3) : toHex(value3) : null;
318107
- if (v.type === "FLOAT") return typeof value3 === "number" && Number.isFinite(value3) ? String(Math.round(value3 * 1e3) / 1e3) : null;
318108
- if (v.type === "STRING") return typeof value3 === "string" ? JSON.stringify(value3) : null;
318109
- return null;
318110
- }
318111
- function siteTokens(doc2) {
318112
- const collections = Object.values(doc2.variableCollections ?? {}).map((c2) => ({
318113
- id: c2.id,
318114
- name: c2.name,
318115
- defaultMode: c2.defaultModeId,
318116
- modes: c2.modes.map((m) => ({ id: m.id, name: m.name, className: modeClass(c2, m) }))
318117
- }));
318118
- const taken = /* @__PURE__ */ new Set();
318119
- const vars = [];
318120
- for (const v of Object.values(doc2.variables ?? {}).sort((a, b) => a.name.localeCompare(b.name) || a.id.localeCompare(b.id))) {
318121
- const values3 = {};
318122
- for (const [mode, value3] of Object.entries(v.valuesByMode ?? {})) {
318123
- const css = cssValue(v, value3);
318124
- if (css !== null) values3[mode] = css;
318125
- }
318126
- if (!Object.keys(values3).length) continue;
318127
- let name2 = codeSyntaxFor(v, "WEB");
318128
- if (!name2.startsWith("--")) name2 = `--${slug(name2)}`;
318129
- if (taken.has(name2)) name2 = `${name2}-${v.id.replace(/[^a-zA-Z0-9]/g, "").slice(-4)}`;
318130
- taken.add(name2);
318131
- vars.push({ id: v.id, name: name2, type: v.type, collection: v.variableCollectionId, values: values3 });
318132
- }
318133
- const active3 = Object.entries(doc2.activeVariableModes ?? {}).flatMap(([cid, mid]) => {
318134
- const c2 = collections.find((x2) => x2.id === cid);
318135
- const m = c2 && mid !== c2.defaultMode ? c2.modes.find((x2) => x2.id === mid) : void 0;
318136
- return m ? [m.className] : [];
318137
- });
318138
- return { collections, vars, active: active3 };
318139
- }
318140
- function tokensCSS(tokens) {
318141
- const rules = [];
318142
- const defaults3 = [];
318143
- const byMode = /* @__PURE__ */ new Map();
318144
- for (const v of tokens.vars) {
318145
- const c2 = tokens.collections.find((x2) => x2.id === v.collection);
318146
- const base = v.values[c2?.defaultMode ?? ""] ?? Object.values(v.values)[0];
318147
- defaults3.push(` ${v.name}: ${base};`);
318148
- if (v.type === "FLOAT") rules.push(`@property ${v.name} { syntax: '<number>'; inherits: true; initial-value: ${base}; }`);
318149
- for (const m of c2?.modes ?? []) {
318150
- if (m.id === c2.defaultMode || v.values[m.id] === void 0 || v.values[m.id] === base) continue;
318151
- (byMode.get(m.className) ?? byMode.set(m.className, []).get(m.className)).push(` ${v.name}: ${v.values[m.id]};`);
318152
- }
318153
- }
318154
- if (defaults3.length) rules.push(`:root {
318155
- ${defaults3.join("\n")}
318156
- }`);
318157
- for (const [cls, lines2] of byMode) rules.push(`.${cls} {
318158
- ${lines2.join("\n")}
318159
- }`);
318160
- return rules;
318161
- }
318162
- function tokenStyle(raw, style, tokens) {
318163
- const name2 = (id3) => id3 ? tokens.vars.find((v) => v.id === id3)?.name : void 0;
318164
- const out = {};
318165
- const fills = (raw.fills ?? []).filter((f2) => f2.visible !== false);
318166
- const fill = fills.length === 1 && fills[0].type === "SOLID" && (fills[0].opacity ?? 1) === 1 ? name2(fills[0].boundVariables?.color) : void 0;
318167
- if (fill) {
318168
- if (raw.type === "TEXT") {
318169
- if (style.color) out.color = `var(${fill})`;
318170
- } else if (style.background) out.background = `var(${fill})`;
318171
- }
318172
- const stroke3 = raw.strokes?.[0];
318173
- const strokeVar = name2(stroke3?.boundVariables?.color);
318174
- if (strokeVar) {
318175
- if (style["border-color"]) out["border-color"] = `var(${strokeVar})`;
318176
- for (const p2 of ["border", "outline"]) if (style[p2]) out[p2] = style[p2].replace(/(#[0-9A-Fa-f]{3,8}|rgba?\([^)]*\))$/, `var(${strokeVar})`);
318177
- }
318178
- for (const [prop, id3] of Object.entries(raw.boundVariables ?? {})) {
318179
- const rule2 = NUMBER_PROPS[prop];
318180
- const token = tokens.vars.find((v) => v.id === id3);
318181
- if (!rule2 || !token || token.type !== "FLOAT" || style[rule2[0]] === void 0) continue;
318182
- out[rule2[0]] = rule2[1](token.name);
318183
- }
318184
- return out;
318185
- }
318186
- var slug, modeClass, isColor3, px2, NUMBER_PROPS;
318187
- var init_tokens2 = __esm({
318188
- "lib/io/web/tokens.ts"() {
318189
- "use strict";
318190
- init_dev_mode();
318191
- init_paint2();
318192
- slug = (s) => s.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "") || "x";
318193
- modeClass = (collection, mode) => `pc-${slug(collection.name)}-${slug(mode.name)}`;
318194
- isColor3 = (v) => !!v && typeof v === "object" && "r" in v && "g" in v && "b" in v;
318195
- px2 = (name2) => `calc(var(${name2}) * 1px)`;
318196
- NUMBER_PROPS = {
318197
- width: ["width", px2],
318198
- height: ["height", px2],
318199
- opacity: ["opacity", (n) => `var(${n})`],
318200
- cornerRadius: ["border-radius", px2],
318201
- itemSpacing: ["gap", px2],
318202
- fontSize: ["font-size", px2],
318203
- letterSpacing: ["letter-spacing", px2]
318204
- };
318205
- }
318206
- });
318207
-
318208
319186
  // lib/io/web/html.ts
318209
319187
  function serializeHTML(tree, opts = {}) {
318210
319188
  const rules = [];
@@ -318342,7 +319320,7 @@ var init_html = __esm({
318342
319320
  init_css();
318343
319321
  init_motion();
318344
319322
  init_runtime3();
318345
- init_state_machine3();
319323
+ init_state_machine2();
318346
319324
  init_element();
318347
319325
  init_fonts3();
318348
319326
  init_naming();
@@ -318448,7 +319426,7 @@ function tailwindFor(style) {
318448
319426
  const out = [];
318449
319427
  for (const [k2, v] of Object.entries(style)) {
318450
319428
  const util = UTILITIES[k2]?.(v);
318451
- out.push(util ?? `[${k2}:${px3(v)}]`);
319429
+ out.push(util ?? `[${k2}:${px4(v)}]`);
318452
319430
  }
318453
319431
  return out.join(" ");
318454
319432
  }
@@ -318468,44 +319446,44 @@ ${indent}</${tag}>` : `${indent}<${tag} class="${cls}"></${tag}>`;
318468
319446
  };
318469
319447
  return emit8(tree.root, 0, true);
318470
319448
  }
318471
- var px3, UTILITIES;
319449
+ var px4, UTILITIES;
318472
319450
  var init_tailwind = __esm({
318473
319451
  "lib/io/web/tailwind.ts"() {
318474
319452
  "use strict";
318475
319453
  init_element();
318476
- px3 = (v) => v.replace(/"/g, "'").replace(/\s+/g, "_");
319454
+ px4 = (v) => v.replace(/"/g, "'").replace(/\s+/g, "_");
318477
319455
  UTILITIES = {
318478
- width: (v) => `w-[${px3(v)}]`,
318479
- height: (v) => `h-[${px3(v)}]`,
319456
+ width: (v) => `w-[${px4(v)}]`,
319457
+ height: (v) => `h-[${px4(v)}]`,
318480
319458
  display: (v) => v === "flex" ? "flex" : v === "block" ? "block" : v === "none" ? "hidden" : null,
318481
319459
  "flex-direction": (v) => v === "row" ? "flex-row" : "flex-col",
318482
- gap: (v) => `gap-[${px3(v)}]`,
319460
+ gap: (v) => `gap-[${px4(v)}]`,
318483
319461
  "justify-content": (v) => ({ "flex-start": "justify-start", "flex-end": "justify-end", center: "justify-center", "space-between": "justify-between" })[v] ?? null,
318484
319462
  "align-items": (v) => ({ "flex-start": "items-start", "flex-end": "items-end", center: "items-center", baseline: "items-baseline" })[v] ?? null,
318485
- padding: (v) => `p-[${px3(v)}]`,
318486
- "border-radius": (v) => `rounded-[${px3(v)}]`,
319463
+ padding: (v) => `p-[${px4(v)}]`,
319464
+ "border-radius": (v) => `rounded-[${px4(v)}]`,
318487
319465
  overflow: (v) => v === "hidden" ? "overflow-hidden" : null,
318488
319466
  position: (v) => ({ absolute: "absolute", relative: "relative", fixed: "fixed" })[v] ?? null,
318489
- left: (v) => `left-[${px3(v)}]`,
318490
- top: (v) => `top-[${px3(v)}]`,
319467
+ left: (v) => `left-[${px4(v)}]`,
319468
+ top: (v) => `top-[${px4(v)}]`,
318491
319469
  opacity: (v) => `opacity-[${v}]`,
318492
- background: (v) => v.startsWith("#") || v.startsWith("rgb") ? `bg-[${px3(v)}]` : `bg-[image:${px3(v)}]`,
318493
- color: (v) => `text-[${px3(v)}]`,
318494
- "font-size": (v) => `text-[${px3(v)}]`,
319470
+ background: (v) => v.startsWith("#") || v.startsWith("rgb") ? `bg-[${px4(v)}]` : `bg-[image:${px4(v)}]`,
319471
+ color: (v) => `text-[${px4(v)}]`,
319472
+ "font-size": (v) => `text-[${px4(v)}]`,
318495
319473
  "font-weight": (v) => `font-[${v}]`,
318496
319474
  "font-style": (v) => v === "italic" ? "italic" : null,
318497
- "line-height": (v) => v === "normal" ? "leading-normal" : `leading-[${px3(v)}]`,
318498
- "letter-spacing": (v) => `tracking-[${px3(v)}]`,
319475
+ "line-height": (v) => v === "normal" ? "leading-normal" : `leading-[${px4(v)}]`,
319476
+ "letter-spacing": (v) => `tracking-[${px4(v)}]`,
318499
319477
  "text-align": (v) => `text-${v}`,
318500
319478
  "text-decoration": (v) => v === "underline" ? "underline" : v === "line-through" ? "line-through" : null,
318501
319479
  "text-transform": (v) => ({ uppercase: "uppercase", lowercase: "lowercase", capitalize: "capitalize" })[v] ?? null,
318502
319480
  "mix-blend-mode": (v) => `mix-blend-${v}`,
318503
- transform: (v) => /^rotate\(/.test(v) ? `rotate-[${px3(v.slice(7, -1))}]` : null,
318504
- filter: (v) => /^blur\(/.test(v) ? `blur-[${px3(v.slice(5, -1))}]` : null,
318505
- "backdrop-filter": (v) => /^blur\(/.test(v) ? `backdrop-blur-[${px3(v.slice(5, -1))}]` : null,
318506
- "box-shadow": (v) => `shadow-[${px3(v)}]`,
318507
- border: (v) => `border-[${px3(v)}]`,
318508
- outline: (v) => `outline-[${px3(v)}]`,
319481
+ transform: (v) => /^rotate\(/.test(v) ? `rotate-[${px4(v.slice(7, -1))}]` : null,
319482
+ filter: (v) => /^blur\(/.test(v) ? `blur-[${px4(v.slice(5, -1))}]` : null,
319483
+ "backdrop-filter": (v) => /^blur\(/.test(v) ? `backdrop-blur-[${px4(v.slice(5, -1))}]` : null,
319484
+ "box-shadow": (v) => `shadow-[${px4(v)}]`,
319485
+ border: (v) => `border-[${px4(v)}]`,
319486
+ outline: (v) => `outline-[${px4(v)}]`,
318509
319487
  "box-sizing": (v) => v === "border-box" ? "box-border" : "box-content"
318510
319488
  };
318511
319489
  }
@@ -318686,7 +319664,7 @@ var init_react2 = __esm({
318686
319664
  init_naming();
318687
319665
  init_motion();
318688
319666
  init_runtime3();
318689
- init_state_machine3();
319667
+ init_state_machine2();
318690
319668
  init_tailwind();
318691
319669
  jsxText = (s) => `{'${s.replace(/\\/g, "\\\\").replace(/'/g, "\\'").replace(/\n/g, "\\n")}'}`;
318692
319670
  template = (s) => "`" + s.replace(/\\/g, "\\\\").replace(/`/g, "\\`").replace(/\$\{/g, "\\${") + "`";
@@ -318713,140 +319691,6 @@ var init_react2 = __esm({
318713
319691
  }
318714
319692
  });
318715
319693
 
318716
- // packages/runtime/src/commerce.ts
318717
- var commerce_exports = {};
318718
- __export(commerce_exports, {
318719
- COMMERCE_ACTIONS: () => COMMERCE_ACTIONS,
318720
- COMMERCE_ACTION_PROP: () => COMMERCE_ACTION_PROP,
318721
- COMMERCE_FIELDS: () => COMMERCE_FIELDS,
318722
- COMMERCE_PROP: () => COMMERCE_PROP,
318723
- COMMERCE_SCHEMAS: () => COMMERCE_SCHEMAS,
318724
- commerceItem: () => commerceItem,
318725
- commerceWords: () => commerceWords,
318726
- formatMoney: () => formatMoney,
318727
- isCommerceAction: () => isCommerceAction
318728
- });
318729
- function formatMoney(m, locale = "en-US") {
318730
- if (!m) return "";
318731
- try {
318732
- return new Intl.NumberFormat(locale, { style: "currency", currency: m.currencyCode, currencyDisplay: "narrowSymbol" }).format(Number(m.amount));
318733
- } catch {
318734
- return `${m.amount} ${m.currencyCode}`;
318735
- }
318736
- }
318737
- function commerceItem(schema, value3) {
318738
- switch (schema) {
318739
- case "commerce.product": {
318740
- const p2 = value3;
318741
- return { id: p2.id, values: {
318742
- title: p2.title,
318743
- handle: p2.handle,
318744
- url: `/product/${p2.handle}`,
318745
- description: p2.description,
318746
- price: formatMoney(p2.priceRange?.minVariantPrice),
318747
- max_price: formatMoney(p2.priceRange?.maxVariantPrice),
318748
- image: p2.featuredImage?.url ?? "",
318749
- image_alt: p2.featuredImage?.altText || p2.title,
318750
- available: !!p2.availableForSale,
318751
- variant_id: p2.variants?.find((v) => v.availableForSale)?.id ?? p2.variants?.[0]?.id ?? "",
318752
- tags: (p2.tags ?? []).join(", ")
318753
- } };
318754
- }
318755
- case "commerce.collection": {
318756
- const c2 = value3;
318757
- return { id: c2.handle || "all", values: { title: c2.title, handle: c2.handle, url: c2.path, description: c2.description } };
318758
- }
318759
- case "commerce.cart": {
318760
- const c2 = value3;
318761
- return { id: c2.id ?? "cart", values: {
318762
- count: c2.totalQuantity,
318763
- subtotal: formatMoney(c2.cost?.subtotalAmount),
318764
- taxes: formatMoney(c2.cost?.totalTaxAmount),
318765
- total: formatMoney(c2.cost?.totalAmount),
318766
- checkout_url: c2.checkoutUrl
318767
- } };
318768
- }
318769
- case "commerce.cartLine": {
318770
- const l = value3;
318771
- const m = l.merchandise;
318772
- return { id: l.id ?? m.id, values: {
318773
- title: m.product.title,
318774
- variant: m.title === "Default Title" ? "" : m.title,
318775
- url: `/product/${m.product.handle}`,
318776
- image: m.product.featuredImage?.url ?? "",
318777
- quantity: l.quantity,
318778
- price: formatMoney(l.cost?.totalAmount),
318779
- merchandise_id: m.id
318780
- } };
318781
- }
318782
- case "commerce.menu": {
318783
- const m = value3;
318784
- return { id: m.path, values: { title: m.title, url: m.path } };
318785
- }
318786
- }
318787
- }
318788
- function commerceWords(item, key5) {
318789
- if (key5 === "id") return item.id;
318790
- const v = item.values[key5];
318791
- return typeof v === "boolean" ? v ? "Yes" : "No" : v === void 0 ? "" : String(v);
318792
- }
318793
- var COMMERCE_SCHEMAS, COMMERCE_FIELDS, COMMERCE_PROP, COMMERCE_ACTIONS, COMMERCE_ACTION_PROP, isCommerceAction;
318794
- var init_commerce = __esm({
318795
- "packages/runtime/src/commerce.ts"() {
318796
- "use strict";
318797
- COMMERCE_SCHEMAS = ["commerce.product", "commerce.collection", "commerce.cart", "commerce.cartLine", "commerce.menu"];
318798
- COMMERCE_FIELDS = {
318799
- "commerce.product": [
318800
- { name: "Title", type: "TEXT" },
318801
- { name: "Handle", type: "TEXT" },
318802
- { name: "URL", type: "URL" },
318803
- { name: "Description", type: "TEXT" },
318804
- { name: "Price", type: "TEXT" },
318805
- { name: "Max price", type: "TEXT" },
318806
- { name: "Image", type: "MEDIA" },
318807
- { name: "Image alt", type: "TEXT" },
318808
- { name: "Available", type: "BOOLEAN" },
318809
- { name: "Variant ID", type: "TEXT" },
318810
- { name: "Tags", type: "TEXT" }
318811
- ],
318812
- "commerce.collection": [{ name: "Title", type: "TEXT" }, { name: "Handle", type: "TEXT" }, { name: "URL", type: "URL" }, { name: "Description", type: "TEXT" }],
318813
- "commerce.cart": [
318814
- { name: "Count", type: "NUMBER" },
318815
- { name: "Subtotal", type: "TEXT" },
318816
- { name: "Taxes", type: "TEXT" },
318817
- { name: "Total", type: "TEXT" },
318818
- { name: "Checkout URL", type: "URL" }
318819
- ],
318820
- "commerce.cartLine": [
318821
- { name: "Title", type: "TEXT" },
318822
- { name: "Variant", type: "TEXT" },
318823
- { name: "URL", type: "URL" },
318824
- { name: "Image", type: "MEDIA" },
318825
- { name: "Quantity", type: "NUMBER" },
318826
- { name: "Price", type: "TEXT" },
318827
- { name: "Merchandise ID", type: "TEXT" }
318828
- ],
318829
- "commerce.menu": [{ name: "Title", type: "TEXT" }, { name: "URL", type: "URL" }]
318830
- };
318831
- COMMERCE_PROP = {
318832
- "commerce.product": { name: "products", type: "Product" },
318833
- "commerce.collection": { name: "collections", type: "Collection" },
318834
- "commerce.cart": { name: "cart", type: "Cart", one: true },
318835
- "commerce.cartLine": { name: "lines", type: "CartItem" },
318836
- "commerce.menu": { name: "menu", type: "Menu" }
318837
- };
318838
- COMMERCE_ACTIONS = ["addToCart", "updateCartLine", "removeCartLine", "checkout", "search"];
318839
- COMMERCE_ACTION_PROP = {
318840
- addToCart: "onAddToCart",
318841
- updateCartLine: "onUpdateCartLine",
318842
- removeCartLine: "onRemoveCartLine",
318843
- checkout: "onCheckout",
318844
- search: "onSearch"
318845
- };
318846
- isCommerceAction = (a) => typeof a === "string" && COMMERCE_ACTIONS.includes(a);
318847
- }
318848
- });
318849
-
318850
319694
  // lib/sites/auth.ts
318851
319695
  function usesSignIn(doc2) {
318852
319696
  if (Object.values(doc2.collections ?? {}).some((c2) => c2.perVisitor)) return true;
@@ -319542,7 +320386,7 @@ var init_package = __esm({
319542
320386
  "packages/runtime/package.json"() {
319543
320387
  package_default = {
319544
320388
  name: "@popcraft/runtime",
319545
- version: "0.16.0",
320389
+ version: "0.17.0",
319546
320390
  description: "What code exported from PopCraft shares: the meaning of expressions (operators and functions) and, as it grows, the parts of a design's behaviour that are common code rather than generated React.",
319547
320391
  license: "MIT",
319548
320392
  homepage: "https://popcraft.app/docs/exporting/nextjs",
@@ -320316,941 +321160,6 @@ var init_physics = __esm({
320316
321160
  }
320317
321161
  });
320318
321162
 
320319
- // lib/code/props.ts
320320
- function propName(key5) {
320321
- const words = key5.split("#")[0].trim().split(/[^A-Za-z0-9]+/).filter(Boolean);
320322
- const name2 = words.map((w, i2) => i2 === 0 ? w.charAt(0).toLowerCase() + w.slice(1) : w.charAt(0).toUpperCase() + w.slice(1)).join("");
320323
- return /^[A-Za-z_$]/.test(name2) ? name2 : `p${name2}`;
320324
- }
320325
- function componentOf(nodes, node2) {
320326
- const c2 = node2.type === "COMPONENT" ? node2 : node2.type === "INSTANCE" ? nodes[node2.mainComponentId] : void 0;
320327
- return c2?.type === "COMPONENT" ? c2 : void 0;
320328
- }
320329
- function codeOf(nodes, node2) {
320330
- if (node2.type !== "COMPONENT" && node2.type !== "INSTANCE") return null;
320331
- return componentOf(nodes, node2)?.code ?? null;
320332
- }
320333
- function codeProps(nodes, node2) {
320334
- const component = componentOf(nodes, node2);
320335
- const out = {};
320336
- if (!component) return out;
320337
- const set4 = component.parentId ? nodes[component.parentId] : void 0;
320338
- const defs = (set4?.type === "COMPONENT_SET" ? set4.componentPropertyDefinitions : component.componentPropertyDefinitions) ?? {};
320339
- const given = node2.type === "INSTANCE" ? node2.componentProperties ?? {} : {};
320340
- for (const key5 of Object.keys(defs).sort()) {
320341
- const v = value(key5 in given ? given[key5] : defs[key5].defaultValue);
320342
- if (v !== void 0) out[propName(key5)] = v;
320343
- }
320344
- out.width = Math.round(node2.width);
320345
- out.height = Math.round(node2.height);
320346
- return out;
320347
- }
320348
- var value;
320349
- var init_props = __esm({
320350
- "lib/code/props.ts"() {
320351
- "use strict";
320352
- init_color();
320353
- value = (v) => typeof v === "string" || typeof v === "number" || typeof v === "boolean" ? v : v && typeof v === "object" && "r" in v ? colorToHex8(v) : void 0;
320354
- }
320355
- });
320356
-
320357
- // lib/document/controls.ts
320358
- function fieldPart(nodes, id3) {
320359
- const n = nodes[id3];
320360
- if (!n) return null;
320361
- if (n.type === "TEXT") return id3;
320362
- for (const c2 of n.childIds ?? []) {
320363
- const hit = fieldPart(nodes, c2);
320364
- if (hit) return hit;
320365
- }
320366
- return null;
320367
- }
320368
- var cleanName2;
320369
- var init_controls = __esm({
320370
- "lib/document/controls.ts"() {
320371
- "use strict";
320372
- cleanName2 = (raw) => raw.trim().replace(/[^A-Za-z0-9_-]+/g, "-").replace(/^-+|-+$/g, "");
320373
- }
320374
- });
320375
-
320376
- // lib/io/web/expressible.ts
320377
- function expressibility(node2, styles) {
320378
- const c2 = capability(node2, "css", styles);
320379
- return { css: c2.reason === "", reason: c2.reason, needsRaster: c2.verdict === "raster" };
320380
- }
320381
- var init_expressible = __esm({
320382
- "lib/io/web/expressible.ts"() {
320383
- "use strict";
320384
- init_capability();
320385
- }
320386
- });
320387
-
320388
- // lib/io/web/responsive.ts
320389
- function containerStyle(f2) {
320390
- const out = {};
320391
- if (isStack(f2) && f2.layoutWrap === "WRAP") {
320392
- out["flex-wrap"] = "wrap";
320393
- const cross2 = f2.counterAxisSpacing ?? f2.itemSpacing ?? 0;
320394
- const main2 = f2.itemSpacing ?? 0;
320395
- if (cross2 !== main2) out.gap = f2.layoutMode === "HORIZONTAL" ? `${cross2}px ${main2}px` : `${main2}px ${cross2}px`;
320396
- out["align-content"] = "flex-start";
320397
- }
320398
- if (isGrid(f2)) {
320399
- out.display = "grid";
320400
- const cols = f2.layoutGridColumns ?? "AUTO";
320401
- out["grid-template-columns"] = cols === "AUTO" ? `repeat(auto-fill, minmax(${f2.layoutGridMinColumnWidth ?? 100}px, 1fr))` : Array.from({ length: Math.max(1, cols) }, (_, i2) => track(f2.layoutGridColumnSizes?.[i2])).join(" ");
320402
- const rows = f2.layoutGridRows ?? "AUTO";
320403
- if (rows === "AUTO") out["grid-auto-rows"] = `minmax(${f2.layoutGridMinRowHeight ?? 100}px, auto)`;
320404
- else out["grid-template-rows"] = Array.from({ length: Math.max(1, rows) }, (_, i2) => track(f2.layoutGridRowSizes?.[i2])).join(" ");
320405
- const colGap = f2.itemSpacing ?? 0, rowGap = f2.counterAxisSpacing ?? colGap;
320406
- out.gap = rowGap === colGap ? `${colGap}px` : `${rowGap}px ${colGap}px`;
320407
- if (f2.padding) {
320408
- out.padding = `${f2.padding.top}px ${f2.padding.right}px ${f2.padding.bottom}px ${f2.padding.left}px`;
320409
- if (f2.padding.top || f2.padding.right || f2.padding.bottom || f2.padding.left) out["box-sizing"] = "border-box";
320410
- }
320411
- }
320412
- const scroll = f2.overflowScrolling;
320413
- if (scroll && scroll !== "NONE") {
320414
- out["overflow-x"] = scroll === "HORIZONTAL" || scroll === "BOTH" ? "auto" : "hidden";
320415
- out["overflow-y"] = scroll === "VERTICAL" || scroll === "BOTH" ? "auto" : "hidden";
320416
- }
320417
- return out;
320418
- }
320419
- function flowChild(node2, parent) {
320420
- const style = { ...limits(node2) };
320421
- const h = node2.layoutSizingHorizontal ?? "FIXED", v = node2.layoutSizingVertical ?? "FIXED";
320422
- if (isGrid(parent)) {
320423
- if (h !== "FIXED") style.width = h === "FILL" ? null : "fit-content";
320424
- if (v !== "FIXED") style.height = null;
320425
- return { style };
320426
- }
320427
- if (h === "FIXED" && style["max-width"] === void 0) style["max-width"] = "100%";
320428
- const row2 = parent.layoutMode === "HORIZONTAL";
320429
- const main2 = row2 ? h : v, cross2 = row2 ? v : h;
320430
- const mainProp = row2 ? "width" : "height", crossProp = row2 ? "height" : "width";
320431
- if (main2 === "FILL") {
320432
- style[mainProp] = null;
320433
- style.flex = "1 1 0";
320434
- if (style[`min-${mainProp}`] === void 0) style[`min-${mainProp}`] = "0";
320435
- } else {
320436
- if (main2 === "HUG") style[mainProp] = null;
320437
- style["flex-shrink"] = "0";
320438
- }
320439
- if (cross2 === "FILL") {
320440
- style[crossProp] = null;
320441
- style["align-self"] = "stretch";
320442
- } else {
320443
- if (cross2 === "HUG") style[crossProp] = null;
320444
- if ((parent.counterAxisAlignItems ?? "MIN") === "MIN") style["align-self"] = "flex-start";
320445
- }
320446
- return { style };
320447
- }
320448
- function constrained(kind, pos, size6, parentSize, start2, end, sizeProp) {
320449
- const far = parentSize - pos - size6;
320450
- switch (kind) {
320451
- case "MAX":
320452
- return { place: { [end]: px4(far) }, style: {} };
320453
- case "STRETCH":
320454
- return { place: { [start2]: px4(pos), [end]: px4(far) }, style: { [sizeProp]: null } };
320455
- // Its centre keeps its distance from the parent's centre.
320456
- case "CENTER":
320457
- return { place: { [start2]: `calc(50% + ${px4(pos - parentSize / 2)})` }, style: {} };
320458
- case "SCALE":
320459
- return parentSize > 0 ? { place: { [start2]: pct2(pos / parentSize) }, style: { [sizeProp]: pct2(size6 / parentSize) } } : { place: { [start2]: px4(pos) }, style: {} };
320460
- default:
320461
- return { place: { [start2]: px4(pos) }, style: {} };
320462
- }
320463
- }
320464
- function placedChild(node2, parent, frame2 = parent) {
320465
- const c2 = node2.constraints ?? { horizontal: "MIN", vertical: "MIN" };
320466
- const x2 = constrained(c2.horizontal, node2.x, node2.width, frame2.width, "left", "right", "width");
320467
- const y = constrained(c2.vertical, node2.y, node2.height, frame2.height, "top", "bottom", "height");
320468
- return { style: { ...limits(node2), ...x2.style, ...y.style }, place: { position: "absolute", ...x2.place, ...y.place } };
320469
- }
320470
- function siteLayout(node2, parent, layout2) {
320471
- const own2 = node2.type === "FRAME" || node2.type === "COMPONENT" || node2.type === "INSTANCE" ? node2 : null;
320472
- if (!parent) {
320473
- const grows = !own2 || laysOut(own2) || own2.overflowScrolling === "NONE" || !own2.overflowScrolling;
320474
- return { style: { ...limits(node2), width: "100%", ...grows ? { height: null, "min-height": `max(${px4(node2.height)}, 100dvh)` } : {} }, place: { position: "relative" } };
320475
- }
320476
- const s = node2;
320477
- return layout2 && laysOut(layout2) && s.layoutPositioning !== "ABSOLUTE" ? flowChild(s, layout2) : placedChild(s, parent, parent.type === "INSTANCE" && layout2 ? layout2 : parent);
320478
- }
320479
- var px4, pct2, isStack, isGrid, laysOut, track, limits;
320480
- var init_responsive = __esm({
320481
- "lib/io/web/responsive.ts"() {
320482
- "use strict";
320483
- px4 = (v) => `${Math.round(v * 100) / 100}px`;
320484
- pct2 = (v) => `${Math.round(v * 1e4) / 100}%`;
320485
- isStack = (f2) => f2?.layoutMode === "HORIZONTAL" || f2?.layoutMode === "VERTICAL";
320486
- isGrid = (f2) => f2?.layoutMode === "GRID";
320487
- laysOut = (f2) => isStack(f2) || isGrid(f2);
320488
- track = (t3) => {
320489
- if (!t3 || t3.sizing === "FILL") return t3?.value && /fr$/.test(t3.value) ? t3.value : "1fr";
320490
- if (t3.sizing === "HUG") return "auto";
320491
- return /^[\d.]+$/.test(t3.value) ? `${t3.value}px` : t3.value;
320492
- };
320493
- limits = (n) => {
320494
- const out = {};
320495
- if (n.minWidth !== void 0) out["min-width"] = px4(n.minWidth);
320496
- if (n.maxWidth !== void 0) out["max-width"] = px4(n.maxWidth);
320497
- if (n.minHeight !== void 0) out["min-height"] = px4(n.minHeight);
320498
- if (n.maxHeight !== void 0) out["max-height"] = px4(n.maxHeight);
320499
- return out;
320500
- };
320501
- }
320502
- });
320503
-
320504
- // lib/io/web/richtext.ts
320505
- function runStyle(seg) {
320506
- const out = {};
320507
- if (seg.fontFamily) out["font-family"] = `"${seg.fontFamily}", system-ui, sans-serif`;
320508
- if (seg.fontSize) out["font-size"] = `${seg.fontSize}px`;
320509
- if (seg.fontWeight) out["font-weight"] = String(seg.fontWeight);
320510
- if (seg.fontStyle) out["font-style"] = seg.fontStyle;
320511
- if (seg.lineHeight !== void 0 && seg.lineHeight !== "AUTO") out["line-height"] = `${seg.lineHeight}px`;
320512
- if (seg.textDecoration === "UNDERLINE") out["text-decoration"] = "underline";
320513
- else if (seg.textDecoration === "STRIKETHROUGH") out["text-decoration"] = "line-through";
320514
- else if (seg.textDecoration === "NONE") out["text-decoration"] = "none";
320515
- if (seg.textCase === "UPPER") out["text-transform"] = "uppercase";
320516
- else if (seg.textCase === "LOWER") out["text-transform"] = "lowercase";
320517
- else if (seg.textCase === "TITLE") out["text-transform"] = "capitalize";
320518
- else if (seg.textCase === "ORIGINAL") out["text-transform"] = "none";
320519
- const solid5 = seg.fills?.find((f2) => f2.visible !== false && f2.type === "SOLID" && f2.color);
320520
- if (solid5?.color) out.color = toHex(solid5.color);
320521
- return out;
320522
- }
320523
- function textRuns(t3) {
320524
- const text = t3.characters ?? "";
320525
- const segs = [...t3.styledSegments ?? []].filter((s) => s.end > s.start).sort((a, b) => a.start - b.start);
320526
- if (!segs.length && !t3.link) return void 0;
320527
- const runs = [];
320528
- const push2 = (from2, to, seg) => {
320529
- if (to <= from2) return;
320530
- const link2 = seg?.link ?? t3.link;
320531
- runs.push({ text: text.slice(from2, to), style: seg ? runStyle(seg) : {}, ...link2 ? { link: link2 } : {} });
320532
- };
320533
- let at3 = 0;
320534
- for (const s of segs) {
320535
- const start2 = Math.max(at3, Math.min(text.length, s.start)), end = Math.min(text.length, s.end);
320536
- push2(at3, start2);
320537
- push2(start2, end, s);
320538
- at3 = Math.max(at3, end);
320539
- }
320540
- push2(at3, text.length);
320541
- return runs;
320542
- }
320543
- var init_richtext = __esm({
320544
- "lib/io/web/richtext.ts"() {
320545
- "use strict";
320546
- init_paint2();
320547
- }
320548
- });
320549
-
320550
- // lib/io/web/timeline.ts
320551
- function frameWebMotion(doc2, frameId, style) {
320552
- const nodes = doc2.nodes;
320553
- const frame2 = nodes[frameId];
320554
- if (!frame2 || !hasFrameMotion(nodes, frameId)) return null;
320555
- const len3 = timelineDuration(nodes, frameId);
320556
- if (!(len3 > 0)) return null;
320557
- const steps = Math.max(1, Math.ceil(len3 / 1e3 * SAMPLE_RATE));
320558
- const times2 = [];
320559
- const poses = [];
320560
- for (let i2 = 0; i2 <= steps; i2++) {
320561
- const t3 = len3 * i2 / steps;
320562
- times2.push(t3);
320563
- poses.push(evaluatePose(nodes, { kind: "frame", frameId }, t3).nodes);
320564
- }
320565
- const ids2 = /* @__PURE__ */ new Set();
320566
- for (const p2 of poses) for (const id3 in p2) if (id3 !== frameId && p2[id3] !== nodes[id3]) ids2.add(id3);
320567
- const loops = frameRunsOn(nodes, frameId);
320568
- const out = /* @__PURE__ */ new Map();
320569
- const tag = frameId.replace(/[^a-zA-Z0-9]/g, "").slice(-6);
320570
- let n = 0;
320571
- for (const id3 of ids2) {
320572
- const rest = id3.includes("::") ? resolveVirtualNode2(nodes, id3) : nodes[id3];
320573
- if (!rest || !underFrame(nodes, id3, frameId)) continue;
320574
- const frames = keyframesOf(times2, poses.map((p2) => declarationsOf(p2[id3] ?? rest, rest, style)), len3);
320575
- if (!frames) continue;
320576
- out.set(id3, {
320577
- name: `timeline-${tag}-${n++}`,
320578
- frames,
320579
- durationMs: Math.round(len3),
320580
- delayMs: 0,
320581
- iterations: loops ? "infinite" : 1,
320582
- direction: "normal",
320583
- fill: "both"
320584
- });
320585
- }
320586
- return out.size ? out : null;
320587
- }
320588
- function underFrame(nodes, id3, frameId) {
320589
- const real = id3.split("::")[0];
320590
- for (let n = nodes[real]; n; n = n.parentId ? nodes[n.parentId] : void 0) if (n.id === frameId) return true;
320591
- return false;
320592
- }
320593
- var init_timeline = __esm({
320594
- "lib/io/web/timeline.ts"() {
320595
- "use strict";
320596
- init_scene_graph();
320597
- init_pose();
320598
- init_instances2();
320599
- init_keyframes();
320600
- }
320601
- });
320602
-
320603
- // lib/io/web/tree.ts
320604
- function anchorTargets(doc2) {
320605
- const hit = anchorMemo.get(doc2.nodes);
320606
- if (hit) return hit;
320607
- const out = /* @__PURE__ */ new Set();
320608
- for (const id3 in doc2.nodes) {
320609
- const n = doc2.nodes[id3];
320610
- if (n.semantics?.link?.kind === "anchor") out.add(n.semantics.link.nodeId);
320611
- for (const ix of n.interactions ?? []) if (ix.action.link?.kind === "anchor" && ix.action.link.nodeId) out.add(ix.action.link.nodeId);
320612
- }
320613
- anchorMemo.set(doc2.nodes, out);
320614
- return out;
320615
- }
320616
- function spriteOnly(nodes, id3) {
320617
- let leaves = 0;
320618
- const visit2 = (nid, depth2) => {
320619
- const n = nodes[nid];
320620
- if (!n || n.visible === false) return true;
320621
- if (n.type === "PIXEL_GRID") {
320622
- leaves++;
320623
- return true;
320624
- }
320625
- if (depth2 > 8 || n.type !== "INSTANCE" && n.type !== "COMPONENT" && n.type !== "FRAME" && n.type !== "GROUP") return false;
320626
- const main2 = n.mainComponentId;
320627
- const kids = n.childIds?.length ? n.childIds : main2 ? [main2] : [];
320628
- return kids.every((k2) => visit2(k2, depth2 + 1));
320629
- };
320630
- return visit2(id3, 0) && leaves > 0;
320631
- }
320632
- function prepared(node2, doc2) {
320633
- let n = node2;
320634
- if (n.id.includes("::")) n = withInstanceBox(n, doc2.nodes);
320635
- n = resolveNodeVariables(n, doc2.variables, doc2.variableCollections, doc2.activeVariableModes, exprData(doc2));
320636
- n = resolveTextNodeStyles(n, doc2.styles ?? {});
320637
- return n;
320638
- }
320639
- function layoutOf2(node2, nodes) {
320640
- if (!node2) return null;
320641
- if (node2.type === "INSTANCE") {
320642
- const mainId = node2.mainComponentId;
320643
- const main2 = mainId ? nodes[mainId] : void 0;
320644
- return main2 ?? null;
320645
- }
320646
- if (node2.id.includes("::")) {
320647
- const real = nodes[node2.id.split("::").pop()];
320648
- return real ?? node2;
320649
- }
320650
- return node2;
320651
- }
320652
- function buildPlainTree(doc2, nodeId2, opts = {}, start2, hooks = {}) {
320653
- const cap2 = opts.nodeCap ?? DEFAULT_NODE_CAP;
320654
- const first2 = doc2.nodes[nodeId2] ?? (nodeId2.includes("::") ? childLookup(doc2, nodeId2) : void 0);
320655
- if (!first2) throw new Error(`No node ${nodeId2}`);
320656
- let emitted = 0;
320657
- let truncated = false;
320658
- let folds = 0;
320659
- const tokens = opts.target === "site" && Object.keys(doc2.variables ?? {}).length ? siteTokens(doc2) : null;
320660
- const anchored = anchorTargets(doc2);
320661
- const pageItem = () => {
320662
- const c2 = opts.item && doc2.collections?.[opts.item.collectionId];
320663
- if (c2 && opts.item.recordId === ITEM_RECORD) return { collection: c2, record: templateRecord(c2), suffix: `~${ITEM_RECORD}` };
320664
- const r = opts.item && doc2.records?.[opts.item.recordId];
320665
- return c2 && r ? { collection: c2, record: r, suffix: "" } : null;
320666
- };
320667
- let item = pageItem();
320668
- const scopeOf2 = (it) => itemScope(it.collection, it.record, withData(variablesScope(doc2.variables, doc2.variableCollections, doc2.activeVariableModes), doc2));
320669
- const itemised = (node2, raw, it) => itemNode(node2, raw, it.collection, it.record, scopeOf2(it));
320670
- const itemLink = (link2, it) => {
320671
- const filled2 = it && link2.kind === "url" ? { ...link2, url: itemText(link2.url, it.collection, it.record) } : it && (link2.kind === "email" || link2.kind === "tel") ? { ...link2, value: itemText(link2.value, it.collection, it.record) } : link2;
320672
- if (filled2.kind === "screen") {
320673
- const dest = doc2.nodes[filled2.frameId];
320674
- const base = opts.routes?.[filled2.frameId];
320675
- const of = dest?.route?.collectionId;
320676
- if (of && base !== void 0) {
320677
- const slugField = it?.record.id === ITEM_RECORD && it.collection.id === of ? it.collection.fields.find((f2) => f2.id === it.collection.slugFieldId) ?? it.collection.fields.find((f2) => f2.type === "SLUG" || f2.type === "TEXT") : void 0;
320678
- if (slugField) return { link: filled2, href: `${base === "/" ? "" : base}/${itemMark(fieldKey(slugField.name))}`, screen: filled2.frameId };
320679
- const slugs = recordSlugs(doc2, of);
320680
- const rec = it?.collection.id === of ? it.record.id : slugs.keys().next().value;
320681
- const slug3 = rec ? slugs.get(rec) : void 0;
320682
- return slug3 ? { link: filled2, href: `${base === "/" ? "" : base}/${slug3}`, screen: `${filled2.frameId}~${rec}` } : { link: filled2, href: null };
320683
- }
320684
- return { link: filled2, href: base ?? null, screen: filled2.frameId };
320685
- }
320686
- if (filled2.kind === "url" && it?.record.id === ITEM_RECORD && itemMarks(filled2.url)) return { link: filled2, href: filled2.url.trim() };
320687
- return { link: filled2, href: hrefOf(filled2, doc2.nodes, opts.routes) };
320688
- };
320689
- const fields = /* @__PURE__ */ new Map();
320690
- const styleOpts = { fullImageUrl: opts.fullImageUrls ?? opts.target === "site" };
320691
- const stylesOf = (n) => styleMapFor(n, doc2.styles, styleOpts);
320692
- let motion = null;
320693
- const timeline = !opts.static && !start2 && first2.type === "FRAME" ? frameWebMotion(doc2, first2.id, (n) => stylesOf(prepared(n, doc2))) : null;
320694
- const build3 = (raw, parent, in3D2, fold) => {
320695
- if (emitted >= cap2) {
320696
- truncated = true;
320697
- return null;
320698
- }
320699
- emitted++;
320700
- const node2 = item ? itemised(prepared(raw, doc2), raw, item) : prepared(raw, doc2);
320701
- const waits = node2.visible === false && parent !== null;
320702
- if (waits && !(opts.target === "site" && followsVisibility(raw))) return null;
320703
- const exp = expressibility(node2, doc2.styles);
320704
- const f2 = layoutOf2(node2, doc2.nodes) ?? node2;
320705
- const style = stylesOf(node2);
320706
- if (f2 !== node2 && !style.display) Object.assign(style, flexDeclarations(f2));
320707
- const through = in3D2 && passesThrough(raw, doc2.nodes);
320708
- const own2 = typeof node2.opacity === "number" ? node2.opacity : 1;
320709
- if (through) {
320710
- style["transform-style"] = "preserve-3d";
320711
- delete style.opacity;
320712
- style[foldVar(fold + 1)] = fold ? `calc(var(${foldVar(fold)}) * ${round3(own2)})` : String(round3(own2));
320713
- folds = Math.max(folds, fold + 1);
320714
- } else if (fold) style.opacity = own2 === 1 ? `var(${foldVar(fold)})` : `calc(var(${foldVar(fold)}) * ${round3(own2)})`;
320715
- if (own2 === 0) style["pointer-events"] = "none";
320716
- if (clickable(raw) && !style.cursor) style.cursor = "pointer";
320717
- const web = {
320718
- id: item?.suffix ? `${node2.id}${item.suffix}` : node2.id,
320719
- name: node2.name || node2.type,
320720
- type: node2.type,
320721
- x: Math.round(node2.x),
320722
- y: Math.round(node2.y),
320723
- width: Math.round(node2.width),
320724
- height: Math.round(node2.height),
320725
- // Absolutely-positioned auto-layout children are taken out of the flow, exactly as the canvas does.
320726
- // A grid's children are in its flow too: its tracks place them.
320727
- positioning: (isFlex(layoutOf2(parent, doc2.nodes)) || layoutOf2(parent, doc2.nodes)?.layoutMode === "GRID") && node2.layoutPositioning !== "ABSOLUTE" ? "flow" : "absolute",
320728
- style,
320729
- children: []
320730
- };
320731
- if (tokens) Object.assign(style, tokenStyle(raw, style, tokens));
320732
- if (opts.target === "site") {
320733
- const lay = siteLayout(node2, parent, layoutOf2(parent, doc2.nodes));
320734
- for (const [k2, v] of Object.entries(lay.style)) {
320735
- if (v === null) delete style[k2];
320736
- else style[k2] = v;
320737
- }
320738
- if (laysOut(f2) || f2.overflowScrolling) Object.assign(style, containerStyle(f2));
320739
- if (node2.type === "TEXT") {
320740
- if (style["white-space"] === "pre") {
320741
- style["white-space"] = "pre-wrap";
320742
- style.width = "fit-content";
320743
- }
320744
- if (style["max-width"] === void 0) style["max-width"] = "100%";
320745
- if (style.height && style.height !== "auto") {
320746
- style["min-height"] = style.height;
320747
- delete style.height;
320748
- }
320749
- }
320750
- if (lay.place && (parent !== null || !start2?.parent)) web.place = lay.place;
320751
- }
320752
- if (waits) web.hidden = true;
320753
- const sem = node2.semantics;
320754
- if (sem) {
320755
- if (sem.tag && sem.tag !== "div") web.tag = sem.tag;
320756
- const attrs = {};
320757
- if (sem.label) attrs["aria-label"] = sem.label;
320758
- if (sem.hidden) attrs["aria-hidden"] = "true";
320759
- if (Object.keys(attrs).length) web.attrs = attrs;
320760
- const to = sem.link ? itemLink(sem.link, item) : null;
320761
- if (to?.href) web.link = { href: to.href, ...opensNewTab(to.link) ? { newTab: true } : {}, ...to.screen ? { screen: to.screen } : {} };
320762
- }
320763
- const control = node2.control;
320764
- if (control) {
320765
- const named = control.name ? { name: control.name } : {};
320766
- if (control.kind === "FORM") {
320767
- web.tag = "form";
320768
- if (isCommerceAction(control.formAction)) web.action = control.formAction;
320769
- } else if (control.kind === "BUTTON") {
320770
- web.tag = "button";
320771
- web.attrs = { ...web.attrs, type: control.buttonType ?? "submit", ...named, ...control.name && control.value !== void 0 ? { value: item && hasItemToken(control.value) ? itemText(control.value, item.collection, item.record) : control.value } : {} };
320772
- } else if (control.kind === "CHECKBOX" || control.kind === "RADIO") {
320773
- web.check = { attrs: { type: control.kind === "RADIO" ? "radio" : "checkbox", ...named, ...control.value !== void 0 ? { value: control.value } : {}, ...control.checked ? { checked: "" } : {}, ...control.required ? { required: "" } : {} }, ...control.variableId ? { variable: control.variableId } : {} };
320774
- } else fields.set(fieldPart(doc2.nodes, raw.id) ?? raw.id, control);
320775
- }
320776
- const control0 = fields.get(raw.id);
320777
- const field = control0 && item && control0.value !== void 0 && hasItemToken(control0.value) ? { ...control0, value: itemText(control0.value, item.collection, item.record) } : control0;
320778
- if (field) {
320779
- const tag = field.kind === "TEXTAREA" ? "textarea" : field.kind === "SELECT" ? "select" : "input";
320780
- const words = node2.characters;
320781
- web.input = {
320782
- tag,
320783
- attrs: {
320784
- ...tag === "input" ? { type: field.inputType ?? "text" } : {},
320785
- ...field.name ? { name: field.name } : {},
320786
- ...tag !== "select" && (field.placeholder ?? words) ? { placeholder: field.placeholder ?? words } : {},
320787
- ...field.required ? { required: "" } : {},
320788
- ...tag === "input" && field.value !== void 0 ? { value: field.value } : {},
320789
- "aria-label": node2.semantics?.label ?? field.placeholder ?? field.name ?? web.name
320790
- },
320791
- ...tag === "select" ? { options: field.options ?? [] } : {},
320792
- ...tag !== "input" && field.value !== void 0 ? { value: field.value } : {},
320793
- ...field.variableId ? { variable: field.variableId } : {}
320794
- };
320795
- }
320796
- if (sem?.anchor || anchored.has(node2.id)) web.attrs = { ...web.attrs, id: anchorOf(node2) };
320797
- if (through) web.preserve3d = true;
320798
- web.tf = transformParts(node2);
320799
- if (typeof node2.altText === "string") web.alt = node2.altText;
320800
- if (parent === null) web.positioning = start2?.parent ? web.positioning : "flow";
320801
- if (f2.layoutMode === "HORIZONTAL" || f2.layoutMode === "VERTICAL") {
320802
- web.layout = {
320803
- direction: f2.layoutMode === "HORIZONTAL" ? "row" : "column",
320804
- gap: f2.itemSpacing ?? 0,
320805
- justify: JUSTIFY[f2.primaryAxisAlignItems ?? "MIN"],
320806
- align: ALIGN2[f2.counterAxisAlignItems ?? "MIN"],
320807
- padding: f2.padding ?? { top: 0, right: 0, bottom: 0, left: 0 }
320808
- };
320809
- }
320810
- if (node2.type === "TEXT") {
320811
- const t3 = node2;
320812
- const solid5 = (t3.fills ?? []).find((p2) => p2.visible !== false && p2.type === "SOLID" && p2.color);
320813
- web.text = {
320814
- characters: t3.characters ?? "",
320815
- align: t3.textAlign,
320816
- fontFamily: t3.fontFamily,
320817
- fontSize: t3.fontSize,
320818
- fontWeight: t3.fontWeight,
320819
- italic: t3.fontStyle === "italic",
320820
- ...solid5?.color ? { color: toHex(solid5.color) } : {},
320821
- ...t3.letterSpacing ? { letterSpacing: t3.letterSpacing } : {},
320822
- ...t3.lineHeight !== "AUTO" ? { lineHeight: t3.lineHeight } : {}
320823
- };
320824
- const runs = textRuns(t3);
320825
- if (runs) web.runs = runs;
320826
- }
320827
- const tl = timeline?.get(node2.id);
320828
- const mo = tl ?? motion?.children.get(node2.id);
320829
- if (mo) web.motion = { style: animationStyle(mo, tl ? "load" : motion.trigger), keyframes: keyframesCSS(mo) };
320830
- const ext = getNativeExtension(raw.type);
320831
- if (ext?.toWeb) {
320832
- const said = ext.toWeb(node2, { escape: escapeHTML, color: (c2) => toRgba({ ...c2, a: c2.a ?? 1 }) });
320833
- if (said.tag) web.tag = said.tag;
320834
- Object.assign(style, said.style);
320835
- web.html = said.html;
320836
- hooks.built?.(web, node2, { parent, in3D: in3D2, fold });
320837
- return web;
320838
- }
320839
- const code = opts.target === "site" ? codeOf(doc2.nodes, raw) : null;
320840
- if (code && doc2.codeModules?.[code.moduleId]) {
320841
- for (const k2 of PAINTED) delete style[k2];
320842
- web.code = { module: code.moduleId, ...code.exportName ? { export: code.exportName } : {}, props: codeProps(doc2.nodes, node2) };
320843
- hooks.built?.(web, node2, { parent, in3D: in3D2, fold });
320844
- return web;
320845
- }
320846
- const sprite = opts.target === "site" && raw.type === "INSTANCE" && !raw.id.includes("::") && spriteOnly(doc2.nodes, raw.id) && isLive(doc2.nodes, raw.id);
320847
- if (!exp.css || sprite) {
320848
- for (const k2 of PAINTED) delete style[k2];
320849
- web.asset = { kind: opts.assetKind ?? (exp.needsRaster ? "png" : "svg"), reason: exp.reason || (sprite ? "an animated sprite" : ""), ...item?.suffix ? { of: node2.id } : {} };
320850
- if (isPixelArt(doc2, raw.id)) style["image-rendering"] = "pixelated";
320851
- if (sprite || opts.target === "site" && renderMode(node2, { styles: doc2.styles, live: isLive(doc2.nodes, raw.id) }) === "island") web.island = true;
320852
- hooks.built?.(web, node2, { parent, in3D: in3D2, fold });
320853
- return web;
320854
- }
320855
- const lost = capability(node2, "css", doc2.styles).dropped.find((f3) => f3.startsWith("paint:"));
320856
- if (lost && !node2.id.includes("::")) {
320857
- const site = opts.target === "site";
320858
- style.isolation = "isolate";
320859
- web.children.push({
320860
- id: `${node2.id}/backdrop${item?.suffix ?? ""}`,
320861
- name: `${web.name} fill`,
320862
- type: "BACKDROP",
320863
- x: 0,
320864
- y: 0,
320865
- width: web.width,
320866
- height: web.height,
320867
- positioning: "absolute",
320868
- ...site ? { place: { position: "absolute", inset: "0" } } : {},
320869
- style: { ...site ? {} : { width: `${web.width}px`, height: `${web.height}px` }, "border-radius": "inherit", overflow: "hidden", "z-index": "-1", "pointer-events": "none" },
320870
- alt: "",
320871
- asset: { kind: "png", reason: featureName(lost), of: node2.id, self: true },
320872
- ...site && movesItself(raw) ? { island: true } : {},
320873
- children: []
320874
- });
320875
- }
320876
- const outer = motion;
320877
- if (!motion && node2.type === "INSTANCE" && !opts.static) {
320878
- motion = instanceWebMotion(doc2, node2, (n) => stylesOf(prepared(n, doc2)));
320879
- if (motion && (motion.trigger !== "load" || opts.target === "site")) web.motionTrigger = motion.trigger;
320880
- }
320881
- try {
320882
- if (opts.includeChildren !== false) {
320883
- const kids3D = in3D2 ? through : is3DContext(raw) && !raw.id.includes("::");
320884
- const kidFold = through ? fold + 1 : 0;
320885
- const repeat = raw.repeat;
320886
- const collection = repeat && doc2.collections?.[repeat.collectionId];
320887
- if (repeat && collection && opts.target === "site") {
320888
- const outerItem = item;
320889
- const under = outerItem ? scopeOf2(outerItem) : withData(variablesScope(doc2.variables, doc2.variableCollections, doc2.activeVariableModes), doc2);
320890
- try {
320891
- for (const record2 of repeatRecords(doc2, repeat, under)) {
320892
- item = { collection, record: record2, suffix: `${outerItem?.suffix ?? ""}~${record2.id}` };
320893
- for (const child of childrenOf(node2, doc2.nodes)) {
320894
- const built = build3(child, node2, kids3D, kidFold);
320895
- if (built) web.children.push(built);
320896
- }
320897
- }
320898
- if (collection.perVisitor && !outerItem || collection.schema && opts.listTemplates) {
320899
- item = { collection, record: templateRecord(collection), suffix: `~${ITEM_RECORD}` };
320900
- const template2 = [];
320901
- for (const child of childrenOf(node2, doc2.nodes)) {
320902
- const built = build3(child, node2, kids3D, kidFold);
320903
- if (built) template2.push(built);
320904
- }
320905
- const sortField = repeat.sort && collection.fields.find((f3) => f3.id === repeat.sort.fieldId);
320906
- web.repeat = {
320907
- collectionId: collection.id,
320908
- template: template2,
320909
- ...repeat.filter?.trim() ? { filter: repeat.filter } : {},
320910
- ...sortField ? { sort: { key: fieldKey(sortField.name), dir: repeat.sort.dir } } : {},
320911
- ...repeat.offset ? { offset: repeat.offset } : {},
320912
- ...repeat.limit ? { limit: repeat.limit } : {}
320913
- };
320914
- }
320915
- } finally {
320916
- item = outerItem;
320917
- }
320918
- } else for (const child of childrenOf(node2, doc2.nodes)) {
320919
- const built = build3(child, node2, kids3D, kidFold);
320920
- if (built) web.children.push(built);
320921
- }
320922
- }
320923
- } finally {
320924
- motion = outer;
320925
- }
320926
- if (web.children.some((c2) => c2.positioning === "absolute")) {
320927
- for (const c2 of web.children) if (c2.positioning === "flow") c2.layered = true;
320928
- }
320929
- hooks.built?.(web, node2, { parent, in3D: in3D2, fold });
320930
- return web;
320931
- };
320932
- const root2 = build3(first2, start2?.parent ?? null, start2?.in3D ?? false, start2?.fold ?? 0);
320933
- if (!root2) throw new Error("Node cap of 0");
320934
- return { root: root2, truncated, ...folds ? { rules: foldRules(folds) } : {}, ...tokens?.vars.length ? { tokens } : {} };
320935
- }
320936
- function childLookup(doc2, id3) {
320937
- const at3 = id3.lastIndexOf("::");
320938
- const host = at3 > 0 ? id3.slice(0, at3) : "";
320939
- const hostNode = doc2.nodes[host] ?? (host.includes("::") ? childLookup(doc2, host) : void 0);
320940
- return hostNode ? childrenOf(hostNode, doc2.nodes).find((c2) => c2.id === id3) : void 0;
320941
- }
320942
- function flatten2(node2, out = []) {
320943
- out.push(node2);
320944
- for (const c2 of node2.children) flatten2(c2, out);
320945
- return out;
320946
- }
320947
- var DEFAULT_NODE_CAP, PAINTED, anchorMemo, followsVisibility, isFlex, round3, foldVar, foldRules, clickable;
320948
- var init_tree = __esm({
320949
- "lib/io/web/tree.ts"() {
320950
- "use strict";
320951
- init_pixel_art();
320952
- init_instance_layout();
320953
- init_text_styles();
320954
- init_variables();
320955
- init_scene3d();
320956
- init_semantics();
320957
- init_commerce();
320958
- init_collections();
320959
- init_props();
320960
- init_native_registry();
320961
- init_controls();
320962
- init_expressions2();
320963
- init_children();
320964
- init_css();
320965
- init_capability();
320966
- init_expressible();
320967
- init_motion();
320968
- init_element();
320969
- init_paint2();
320970
- init_responsive();
320971
- init_richtext();
320972
- init_tokens2();
320973
- init_timeline();
320974
- init_interactive();
320975
- DEFAULT_NODE_CAP = 120;
320976
- PAINTED = ["background", "border", "border-style", "border-color", "border-width", "outline", "border-radius", "box-shadow", "box-sizing", "filter", "backdrop-filter"];
320977
- anchorMemo = /* @__PURE__ */ new WeakMap();
320978
- followsVisibility = (n) => !!n.boundVariables?.visible || !!n.boundExpressions?.visible || // Hidden in the design and shown at a breakpoint: on the page, for the media query that shows it.
320979
- Object.values(n.responsive ?? {}).some((o) => o.visible === true) || // A game's win banner (LayerPhysics role 'win') and a player's run and jump poses: hidden in the design, shown by
320980
- // the platformer on winning or as the player moves.
320981
- n.physics?.role === "win" || n.physics?.role === "pose" || n.physics?.role === "reveal";
320982
- isFlex = (f2) => f2?.layoutMode === "HORIZONTAL" || f2?.layoutMode === "VERTICAL";
320983
- round3 = (v) => Math.round(v * 1e3) / 1e3;
320984
- foldVar = (depth2) => `--pc-f${depth2}`;
320985
- foldRules = (depth2) => Array.from({ length: depth2 }, (_, i2) => `@property ${foldVar(i2 + 1)} { syntax: '<number>'; inherits: true; initial-value: 1; }`);
320986
- clickable = (n) => !!n.semantics?.link || (n.interactions ?? []).some((ix) => ix.trigger === "ON_CLICK" || ix.trigger === "ON_PRESS");
320987
- }
320988
- });
320989
-
320990
- // lib/io/web/interactive.ts
320991
- function subtreeIds(doc2, id3, out = /* @__PURE__ */ new Set()) {
320992
- if (out.has(id3)) return out;
320993
- const n = doc2.nodes[id3];
320994
- if (!n) return out;
320995
- out.add(id3);
320996
- if (n.type === "INSTANCE") subtreeIds(doc2, n.mainComponentId, out);
320997
- for (const c2 of n.childIds ?? []) subtreeIds(doc2, c2, out);
320998
- return out;
320999
- }
321000
- function flowScreens(doc2, startId) {
321001
- const start2 = doc2.nodes[startId];
321002
- if (!start2 || start2.type !== "FRAME" || doc2.nodes[start2.parentId ?? ""]?.type !== "PAGE") return [startId];
321003
- const out = [startId];
321004
- for (let i2 = 0; i2 < out.length; i2++) {
321005
- for (const id3 of subtreeIds(doc2, out[i2])) {
321006
- for (const ix of interactionsOf(doc2.nodes[id3])) {
321007
- const to = ix.action.navigationType === "NAVIGATE" ? ix.action.destinationId : null;
321008
- const dest = to ? doc2.nodes[to] : void 0;
321009
- if (!dest || out.includes(dest.id) || dest.type !== "FRAME" || doc2.nodes[dest.parentId ?? ""]?.type !== "PAGE") continue;
321010
- if (Math.round(dest.width) !== Math.round(start2.width) || Math.round(dest.height) !== Math.round(start2.height)) continue;
321011
- out.push(dest.id);
321012
- }
321013
- }
321014
- }
321015
- return out;
321016
- }
321017
- function variantStates(doc2, mainId) {
321018
- const out = [mainId];
321019
- for (let i2 = 0; i2 < out.length; i2++) {
321020
- for (const id3 of subtreeIds(doc2, out[i2])) {
321021
- for (const ix of interactionsOf(doc2.nodes[id3])) {
321022
- const to = ix.action.navigationType === "CHANGE_TO" ? ix.action.destinationId : null;
321023
- if (to && !out.includes(to) && doc2.nodes[to]?.type === "COMPONENT") out.push(to);
321024
- }
321025
- }
321026
- }
321027
- return out;
321028
- }
321029
- function buildState(ctx2, doc2, id3, machine, state, start2, variantOf2) {
321030
- const expand = /* @__PURE__ */ new Map();
321031
- const tree = buildPlainTree(doc2, id3, ctx2.opts, start2, { built: (web, _node, at3) => {
321032
- if (web.type === "INSTANCE") expand.set(web, at3);
321033
- } });
321034
- for (const r of tree.rules ?? []) ctx2.rules.add(r);
321035
- if (tree.truncated) ctx2.truncated = true;
321036
- const ids2 = /* @__PURE__ */ new Map();
321037
- const index2 = (w) => {
321038
- ids2.set(w.id, w);
321039
- w.children.forEach(index2);
321040
- };
321041
- index2(tree.root);
321042
- const visit2 = (w, owner, st, isRoot) => {
321043
- w.owner = owner;
321044
- w.looks = { [st]: lookOf(w, isRoot) };
321045
- if (w.motion) ctx2.keyframes.add(w.motion.keyframes);
321046
- const node2 = nodeOf(doc2, w.id);
321047
- note(ctx2, w, interactionsOf(doc2.nodes[realId(w.id)]), owner, st, ids2);
321048
- const at3 = expand.get(w);
321049
- const inst = node2?.type === "INSTANCE" ? node2 : void 0;
321050
- const states = inst && at3 && ctx2.depth < 4 ? variantStates(doc2, inst.mainComponentId) : [];
321051
- if (inst && at3 && states.length > 1 && w.id !== variantOf2) {
321052
- const m = { id: `m${ctx2.machines.length}`, initial: inst.mainComponentId, states: states.map((s) => ({ id: s, name: stateName(doc2, s) })) };
321053
- ctx2.machines.push(m);
321054
- w.machine = m;
321055
- const perState = [];
321056
- for (const s of states) {
321057
- let kids;
321058
- if (s === inst.mainComponentId) {
321059
- kids = w.children;
321060
- kids.forEach((c2) => visit2(c2, m.id, s, false));
321061
- } else {
321062
- const shown2 = { ...doc2, nodes: { ...doc2.nodes, [inst.id]: { ...inst, mainComponentId: s } } };
321063
- ctx2.depth++;
321064
- try {
321065
- kids = buildState(ctx2, shown2, inst.id, m.id, s, at3, inst.id).children;
321066
- } finally {
321067
- ctx2.depth--;
321068
- }
321069
- }
321070
- note(ctx2, w, interactionsOf(doc2.nodes[s]), m.id, s, ids2, m.id);
321071
- perState.push([s, kids]);
321072
- }
321073
- w.children = mergeChildren(perState, m.id, m.states.map((s) => s.id), ctx2);
321074
- } else if (w.id === variantOf2) {
321075
- w.children.forEach((c2) => visit2(c2, owner, st, false));
321076
- } else {
321077
- if (inst) note(ctx2, w, interactionsOf(doc2.nodes[inst.mainComponentId]), owner, st, ids2);
321078
- w.children.forEach((c2) => visit2(c2, owner, st, false));
321079
- }
321080
- };
321081
- visit2(tree.root, machine, state, !start2);
321082
- return tree.root;
321083
- }
321084
- function note(ctx2, w, list2, machine, state, ids2, hostMachine) {
321085
- if (!list2.length) return;
321086
- const at3 = ctx2.pending.get(w) ?? [];
321087
- for (const ix of list2) at3.push({ machine, state, ix, hostMachine: hostMachine ?? (machine !== FLOW ? machine : void 0), ids: ids2 });
321088
- ctx2.pending.set(w, at3);
321089
- }
321090
- function lookOf(w, isRoot) {
321091
- return {
321092
- style: { ...placementStyle(w, isRoot), ...w.style, ...w.motion?.style ?? {} },
321093
- ...w.text ? { text: w.text.characters } : {},
321094
- ...w.tf ? { tf: w.tf } : {}
321095
- };
321096
- }
321097
- function keyed(kids) {
321098
- const seen = /* @__PURE__ */ new Map();
321099
- return kids.map((k2) => {
321100
- const base = `${k2.name}\0${k2.type}`;
321101
- const i2 = seen.get(base) ?? 0;
321102
- seen.set(base, i2 + 1);
321103
- return [`${base}\0${i2}`, k2];
321104
- });
321105
- }
321106
- function mergeChildren(perState, machine, states, ctx2) {
321107
- const order2 = [];
321108
- const groups = /* @__PURE__ */ new Map();
321109
- for (const [state, kids] of perState) {
321110
- let after = -1;
321111
- for (const [k2, node2] of keyed(kids)) {
321112
- let at3 = order2.indexOf(k2);
321113
- if (at3 < 0) {
321114
- order2.splice(after + 1, 0, k2);
321115
- at3 = after + 1;
321116
- }
321117
- after = at3;
321118
- (groups.get(k2) ?? groups.set(k2, []).get(k2)).push([state, node2]);
321119
- }
321120
- }
321121
- return order2.map((k2) => mergeNode(groups.get(k2), machine, states, ctx2));
321122
- }
321123
- function mergeNode(items, machine, states, ctx2) {
321124
- const [, first2] = items[0];
321125
- if (first2.owner !== machine) {
321126
- for (const [, w] of items.slice(1)) alias(ctx2, w, first2);
321127
- return first2;
321128
- }
321129
- const looks = {};
321130
- for (const s of states) looks[s] = null;
321131
- for (const [s, w] of items) looks[s] = w.looks?.[s] ?? null;
321132
- const merged = { ...first2, looks };
321133
- const pend = items.flatMap(([, w]) => ctx2.pending.get(w) ?? []);
321134
- if (pend.length) ctx2.pending.set(merged, pend);
321135
- for (const [, w] of items) if (w !== merged) alias(ctx2, w, merged);
321136
- if (first2.machine) {
321137
- for (const [, w] of items) if (w.machine && w.machine !== first2.machine) ctx2.renamed.set(w.machine.id, first2.machine.id);
321138
- }
321139
- merged.children = first2.machine ? first2.children : mergeChildren(items.map(([s, w]) => [s, w.children]), machine, states, ctx2);
321140
- return merged;
321141
- }
321142
- function alias(ctx2, from2, to) {
321143
- const a = ctx2.alias ??= /* @__PURE__ */ new Map();
321144
- a.set(from2, to);
321145
- }
321146
- function mergedOf(ctx2, w) {
321147
- const a = ctx2.alias;
321148
- let cur = w;
321149
- for (let i2 = 0; i2 < 16 && a?.has(cur); i2++) cur = a.get(cur);
321150
- return cur;
321151
- }
321152
- function actionOf(ctx2, p2) {
321153
- const a = p2.ix.action;
321154
- const glide2 = glideOf2(a.transition);
321155
- const hold = p2.ix.trigger === "ON_HOVER" || p2.ix.trigger === "ON_PRESS";
321156
- switch (a.navigationType) {
321157
- case "NAVIGATE":
321158
- return a.destinationId && ctx2.screens.has(a.destinationId) ? { kind: "go", machine: FLOW, to: a.destinationId, ...glide2, ...hold ? { hold } : {} } : null;
321159
- case "BACK":
321160
- return ctx2.screens.size > 1 ? { kind: "back", machine: FLOW } : null;
321161
- case "CHANGE_TO":
321162
- return p2.hostMachine && a.destinationId ? { kind: "go", machine: p2.hostMachine, to: a.destinationId, ...glide2, ...hold ? { hold } : {} } : null;
321163
- case "ORBIT_3D": {
321164
- const o = a.orbit ?? {};
321165
- const uidOf = (id3) => {
321166
- const w = id3 ? p2.ids.get(id3) : void 0;
321167
- return w ? mergedOf(ctx2, w).uid : void 0;
321168
- };
321169
- const uid2 = uidOf(a.destinationId);
321170
- const tiltUid = uidOf(o.tiltLayerId) ?? uid2;
321171
- return uid2 === void 0 || tiltUid === void 0 ? null : { kind: "orbit", target: uid2, tiltTarget: tiltUid, degreesPerPx: o.degreesPerPx ?? 0.4, tilt: !!o.tilt, tiltRange: o.tiltRange ?? [-30, 30] };
321172
- }
321173
- default:
321174
- return null;
321175
- }
321176
- }
321177
- function buildWebTree(doc2, nodeId2, opts = {}) {
321178
- const tree = buildTree(doc2, nodeId2, opts);
321179
- const machine = opts.static || opts.stateMachine === false ? null : webStateMachine(doc2, nodeId2);
321180
- return machine ? { ...tree, stateMachine: machine } : tree;
321181
- }
321182
- function buildTree(doc2, nodeId2, opts = {}) {
321183
- if (opts.static || opts.target === "site") return buildPlainTree(doc2, nodeId2, opts);
321184
- const screens = flowScreens(doc2, nodeId2);
321185
- const anything = screens.length > 1 || [...subtreeIds(doc2, nodeId2)].some((id3) => interactionsOf(doc2.nodes[id3]).some((ix) => ix.action.navigationType === "CHANGE_TO" || ix.action.navigationType === "ORBIT_3D"));
321186
- if (!anything) return buildPlainTree(doc2, nodeId2, opts);
321187
- const flow = { id: FLOW, initial: nodeId2, states: screens.map((s) => ({ id: s, name: doc2.nodes[s]?.name ?? s })) };
321188
- const ctx2 = { doc: doc2, opts, screens: new Set(screens), machines: [flow], keyframes: /* @__PURE__ */ new Set(), rules: /* @__PURE__ */ new Set(), pending: /* @__PURE__ */ new Map(), depth: 0, renamed: /* @__PURE__ */ new Map() };
321189
- const roots = screens.map((s) => [s, buildState(ctx2, doc2, s, FLOW, s)]);
321190
- const truncated = !!ctx2.truncated;
321191
- const root2 = mergeNode(roots, FLOW, screens, ctx2);
321192
- let uid2 = 0;
321193
- const number4 = (w) => {
321194
- w.uid = uid2++;
321195
- w.children.forEach(number4);
321196
- };
321197
- number4(root2);
321198
- const place4 = (w) => {
321199
- const pend = ctx2.pending.get(w);
321200
- if (pend) {
321201
- const seen = /* @__PURE__ */ new Set();
321202
- const on = [];
321203
- for (const raw of pend) {
321204
- const p2 = { ...raw, machine: ctx2.renamed.get(raw.machine) ?? raw.machine, ...raw.hostMachine ? { hostMachine: ctx2.renamed.get(raw.hostMachine) ?? raw.hostMachine } : {} };
321205
- const trigger = TRIGGERS[p2.ix.trigger];
321206
- const action3 = trigger ? actionOf(ctx2, p2) : null;
321207
- if (!trigger || !action3) continue;
321208
- const ix = { machine: p2.machine, state: p2.state, trigger, ...p2.ix.triggerDelay ? { delay: p2.ix.triggerDelay } : {}, ...p2.ix.triggerKey ? { key: p2.ix.triggerKey } : {}, action: action3 };
321209
- const sig = JSON.stringify(ix);
321210
- if (!seen.has(sig)) {
321211
- seen.add(sig);
321212
- on.push(ix);
321213
- }
321214
- }
321215
- if (on.length) w.on = on;
321216
- }
321217
- w.children.forEach(place4);
321218
- };
321219
- place4(root2);
321220
- return { root: root2, truncated, ...ctx2.rules.size ? { rules: [...ctx2.rules].sort() } : {}, interactive: { machines: ctx2.machines.filter((m) => !ctx2.renamed.has(m.id)), keyframes: [...ctx2.keyframes] } };
321221
- }
321222
- var FLOW, interactionsOf, realId, nodeOf, stateName, TRIGGERS, EASINGS2, glideOf2;
321223
- var init_interactive = __esm({
321224
- "lib/io/web/interactive.ts"() {
321225
- "use strict";
321226
- init_scene_graph();
321227
- init_tree();
321228
- init_state_machine3();
321229
- init_element();
321230
- FLOW = "flow";
321231
- interactionsOf = (n) => n?.interactions ?? [];
321232
- realId = (id3) => id3.includes("::") ? id3.slice(id3.lastIndexOf("::") + 2) : id3;
321233
- nodeOf = (doc2, id3) => doc2.nodes[id3] ?? (id3.includes("::") ? resolveVirtualNode2(doc2.nodes, id3) ?? void 0 : void 0);
321234
- stateName = (doc2, id3) => {
321235
- const n = doc2.nodes[id3];
321236
- const v = n?.variantProperties;
321237
- return v ? Object.values(v).join(", ") : n?.name ?? id3;
321238
- };
321239
- TRIGGERS = {
321240
- ON_CLICK: "click",
321241
- ON_HOVER: "hover",
321242
- ON_PRESS: "press",
321243
- ON_DRAG: "drag",
321244
- MOUSE_ENTER: "enter",
321245
- MOUSE_LEAVE: "leave",
321246
- AFTER_TIMEOUT: "timeout",
321247
- KEY_DOWN: "key"
321248
- };
321249
- EASINGS2 = { EASE_IN: "ease-in", EASE_OUT: "ease-out", EASE_IN_OUT: "ease-in-out", LINEAR: "linear", SPRING: "cubic-bezier(0.34, 1.56, 0.64, 1)" };
321250
- glideOf2 = (t3) => !t3 || t3.type === "INSTANT" || t3.type === "CUT" ? { ms: 0, easing: "linear" } : { ms: Math.max(0, Math.round(t3.duration)), easing: EASINGS2[t3.easing] ?? "ease-in-out" };
321251
- }
321252
- });
321253
-
321254
321163
  // lib/io/web/site.ts
321255
321164
  function light(node2) {
321256
321165
  const out = {};
@@ -321474,7 +321383,7 @@ var init_site = __esm({
321474
321383
  init_fonts3();
321475
321384
  init_slice();
321476
321385
  init_render();
321477
- init_state_machine3();
321386
+ init_state_machine2();
321478
321387
  init_physics();
321479
321388
  init_interactive();
321480
321389
  init_tree();
@@ -345136,6 +345045,7 @@ function exportsOf(source3) {
345136
345045
  var CODE_LIMITS, packageOf;
345137
345046
  var init_source2 = __esm({
345138
345047
  "lib/code/source.ts"() {
345048
+ "use strict";
345139
345049
  CODE_LIMITS = { modules: 100, sourceLength: 2e5, packages: 12 };
345140
345050
  packageOf = (spec) => spec.split("/").slice(0, spec.startsWith("@") ? 2 : 1).join("/");
345141
345051
  }
@@ -345178,6 +345088,7 @@ function compileModule(module2) {
345178
345088
  var import_sucrase, BUILT_IN, memo4;
345179
345089
  var init_compile2 = __esm({
345180
345090
  "lib/code/compile.ts"() {
345091
+ "use strict";
345181
345092
  import_sucrase = __toESM(require_dist2());
345182
345093
  init_source2();
345183
345094
  init_source2();
@@ -345760,6 +345671,7 @@ __export(web_exports, {
345760
345671
  CODE_FORMAT_IDS: () => CODE_FORMAT_IDS,
345761
345672
  DEFAULT_NODE_CAP: () => DEFAULT_NODE_CAP,
345762
345673
  EMAIL_DEFAULT_WIDTH: () => EMAIL_DEFAULT_WIDTH,
345674
+ EXPORT_NODE_CAP: () => EXPORT_NODE_CAP,
345763
345675
  WEB_LANGUAGES: () => WEB_LANGUAGES,
345764
345676
  assetKindFor: () => assetKindFor,
345765
345677
  buildWebSite: () => buildWebSite,
@@ -347108,24 +347020,6 @@ var init_board_export = __esm({
347108
347020
  });
347109
347021
 
347110
347022
  // lib/commands/export.ts
347111
- var export_exports2 = {};
347112
- __export(export_exports2, {
347113
- EXPORT_NODE_CAP: () => EXPORT_NODE_CAP,
347114
- exportBoard: () => exportBoard,
347115
- exportCopy: () => exportCopy,
347116
- exportGif: () => exportGif,
347117
- exportLottie: () => exportLottie2,
347118
- exportMp4: () => exportMp4,
347119
- exportNodes: () => exportNodes,
347120
- exportPages: () => exportPages,
347121
- exportPdf: () => exportPdf,
347122
- exportPngSequence: () => exportPngSequence,
347123
- exportPptx: () => exportPptx,
347124
- exportStorefront: () => exportStorefront,
347125
- exportSvg: () => exportSvg,
347126
- exportWeb: () => exportWeb,
347127
- exportWebm: () => exportWebm
347128
- });
347129
347023
  function animationTarget(args2, ctx2, doc2) {
347130
347024
  if (args2.composition) {
347131
347025
  if (!doc2.compositions?.[args2.composition]) throw new ToolError(`There is no composition "${args2.composition}".`);
@@ -347233,7 +347127,7 @@ async function exportSite(doc2, pageId2, packaging, styling = "css") {
347233
347127
  downloadBlob2(zipFiles2(files.map((f2) => ({ name: f2.path, bytes: bytesOf2(f2) }))), `${base}.zip`);
347234
347128
  return { summary: `Exported ${plural2(site.pages.length, "page")} as ${packaging === "next" ? "a Next.js project" : "a static site"} (${base}.zip)`, data: { filename: `${base}.zip`, packaging, pages: site.pages.map((p2) => p2.route), files: files.length } };
347235
347129
  }
347236
- var MAX_INLINE_BYTES, exportSvg, exportNodes, exportPdf, exportCopy, exportPages, exportPptx, animationParams, videoParams, gifParams, lottieParams, animationCommand, TARGET, exportMp4, exportWebm, exportGif, exportPngSequence, exportLottie2, EXPORT_NODE_CAP, exportWeb, exportStorefront, exportBoard;
347130
+ var MAX_INLINE_BYTES, exportSvg, exportNodes, exportPdf, exportCopy, exportPages, exportPptx, animationParams, videoParams, gifParams, lottieParams, animationCommand, TARGET, exportMp4, exportWebm, exportGif, exportPngSequence, exportLottie2, exportWeb, APP_STOREFRONT_TARGETS, exportStorefront, exportBoard;
347237
347131
  var init_export2 = __esm({
347238
347132
  "lib/commands/export.ts"() {
347239
347133
  "use strict";
@@ -347246,6 +347140,7 @@ var init_export2 = __esm({
347246
347140
  init_markers();
347247
347141
  init_doc_helpers();
347248
347142
  init_formats();
347143
+ init_tree();
347249
347144
  MAX_INLINE_BYTES = 15e5;
347250
347145
  exportSvg = defineCommand({
347251
347146
  id: "export.svg",
@@ -347594,7 +347489,6 @@ var init_export2 = __esm({
347594
347489
  name: "export_lottie",
347595
347490
  description: `Write ${TARGET.replace(" and \u2014 for video \u2014 its sound", "")} as a Lottie (bodymovin JSON, or a .lottie zip) the user downloads: vector shapes, fills, strokes, masks, text as outlines and images as embedded assets, with our keys and bezier / hold easing where Lottie can say them and every other curve, behaviour and text animator keyed frame by frame. Refuses what Lottie cannot carry (shader fills, blurs, glass, halftone, 3D, video) and lists what it baked. The timeline's markers go in as Lottie markers; a .lottie also carries the frame's state machine. Options: frame rate, range, container, stateMachine.`
347596
347491
  });
347597
- EXPORT_NODE_CAP = 2e4;
347598
347492
  exportWeb = defineCommand({
347599
347493
  id: "export.web",
347600
347494
  title: "Export as web code",
@@ -347639,6 +347533,7 @@ var init_export2 = __esm({
347639
347533
  return { summary: `Exported ${node2.name || "layer"} as ${filename}`, data: { filename, format, bytes: markup.length, truncated: tree.truncated } };
347640
347534
  }
347641
347535
  });
347536
+ APP_STOREFRONT_TARGETS = STOREFRONT_TARGET_IDS.filter((t3) => t3 !== "shopify-theme");
347642
347537
  exportStorefront = defineCommand({
347643
347538
  id: "export.storefront",
347644
347539
  title: "Export storefront",
@@ -347647,21 +347542,20 @@ var init_export2 = __esm({
347647
347542
  permission: "export",
347648
347543
  needs: ["canvas"],
347649
347544
  params: external_exports.object({
347650
- target: external_exports.enum(STOREFRONT_TARGET_IDS).default("next-commerce").describe("next-commerce-store: a whole Next.js Commerce store drawn by the design, to deploy with a Shopify store's domain and Storefront token (publish_store deploys it for you). next-commerce: React components a Next.js Commerce store renders with its own data and server actions. shopify-theme: an Online Store 2.0 theme (Liquid) to upload in the store's admin, running on Shopify with its own cart and checkout."),
347545
+ target: external_exports.enum(APP_STOREFRONT_TARGETS).default("next-commerce").describe("next-commerce-store: a whole Next.js Commerce store drawn by the design, to deploy with a Shopify store's domain and Storefront token (publish_store deploys it for you). next-commerce: React components a Next.js Commerce store renders with its own data and server actions. A Shopify theme is the Ecommerce plugin's."),
347651
347546
  styling: external_exports.enum(["inline", "tailwind"]).optional().describe("next-commerce: style objects (default) or Tailwind CSS v4 classes."),
347652
347547
  dir: external_exports.string().max(200).optional().describe("next-commerce: where the components go in the store's project (default components/popcraft).")
347653
347548
  }).strict(),
347654
347549
  expose: {
347655
347550
  ui: {
347656
347551
  label: "Export storefront\u2026",
347657
- keywords: ["commerce", "shopify", "theme", "liquid", "store", "shop", "next", "react", "components", "export"],
347552
+ keywords: ["commerce", "shopify", "store", "shop", "next", "react", "components", "export"],
347658
347553
  variants: [
347659
347554
  { id: "next-commerce-store", label: "Export storefront as a Next.js Commerce store", params: { target: "next-commerce-store" } },
347660
- { id: "next-commerce", label: "Export storefront as Next.js Commerce components", params: { target: "next-commerce" } },
347661
- { id: "shopify-theme", label: "Export storefront as a Shopify theme", params: { target: "shopify-theme" } }
347555
+ { id: "next-commerce", label: "Export storefront as Next.js Commerce components", params: { target: "next-commerce" } }
347662
347556
  ]
347663
347557
  },
347664
- agent: { name: "export_storefront", readOnly: false, description: "Download a storefront design (a page whose lists and pages read collections with a commerce schema) as a store's project, in a zip. target next-commerce-store: the whole Next.js Commerce app (Shopify client, cart, checkout, a page per screen), ready to deploy. target next-commerce: a React component per screen, each list a typed prop of Next.js Commerce's own types, each storefront form (addToCart, updateCartLine, removeCartLine, checkout, search) an action prop for a server action. target shopify-theme: an Online Store 2.0 theme, each screen a section and template (home: index, a page about a product: product, about a category: collection, search, cart), each list a Liquid loop over the store's products, cart or menu, each form posting to Shopify's cart; uploaded in Online Store \u203A Themes. With no store data a Next.js Commerce component draws the design's samples." }
347558
+ agent: { name: "export_storefront", readOnly: false, description: "Download a storefront design (a page whose lists and pages read collections with a commerce schema) as a store's project, in a zip. target next-commerce-store: the whole Next.js Commerce app (Shopify client, cart, checkout, a page per screen), ready to deploy. target next-commerce: a React component per screen, each list a typed prop of Next.js Commerce's own types, each storefront form (addToCart, updateCartLine, removeCartLine, checkout, search) an action prop for a server action. With no store data a Next.js Commerce component draws the design's samples." }
347665
347559
  },
347666
347560
  run: async (args2, ctx2) => {
347667
347561
  const doc2 = ctx2.doc();
@@ -353593,7 +353487,6 @@ __export(integrations_exports, {
353593
353487
  attachDatabase: () => attachDatabase,
353594
353488
  connectWithOAuth: () => connectWithOAuth,
353595
353489
  connectWithToken: () => connectWithToken,
353596
- connectedStore: () => connectedStore,
353597
353490
  createDatabase: () => createDatabase,
353598
353491
  createDestination: () => createDestination,
353599
353492
  createResource: () => createResource,
@@ -353609,8 +353502,7 @@ __export(integrations_exports, {
353609
353502
  listWorkspaceIntegrations: () => listWorkspaceIntegrations,
353610
353503
  removeDestination: () => removeDestination,
353611
353504
  setSignIn: () => setSignIn,
353612
- siteBackend: () => siteBackend,
353613
- storeProducts: () => storeProducts
353505
+ siteBackend: () => siteBackend
353614
353506
  });
353615
353507
  function connectWithOAuth(workspaceId, provider2) {
353616
353508
  const popup = window.open("", "popcraft-integration", "popup,width=640,height=760");
@@ -353647,7 +353539,7 @@ async function sha12(bytes2) {
353647
353539
  const digest = await crypto.subtle.digest("SHA-1", bytes2);
353648
353540
  return [...new Uint8Array(digest)].map((b) => b.toString(16).padStart(2, "0")).join("");
353649
353541
  }
353650
- async function deployStore(key5, id3, files, shopifyConnectionId, onProgress) {
353542
+ async function deployStore(key5, id3, files, env, onProgress) {
353651
353543
  const listed = await Promise.all(files.map(async (f2) => ({ path: f2.path, sha: await sha12(f2.bytes), size: f2.bytes.length, bytes: f2.bytes })));
353652
353544
  const queue2 = [...new Map(listed.map((f2) => [f2.sha, f2])).values()];
353653
353545
  const total2 = queue2.length;
@@ -353658,18 +353550,9 @@ async function deployStore(key5, id3, files, shopifyConnectionId, onProgress) {
353658
353550
  onProgress?.(++done, total2);
353659
353551
  }
353660
353552
  }));
353661
- return (await api(`/api/sites/${key5}/destinations/${id3}/store`, { method: "POST", json: { shopifyConnectionId, files: listed.map(({ path, sha, size: size6 }) => ({ path, sha, size: size6 })) } })).deploy;
353662
- }
353663
- async function connectedStore(connectionId) {
353664
- if (connectionId) return connectionId;
353665
- const workspaceId = integrationsWorkspaceId();
353666
- if (!workspaceId) throw new Error("Your workspaces have not loaded yet. Try again in a moment.");
353667
- const stores2 = (await listWorkspaceIntegrations(workspaceId)).integrations.filter((i2) => i2.manifest.capabilities.includes("commerce")).flatMap((i2) => i2.connections);
353668
- if (!stores2.length) throw new Error("No store is connected. Connect Shopify in Integrations first.");
353669
- if (stores2.length > 1) throw new Error(`Name the store: ${stores2.map((c2) => `${c2.account} (${c2.id})`).join(", ")}.`);
353670
- return stores2[0].id;
353671
- }
353672
- var integrationsWorkspaceId, listWorkspaceIntegrations, connectWithToken, disconnect, listResources, createResource, listDestinations, addDestination, removeDestination, deployDestination, siteBackend, attachDatabase, setSignIn, detachDatabase, listSubmissions, listCandidates, createDatabase, createDestination, storeProducts;
353553
+ return (await api(`/api/sites/${key5}/destinations/${id3}/store`, { method: "POST", json: { env, files: listed.map(({ path, sha, size: size6 }) => ({ path, sha, size: size6 })) } })).deploy;
353554
+ }
353555
+ var integrationsWorkspaceId, listWorkspaceIntegrations, connectWithToken, disconnect, listResources, createResource, listDestinations, addDestination, removeDestination, deployDestination, siteBackend, attachDatabase, setSignIn, detachDatabase, listSubmissions, listCandidates, createDatabase, createDestination;
353673
353556
  var init_integrations = __esm({
353674
353557
  "lib/client/cloud/integrations.ts"() {
353675
353558
  init_api4();
@@ -353692,7 +353575,48 @@ var init_integrations = __esm({
353692
353575
  listCandidates = async (workspaceId, capability2) => (await api(`/api/workspaces/${encodeURIComponent(workspaceId)}/integrations/candidates?capability=${capability2}`)).candidates;
353693
353576
  createDatabase = (key5, provider2, connectionId) => api(`/api/sites/${key5}/backend`, { method: "PUT", json: { create: true, ...provider2 ? { provider: provider2 } : {}, ...connectionId ? { connectionId } : {} } });
353694
353577
  createDestination = async (key5, capability2, provider2, connectionId) => (await api(`/api/sites/${key5}/destinations`, { method: "POST", json: { create: true, capability: capability2, ...provider2 ? { provider: provider2 } : {}, ...connectionId ? { connectionId } : {} } })).destination;
353695
- storeProducts = async (connectionId, first2) => (await api(`/api/integrations/connections/${encodeURIComponent(connectionId)}/products?first=${first2}`)).products;
353578
+ }
353579
+ });
353580
+
353581
+ // lib/client/cloud/publish-store.ts
353582
+ var publish_store_exports = {};
353583
+ __export(publish_store_exports, {
353584
+ deployOpenStore: () => deployOpenStore,
353585
+ isStorefront: () => isStorefront
353586
+ });
353587
+ async function deployOpenStore(doc2, pageId2, o = {}) {
353588
+ const [{ openFileKey: openFileKey2 }, { uploadActiveDocument: uploadActiveDocument2 }, cloud, { storefrontInputs: storefrontInputs2 }, { nextCommerceFiles: nextCommerceFiles2 }, { bytesOf: bytesOf2 }] = await Promise.all([
353589
+ Promise.resolve().then(() => (init_publish_site(), publish_site_exports)),
353590
+ Promise.resolve().then(() => (init_sync2(), sync_exports2)),
353591
+ Promise.resolve().then(() => (init_integrations(), integrations_exports)),
353592
+ Promise.resolve().then(() => (init_storefront_prepare(), storefront_prepare_exports)),
353593
+ Promise.resolve().then(() => (init_next_commerce(), next_commerce_exports)),
353594
+ Promise.resolve().then(() => (init_project(), project_exports))
353595
+ ]);
353596
+ if (!isStorefront(doc2)) throw new Error("This file is not a storefront: set a collection to Store products in Collections, or start from a Storefronts template.");
353597
+ const env = doc2.site?.env ?? {};
353598
+ if (!env.SHOPIFY_STORE_DOMAIN || !env.SHOPIFY_STOREFRONT_ACCESS_TOKEN) throw new Error("This store does not say which Shopify store it sells from: connect one in the Ecommerce plugin (it sets SHOPIFY_STORE_DOMAIN and SHOPIFY_STOREFRONT_ACCESS_TOKEN in the site environment).");
353599
+ o.onStep?.("Building the store\u2026");
353600
+ const { screens, media: media2 } = await storefrontInputs2(doc2, pageId2, EXPORT_NODE_CAP);
353601
+ if (!screens.length) throw new Error("This page has no screens: a top-level frame is a page of the store.");
353602
+ const key5 = openFileKey2() ?? await uploadActiveDocument2();
353603
+ const all4 = await cloud.listDestinations(key5);
353604
+ let dest = o.destinationId ? all4.find((d) => d.id === o.destinationId) : all4.find((d) => d.capability === "deploy");
353605
+ if (o.destinationId && !dest) throw new Error(`This file has no destination ${o.destinationId}.`);
353606
+ if (!dest) {
353607
+ o.onStep?.("Making a Vercel project\u2026");
353608
+ dest = await cloud.createDestination(key5, "deploy", "vercel");
353609
+ }
353610
+ const files = nextCommerceFiles2(doc2, screens, { media: media2 }).map((f2) => ({ path: f2.path, bytes: bytesOf2(f2) }));
353611
+ const project = dest.target.map((t3) => t3.name).join(" / ");
353612
+ const done = await cloud.deployStore(key5, dest.id, files, env, (n, total2) => o.onStep?.(`Sending files ${n} of ${total2}\u2026`));
353613
+ return { ...done, destinationId: dest.id, project, files: files.length, pages: screens.map((s) => s.name) };
353614
+ }
353615
+ var isStorefront;
353616
+ var init_publish_store = __esm({
353617
+ "lib/client/cloud/publish-store.ts"() {
353618
+ init_tree();
353619
+ isStorefront = (doc2) => Object.values(doc2.collections ?? {}).some((c2) => c2.schema === "commerce.product");
353696
353620
  }
353697
353621
  });
353698
353622
 
@@ -353821,55 +353745,28 @@ var init_publish = __esm({
353821
353745
  permission: null,
353822
353746
  needs: ["canvas"],
353823
353747
  params: external_exports.object({
353824
- shopifyConnectionId: external_exports.string().optional().describe("The Shopify store it sells from, from list_integrations (capability commerce). Omit when one store is connected."),
353825
353748
  destinationId: external_exports.string().optional().describe("The Vercel project to deploy to (a deploy destination, from get_site_status). Omit: the file's deploy destination, or a new project named after the file.")
353826
353749
  }),
353827
353750
  confirm: {
353828
353751
  level: "confirm",
353829
353752
  summary: () => "Deploy this page as a store selling your Shopify products",
353830
- detail: () => "The page becomes a Next.js Commerce store on Vercel, its products, cart and checkout your Shopify store's. A Vercel project is made for it when the file has none, and your store's address and Storefront token are set as that project's environment. Visitors can buy from it once it is live."
353753
+ detail: () => "The page becomes a Next.js Commerce store on Vercel, its products, cart and checkout your Shopify store's. A Vercel project is made for it when the file has none, and the site environment (your store's address and public Storefront token) is set as that project's. Visitors can buy from it once it is live."
353831
353754
  },
353832
353755
  expose: {
353833
353756
  ui: { label: "Publish as a store\u2026", keywords: ["store", "shop", "shopify", "commerce", "next", "vercel", "deploy", "sell", "ecommerce", "checkout", "cart"] },
353834
353757
  agent: {
353835
353758
  name: "publish_store",
353836
- description: "Deploy a storefront design (its lists and pages bound to collections with a commerce schema) as a working store: a Next.js Commerce app on Vercel selling the connected Shopify store's products, with its cart and checkout. Needs a Shopify connection (capability commerce) and a Vercel connection; uses the file's Vercel deploy destination or makes one. Returns the deployment URL (it builds for a minute or two). The user approves every call."
353759
+ description: "Deploy a storefront design (its lists and pages bound to collections with a commerce schema) as a working store: a Next.js Commerce app on Vercel selling the connected Shopify store's products, with its cart and checkout. Needs the site environment to name the Shopify store (SHOPIFY_STORE_DOMAIN, SHOPIFY_STOREFRONT_ACCESS_TOKEN: get_site_environment; the Ecommerce plugin sets them) and a Vercel connection; uses the file's Vercel deploy destination or makes one. Returns the deployment URL (it builds for a minute or two). The user approves every call."
353837
353760
  }
353838
353761
  },
353839
353762
  run: async (p2, ctx2) => {
353840
353763
  await signedIn();
353841
- const [{ openFileKey: openFileKey2 }, { uploadActiveDocument: uploadActiveDocument2 }, cloud, { storefrontInputs: storefrontInputs2 }, { nextCommerceFiles: nextCommerceFiles2 }, { bytesOf: bytesOf2 }, { EXPORT_NODE_CAP: EXPORT_NODE_CAP2 }] = await Promise.all([
353842
- Promise.resolve().then(() => (init_publish_site(), publish_site_exports)),
353843
- Promise.resolve().then(() => (init_sync2(), sync_exports2)),
353844
- Promise.resolve().then(() => (init_integrations(), integrations_exports)),
353845
- Promise.resolve().then(() => (init_storefront_prepare(), storefront_prepare_exports)),
353846
- Promise.resolve().then(() => (init_next_commerce(), next_commerce_exports)),
353847
- Promise.resolve().then(() => (init_project(), project_exports)),
353848
- Promise.resolve().then(() => (init_export2(), export_exports2))
353849
- ]);
353850
- const doc2 = ctx2.doc();
353851
- if (!Object.values(doc2.collections ?? {}).some((c2) => c2.schema === "commerce.product")) throw new CommandError("This file is not a storefront: set a collection to Store products in Collections, or start from a Storefronts template.", "failed");
353852
- const shop = await cloud.connectedStore(p2.shopifyConnectionId).catch((e) => {
353764
+ const { deployOpenStore: deployOpenStore2 } = await Promise.resolve().then(() => (init_publish_store(), publish_store_exports));
353765
+ const done = await deployOpenStore2(ctx2.doc(), ctx2.pageId(), { destinationId: p2.destinationId }).catch((e) => {
353853
353766
  throw new CommandError(e instanceof Error ? e.message : String(e), "failed");
353854
353767
  });
353855
- const { screens, media: media2 } = await storefrontInputs2(doc2, ctx2.pageId(), EXPORT_NODE_CAP2);
353856
- if (!screens.length) throw new CommandError("This page has no screens: a top-level frame is a page of the store.", "failed");
353857
- const key5 = openFileKey2() ?? await uploadActiveDocument2();
353858
- const all4 = await cloud.listDestinations(key5);
353859
- const deploys = all4.filter((d) => d.capability === "deploy");
353860
- let dest = p2.destinationId ? all4.find((d) => d.id === p2.destinationId) : deploys[0];
353861
- if (p2.destinationId && !dest) throw new CommandError(`This file has no destination ${p2.destinationId}.`, "invalid_params");
353862
- if (!dest) {
353863
- ctx2.notice("Making a Vercel project for the store\u2026");
353864
- dest = await cloud.createDestination(key5, "deploy", "vercel");
353865
- }
353866
- const files = nextCommerceFiles2(doc2, screens, { media: media2 }).map((f2) => ({ path: f2.path, bytes: bytesOf2(f2) }));
353867
- const where = dest.target.map((t3) => t3.name).join(" / ");
353868
- const done = await cloud.deployStore(key5, dest.id, files, shop, (n, total2) => {
353869
- if (n === total2) ctx2.notice(`Sent ${total2} files to ${where}: building the store`);
353870
- });
353871
353768
  ctx2.notice(done.status === "failed" ? `The store did not deploy: ${done.error ?? "Vercel refused it"}` : `Store deploying: ${done.url}`);
353872
- return { summary: `Store ${done.status === "ready" ? "is live" : done.status === "building" ? "is building" : "failed"} at ${done.url} (${where}, ${screens.length} ${screens.length === 1 ? "page" : "pages"}, ${files.length} files)`, data: { url: done.url, status: done.status, destinationId: dest.id, project: where, files: files.length, pages: screens.map((s) => s.name) } };
353769
+ return { summary: `Store ${done.status === "ready" ? "is live" : done.status === "building" ? "is building" : "failed"} at ${done.url} (${done.project}, ${done.pages.length} ${done.pages.length === 1 ? "page" : "pages"}, ${done.files} files)`, data: { url: done.url, status: done.status, destinationId: done.destinationId, project: done.project, files: done.files, pages: done.pages } };
353873
353770
  }
353874
353771
  });
353875
353772
  publishCommands = [publishSite2, publishSetVersion, publishStore];
@@ -356276,7 +356173,7 @@ var init_storefront2 = __esm({
356276
356173
  name: "Design a storefront",
356277
356174
  description: "Bind a shop to a store's data and publish or export it for Next.js Commerce or Shopify.",
356278
356175
  whenToUse: "the design should sell",
356279
- tools: ["get_document_outline", "edit_collection", "edit_records", "set_repeat", "set_route", "set_control", "export_storefront", "list_integrations", "open_integrations", "pull_store_products", "ask_user", "manage_todos"],
356176
+ tools: ["get_document_outline", "edit_collection", "edit_records", "set_repeat", "set_route", "set_control", "export_storefront", "list_integrations", "open_integrations", "get_site_environment", "ask_user", "manage_todos"],
356280
356177
  instructions: `# Design a storefront
356281
356178
 
356282
356179
  PopCraft draws the shop; a Next.js Commerce store runs it. The store keeps Shopify, the cart, checkout and search;
@@ -356292,9 +356189,8 @@ are whole stores to begin from.
356292
356189
  - \`commerce.product\` for products (title, handle, url, description, price, image, variant_id\u2026)
356293
356190
  - \`commerce.cartLine\` for the cart's lines, \`commerce.cart\` for its count and totals (one record)
356294
356191
  - \`commerce.menu\` for the store's menu, \`commerce.collection\` for its categories
356295
- Add a few real sample records with \`edit_records\`: the canvas is drawn with them. When the user has a Shopify
356296
- store, draw the design with its real products instead: \`list_integrations\` (capability commerce) for a connected
356297
- store, then \`pull_store_products\`. You cannot connect a store yourself: say why it helps and \`open_integrations\`.
356192
+ Add a few real sample records with \`edit_records\`: the canvas is drawn with them. A store's real catalogue
356193
+ comes from the Ecommerce plugin (Marketplace \u203A Plugins): it fills these collections from Shopify.
356298
356194
  3. **The lists.** \`set_repeat\` on the frame that holds one card, over the collection; the card's texts say
356299
356195
  \`{{item.title}}\`, \`{{item.price}}\`, and its picture follows \`item_image\`. The cart's totals are a list of one
356300
356196
  (\`limit: 1\`) over the \`commerce.cart\` collection.
@@ -356306,12 +356202,13 @@ are whole stores to begin from.
356306
356202
  - \`checkout\`
356307
356203
  - \`search\`: a field named \`q\`
356308
356204
  6. **Sell.** \`publish_store\` deploys it as a working store: a Next.js Commerce app on Vercel selling the connected
356309
- Shopify store's products, with its cart and checkout (needs Shopify and Vercel connected: \`list_integrations\`).
356205
+ Shopify store's products, with its cart and checkout (needs the site environment to name the Shopify store,
356206
+ \`get_site_environment\`, which the Ecommerce plugin sets, and Vercel connected: \`list_integrations\`).
356310
356207
  Or \`export_storefront\` writes the project for a store the user runs:
356311
356208
  - \`target: 'next-commerce-store'\`: the whole Next.js Commerce store, to deploy with Shopify's keys.
356312
356209
  - \`target: 'next-commerce'\`: components only, for a Next.js Commerce store that exists: a prop per list
356313
356210
  (\`products\`, \`cartLines\`, \`cart\`, \`menu\`), \`product\` on a product's page, \`onAddToCart\`, \`onCheckout\`\u2026 for the forms.
356314
- - \`target: 'shopify-theme'\`: an Online Store 2.0 theme the user uploads in Shopify (Online Store \u203A Themes).
356211
+ A Shopify theme, the store's catalogue and its setup are the Ecommerce plugin's (Marketplace \u203A Plugins).
356315
356212
  Say which, and where it goes (/docs/exporting/commerce).
356316
356213
 
356317
356214
  ## Rules
@@ -358714,16 +358611,16 @@ var init_api5 = __esm({
358714
358611
  }
358715
358612
  });
358716
358613
 
358717
- // node_modules/.pnpm/@popcraft+plugins@1.0.0_patch_hash=997b73fa0364896bf8afb3420ac81e52de261b88cad7cac3e2e206341916c9a5/node_modules/@popcraft/plugins/dist/generated/runtime.js
358614
+ // node_modules/.pnpm/@popcraft+plugins@1.0.0_patch_hash=e61849e2a6a59df95f0ebad36ab274c37a933fcf798d8b4dd6b3f0ffc625a1da/node_modules/@popcraft/plugins/dist/generated/runtime.js
358718
358615
  var MAIN_RUNTIME, UI_RUNTIME;
358719
358616
  var init_runtime4 = __esm({
358720
- "node_modules/.pnpm/@popcraft+plugins@1.0.0_patch_hash=997b73fa0364896bf8afb3420ac81e52de261b88cad7cac3e2e206341916c9a5/node_modules/@popcraft/plugins/dist/generated/runtime.js"() {
358721
- MAIN_RUNTIME = '"use strict";\n(() => {\n // src/runtime/rpc.ts\n function createRpcClient() {\n let port = null;\n const queue = [];\n const pending = {};\n const listeners = {};\n let nextId = 1;\n function send(msg) {\n if (port) port.postMessage(msg);\n else queue.push(msg);\n }\n function call(method, params) {\n return new Promise((resolve, reject) => {\n const id = nextId++;\n pending[id] = { resolve, reject };\n send({ kind: "rpc", id, method, params });\n });\n }\n function emit(event, data) {\n for (const cb of (listeners[event] || []).slice()) {\n try {\n cb(data);\n } catch (e) {\n console.error(e);\n }\n }\n }\n window.addEventListener("message", (e) => {\n const data = e.data;\n if (e.source !== window.parent || !data || data.type !== "popcraft-plugin-port" || port) return;\n port = e.ports[0];\n port.onmessage = (ev) => {\n const m = ev.data || {};\n if (m.kind === "result" && m.id !== void 0 && pending[m.id]) {\n const p = pending[m.id];\n delete pending[m.id];\n if (m.error) p.reject(new Error(m.error));\n else p.resolve(m.result);\n } else if (m.kind === "event" && m.event) {\n emit(m.event, m.data);\n }\n };\n for (const msg of queue.splice(0)) port.postMessage(msg);\n });\n return {\n call,\n send,\n on(event, cb) {\n (listeners[event] = listeners[event] || []).push(cb);\n },\n off(event, cb) {\n listeners[event] = (listeners[event] || []).filter((x) => x !== cb);\n }\n };\n }\n\n // src/runtime/main.ts\n function clone(v) {\n return v === void 0 ? {} : JSON.parse(JSON.stringify(v));\n }\n function createMainApi(rpc = createRpcClient()) {\n const uiHandlers = [];\n let uiOnMessage = null;\n const uiQueue = [];\n function deliverUI(msg) {\n for (const cb of uiHandlers) {\n try {\n cb(msg);\n } catch (e) {\n console.error(e);\n }\n }\n if (typeof uiOnMessage === "function") {\n try {\n uiOnMessage(msg);\n } catch (e) {\n console.error(e);\n }\n }\n }\n function flushUI() {\n if (uiHandlers.length || typeof uiOnMessage === "function") uiQueue.splice(0).forEach(deliverUI);\n }\n rpc.on("uimessage", (msg) => {\n if (!uiHandlers.length && typeof uiOnMessage !== "function") uiQueue.push(msg);\n else deliverUI(msg);\n });\n let widgetDef = null;\n const widgetQueue = [];\n function renderWidget(state) {\n const handlers = {};\n function walk(el, path) {\n if (!el || typeof el !== "object") return el;\n const out = {};\n for (const k of Object.keys(el)) {\n const v = el[k];\n if (k === "children") {\n out.children = (Array.isArray(v) ? v : [v]).filter((c) => c !== null && c !== void 0 && c !== false).map((c, i) => walk(c, path + "." + i));\n } else if (k === "onClick" && typeof v === "function") {\n handlers[path] = v;\n out.onClick = path;\n } else {\n out[k] = v;\n }\n }\n return out;\n }\n return { tree: walk(widgetDef.render(state), "root"), handlers };\n }\n function initialWidgetState() {\n const s = widgetDef && widgetDef.initialState;\n return clone(typeof s === "function" ? s() : s);\n }\n function commitWidget(nodeId, state) {\n return rpc.call("widgetUpdate", { id: nodeId, state, tree: renderWidget(clone(state)).tree });\n }\n function handleWidgetClick(e) {\n Promise.resolve().then(() => {\n const state = clone(e.state);\n const rendered = renderWidget(state);\n const h = rendered.handlers[e.handler] || widgetDef.handlers && widgetDef.handlers[e.handler];\n if (typeof h !== "function") return;\n return Promise.resolve(h(state, { nodeId: e.nodeId })).then((ret) => commitWidget(e.nodeId, ret === void 0 ? state : ret));\n }).catch((err) => rpc.send({ kind: "error", message: String((err == null ? void 0 : err.message) || err) }));\n }\n rpc.on("widgetclick", (e) => {\n if (widgetDef) handleWidgetClick(e);\n else widgetQueue.push(e);\n });\n const popcraft = {\n /** Which menu command the user picked, or null when the plugin ran some other way. */\n command: null,\n /** Host import mode when launched as an importer, else null. */\n importMode: null,\n /** Pending import file when the host handed one over, else null. */\n importFile: null,\n /** Pending export request when the host started this plugin as an exporter, else null. */\n exportRequest: null,\n getSelection: () => rpc.call("getSelection"),\n setSelection: (ids) => rpc.call("setSelection", { ids }),\n getNode: (id) => rpc.call("getNode", { id }),\n findNodes: (query) => rpc.call("findNodes", query || {}),\n getCurrentPage: () => rpc.call("getCurrentPage"),\n createNode: (type, props) => rpc.call("createNode", { type, props: props || {} }),\n updateNode: (id, props) => rpc.call("updateNode", { id, props }),\n deleteNode: (id) => rpc.call("deleteNode", { id }),\n setText: (id, characters) => rpc.call("setText", { id, characters }),\n setTextPath: (opts) => rpc.call("setTextPath", opts || {}),\n flowTextIntoShape: (opts) => rpc.call("flowTextIntoShape", opts || {}),\n detachText: (opts) => rpc.call("detachText", opts || {}),\n setTextFit: (opts) => rpc.call("setTextFit", opts || {}),\n createPage: (name) => rpc.call("createPage", name != null ? { name: String(name) } : {}),\n setCurrentPage: (pageId) => rpc.call("setCurrentPage", { pageId }),\n createImage: (opts) => rpc.call("createImage", opts || {}),\n createDocument: (opts) => rpc.call("createDocument", opts || {}),\n getImportMode: () => rpc.call("getImportMode"),\n getImportFile: () => rpc.call("getImportFile"),\n getStorefront: () => rpc.call("getStorefront"),\n getExportRequest: () => rpc.call("getExportRequest"),\n saveExport: (file) => rpc.call("saveExport", file || {}),\n getPresentationAudio: (opts) => rpc.call("getPresentationAudio", opts || {}),\n setPresentationAudioSettings: (opts) => rpc.call("setPresentationAudioSettings", opts || {}),\n setPresentationAudioClip: (opts) => rpc.call("setPresentationAudioClip", opts || {}),\n removePresentationAudioClip: (opts) => rpc.call("removePresentationAudioClip", opts || {}),\n setPresentationTiming: (opts) => rpc.call("setPresentationTiming", opts || {}),\n getPresentationMix: (opts) => rpc.call("getPresentationMix", opts || {}),\n requestPresentationAudio: (opts) => rpc.call("requestPresentationAudio", opts || {}),\n moveNodes: (opts) => rpc.call("moveNodes", opts || {}),\n resizeNodes: (opts) => rpc.call("resizeNodes", opts || {}),\n renameNodes: (opts) => rpc.call("renameNodes", opts || {}),\n reparentNodes: (opts) => rpc.call("reparentNodes", opts || {}),\n duplicateNodes: (opts) => rpc.call("duplicateNodes", opts || {}),\n groupNodes: (opts) => rpc.call("groupNodes", opts || {}),\n ungroupNodes: (opts) => rpc.call("ungroupNodes", opts || {}),\n alignNodes: (opts) => rpc.call("alignNodes", opts || {}),\n distributeNodes: (opts) => rpc.call("distributeNodes", opts || {}),\n flipNodes: (opts) => rpc.call("flipNodes", opts || {}),\n rotateNodes: (opts) => rpc.call("rotateNodes", opts || {}),\n reorderNodes: (opts) => rpc.call("reorderNodes", opts || {}),\n setLocked: (opts) => rpc.call("setLocked", opts || {}),\n setVisible: (opts) => rpc.call("setVisible", opts || {}),\n setAutoLayout: (opts) => rpc.call("setAutoLayout", opts || {}),\n importSvg: (opts) => rpc.call("importSvg", opts || {}),\n measureNodes: (opts) => rpc.call("measureNodes", opts || {}),\n setFills: (opts) => rpc.call("setFills", opts || {}),\n setStrokes: (opts) => rpc.call("setStrokes", opts || {}),\n setEffects: (opts) => rpc.call("setEffects", opts || {}),\n replaceColor: (opts) => rpc.call("replaceColor", opts || {}),\n setTypography: (opts) => rpc.call("setTypography", opts || {}),\n applyStyle: (opts) => rpc.call("applyStyle", opts || {}),\n createComponent: (opts) => rpc.call("createComponent", opts || {}),\n createInstance: (opts) => rpc.call("createInstance", opts || {}),\n renamePage: (opts) => rpc.call("renamePage", opts || {}),\n getDocumentOutline: (opts) => rpc.call("getDocumentOutline", opts || {}),\n setPageSetup: (opts) => rpc.call("setPageSetup", opts || {}),\n setShowAdvance: (opts) => rpc.call("setShowAdvance", opts || {}),\n booleanOperation: (opts) => rpc.call("booleanOperation", opts || {}),\n flattenNodes: (opts) => rpc.call("flattenNodes", opts || {}),\n outlineStroke: (opts) => rpc.call("outlineStroke", opts || {}),\n setMask: (opts) => rpc.call("setMask", opts || {}),\n setMaskType: (opts) => rpc.call("setMaskType", opts || {}),\n shapeBuilder: (opts) => rpc.call("shapeBuilder", opts || {}),\n setKeyframes: (opts) => rpc.call("setKeyframes", opts || {}),\n getAnimation: (opts) => rpc.call("getAnimation", opts || {}),\n getCompositions: (opts) => rpc.call("getCompositions", opts || {}),\n editBehaviours: (opts) => rpc.call("editBehaviours", opts || {}),\n setTimeline: (opts) => rpc.call("setTimeline", opts || {}),\n setLayerTiming: (opts) => rpc.call("setLayerTiming", opts || {}),\n editTextAnimation: (opts) => rpc.call("editTextAnimation", opts || {}),\n edit3DScene: (opts) => rpc.call("edit3DScene", opts || {}),\n setInstancePlayback: (opts) => rpc.call("setInstancePlayback", opts || {}),\n editComponentProperty: (opts) => rpc.call("editComponentProperty", opts || {}),\n setShaderFill: (opts) => rpc.call("setShaderFill", opts || {}),\n createComposition: (opts) => rpc.call("createComposition", opts || {}),\n editComposition: (opts) => rpc.call("editComposition", opts || {}),\n editStateMachine: (opts) => rpc.call("editStateMachine", opts || {}),\n getStateMachine: (opts) => rpc.call("getStateMachine", opts || {}),\n applyMotionPreset: (opts) => rpc.call("applyMotionPreset", opts || {}),\n staggerMotion: (opts) => rpc.call("staggerMotion", opts || {}),\n createMotionComponent: (opts) => rpc.call("createMotionComponent", opts || {}),\n addAudio: (opts) => rpc.call("addAudio", opts || {}),\n editFrameAudio: (opts) => rpc.call("editFrameAudio", opts || {}),\n editVideoClip: (opts) => rpc.call("editVideoClip", opts || {}),\n detectAudioOnsets: (opts) => rpc.call("detectAudioOnsets", opts || {}),\n cutToBeat: (opts) => rpc.call("cutToBeat", opts || {}),\n editPrototype: (opts) => rpc.call("editPrototype", opts || {}),\n importFile: (opts) => rpc.call("importFile", opts || {}),\n usePresentationFallbackAudio: (opts) => rpc.call("usePresentationFallbackAudio", opts || {}),\n getStyles: () => rpc.call("getStyles"),\n createPaintStyle: (name, paints) => rpc.call("createPaintStyle", { name, paints }),\n getVariables: () => rpc.call("getVariables"),\n setVariableValue: (variableId, modeId, value) => rpc.call("setVariableValue", { variableId, modeId, value }),\n exportNode: (id, options) => rpc.call("exportNode", { id, options: options || {} }),\n openExternal: (url) => rpc.call("openExternal", { url }),\n notify: (message, options) => rpc.call("notify", { message: String(message), error: !!(options && options.error) }),\n showUI: (options) => rpc.call("showUI", options || {}),\n hideUI: () => rpc.call("hideUI"),\n /** Ends the run. The optional message is shown as a notification. */\n closePlugin: (message) => rpc.call("closePlugin", { message }),\n storage: {\n get: (key) => rpc.call("storageGet", { key }),\n set: (key, value) => rpc.call("storageSet", { key, value })\n },\n ui: {\n get onmessage() {\n return uiOnMessage;\n },\n set onmessage(cb) {\n uiOnMessage = cb;\n flushUI();\n },\n postMessage: (msg) => rpc.send({ kind: "toUI", data: msg }),\n on: (cb) => {\n uiHandlers.push(cb);\n flushUI();\n }\n },\n widget: {\n register(def) {\n if (!def || typeof def.render !== "function") throw new Error("popcraft.widget.register needs a render(state) function");\n widgetDef = def;\n widgetQueue.splice(0).forEach(handleWidgetClick);\n },\n insert(options) {\n if (!widgetDef) return Promise.reject(new Error("Call popcraft.widget.register first"));\n const o = options || {};\n const state = o.state !== void 0 ? clone(o.state) : initialWidgetState();\n return rpc.call("widgetInsert", { state, tree: renderWidget(state).tree, x: o.x, y: o.y });\n },\n getState: (nodeId) => rpc.call("widgetGet", { id: nodeId }),\n setState(nodeId, state) {\n if (!widgetDef) return Promise.reject(new Error("Call popcraft.widget.register first"));\n return commitWidget(nodeId, clone(state));\n }\n },\n on: (event, cb) => rpc.on(event, cb),\n off: (event, cb) => rpc.off(event, cb)\n };\n rpc.on("init", (data) => {\n var _a, _b, _c;\n popcraft.command = data.command;\n popcraft.exportRequest = (_c = data.exportRequest) != null ? _c : null;\n popcraft.importMode = (_a = data.importMode) != null ? _a : null;\n popcraft.importFile = (_b = data.importFile) != null ? _b : null;\n });\n return popcraft;\n }\n function installMainApi() {\n const rpc = createRpcClient();\n const api = createMainApi(rpc);\n const w = window;\n w.__popcraftRpc = rpc;\n w.popcraft = api;\n w.vizpops = api;\n window.addEventListener("error", (e) => rpc.send({ kind: "error", message: String(e.message || e) }));\n window.addEventListener("unhandledrejection", (e) => rpc.send({ kind: "error", message: String(e.reason && e.reason.message || e.reason) }));\n return api;\n }\n\n // src/runtime/main.entry.ts\n installMainApi();\n})();';
358617
+ "node_modules/.pnpm/@popcraft+plugins@1.0.0_patch_hash=e61849e2a6a59df95f0ebad36ab274c37a933fcf798d8b4dd6b3f0ffc625a1da/node_modules/@popcraft/plugins/dist/generated/runtime.js"() {
358618
+ MAIN_RUNTIME = '"use strict";\n(() => {\n // src/runtime/rpc.ts\n function createRpcClient() {\n let port = null;\n const queue = [];\n const pending = {};\n const listeners = {};\n let nextId = 1;\n function send(msg) {\n if (port) port.postMessage(msg);\n else queue.push(msg);\n }\n function call(method, params) {\n return new Promise((resolve, reject) => {\n const id = nextId++;\n pending[id] = { resolve, reject };\n send({ kind: "rpc", id, method, params });\n });\n }\n function emit(event, data) {\n for (const cb of (listeners[event] || []).slice()) {\n try {\n cb(data);\n } catch (e) {\n console.error(e);\n }\n }\n }\n window.addEventListener("message", (e) => {\n const data = e.data;\n if (e.source !== window.parent || !data || data.type !== "popcraft-plugin-port" || port) return;\n port = e.ports[0];\n port.onmessage = (ev) => {\n const m = ev.data || {};\n if (m.kind === "result" && m.id !== void 0 && pending[m.id]) {\n const p = pending[m.id];\n delete pending[m.id];\n if (m.error) p.reject(new Error(m.error));\n else p.resolve(m.result);\n } else if (m.kind === "event" && m.event) {\n emit(m.event, m.data);\n }\n };\n for (const msg of queue.splice(0)) port.postMessage(msg);\n });\n return {\n call,\n send,\n on(event, cb) {\n (listeners[event] = listeners[event] || []).push(cb);\n },\n off(event, cb) {\n listeners[event] = (listeners[event] || []).filter((x) => x !== cb);\n }\n };\n }\n\n // src/runtime/main.ts\n function clone(v) {\n return v === void 0 ? {} : JSON.parse(JSON.stringify(v));\n }\n function createMainApi(rpc = createRpcClient()) {\n const uiHandlers = [];\n let uiOnMessage = null;\n const uiQueue = [];\n function deliverUI(msg) {\n for (const cb of uiHandlers) {\n try {\n cb(msg);\n } catch (e) {\n console.error(e);\n }\n }\n if (typeof uiOnMessage === "function") {\n try {\n uiOnMessage(msg);\n } catch (e) {\n console.error(e);\n }\n }\n }\n function flushUI() {\n if (uiHandlers.length || typeof uiOnMessage === "function") uiQueue.splice(0).forEach(deliverUI);\n }\n rpc.on("uimessage", (msg) => {\n if (!uiHandlers.length && typeof uiOnMessage !== "function") uiQueue.push(msg);\n else deliverUI(msg);\n });\n let widgetDef = null;\n const widgetQueue = [];\n function renderWidget(state) {\n const handlers = {};\n function walk(el, path) {\n if (!el || typeof el !== "object") return el;\n const out = {};\n for (const k of Object.keys(el)) {\n const v = el[k];\n if (k === "children") {\n out.children = (Array.isArray(v) ? v : [v]).filter((c) => c !== null && c !== void 0 && c !== false).map((c, i) => walk(c, path + "." + i));\n } else if (k === "onClick" && typeof v === "function") {\n handlers[path] = v;\n out.onClick = path;\n } else {\n out[k] = v;\n }\n }\n return out;\n }\n return { tree: walk(widgetDef.render(state), "root"), handlers };\n }\n function initialWidgetState() {\n const s = widgetDef && widgetDef.initialState;\n return clone(typeof s === "function" ? s() : s);\n }\n function commitWidget(nodeId, state) {\n return rpc.call("widgetUpdate", { id: nodeId, state, tree: renderWidget(clone(state)).tree });\n }\n function handleWidgetClick(e) {\n Promise.resolve().then(() => {\n const state = clone(e.state);\n const rendered = renderWidget(state);\n const h = rendered.handlers[e.handler] || widgetDef.handlers && widgetDef.handlers[e.handler];\n if (typeof h !== "function") return;\n return Promise.resolve(h(state, { nodeId: e.nodeId })).then((ret) => commitWidget(e.nodeId, ret === void 0 ? state : ret));\n }).catch((err) => rpc.send({ kind: "error", message: String((err == null ? void 0 : err.message) || err) }));\n }\n rpc.on("widgetclick", (e) => {\n if (widgetDef) handleWidgetClick(e);\n else widgetQueue.push(e);\n });\n const popcraft = {\n /** Which menu command the user picked, or null when the plugin ran some other way. */\n command: null,\n /** Host import mode when launched as an importer, else null. */\n importMode: null,\n /** Pending import file when the host handed one over, else null. */\n importFile: null,\n /** Pending export request (File \u2192 Export \u2192 this plugin\'s format), else null. */\n exportRequest: null,\n getSelection: () => rpc.call("getSelection"),\n setSelection: (ids) => rpc.call("setSelection", { ids }),\n getNode: (id) => rpc.call("getNode", { id }),\n findNodes: (query) => rpc.call("findNodes", query || {}),\n getCurrentPage: () => rpc.call("getCurrentPage"),\n createNode: (type, props) => rpc.call("createNode", { type, props: props || {} }),\n updateNode: (id, props) => rpc.call("updateNode", { id, props }),\n deleteNode: (id) => rpc.call("deleteNode", { id }),\n setText: (id, characters) => rpc.call("setText", { id, characters }),\n /** Put TEXT layers on a path (another layer\'s outline, or their own arc, circle or wave), or tune one: brackets, alignment, placement, effect, overflow. */\n setTextPath: (opts) => rpc.call("setTextPath", opts || {}),\n /** Area type: flow a TEXT layer inside a closed shape, kept `inset` px in. */\n flowTextIntoShape: (opts) => rpc.call("flowTextIntoShape", opts || {}),\n /** Take TEXT layers off their path or out of their shape (or free every text linked to a path / shape). */\n detachText: (opts) => rpc.call("detachText", opts || {}),\n /** Auto-size TEXT layers\' type to their box, shape or path. */\n setTextFit: (opts) => rpc.call("setTextFit", opts || {}),\n createPage: (name) => rpc.call("createPage", name != null ? { name: String(name) } : {}),\n setCurrentPage: (pageId) => rpc.call("setCurrentPage", { pageId }),\n createImage: (opts) => rpc.call("createImage", opts || {}),\n createDocument: (opts) => rpc.call("createDocument", opts || {}),\n getImportMode: () => rpc.call("getImportMode"),\n getImportFile: () => rpc.call("getImportFile"),\n /**\n * The open page as a storefront design in a neutral form, for an exporter that writes its own store\'s templates:\n * each page\'s HTML with the store\'s data marked (`{{page.title}}`, `{{item.price}}`, `<!-- pc:each \u2026 -->` lists,\n * `data-pc-action` forms), and its collections with their commerce schema and sample records.\n */\n getStorefront: () => rpc.call("getStorefront"),\n /**\n * A design\'s data (docs: Collections): a collection and its fields (`schema`: what it stands for, e.g.\n * `commerce.product`, whose fields are made for it), its records, and reading them.\n */\n editCollection: (opts) => rpc.call("editCollection", opts || {}),\n editRecords: (opts) => rpc.call("editRecords", opts || {}),\n getRecords: (opts) => rpc.call("getRecords", opts || {}),\n /** A layer as a web page\'s form control (a FORM\'s `formAction`, an INPUT\'s name and value), repeated per record, a page\'s address, its semantics. */\n setControl: (opts) => rpc.call("setControl", opts || {}),\n setRepeat: (opts) => rpc.call("setRepeat", opts || {}),\n setRoute: (opts) => rpc.call("setRoute", opts || {}),\n setSemantics: (opts) => rpc.call("setSemantics", opts || {}),\n /** The site\'s environment: public settings its host reads by name when it is deployed (never a secret: the file keeps them). */\n getSiteEnvironment: () => rpc.call("getSiteEnvironment"),\n setSiteEnvironment: (set) => rpc.call("setSiteEnvironment", { set }),\n /** What this plugin keeps with the open file (its settings for this design), under its own id; JSON only. */\n getFileData: (key) => rpc.call("getFileData", { key }),\n setFileData: (key, value) => rpc.call("setFileData", { key, value }),\n /** A store\'s project built from the open page, zipped (needs `export`): what an exporter saves with `saveExport`. */\n getStorefrontFiles: (target) => rpc.call("getStorefrontFiles", { target }),\n getExportRequest: () => rpc.call("getExportRequest"),\n /** Save the exporter\'s file (once per export request); the host enforces the contributed extension. */\n saveExport: (file) => rpc.call("saveExport", file || {}),\n /**\n * Presentation audio (docs/plugins/presentation-audio.md): the deck\'s slides, notes, narration and timing; the\n * soundtrack\'s settings, bed and stinger.\n */\n getPresentationAudio: (opts) => rpc.call("getPresentationAudio", opts || {}),\n /** Change the soundtrack\'s settings (voice, style, mood, loudness, beat alignment, levels) and re-time it. */\n setPresentationAudioSettings: (opts) => rpc.call("setPresentationAudioSettings", opts || {}),\n /** Put a sound in (a slide\'s narration, the bed or the stinger): bytes are normalised to the soundtrack\'s target and stored. */\n setPresentationAudioClip: (opts) => rpc.call("setPresentationAudioClip", opts || {}),\n removePresentationAudioClip: (opts) => rpc.call("removePresentationAudioClip", opts || {}),\n /** Re-time: fixed slide lengths (ms, null clears) and beat-aligned changes. */\n setPresentationTiming: (opts) => rpc.call("setPresentationTiming", opts || {}),\n /** The mix as the export carries it: loudness, true peak, and (wav: true) the 48 kHz stereo WAV. */\n getPresentationMix: (opts) => rpc.call("getPresentationMix", opts || {}),\n /** Ask the user to generate with AI (the panel opens with the request filled in; the user decides). */\n requestPresentationAudio: (opts) => rpc.call("requestPresentationAudio", opts || {}),\n /** Editor commands: each takes the arguments documented in docs/plugins/methods.md (the agent tool of the same purpose). */\n moveNodes: (opts) => rpc.call("moveNodes", opts || {}),\n resizeNodes: (opts) => rpc.call("resizeNodes", opts || {}),\n renameNodes: (opts) => rpc.call("renameNodes", opts || {}),\n reparentNodes: (opts) => rpc.call("reparentNodes", opts || {}),\n duplicateNodes: (opts) => rpc.call("duplicateNodes", opts || {}),\n groupNodes: (opts) => rpc.call("groupNodes", opts || {}),\n ungroupNodes: (opts) => rpc.call("ungroupNodes", opts || {}),\n alignNodes: (opts) => rpc.call("alignNodes", opts || {}),\n distributeNodes: (opts) => rpc.call("distributeNodes", opts || {}),\n flipNodes: (opts) => rpc.call("flipNodes", opts || {}),\n rotateNodes: (opts) => rpc.call("rotateNodes", opts || {}),\n reorderNodes: (opts) => rpc.call("reorderNodes", opts || {}),\n setLocked: (opts) => rpc.call("setLocked", opts || {}),\n setVisible: (opts) => rpc.call("setVisible", opts || {}),\n setAutoLayout: (opts) => rpc.call("setAutoLayout", opts || {}),\n importSvg: (opts) => rpc.call("importSvg", opts || {}),\n measureNodes: (opts) => rpc.call("measureNodes", opts || {}),\n setFills: (opts) => rpc.call("setFills", opts || {}),\n setStrokes: (opts) => rpc.call("setStrokes", opts || {}),\n setEffects: (opts) => rpc.call("setEffects", opts || {}),\n replaceColor: (opts) => rpc.call("replaceColor", opts || {}),\n setTypography: (opts) => rpc.call("setTypography", opts || {}),\n applyStyle: (opts) => rpc.call("applyStyle", opts || {}),\n createComponent: (opts) => rpc.call("createComponent", opts || {}),\n createInstance: (opts) => rpc.call("createInstance", opts || {}),\n renamePage: (opts) => rpc.call("renamePage", opts || {}),\n getDocumentOutline: (opts) => rpc.call("getDocumentOutline", opts || {}),\n setPageSetup: (opts) => rpc.call("setPageSetup", opts || {}),\n setShowAdvance: (opts) => rpc.call("setShowAdvance", opts || {}),\n booleanOperation: (opts) => rpc.call("booleanOperation", opts || {}),\n flattenNodes: (opts) => rpc.call("flattenNodes", opts || {}),\n outlineStroke: (opts) => rpc.call("outlineStroke", opts || {}),\n setMask: (opts) => rpc.call("setMask", opts || {}),\n setMaskType: (opts) => rpc.call("setMaskType", opts || {}),\n shapeBuilder: (opts) => rpc.call("shapeBuilder", opts || {}),\n setKeyframes: (opts) => rpc.call("setKeyframes", opts || {}),\n getAnimation: (opts) => rpc.call("getAnimation", opts || {}),\n getCompositions: (opts) => rpc.call("getCompositions", opts || {}),\n editBehaviours: (opts) => rpc.call("editBehaviours", opts || {}),\n setTimeline: (opts) => rpc.call("setTimeline", opts || {}),\n setLayerTiming: (opts) => rpc.call("setLayerTiming", opts || {}),\n editTextAnimation: (opts) => rpc.call("editTextAnimation", opts || {}),\n edit3DScene: (opts) => rpc.call("edit3DScene", opts || {}),\n setInstancePlayback: (opts) => rpc.call("setInstancePlayback", opts || {}),\n editComponentProperty: (opts) => rpc.call("editComponentProperty", opts || {}),\n setShaderFill: (opts) => rpc.call("setShaderFill", opts || {}),\n createComposition: (opts) => rpc.call("createComposition", opts || {}),\n editComposition: (opts) => rpc.call("editComposition", opts || {}),\n editStateMachine: (opts) => rpc.call("editStateMachine", opts || {}),\n getStateMachine: (opts) => rpc.call("getStateMachine", opts || {}),\n applyMotionPreset: (opts) => rpc.call("applyMotionPreset", opts || {}),\n staggerMotion: (opts) => rpc.call("staggerMotion", opts || {}),\n createMotionComponent: (opts) => rpc.call("createMotionComponent", opts || {}),\n addAudio: (opts) => rpc.call("addAudio", opts || {}),\n editFrameAudio: (opts) => rpc.call("editFrameAudio", opts || {}),\n editVideoClip: (opts) => rpc.call("editVideoClip", opts || {}),\n detectAudioOnsets: (opts) => rpc.call("detectAudioOnsets", opts || {}),\n cutToBeat: (opts) => rpc.call("cutToBeat", opts || {}),\n editPrototype: (opts) => rpc.call("editPrototype", opts || {}),\n usePresentationFallbackAudio: (opts) => rpc.call("usePresentationFallbackAudio", opts || {}),\n /** Bring a Lottie, PDF or PopCraft file into the open document (the `importFile` field is the file an importer was handed). */\n importDocumentFile: (opts) => rpc.call("importDocumentFile", opts || {}),\n getStyles: () => rpc.call("getStyles"),\n createPaintStyle: (name, paints) => rpc.call("createPaintStyle", { name, paints }),\n getVariables: () => rpc.call("getVariables"),\n setVariableValue: (variableId, modeId, value) => rpc.call("setVariableValue", { variableId, modeId, value }),\n exportNode: (id, options) => rpc.call("exportNode", { id, options: options || {} }),\n openExternal: (url) => rpc.call("openExternal", { url }),\n notify: (message, options) => rpc.call("notify", { message: String(message), error: !!(options && options.error) }),\n showUI: (options) => rpc.call("showUI", options || {}),\n hideUI: () => rpc.call("hideUI"),\n /** Ends the run. The optional message is shown as a notification. */\n closePlugin: (message) => rpc.call("closePlugin", { message }),\n storage: {\n get: (key) => rpc.call("storageGet", { key }),\n set: (key, value) => rpc.call("storageSet", { key, value })\n },\n ui: {\n get onmessage() {\n return uiOnMessage;\n },\n set onmessage(cb) {\n uiOnMessage = cb;\n flushUI();\n },\n postMessage: (msg) => rpc.send({ kind: "toUI", data: msg }),\n on: (cb) => {\n uiHandlers.push(cb);\n flushUI();\n }\n },\n widget: {\n register(def) {\n if (!def || typeof def.render !== "function") throw new Error("popcraft.widget.register needs a render(state) function");\n widgetDef = def;\n widgetQueue.splice(0).forEach(handleWidgetClick);\n },\n insert(options) {\n if (!widgetDef) return Promise.reject(new Error("Call popcraft.widget.register first"));\n const o = options || {};\n const state = o.state !== void 0 ? clone(o.state) : initialWidgetState();\n return rpc.call("widgetInsert", { state, tree: renderWidget(state).tree, x: o.x, y: o.y });\n },\n getState: (nodeId) => rpc.call("widgetGet", { id: nodeId }),\n setState(nodeId, state) {\n if (!widgetDef) return Promise.reject(new Error("Call popcraft.widget.register first"));\n return commitWidget(nodeId, clone(state));\n }\n },\n on: (event, cb) => rpc.on(event, cb),\n off: (event, cb) => rpc.off(event, cb)\n };\n rpc.on("init", (data) => {\n var _a, _b, _c;\n popcraft.command = data.command;\n popcraft.importMode = (_a = data.importMode) != null ? _a : null;\n popcraft.importFile = (_b = data.importFile) != null ? _b : null;\n popcraft.exportRequest = (_c = data.exportRequest) != null ? _c : null;\n });\n return popcraft;\n }\n function installMainApi() {\n const rpc = createRpcClient();\n const api = createMainApi(rpc);\n const w = window;\n w.__popcraftRpc = rpc;\n w.popcraft = api;\n w.vizpops = api;\n window.addEventListener("error", (e) => rpc.send({ kind: "error", message: String(e.message || e) }));\n window.addEventListener("unhandledrejection", (e) => rpc.send({ kind: "error", message: String(e.reason && e.reason.message || e.reason) }));\n return api;\n }\n\n // src/runtime/main.entry.ts\n installMainApi();\n})();';
358722
358619
  UI_RUNTIME = '"use strict";\n(() => {\n // src/runtime/rpc.ts\n function createRpcClient() {\n let port = null;\n const queue = [];\n const pending = {};\n const listeners = {};\n let nextId = 1;\n function send(msg) {\n if (port) port.postMessage(msg);\n else queue.push(msg);\n }\n function call(method, params) {\n return new Promise((resolve, reject) => {\n const id = nextId++;\n pending[id] = { resolve, reject };\n send({ kind: "rpc", id, method, params });\n });\n }\n function emit(event, data) {\n for (const cb of (listeners[event] || []).slice()) {\n try {\n cb(data);\n } catch (e) {\n console.error(e);\n }\n }\n }\n window.addEventListener("message", (e) => {\n const data = e.data;\n if (e.source !== window.parent || !data || data.type !== "popcraft-plugin-port" || port) return;\n port = e.ports[0];\n port.onmessage = (ev) => {\n const m = ev.data || {};\n if (m.kind === "result" && m.id !== void 0 && pending[m.id]) {\n const p = pending[m.id];\n delete pending[m.id];\n if (m.error) p.reject(new Error(m.error));\n else p.resolve(m.result);\n } else if (m.kind === "event" && m.event) {\n emit(m.event, m.data);\n }\n };\n for (const msg of queue.splice(0)) port.postMessage(msg);\n });\n return {\n call,\n send,\n on(event, cb) {\n (listeners[event] = listeners[event] || []).push(cb);\n },\n off(event, cb) {\n listeners[event] = (listeners[event] || []).filter((x) => x !== cb);\n }\n };\n }\n\n // src/runtime/ui.ts\n function createUiApi(rpc = createRpcClient()) {\n const popcraft = {\n onmessage: null,\n postMessage: (msg) => rpc.send({ kind: "fromUI", data: msg }),\n close: () => rpc.send({ kind: "closeUI" })\n };\n rpc.on("message", (msg) => {\n if (typeof popcraft.onmessage === "function") popcraft.onmessage(msg);\n window.dispatchEvent(new MessageEvent("message", { data: { pluginMessage: msg } }));\n });\n return popcraft;\n }\n function installUiApi() {\n const rpc = createRpcClient();\n const api = createUiApi(rpc);\n const w = window;\n w.__popcraftRpc = rpc;\n w.popcraft = api;\n w.vizpops = api;\n return api;\n }\n\n // src/runtime/ui.entry.ts\n installUiApi();\n})();';
358723
358620
  }
358724
358621
  });
358725
358622
 
358726
- // node_modules/.pnpm/@popcraft+plugins@1.0.0_patch_hash=997b73fa0364896bf8afb3420ac81e52de261b88cad7cac3e2e206341916c9a5/node_modules/@popcraft/plugins/dist/host.js
358623
+ // node_modules/.pnpm/@popcraft+plugins@1.0.0_patch_hash=e61849e2a6a59df95f0ebad36ab274c37a933fcf798d8b4dd6b3f0ffc625a1da/node_modules/@popcraft/plugins/dist/host.js
358727
358624
  function csp(network) {
358728
358625
  const connect2 = network ? "connect-src * data: blob:;" : "connect-src 'none';";
358729
358626
  const img = network ? "img-src * data: blob:;" : "img-src data: blob:;";
@@ -358751,40 +358648,40 @@ function buildUIDocument(uiHtml, network) {
358751
358648
  }
358752
358649
  var escapeScript;
358753
358650
  var init_host2 = __esm({
358754
- "node_modules/.pnpm/@popcraft+plugins@1.0.0_patch_hash=997b73fa0364896bf8afb3420ac81e52de261b88cad7cac3e2e206341916c9a5/node_modules/@popcraft/plugins/dist/host.js"() {
358651
+ "node_modules/.pnpm/@popcraft+plugins@1.0.0_patch_hash=e61849e2a6a59df95f0ebad36ab274c37a933fcf798d8b4dd6b3f0ffc625a1da/node_modules/@popcraft/plugins/dist/host.js"() {
358755
358652
  init_runtime4();
358756
358653
  escapeScript = (code) => code.replace(/<\/script/gi, "<\\/script");
358757
358654
  }
358758
358655
  });
358759
358656
 
358760
- // node_modules/.pnpm/@popcraft+plugins@1.0.0_patch_hash=997b73fa0364896bf8afb3420ac81e52de261b88cad7cac3e2e206341916c9a5/node_modules/@popcraft/plugins/dist/runtime/rpc.js
358657
+ // node_modules/.pnpm/@popcraft+plugins@1.0.0_patch_hash=e61849e2a6a59df95f0ebad36ab274c37a933fcf798d8b4dd6b3f0ffc625a1da/node_modules/@popcraft/plugins/dist/runtime/rpc.js
358761
358658
  var init_rpc = __esm({
358762
- "node_modules/.pnpm/@popcraft+plugins@1.0.0_patch_hash=997b73fa0364896bf8afb3420ac81e52de261b88cad7cac3e2e206341916c9a5/node_modules/@popcraft/plugins/dist/runtime/rpc.js"() {
358659
+ "node_modules/.pnpm/@popcraft+plugins@1.0.0_patch_hash=e61849e2a6a59df95f0ebad36ab274c37a933fcf798d8b4dd6b3f0ffc625a1da/node_modules/@popcraft/plugins/dist/runtime/rpc.js"() {
358763
358660
  }
358764
358661
  });
358765
358662
 
358766
- // node_modules/.pnpm/@popcraft+plugins@1.0.0_patch_hash=997b73fa0364896bf8afb3420ac81e52de261b88cad7cac3e2e206341916c9a5/node_modules/@popcraft/plugins/dist/runtime/main.js
358663
+ // node_modules/.pnpm/@popcraft+plugins@1.0.0_patch_hash=e61849e2a6a59df95f0ebad36ab274c37a933fcf798d8b4dd6b3f0ffc625a1da/node_modules/@popcraft/plugins/dist/runtime/main.js
358767
358664
  var init_main = __esm({
358768
- "node_modules/.pnpm/@popcraft+plugins@1.0.0_patch_hash=997b73fa0364896bf8afb3420ac81e52de261b88cad7cac3e2e206341916c9a5/node_modules/@popcraft/plugins/dist/runtime/main.js"() {
358665
+ "node_modules/.pnpm/@popcraft+plugins@1.0.0_patch_hash=e61849e2a6a59df95f0ebad36ab274c37a933fcf798d8b4dd6b3f0ffc625a1da/node_modules/@popcraft/plugins/dist/runtime/main.js"() {
358769
358666
  init_rpc();
358770
358667
  }
358771
358668
  });
358772
358669
 
358773
- // node_modules/.pnpm/@popcraft+plugins@1.0.0_patch_hash=997b73fa0364896bf8afb3420ac81e52de261b88cad7cac3e2e206341916c9a5/node_modules/@popcraft/plugins/dist/types.js
358670
+ // node_modules/.pnpm/@popcraft+plugins@1.0.0_patch_hash=e61849e2a6a59df95f0ebad36ab274c37a933fcf798d8b4dd6b3f0ffc625a1da/node_modules/@popcraft/plugins/dist/types.js
358774
358671
  var init_types9 = __esm({
358775
- "node_modules/.pnpm/@popcraft+plugins@1.0.0_patch_hash=997b73fa0364896bf8afb3420ac81e52de261b88cad7cac3e2e206341916c9a5/node_modules/@popcraft/plugins/dist/types.js"() {
358672
+ "node_modules/.pnpm/@popcraft+plugins@1.0.0_patch_hash=e61849e2a6a59df95f0ebad36ab274c37a933fcf798d8b4dd6b3f0ffc625a1da/node_modules/@popcraft/plugins/dist/types.js"() {
358776
358673
  }
358777
358674
  });
358778
358675
 
358779
- // node_modules/.pnpm/@popcraft+plugins@1.0.0_patch_hash=997b73fa0364896bf8afb3420ac81e52de261b88cad7cac3e2e206341916c9a5/node_modules/@popcraft/plugins/dist/widget.js
358676
+ // node_modules/.pnpm/@popcraft+plugins@1.0.0_patch_hash=e61849e2a6a59df95f0ebad36ab274c37a933fcf798d8b4dd6b3f0ffc625a1da/node_modules/@popcraft/plugins/dist/widget.js
358780
358677
  var init_widget = __esm({
358781
- "node_modules/.pnpm/@popcraft+plugins@1.0.0_patch_hash=997b73fa0364896bf8afb3420ac81e52de261b88cad7cac3e2e206341916c9a5/node_modules/@popcraft/plugins/dist/widget.js"() {
358678
+ "node_modules/.pnpm/@popcraft+plugins@1.0.0_patch_hash=e61849e2a6a59df95f0ebad36ab274c37a933fcf798d8b4dd6b3f0ffc625a1da/node_modules/@popcraft/plugins/dist/widget.js"() {
358782
358679
  }
358783
358680
  });
358784
358681
 
358785
- // node_modules/.pnpm/@popcraft+plugins@1.0.0_patch_hash=997b73fa0364896bf8afb3420ac81e52de261b88cad7cac3e2e206341916c9a5/node_modules/@popcraft/plugins/dist/index.js
358682
+ // node_modules/.pnpm/@popcraft+plugins@1.0.0_patch_hash=e61849e2a6a59df95f0ebad36ab274c37a933fcf798d8b4dd6b3f0ffc625a1da/node_modules/@popcraft/plugins/dist/index.js
358786
358683
  var init_dist = __esm({
358787
- "node_modules/.pnpm/@popcraft+plugins@1.0.0_patch_hash=997b73fa0364896bf8afb3420ac81e52de261b88cad7cac3e2e206341916c9a5/node_modules/@popcraft/plugins/dist/index.js"() {
358684
+ "node_modules/.pnpm/@popcraft+plugins@1.0.0_patch_hash=e61849e2a6a59df95f0ebad36ab274c37a933fcf798d8b4dd6b3f0ffc625a1da/node_modules/@popcraft/plugins/dist/index.js"() {
358788
358685
  init_host2();
358789
358686
  init_main();
358790
358687
  init_runtime4();
@@ -359532,7 +359429,7 @@ var init_import = __esm({
359532
359429
  init_esm2();
359533
359430
  init_scene_graph();
359534
359431
  init_types();
359535
- init_state_machine2();
359432
+ init_state_machine3();
359536
359433
  GEOMETRY = /* @__PURE__ */ new Set(["gr", "rc", "el", "sh", "sr"]);
359537
359434
  BLENDS = ["NORMAL", "MULTIPLY", "SCREEN", "OVERLAY", "DARKEN", "LIGHTEN", "COLOR_DODGE", "COLOR_BURN", "HARD_LIGHT", "SOFT_LIGHT", "DIFFERENCE", "EXCLUSION", "HUE", "SATURATION", "COLOR", "LUMINOSITY"];
359538
359435
  nearestFps = (fr) => TIMELINE_FPS_VALUES.reduce((a, b) => Math.abs(b - fr) < Math.abs(a - fr) ? b : a, TIMELINE_FPS_VALUES[0]);
@@ -388978,6 +388875,10 @@ function isOpenableUrl(v) {
388978
388875
  return false;
388979
388876
  }
388980
388877
  }
388878
+ function pluginOf(ctx2) {
388879
+ if (ctx2.actor.kind !== "plugin" || !ctx2.actor.id) throw new PluginApiError("Only a plugin keeps file data");
388880
+ return ctx2.actor.id;
388881
+ }
388981
388882
  function pluginMethods() {
388982
388883
  registerPluginCommands();
388983
388884
  return listCommandsForSurface("plugin").map((c2) => c2.expose.plugin.method);
@@ -389241,7 +389142,7 @@ var init_plugin = __esm({
389241
389142
  permission: "read",
389242
389143
  expose: { plugin: { method: "getStorefront", shape: (r) => r.data } },
389243
389144
  // A storefront design in a neutral form (lib/io/web/project/storefront.ts `storefrontDesign`): what an exporter
389244
- // plugin turns into its own store's templates, as PopCraft turns it into a Next.js Commerce store or a Shopify theme.
389145
+ // plugin turns into its own store's templates, as PopCraft turns it into a Next.js Commerce store (the Ecommerce plugin makes a Shopify theme of it).
389245
389146
  run: async (_p, ctx2) => {
389246
389147
  const [{ componentScreens: componentScreens2 }, { storefrontDesign: storefrontDesign2 }] = await Promise.all([Promise.resolve().then(() => (init_components(), components_exports)), Promise.resolve().then(() => (init_storefront(), storefront_exports))]);
389247
389148
  const doc2 = ctx2.doc();
@@ -389249,6 +389150,32 @@ var init_plugin = __esm({
389249
389150
  return { summary: `Storefront: ${design.pages.length} pages`, data: design };
389250
389151
  }
389251
389152
  }),
389153
+ defineCommand({
389154
+ id: pluginCommandId("getStorefrontFiles"),
389155
+ title: "Build a storefront target",
389156
+ domain: "export",
389157
+ params: external_exports.object({ target: external_exports.enum(["shopify-theme", "next-commerce", "next-commerce-store"]) }),
389158
+ effect: "none",
389159
+ permission: "export",
389160
+ expose: { plugin: { method: "getStorefrontFiles", shape: (r) => r.data } },
389161
+ // A store's project, built from the open page as Export storefront builds it, zipped: what an exporter plugin
389162
+ // saves (the Ecommerce plugin's Shopify theme), so a target is written once, here, and never again in a plugin.
389163
+ run: async (p2, ctx2) => {
389164
+ const [{ storefrontInputs: storefrontInputs2 }, { STOREFRONT_TARGETS: STOREFRONT_TARGETS2 }, { bytesOf: bytesOf2 }, { zipFiles: zipFiles2 }, { EXPORT_NODE_CAP: EXPORT_NODE_CAP2 }] = await Promise.all([
389165
+ Promise.resolve().then(() => (init_storefront_prepare(), storefront_prepare_exports)),
389166
+ Promise.resolve().then(() => (init_storefront(), storefront_exports)),
389167
+ Promise.resolve().then(() => (init_project(), project_exports)),
389168
+ Promise.resolve().then(() => (init_zip_export(), zip_export_exports)),
389169
+ Promise.resolve().then(() => (init_tree(), tree_exports))
389170
+ ]);
389171
+ const doc2 = ctx2.doc();
389172
+ const { screens, media: media2 } = await storefrontInputs2(doc2, ctx2.pageId(), EXPORT_NODE_CAP2);
389173
+ if (!screens.length) throw new PluginApiError("This page has no screens: a top-level frame is a page of the store.");
389174
+ const files = STOREFRONT_TARGETS2[p2.target].files(doc2, screens, { media: media2 });
389175
+ const zip = zipFiles2(files.map((f2) => ({ name: f2.path, bytes: bytesOf2(f2) })));
389176
+ return { summary: `${STOREFRONT_TARGETS2[p2.target].label}: ${files.length} files`, data: { name: `${doc2.name || "store"}-${p2.target}.zip`, files: files.length, bytes: new Uint8Array(await zip.arrayBuffer()) } };
389177
+ }
389178
+ }),
389252
389179
  defineCommand({
389253
389180
  id: pluginCommandId("getExportRequest"),
389254
389181
  title: "Get export request",
@@ -389378,6 +389305,36 @@ var init_plugin = __esm({
389378
389305
  return { summary: `Wrote ${p2.key}` };
389379
389306
  }
389380
389307
  }),
389308
+ // What the plugin keeps with the open file (Document.pluginData), under its own id: its settings for this design.
389309
+ defineCommand({
389310
+ id: pluginCommandId("getFileData"),
389311
+ title: "Read plugin file data",
389312
+ domain: "storage",
389313
+ params: external_exports.object({ key: external_exports.unknown().transform((v) => String(v)) }),
389314
+ effect: "none",
389315
+ permission: "read",
389316
+ expose: { plugin: { method: "getFileData", shape: (r) => r.data } },
389317
+ run: (p2, ctx2) => ({ summary: `Read ${p2.key}`, data: ctx2.doc().pluginData?.[pluginOf(ctx2)]?.[p2.key] })
389318
+ }),
389319
+ defineCommand({
389320
+ id: pluginCommandId("setFileData"),
389321
+ title: "Write plugin file data",
389322
+ domain: "storage",
389323
+ params: external_exports.object({ key: external_exports.unknown().transform((v) => String(v)), value: external_exports.unknown() }),
389324
+ effect: "document",
389325
+ permission: "write",
389326
+ expose: { plugin: { method: "setFileData" } },
389327
+ run: (p2, ctx2) => {
389328
+ const doc2 = ctx2.doc();
389329
+ const id3 = pluginOf(ctx2);
389330
+ const mine = { ...doc2.pluginData?.[id3] ?? {} };
389331
+ if (p2.value === void 0 || p2.value === null) delete mine[p2.key];
389332
+ else mine[p2.key] = plain(p2.value);
389333
+ const { [id3]: _, ...others } = doc2.pluginData ?? {};
389334
+ ctx2.commit({ ...doc2, pluginData: Object.keys(mine).length ? { ...others, [id3]: mine } : others });
389335
+ return { summary: `Wrote ${p2.key}` };
389336
+ }
389337
+ }),
389381
389338
  ...widgetCommands(pluginCommandId)
389382
389339
  ];
389383
389340
  pluginRun = defineCommand({
@@ -389435,7 +389392,7 @@ function attached(done, ctx2) {
389435
389392
  ctx2.notice(`Database attached: ${where}`);
389436
389393
  return { summary: `Attached ${where} (${db3.connection.provider}, ${db3.connection.account}): the site's forms are saved there once it is published`, data: { provider: db3.connection.provider, account: db3.connection.account, target: db3.target } };
389437
389394
  }
389438
- var integrationList, integrationOpen, asPath2, integrationListResources, place3, integrationAddDestination, integrationDeploy, integrationAttachDatabase, integrationSubmissions, integrationSetSignIn, integrationConfirmCommands, integrationPullProducts;
389395
+ var integrationList, integrationOpen, asPath2, integrationListResources, place3, integrationAddDestination, integrationDeploy, integrationAttachDatabase, integrationSubmissions, integrationSetSignIn, integrationConfirmCommands;
389439
389396
  var init_integration = __esm({
389440
389397
  "lib/commands/integration.ts"() {
389441
389398
  "use strict";
@@ -389449,13 +389406,13 @@ var init_integration = __esm({
389449
389406
  effect: "none",
389450
389407
  permission: null,
389451
389408
  params: external_exports.object({
389452
- capability: external_exports.enum(["repo", "deploy", "database", "auth", "commerce"]).optional().describe("Only the integrations that can do this: repo (push code to a repository), deploy (host the site), database (store what forms send and what collections hold), auth (sign-in for the site's visitors), commerce (a store whose products a storefront design is drawn with).")
389409
+ capability: external_exports.enum(["repo", "deploy", "database", "auth"]).optional().describe("Only the integrations that can do this: repo (push code to a repository), deploy (host the site), database (store what forms send and what collections hold), auth (sign-in for the site's visitors).")
389453
389410
  }),
389454
389411
  expose: {
389455
389412
  agent: {
389456
389413
  name: "list_integrations",
389457
389414
  readOnly: true,
389458
- description: "The services this workspace can connect its own accounts to (GitHub, Vercel, Neon, Supabase, Shopify), what each can do (repo, deploy, database, auth, commerce), which accounts are connected, and whether the user can connect more. `notYet` lists what an integration is meant to do and cannot yet: never promise those. Call it before recommending one, and before any step that needs a connection. You cannot connect an account yourself: when one is missing, say which integration fits and why, then call open_integrations so the user can connect it."
389415
+ description: "The services this workspace can connect its own accounts to (GitHub, Vercel, Neon, Supabase), what each can do (repo, deploy, database, auth), which accounts are connected, and whether the user can connect more. `notYet` lists what an integration is meant to do and cannot yet: never promise those. Call it before recommending one, and before any step that needs a connection. You cannot connect an account yourself: when one is missing, say which integration fits and why, then call open_integrations so the user can connect it."
389459
389416
  }
389460
389417
  },
389461
389418
  run: async ({ capability: capability2 }) => {
@@ -389690,50 +389647,6 @@ var init_integration = __esm({
389690
389647
  }
389691
389648
  });
389692
389649
  integrationConfirmCommands = [integrationAddDestination, integrationDeploy, integrationAttachDatabase, integrationSetSignIn];
389693
- integrationPullProducts = defineCommand({
389694
- id: "integration.pullProducts",
389695
- title: "Draw the design with a store's products",
389696
- domain: "integration",
389697
- effect: "document",
389698
- permission: "write",
389699
- undoLabel: "Store products",
389700
- params: external_exports.object({
389701
- connectionId: external_exports.string().optional().describe("The connected store, from list_integrations (capability commerce). Omit when one store is connected."),
389702
- collection: external_exports.string().optional().describe("The collection to fill, by id or name; it must stand for store products (schema commerce.product). Omit when the file has one."),
389703
- limit: external_exports.number().int().min(1).max(100).default(24).describe("How many of the store's newest products.")
389704
- }).strict(),
389705
- expose: {
389706
- ui: { label: "Draw with my store's products", keywords: ["shopify", "store", "products", "commerce", "shop", "catalogue", "import"] },
389707
- agent: {
389708
- name: "pull_store_products",
389709
- description: "Replace the records of a storefront design's product collection (schema commerce.product) with a connected store's real products (Shopify): titles, prices, pictures, handles and variant ids, newest first. The design's lists and product pages then show them. It reads the store; it never changes it. Needs a Shopify connection (list_integrations, capability commerce); you cannot connect one yourself."
389710
- }
389711
- },
389712
- run: async (args2, ctx2) => {
389713
- const [{ cloudUser: cloudUser2 }, { connectedStore: connectedStore2, storeProducts: storeProducts2 }, { commerceItem: commerceItem2, COMMERCE_FIELDS: COMMERCE_FIELDS2 }, { fieldKey: fieldKey2, removeRecords: removeRecords2, upsertRecords: upsertRecords2 }] = await Promise.all([
389714
- Promise.resolve().then(() => (init_session(), session_exports)),
389715
- Promise.resolve().then(() => (init_integrations(), integrations_exports)),
389716
- Promise.resolve().then(() => (init_commerce(), commerce_exports)),
389717
- Promise.resolve().then(() => (init_collections(), collections_exports))
389718
- ]);
389719
- if (!cloudUser2()) throw new CommandError("You are not signed in: a store is connected to your account's workspace.", "denied");
389720
- const doc2 = ctx2.doc();
389721
- const pick5 = Object.values(doc2.collections ?? {}).filter((c2) => c2.schema === "commerce.product" && (!args2.collection || c2.id === args2.collection || c2.name.toLowerCase() === args2.collection.toLowerCase()));
389722
- if (!pick5.length) throw new CommandError(args2.collection ? `No store products collection "${args2.collection}".` : "This file has no collection that stands for store products: set one to Store products in Collections first.", "invalid_params");
389723
- if (pick5.length > 1) throw new CommandError(`Name the collection: ${pick5.map((c2) => c2.name).join(", ")}.`, "invalid_params");
389724
- const collection = pick5[0];
389725
- const connectionId = await connectedStore2(args2.connectionId).catch((e) => {
389726
- throw new CommandError(e instanceof Error ? e.message : String(e), "failed");
389727
- });
389728
- const products = await storeProducts2(connectionId, args2.limit);
389729
- if (!products.length) throw new CommandError("The store has no products to show.", "failed");
389730
- const keys4 = new Map(COMMERCE_FIELDS2["commerce.product"].map((f2) => [fieldKey2(f2.name), f2.name]));
389731
- const rows = products.map((p2) => ({ values: Object.fromEntries(Object.entries(commerceItem2("commerce.product", p2).values).filter(([k2]) => keys4.has(k2)).map(([k2, v]) => [keys4.get(k2), v])) }));
389732
- const cleared = removeRecords2(doc2, collection.order);
389733
- ctx2.commit(upsertRecords2(cleared, collection.id, rows).document);
389734
- return { summary: `Drew ${collection.name} with ${products.length} of the store's products`, data: { collection: collection.id, products: products.length } };
389735
- }
389736
- });
389737
389650
  }
389738
389651
  });
389739
389652
 
@@ -390356,6 +390269,7 @@ function record(source, namespaces, globals, limits) {
390356
390269
  var HELPER_NAMES;
390357
390270
  var init_helper_names = __esm({
390358
390271
  "lib/agent/design-script/helper-names.ts"() {
390272
+ "use strict";
390359
390273
  HELPER_NAMES = ["draw", "marks", "fit", "motion", "captions", "overlays", "texture", "pointer", "windows", "devices", "type", "beat", "web", "social", "video", "site", "effects"];
390360
390274
  }
390361
390275
  });
@@ -393873,7 +393787,7 @@ function collectionOf(doc2, ref3) {
393873
393787
  if (!c2) throw new ToolError(`No collection "${ref3}". ${Object.values(doc2.collections ?? {}).length ? `There is: ${Object.values(doc2.collections).map((x2) => x2.name).join(", ")}.` : "Make one with edit_collection."}`);
393874
393788
  return c2;
393875
393789
  }
393876
- var sizing2, padding2, overrides, nodeSetResponsive, link, nodeSetSemantics, nodeSetControl, siteSetRoute, breakpoint, siteSetBreakpoints, siteSetGpuTransitions, siteGetBreakpoints, described2, dataEditCollection, dataEditRecords, dataGetRecords, nodeSetRepeat;
393790
+ var sizing2, padding2, overrides, nodeSetResponsive, link, nodeSetSemantics, nodeSetControl, siteSetRoute, breakpoint, siteSetBreakpoints, siteSetGpuTransitions, ENV_NAME, RESERVED_ENV, siteSetEnvironment, siteGetEnvironment, siteGetBreakpoints, described2, dataEditCollection, dataEditRecords, dataGetRecords, nodeSetRepeat;
393877
393791
  var init_site3 = __esm({
393878
393792
  "lib/commands/site.ts"() {
393879
393793
  "use strict";
@@ -393983,6 +393897,7 @@ var init_site3 = __esm({
393983
393897
  link: link.nullable().optional().describe('Make the whole layer a link: {kind:"url", url, newTab?}, {kind:"screen", frameId} (another top-level frame), {kind:"anchor", nodeId} (a layer on the page), {kind:"email", value} or {kind:"tel", value}; null removes it.')
393984
393898
  }).strict(),
393985
393899
  expose: {
393900
+ plugin: { method: "setSemantics" },
393986
393901
  ui: { label: "Web semantics", keywords: ["semantic", "html", "tag", "heading", "link", "anchor", "accessibility", "aria"], enabled: needsSelection(1), palette: false },
393987
393902
  agent: {
393988
393903
  name: "set_semantics",
@@ -394045,6 +393960,7 @@ var init_site3 = __esm({
394045
393960
  onSubmit: external_exports.record(external_exports.string(), external_exports.unknown()).nullable().optional().describe('FORM: a prototype action run once it is sent, as edit_prototype takes them ({navigationType: "NAVIGATE", destinationId: <thank-you frame>}).')
394046
393961
  }).strict(),
394047
393962
  expose: {
393963
+ plugin: { method: "setControl" },
394048
393964
  ui: { label: "Form control", keywords: ["form", "input", "field", "textarea", "select", "checkbox", "radio", "button", "submit"], enabled: needsSelection(1), palette: false },
394049
393965
  agent: {
394050
393966
  name: "set_control",
@@ -394056,7 +393972,7 @@ var init_site3 = __esm({
394056
393972
  const { ids: _ids, kind, ...rest } = args2;
394057
393973
  void _ids;
394058
393974
  if (rest.variableId && !doc2.variables?.[rest.variableId]) throw new ToolError(`No variable ${rest.variableId}.`);
394059
- const name2 = rest.name !== void 0 ? cleanName2(rest.name) : void 0;
393975
+ const name2 = rest.name !== void 0 ? cleanName(rest.name) : void 0;
394060
393976
  if (rest.name && !name2) throw new ToolError(`"${rest.name}" has nothing a form can send a value under: use letters, digits, dashes and underscores.`);
394061
393977
  const patches = /* @__PURE__ */ new Map();
394062
393978
  for (const id3 of ids2) {
@@ -394093,6 +394009,7 @@ var init_site3 = __esm({
394093
394009
  collectionId: external_exports.string().nullable().optional().describe("Make the screen one page per record of this collection (its address, then the record's: /blog/first-post); texts on it say fields with {{item.title}}. null: an ordinary page again.")
394094
394010
  }).strict(),
394095
394011
  expose: {
394012
+ plugin: { method: "setRoute" },
394096
394013
  ui: { label: "Page address", keywords: ["route", "url", "path", "slug", "page title", "seo", "404"], enabled: needsSelection(1), palette: false },
394097
394014
  agent: {
394098
394015
  name: "set_route",
@@ -394184,6 +394101,56 @@ var init_site3 = __esm({
394184
394101
  return { summary: args2.on ? "3D transitions draw with WebGPU where the browser has it" : "3D transitions draw in CSS 3D only", data: { on: args2.on } };
394185
394102
  }
394186
394103
  });
394104
+ ENV_NAME = /^[A-Z][A-Z0-9_]{0,63}$/;
394105
+ RESERVED_ENV = /^(VERCEL|NEXT_RUNTIME|NODE_ENV|PORT|DATABASE_URL|SITE_AUTH_)/;
394106
+ siteSetEnvironment = defineCommand({
394107
+ id: "site.setEnvironment",
394108
+ title: "Set site environment",
394109
+ domain: "site",
394110
+ effect: "document",
394111
+ permission: "write",
394112
+ undoLabel: "Change the site environment",
394113
+ params: external_exports.object({
394114
+ set: external_exports.record(external_exports.string().regex(ENV_NAME, "Names are upper case, digits and underscores (SHOPIFY_STORE_DOMAIN)"), external_exports.string().max(4096).nullable()).describe("Each name to its value; null removes it. Public values only: everyone who can open the file sees them.")
394115
+ }).strict(),
394116
+ expose: {
394117
+ plugin: { method: "setSiteEnvironment" },
394118
+ ui: { label: "Site environment", keywords: ["environment", "env", "variables", "settings", "deploy", "store"], palette: false },
394119
+ agent: {
394120
+ name: "set_site_environment",
394121
+ description: "Set or remove the site's environment variables: public settings its host reads by name when it is deployed (a store's SHOPIFY_STORE_DOMAIN and public SHOPIFY_STOREFRONT_ACCESS_TOKEN). Kept in the file, seen by everyone who can open it: never put a secret here. null removes a name."
394122
+ }
394123
+ },
394124
+ run: (args2, ctx2) => {
394125
+ const doc2 = ctx2.doc();
394126
+ const bad = Object.keys(args2.set).find((k2) => RESERVED_ENV.test(k2));
394127
+ if (bad) throw new ToolError(`${bad} is set by the host or kept on the server: a file cannot set it.`);
394128
+ const env = { ...doc2.site?.env ?? {} };
394129
+ for (const [k2, v] of Object.entries(args2.set)) {
394130
+ if (v === null) delete env[k2];
394131
+ else env[k2] = v;
394132
+ }
394133
+ const { env: _, ...rest } = doc2.site ?? {};
394134
+ ctx2.commit({ ...doc2, site: Object.keys(env).length ? { ...rest, env } : rest });
394135
+ return { summary: `Site environment: ${Object.keys(env).sort().join(", ") || "none"}`, data: { names: Object.keys(env).sort() } };
394136
+ }
394137
+ });
394138
+ siteGetEnvironment = defineCommand({
394139
+ id: "site.getEnvironment",
394140
+ title: "Get site environment",
394141
+ domain: "site",
394142
+ effect: "none",
394143
+ permission: "read",
394144
+ params: external_exports.object({}).strict(),
394145
+ expose: {
394146
+ plugin: { method: "getSiteEnvironment", shape: (r) => r.data },
394147
+ agent: { name: "get_site_environment", readOnly: true, description: "The site's environment variables (public settings its host reads by name when it is deployed), by name." }
394148
+ },
394149
+ run: (_args, ctx2) => {
394150
+ const env = ctx2.doc().site?.env ?? {};
394151
+ return { summary: `${Object.keys(env).length} environment variable(s)`, data: env };
394152
+ }
394153
+ });
394187
394154
  siteGetBreakpoints = defineCommand({
394188
394155
  id: "site.getBreakpoints",
394189
394156
  title: "Get breakpoints",
@@ -394238,6 +394205,7 @@ var init_site3 = __esm({
394238
394205
  remove: external_exports.boolean().optional().describe("Delete the collection, its records, and the repeaters and collection pages that used it.")
394239
394206
  }).strict(),
394240
394207
  expose: {
394208
+ plugin: { method: "editCollection" },
394241
394209
  ui: { label: "Collections", keywords: ["cms", "collection", "data", "records", "content", "blog", "products"], palette: false },
394242
394210
  agent: {
394243
394211
  name: "edit_collection",
@@ -394306,6 +394274,7 @@ var init_site3 = __esm({
394306
394274
  order: external_exports.array(external_exports.string()).max(COLLECTION_LIMITS.records).optional().describe("Record ids in the order the collection should list them; ones left out keep their order after these.")
394307
394275
  }).strict(),
394308
394276
  expose: {
394277
+ plugin: { method: "editRecords" },
394309
394278
  ui: { label: "Edit records", keywords: ["cms", "record", "row", "content"], palette: false },
394310
394279
  agent: {
394311
394280
  name: "edit_records",
@@ -394349,6 +394318,7 @@ var init_site3 = __esm({
394349
394318
  offset: external_exports.number().int().min(0).optional()
394350
394319
  }).strict(),
394351
394320
  expose: {
394321
+ plugin: { method: "getRecords" },
394352
394322
  agent: {
394353
394323
  name: "get_records",
394354
394324
  readOnly: true,
@@ -394385,6 +394355,7 @@ var init_site3 = __esm({
394385
394355
  filter: external_exports.string().max(500).nullable().optional().describe('An expression over the record, only records it holds for are shown: "item_price > 100", "item_featured".')
394386
394356
  }).strict(),
394387
394357
  expose: {
394358
+ plugin: { method: "setRepeat" },
394388
394359
  ui: { label: "Repeat for each record", keywords: ["repeat", "repeater", "list", "cms", "collection", "loop"], enabled: needsSelection(1), palette: false },
394389
394360
  agent: {
394390
394361
  name: "set_repeat",
@@ -394450,7 +394421,7 @@ var init_import2 = __esm({
394450
394421
  url: external_exports.string().url().max(2e3).optional().describe("Or fetch it from an https URL.")
394451
394422
  }).strict(),
394452
394423
  expose: {
394453
- plugin: { method: "importFile" },
394424
+ plugin: { method: "importDocumentFile" },
394454
394425
  agent: {
394455
394426
  name: "import_file",
394456
394427
  description: "Import a Lottie animation (.json or .lottie: a frame with its timeline, precomps as components), a PDF or a PopCraft file into the open file, onto the current page; later pages are appended. Pass the content as text, base64 or an https url. Returns the added layer ids and anything that did not map."
@@ -395340,7 +395311,6 @@ function registerBuiltinCommands() {
395340
395311
  var builtinCommands, uiOnlyCommands;
395341
395312
  var init_builtin4 = __esm({
395342
395313
  "lib/commands/builtin.ts"() {
395343
- "use strict";
395344
395314
  init_registry();
395345
395315
  init_node();
395346
395316
  init_node();
@@ -395521,6 +395491,8 @@ var init_builtin4 = __esm({
395521
395491
  siteSetRoute,
395522
395492
  nodeSetControl,
395523
395493
  nodeSetRepeat,
395494
+ siteSetEnvironment,
395495
+ siteGetEnvironment,
395524
395496
  codeEditModule,
395525
395497
  codeGetModules,
395526
395498
  componentSetCode,
@@ -395541,7 +395513,6 @@ var init_builtin4 = __esm({
395541
395513
  integrationOpen,
395542
395514
  integrationListResources,
395543
395515
  integrationSubmissions,
395544
- integrationPullProducts,
395545
395516
  // a copy of the open file as a new file (lib/commands/file.ts) (appended, as above)
395546
395517
  fileDuplicate,
395547
395518
  // a whiteboard as one picture, or its stickies as Markdown / CSV (lib/popcorn/board-export.ts) (appended, as above)
@@ -402825,7 +402796,7 @@ init_resources();
402825
402796
  init_desktop();
402826
402797
  init_hypery();
402827
402798
  import { createInterface } from "node:readline";
402828
- var VERSION2 = "0.16.0";
402799
+ var VERSION2 = "0.17.0";
402829
402800
  var HELP = `popcraft ${VERSION2} \u2014 the PopCraft command line
402830
402801
 
402831
402802
  Files (headless, on .popcraft files):