@popcraft/cli 0.20.3 → 0.21.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/popcraft.mjs +207 -44
- 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.
|
|
1189
|
+
const headers = { "user-agent": `popcraft-cli/${"0.21.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 {
|
|
@@ -5303,6 +5303,9 @@ var init_properties = __esm({
|
|
|
5303
5303
|
// Fill
|
|
5304
5304
|
itemProp(FILLS, "color", "Color", { valueType: "color", group: "Fill", control: color, essential: true, accepts: (it) => it.type === "SOLID" }),
|
|
5305
5305
|
itemProp(FILLS, "opacity", "Opacity", { valueType: "number", group: "Fill", control: percent, accepts: () => true, defaultOf: () => 1 }),
|
|
5306
|
+
// A picture's address, swapped whole: what an IMAGE component property feeds (a product card's photo).
|
|
5307
|
+
itemProp(FILLS, "imageUrl", "Picture", { valueType: "string", group: "Fill", control: { kind: "text" }, accepts: (it) => it.type === "IMAGE" }),
|
|
5308
|
+
nodeProp("imageUrl", "Picture", { valueType: "string", group: "Fill", control: { kind: "text" }, appliesTo: (n) => n.type === "IMAGE" }),
|
|
5306
5309
|
itemProp(FILLS, "color", "Color", { valueType: "color", group: "Fill", control: color, accepts: (it) => GRADIENTS.has(it.type), sub: { list: "gradientStops", label: (j) => `Stop ${j + 1}` } }),
|
|
5307
5310
|
itemProp(FILLS, "position", "Position", { valueType: "number", group: "Fill", control: percent, accepts: (it) => GRADIENTS.has(it.type), sub: { list: "gradientStops", label: (j) => `Stop ${j + 1}` } }),
|
|
5308
5311
|
shaderParamProp(),
|
|
@@ -32639,6 +32642,7 @@ var init_en2 = __esm({
|
|
|
32639
32642
|
"command:node.align#right": "Align right",
|
|
32640
32643
|
"command:node.align#top": "Align top",
|
|
32641
32644
|
"command:node.applyAutoLayout": "Infer auto layout",
|
|
32645
|
+
"command:node.bindField": "Bind to a field",
|
|
32642
32646
|
"command:node.delete": "Delete selection",
|
|
32643
32647
|
"command:node.distribute": "Distribute",
|
|
32644
32648
|
"command:node.distribute#horizontal": "Distribute horizontally",
|
|
@@ -32662,6 +32666,7 @@ var init_en2 = __esm({
|
|
|
32662
32666
|
"command:node.setLock": "Lock",
|
|
32663
32667
|
"command:node.setLock#lock": "Lock selection",
|
|
32664
32668
|
"command:node.setLock#unlock": "Unlock selection",
|
|
32669
|
+
"command:node.setRecord": "Show a record",
|
|
32665
32670
|
"command:node.setRepeat": "Repeat for each record",
|
|
32666
32671
|
"command:node.setResponsive": "Breakpoint overrides",
|
|
32667
32672
|
"command:node.setSemantics": "Web semantics",
|
|
@@ -32957,6 +32962,16 @@ var init_en2 = __esm({
|
|
|
32957
32962
|
"cropToolbar.keepThisCropEnter": "Keep this crop (Enter)",
|
|
32958
32963
|
"cropToolbar.putTheCropBackAs": "Put the crop back as it was (Esc)",
|
|
32959
32964
|
"cropToolbar.ratio": "Ratio",
|
|
32965
|
+
"dataSection.collectionHint": "Which collection this layer shows a record of",
|
|
32966
|
+
"dataSection.fieldHint": "The field {name} shows",
|
|
32967
|
+
"dataSection.fromAround": "From around it: {name}",
|
|
32968
|
+
"dataSection.noRecord": "No record",
|
|
32969
|
+
"dataSection.notBound": "Not bound",
|
|
32970
|
+
"dataSection.pickFirst": "Pick a record above, or put this layer in a list, to bind it to fields.",
|
|
32971
|
+
"dataSection.picture": "Picture",
|
|
32972
|
+
"dataSection.recordHint": "Which record this layer shows",
|
|
32973
|
+
"dataSection.text": "Text",
|
|
32974
|
+
"dataSection.title": "Data",
|
|
32960
32975
|
"deleteAccountDialog.cancel": "Cancel",
|
|
32961
32976
|
"deleteAccountDialog.couldNotDelete": "Your account could not be deleted. Try again.",
|
|
32962
32977
|
"deleteAccountDialog.deleteAccount": "Delete account",
|
|
@@ -33138,6 +33153,8 @@ var init_en2 = __esm({
|
|
|
33138
33153
|
"designPanel.pairThePaddingLeftWith": "Pair the padding (left with right, top with bottom)",
|
|
33139
33154
|
"designPanel.perspective": "Perspective",
|
|
33140
33155
|
"designPanel.pick": "\u2014 Pick \u2014",
|
|
33156
|
+
"designPanel.pictureAddress": "The picture's address",
|
|
33157
|
+
"designPanel.pictureAddressPlaceholder": "https://\u2026",
|
|
33141
33158
|
"designPanel.pixelCanvas": "Pixel canvas",
|
|
33142
33159
|
"designPanel.placeholdersLikeTakeTheSelected": "Placeholders like '{{'Label'}}' take the selected instance's property values in the Dev panel.",
|
|
33143
33160
|
"designPanel.pointCount": "Point count",
|
|
@@ -33737,9 +33754,9 @@ var init_en2 = __esm({
|
|
|
33737
33754
|
"homeTeam.publicInMarketplace": "Public in the marketplace",
|
|
33738
33755
|
"homeTeam.putOnline": "Put online",
|
|
33739
33756
|
"homeTeam.reject": "Reject",
|
|
33740
|
-
"homeTeam.rejectNote": "Why (for the publisher)",
|
|
33741
33757
|
"homeTeam.rejected": "Rejected",
|
|
33742
33758
|
"homeTeam.rejectedBecause": "Rejected: {note}",
|
|
33759
|
+
"homeTeam.rejectNote": "Why (for the publisher)",
|
|
33743
33760
|
"homeTeam.removeConfirm": "Take {name} off the marketplace? A plugin is unlisted (those who installed it keep it); anything else is deleted.",
|
|
33744
33761
|
"homeTeam.removeTitle": "Take {name} off the marketplace?",
|
|
33745
33762
|
"homeTeam.review": "Review",
|
|
@@ -254923,14 +254940,24 @@ function repeatRecords(doc2, repeat, under) {
|
|
|
254923
254940
|
return list2.slice(from2, repeat.limit !== void 0 ? from2 + Math.max(0, repeat.limit) : void 0);
|
|
254924
254941
|
}
|
|
254925
254942
|
function shownRecordOf(nodes, doc2, id3) {
|
|
254943
|
+
const own2 = pinnedRecord(doc2, nodes[id3]);
|
|
254944
|
+
if (own2) return own2;
|
|
254926
254945
|
for (let at3 = nodes[id3]?.parentId, hops = 0; at3 && hops < 64; at3 = nodes[at3]?.parentId, hops++) {
|
|
254927
254946
|
const frame2 = nodes[at3];
|
|
254947
|
+
const pinned = pinnedRecord(doc2, frame2);
|
|
254948
|
+
if (pinned) return pinned;
|
|
254928
254949
|
if (frame2?.repeat) return repeatRecords(doc2, frame2.repeat)[0] ?? null;
|
|
254929
254950
|
const of = frame2?.route?.collectionId;
|
|
254930
254951
|
if (of && doc2.collections?.[of]) return repeatRecords(doc2, { collectionId: of })[0] ?? null;
|
|
254931
254952
|
}
|
|
254932
254953
|
return null;
|
|
254933
254954
|
}
|
|
254955
|
+
function pinnedRecord(doc2, node2) {
|
|
254956
|
+
const pin = node2?.record;
|
|
254957
|
+
if (!pin) return null;
|
|
254958
|
+
const r = doc2.records?.[pin.recordId];
|
|
254959
|
+
return r && r.collectionId === pin.collectionId && doc2.collections?.[pin.collectionId] ? r : null;
|
|
254960
|
+
}
|
|
254934
254961
|
function recordSlugs(doc2, collectionId) {
|
|
254935
254962
|
const c2 = doc2.collections?.[collectionId];
|
|
254936
254963
|
const out = /* @__PURE__ */ new Map();
|
|
@@ -254961,6 +254988,12 @@ function itemNode(node2, raw, collection, record2, scope) {
|
|
|
254961
254988
|
if (bound) for (const [prop, src] of Object.entries(bound)) {
|
|
254962
254989
|
const val = tryEvaluate(src, scope);
|
|
254963
254990
|
if (val === void 0) continue;
|
|
254991
|
+
if (prop.startsWith(PROP_BINDING) && out.type === "INSTANCE") {
|
|
254992
|
+
const name2 = prop.slice(PROP_BINDING.length);
|
|
254993
|
+
const props = out.componentProperties;
|
|
254994
|
+
out = { ...out, componentProperties: { ...props, [name2]: typeof val === "boolean" ? val : fieldText(val) } };
|
|
254995
|
+
continue;
|
|
254996
|
+
}
|
|
254964
254997
|
const value3 = prop === "imageUrl" ? String(val) : boundPropValue(prop, val);
|
|
254965
254998
|
if (value3 !== void 0) out = { ...out, [prop]: value3 };
|
|
254966
254999
|
}
|
|
@@ -255043,7 +255076,7 @@ function removeRecords(doc2, ids2) {
|
|
|
255043
255076
|
const collections = Object.fromEntries(Object.entries(doc2.collections ?? {}).map(([id3, c2]) => [id3, c2.order.some((r) => gone.has(r)) ? { ...c2, order: c2.order.filter((r) => !gone.has(r)) } : c2]));
|
|
255044
255077
|
return { ...doc2, records, collections };
|
|
255045
255078
|
}
|
|
255046
|
-
var COLLECTION_LIMITS, slugify2, dataMemo, withData, ITEM_RECORD, MARK, itemMark, templateRecord, compare, TOKEN2, hasItemToken, layerId, copySuffix, copyRecord, coerce3, newId;
|
|
255079
|
+
var COLLECTION_LIMITS, slugify2, dataMemo, withData, ITEM_RECORD, MARK, itemMark, templateRecord, compare, PROP_BINDING, TOKEN2, hasItemToken, layerId, copySuffix, copyRecord, coerce3, newId;
|
|
255047
255080
|
var init_collections = __esm({
|
|
255048
255081
|
"lib/document/collections.ts"() {
|
|
255049
255082
|
"use strict";
|
|
@@ -255067,6 +255100,7 @@ var init_collections = __esm({
|
|
|
255067
255100
|
values: Object.fromEntries(collection.fields.map((f2) => [f2.id, itemMark(fieldKey(f2.name))]))
|
|
255068
255101
|
});
|
|
255069
255102
|
compare = (a, b) => typeof a === "number" && typeof b === "number" ? a - b : String(a ?? "").localeCompare(String(b ?? ""), void 0, { numeric: true });
|
|
255103
|
+
PROP_BINDING = "prop:";
|
|
255070
255104
|
TOKEN2 = /\{\{\s*item\.([A-Za-z0-9_]+)\s*\}\}/g;
|
|
255071
255105
|
hasItemToken = (text) => !!text && text.includes("{{") && /\{\{\s*item\./.test(text);
|
|
255072
255106
|
layerId = (id3) => {
|
|
@@ -256251,7 +256285,6 @@ function planEntryAction({ home }) {
|
|
|
256251
256285
|
var STORAGE_KEY2, useHyperyTeam, TEAM_PROMPT_ENABLED, TEAM_PROMPTED_KEY, PROMPTED_KEY, useTeamPrompt, started;
|
|
256252
256286
|
var init_team = __esm({
|
|
256253
256287
|
"lib/client/cloud/team.ts"() {
|
|
256254
|
-
"use strict";
|
|
256255
256288
|
init_esm();
|
|
256256
256289
|
init_api4();
|
|
256257
256290
|
init_session();
|
|
@@ -304671,7 +304704,6 @@ async function dispatchShaped(key5, options) {
|
|
|
304671
304704
|
var onViolation;
|
|
304672
304705
|
var init_dispatch = __esm({
|
|
304673
304706
|
"lib/commands/dispatch.ts"() {
|
|
304674
|
-
"use strict";
|
|
304675
304707
|
init_errors();
|
|
304676
304708
|
init_registry();
|
|
304677
304709
|
init_confirm();
|
|
@@ -305060,7 +305092,6 @@ function creditLine(c2) {
|
|
|
305060
305092
|
var MAX_PHOTO_PAGE, MAX_PHOTO_QUERY, UUID, isPhotoId, photoImagePath;
|
|
305061
305093
|
var init_stock = __esm({
|
|
305062
305094
|
"lib/photos/stock.ts"() {
|
|
305063
|
-
"use strict";
|
|
305064
305095
|
MAX_PHOTO_PAGE = 12;
|
|
305065
305096
|
MAX_PHOTO_QUERY = 200;
|
|
305066
305097
|
UUID = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
@@ -316779,7 +316810,29 @@ function buildPlainTree(doc2, nodeId2, opts = {}, start2, hooks = {}) {
|
|
|
316779
316810
|
const stylesOf = (n) => styleMapFor(n, doc2.styles, styleOpts);
|
|
316780
316811
|
let motion = null;
|
|
316781
316812
|
const timeline = !opts.static && !start2 && first2.type === "FRAME" ? frameWebMotion(doc2, first2.id, (n) => stylesOf(prepared(n, doc2))) : null;
|
|
316813
|
+
let nodesNow = doc2.nodes;
|
|
316782
316814
|
const build3 = (raw, parent, in3D2, fold) => {
|
|
316815
|
+
const pinned = pinnedRecord(doc2, raw);
|
|
316816
|
+
const outerItem = item, outerNodes = nodesNow;
|
|
316817
|
+
const pinnedTo = pinned ? doc2.collections[pinned.collectionId] : void 0;
|
|
316818
|
+
const holds2 = raw.type === "INSTANCE" || !!raw.childIds?.length;
|
|
316819
|
+
const slugField = holds2 && pinnedTo?.schema && opts.listTemplates && opts.target === "site" ? pinnedTo.fields.find((f2) => f2.id === pinnedTo.slugFieldId) ?? pinnedTo.fields.find((f2) => f2.type === "SLUG") : void 0;
|
|
316820
|
+
if (pinned && pinnedTo) item = slugField ? { collection: pinnedTo, record: templateRecord(pinnedTo), suffix: item?.suffix ?? "" } : { collection: pinnedTo, record: pinned, suffix: item?.suffix ?? "" };
|
|
316821
|
+
if (item && raw.type === "INSTANCE" && raw.boundExpressions) {
|
|
316822
|
+
const shown2 = itemised(raw, raw, item);
|
|
316823
|
+
if (shown2 !== raw) nodesNow = { ...nodesNow, [raw.id]: shown2 };
|
|
316824
|
+
}
|
|
316825
|
+
try {
|
|
316826
|
+
const web = buildLayer(raw, parent, in3D2, fold);
|
|
316827
|
+
if (!web || !pinned || !slugField) return web;
|
|
316828
|
+
const value3 = String(pinned.values[slugField.id] ?? "");
|
|
316829
|
+
return { ...web, children: [], repeat: { collectionId: pinnedTo.id, template: web.children, limit: 1, pick: { key: fieldKey(slugField.name), value: value3 } } };
|
|
316830
|
+
} finally {
|
|
316831
|
+
item = outerItem;
|
|
316832
|
+
nodesNow = outerNodes;
|
|
316833
|
+
}
|
|
316834
|
+
};
|
|
316835
|
+
const buildLayer = (raw, parent, in3D2, fold) => {
|
|
316783
316836
|
if (emitted >= cap2) {
|
|
316784
316837
|
truncated = true;
|
|
316785
316838
|
return null;
|
|
@@ -316978,7 +317031,7 @@ function buildPlainTree(doc2, nodeId2, opts = {}, start2, hooks = {}) {
|
|
|
316978
317031
|
try {
|
|
316979
317032
|
for (const record2 of repeatRecords(doc2, repeat, under)) {
|
|
316980
317033
|
item = { collection, record: record2, suffix: `${outerItem?.suffix ?? ""}~${record2.id}` };
|
|
316981
|
-
for (const child of childrenOf(node2,
|
|
317034
|
+
for (const child of childrenOf(node2, nodesNow)) {
|
|
316982
317035
|
const built = build3(child, node2, kids3D, kidFold);
|
|
316983
317036
|
if (built) web.children.push(built);
|
|
316984
317037
|
}
|
|
@@ -316986,7 +317039,7 @@ function buildPlainTree(doc2, nodeId2, opts = {}, start2, hooks = {}) {
|
|
|
316986
317039
|
if (collection.perVisitor && !outerItem || collection.schema && opts.listTemplates) {
|
|
316987
317040
|
item = { collection, record: templateRecord(collection), suffix: `~${ITEM_RECORD}` };
|
|
316988
317041
|
const template2 = [];
|
|
316989
|
-
for (const child of childrenOf(node2,
|
|
317042
|
+
for (const child of childrenOf(node2, nodesNow)) {
|
|
316990
317043
|
const built = build3(child, node2, kids3D, kidFold);
|
|
316991
317044
|
if (built) template2.push(built);
|
|
316992
317045
|
}
|
|
@@ -317003,7 +317056,7 @@ function buildPlainTree(doc2, nodeId2, opts = {}, start2, hooks = {}) {
|
|
|
317003
317056
|
} finally {
|
|
317004
317057
|
item = outerItem;
|
|
317005
317058
|
}
|
|
317006
|
-
} else for (const child of childrenOf(node2,
|
|
317059
|
+
} else for (const child of childrenOf(node2, nodesNow)) {
|
|
317007
317060
|
const built = build3(child, node2, kids3D, kidFold);
|
|
317008
317061
|
if (built) web.children.push(built);
|
|
317009
317062
|
}
|
|
@@ -320600,7 +320653,7 @@ var init_package = __esm({
|
|
|
320600
320653
|
"packages/runtime/package.json"() {
|
|
320601
320654
|
package_default = {
|
|
320602
320655
|
name: "@popcraft/runtime",
|
|
320603
|
-
version: "0.
|
|
320656
|
+
version: "0.21.0",
|
|
320604
320657
|
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.",
|
|
320605
320658
|
license: "MIT",
|
|
320606
320659
|
homepage: "https://popcraft.app/docs/exporting/nextjs",
|
|
@@ -345259,7 +345312,6 @@ function exportsOf(source3) {
|
|
|
345259
345312
|
var CODE_LIMITS, packageOf;
|
|
345260
345313
|
var init_source2 = __esm({
|
|
345261
345314
|
"lib/code/source.ts"() {
|
|
345262
|
-
"use strict";
|
|
345263
345315
|
CODE_LIMITS = { modules: 100, sourceLength: 2e5, packages: 12 };
|
|
345264
345316
|
packageOf = (spec) => spec.split("/").slice(0, spec.startsWith("@") ? 2 : 1).join("/");
|
|
345265
345317
|
}
|
|
@@ -345302,7 +345354,6 @@ function compileModule(module2) {
|
|
|
345302
345354
|
var import_sucrase, BUILT_IN, memo4;
|
|
345303
345355
|
var init_compile2 = __esm({
|
|
345304
345356
|
"lib/code/compile.ts"() {
|
|
345305
|
-
"use strict";
|
|
345306
345357
|
import_sucrase = __toESM(require_dist2());
|
|
345307
345358
|
init_source2();
|
|
345308
345359
|
init_source2();
|
|
@@ -346270,7 +346321,8 @@ function componentPlan(doc2, screens) {
|
|
|
346270
346321
|
props.push({ name: propName2(one ? COMMERCE_PROP[c2.schema].name : camel3(c2.name)), type: one ? type : `${type}[]`, doc: `${c2.name}; none: the design's samples.`, schema: c2.schema, collectionId: c2.id });
|
|
346271
346322
|
}
|
|
346272
346323
|
for (const a of new Set(all3(s.tree.root).map((n) => n.action).filter((a2) => !!a2))) props.push({ name: COMMERCE_ACTION_PROP[a], type: "(formData: FormData) => void | Promise<void>", doc: `What sending its ${a} form does (a server action).`, action: a });
|
|
346273
|
-
|
|
346324
|
+
const picks = [...new Set(all3(s.tree.root).filter((n) => n.repeat?.pick && doc2.collections?.[n.repeat.collectionId]?.schema === "commerce.product").map((n) => n.repeat.pick.value))].sort();
|
|
346325
|
+
return { screen: s, name: name2, props, ...picks.length ? { picks } : {} };
|
|
346274
346326
|
});
|
|
346275
346327
|
}
|
|
346276
346328
|
function componentMedia(doc2, screens) {
|
|
@@ -346323,6 +346375,7 @@ function componentFiles(doc2, screens, o = {}) {
|
|
|
346323
346375
|
if (!p2) return null;
|
|
346324
346376
|
const c2 = doc2.collections[r.collectionId];
|
|
346325
346377
|
let out = COMMERCE_PROP[c2.schema].one ? `(${p2} ? [commerceItem(${JSON.stringify(c2.schema)}, ${p2})] : SAMPLE_${p2.toUpperCase()})` : `(${p2} ? ${p2}.map(v => commerceItem(${JSON.stringify(c2.schema)}, v)) : SAMPLE_${p2.toUpperCase()})`;
|
|
346378
|
+
if (r.pick) return `((list) => [list.find(item => String(item.values[${JSON.stringify(r.pick.key)}] ?? "") === ${JSON.stringify(r.pick.value)}) ?? list[0]].filter((item): item is CommerceItem => !!item))(${out})`;
|
|
346326
346379
|
if (r.offset || r.limit) out += `.slice(${r.offset ?? 0}${r.limit ? `, ${(r.offset ?? 0) + r.limit}` : ""})`;
|
|
346327
346380
|
return out;
|
|
346328
346381
|
},
|
|
@@ -346497,6 +346550,10 @@ function shopifyThemeFiles(doc2, screens, o = {}) {
|
|
|
346497
346550
|
const schema = n.repeat && schemaOf(n.repeat.collectionId);
|
|
346498
346551
|
if (!schema || !n.repeat) return null;
|
|
346499
346552
|
const range3 = `${n.repeat.limit ? ` limit: ${n.repeat.limit}` : ""}${n.repeat.offset ? ` offset: ${n.repeat.offset}` : ""}`;
|
|
346553
|
+
if (n.repeat.pick && schema === "commerce.product") {
|
|
346554
|
+
const handle = n.repeat.pick.value.replace(/[^a-z0-9-]/gi, "");
|
|
346555
|
+
return { open: `{% assign p = all_products['${handle}'] %}{% if p == empty %}{% assign p = ${source3} | first %}{% endif %}{% if p %}`, close: "{% endif %}" };
|
|
346556
|
+
}
|
|
346500
346557
|
switch (schema) {
|
|
346501
346558
|
case "commerce.product":
|
|
346502
346559
|
return { open: `{% for p in ${source3}${range3} %}`, close: "{% endfor %}" };
|
|
@@ -346879,14 +346936,16 @@ function pageSource(plan2, kind) {
|
|
|
346879
346936
|
cart: 'getProducts({ sortKey: "CREATED_AT", reverse: true })',
|
|
346880
346937
|
page: 'getProducts({ sortKey: "CREATED_AT", reverse: true })'
|
|
346881
346938
|
};
|
|
346939
|
+
const picks = uses("products") ? plan2.picks ?? [] : [];
|
|
346940
|
+
const listed = picks.length ? `Promise.all([${productsFrom[kind]}, ...${JSON.stringify(picks)}.map((h) => getProduct(h))]).then(([list, ...picked]) => [...picked.filter((p): p is NonNullable<typeof p> => !!p), ...list])` : productsFrom[kind];
|
|
346882
346941
|
const fetches = [
|
|
346883
346942
|
...kind === "collection" ? [["collection", "getCollection(handle)"]] : [],
|
|
346884
|
-
...uses("products") ? [["products",
|
|
346943
|
+
...uses("products") ? [["products", listed]] : [],
|
|
346885
346944
|
...uses("categories") ? [["categories", "storeCategories()"]] : [],
|
|
346886
346945
|
["frame", "storeFrame()"]
|
|
346887
346946
|
];
|
|
346888
346947
|
const shopify = [
|
|
346889
|
-
...kind === "product" ? ["getProduct"] : [],
|
|
346948
|
+
...kind === "product" || picks.length ? ["getProduct"] : [],
|
|
346890
346949
|
...kind === "collection" ? ["getCollection"] : [],
|
|
346891
346950
|
...uses("products") ? [productsFrom[kind].slice(0, productsFrom[kind].indexOf("("))] : []
|
|
346892
346951
|
];
|
|
@@ -347033,7 +347092,8 @@ function storefrontDesign(doc2, screens) {
|
|
|
347033
347092
|
const c2 = n.repeat && named(n.repeat.collectionId);
|
|
347034
347093
|
if (!c2 || !n.repeat) return null;
|
|
347035
347094
|
const range3 = `${n.repeat.limit ? ` limit="${n.repeat.limit}"` : ""}${n.repeat.offset ? ` offset="${n.repeat.offset}"` : ""}`;
|
|
347036
|
-
|
|
347095
|
+
const pick5 = n.repeat.pick ? ` pick-${n.repeat.pick.key}="${n.repeat.pick.value.replace(/[&"<>]/g, (ch) => `&#${ch.charCodeAt(0)};`)}"` : "";
|
|
347096
|
+
return { open: `<!-- pc:each list="${c2.name}" schema="${c2.schema ?? ""}" as="item"${range3}${pick5} -->`, close: "<!-- pc:end -->" };
|
|
347037
347097
|
},
|
|
347038
347098
|
form: (n) => n.action ? { attrs: { "data-pc-action": n.action } } : null
|
|
347039
347099
|
});
|
|
@@ -350976,7 +351036,7 @@ var init_motion_rich = __esm({
|
|
|
350976
351036
|
return { summary: `Playback on ${plural2(patches.size, "instance")}`, data: { ids: [...patches.keys()] } };
|
|
350977
351037
|
}
|
|
350978
351038
|
});
|
|
350979
|
-
PROP_TYPES = ["NUMBER", "COLOR", "MOTION", "BOOLEAN", "TEXT"];
|
|
351039
|
+
PROP_TYPES = ["NUMBER", "COLOR", "MOTION", "BOOLEAN", "TEXT", "IMAGE"];
|
|
350980
351040
|
componentPropOp = external_exports.discriminatedUnion("op", [
|
|
350981
351041
|
external_exports.object({
|
|
350982
351042
|
op: external_exports.literal("add"),
|
|
@@ -350993,8 +351053,8 @@ var init_motion_rich = __esm({
|
|
|
350993
351053
|
external_exports.object({
|
|
350994
351054
|
op: external_exports.literal("bindLayer"),
|
|
350995
351055
|
layer: external_exports.string().describe("A layer inside the component."),
|
|
350996
|
-
name: external_exports.string().describe("A NUMBER or
|
|
350997
|
-
path: external_exports.string().max(300).nullable().describe("The layer property it feeds (a number path for NUMBER, a colour path for COLOR: fills[#0].color, opacity, text.counter \u2026); null unbinds.")
|
|
351056
|
+
name: external_exports.string().describe("A NUMBER, COLOR or IMAGE property."),
|
|
351057
|
+
path: external_exports.string().max(300).nullable().describe("The layer property it feeds (a number path for NUMBER, a colour path for COLOR: fills[#0].color, opacity, text.counter \u2026; a picture for IMAGE: imageUrl on an image layer, fills[#0].imageUrl on an image fill); null unbinds.")
|
|
350998
351058
|
}).describe("Make a layer property an input: each instance's value of the property plays there (a keyed path too).")
|
|
350999
351059
|
]);
|
|
351000
351060
|
motionEditComponentProperty = defineCommand({
|
|
@@ -351010,7 +351070,7 @@ var init_motion_rich = __esm({
|
|
|
351010
351070
|
ui: { label: "Edit component property", palette: false },
|
|
351011
351071
|
agent: {
|
|
351012
351072
|
name: "edit_component_property",
|
|
351013
|
-
description: `A component's properties, as its instances set them: add a NUMBER, COLOR, MOTION (one playback setting shown on every instance), BOOLEAN or
|
|
351073
|
+
description: `A component's properties, as its instances set them: add a NUMBER, COLOR, MOTION (one playback setting shown on every instance), BOOLEAN, TEXT or IMAGE (a picture's address) property, remove one, change its default, or bind a layer property inside the component to a NUMBER / COLOR / IMAGE property (a layer input; IMAGE feeds a picture). An instance's TEXT and IMAGE properties can follow a record's field (bind_field). Keys can also take their value from a property per instance (set_keyframes with bind), so "count to N" or "slide this far" is set per instance with set_instance_playback properties.`
|
|
351014
351074
|
}
|
|
351015
351075
|
},
|
|
351016
351076
|
run: (args2, ctx2) => {
|
|
@@ -351052,7 +351112,7 @@ var init_motion_rich = __esm({
|
|
|
351052
351112
|
}
|
|
351053
351113
|
case "bindLayer": {
|
|
351054
351114
|
const def = has(op4.name);
|
|
351055
|
-
if (def.type !== "NUMBER" && def.type !== "COLOR") throw new ToolError("Only a NUMBER or
|
|
351115
|
+
if (def.type !== "NUMBER" && def.type !== "COLOR" && def.type !== "IMAGE") throw new ToolError("Only a NUMBER, COLOR or IMAGE property feeds a layer input.");
|
|
351056
351116
|
const layer2 = nodeOrThrow(doc2, op4.layer);
|
|
351057
351117
|
const owner = target2.type === "COMPONENT_SET" ? target2.id : target2.id;
|
|
351058
351118
|
let inside2 = false;
|
|
@@ -354042,7 +354102,6 @@ var init_publish = __esm({
|
|
|
354042
354102
|
var storeOpsSeam;
|
|
354043
354103
|
var init_seams = __esm({
|
|
354044
354104
|
"lib/commands/seams.ts"() {
|
|
354045
|
-
"use strict";
|
|
354046
354105
|
storeOpsSeam = (st) => ({
|
|
354047
354106
|
booleanOperation: (op4) => st().booleanOperation(op4),
|
|
354048
354107
|
flatten: () => st().flattenSelection(),
|
|
@@ -356456,9 +356515,11 @@ are whole stores to begin from.
|
|
|
356456
356515
|
- \`commerce.menu\` for the store's menu, \`commerce.collection\` for its categories
|
|
356457
356516
|
Add a few real sample records with \`edit_records\`: the canvas is drawn with them. A store's real catalogue
|
|
356458
356517
|
comes from the Ecommerce plugin (Marketplace \u203A Plugins): it fills these collections from Shopify.
|
|
356459
|
-
3. **The lists.**
|
|
356460
|
-
|
|
356461
|
-
|
|
356518
|
+
3. **The cards and lists.** Make the card a component with properties (\`edit_component_property\`: TEXT Title and
|
|
356519
|
+
Price, IMAGE Image fed to its picture with \`bindLayer\` path \`imageUrl\`). \`set_repeat\` on the frame that holds
|
|
356520
|
+
one instance, over the collection, and \`bind_field\` each property to a field (Title \u2190 title, Price \u2190 price,
|
|
356521
|
+
Image \u2190 image). One product in a hero or feature is \`set_record\` (by its handle), never a list of one with an
|
|
356522
|
+
offset. The cart's totals are a list of one (\`limit: 1\`) over the \`commerce.cart\` collection.
|
|
356462
356523
|
4. **A page per product.** \`set_route\` on the product screen with the product collection's id: the route is
|
|
356463
356524
|
\`/product\` and each product's page is \`/product/<handle>\`. A card links to that screen.
|
|
356464
356525
|
5. **The forms.** \`set_control\` FORM with a storefront \`formAction\`:
|
|
@@ -358876,16 +358937,16 @@ var init_api5 = __esm({
|
|
|
358876
358937
|
}
|
|
358877
358938
|
});
|
|
358878
358939
|
|
|
358879
|
-
// node_modules/.pnpm/@popcraft+plugins@1.0.0_patch_hash=
|
|
358940
|
+
// node_modules/.pnpm/@popcraft+plugins@1.0.0_patch_hash=6826cb40a12857607fa1f7d7d102e5d8316bd483c1ff06865dac73139dfe709b/node_modules/@popcraft/plugins/dist/generated/runtime.js
|
|
358880
358941
|
var MAIN_RUNTIME, UI_RUNTIME;
|
|
358881
358942
|
var init_runtime4 = __esm({
|
|
358882
|
-
"node_modules/.pnpm/@popcraft+plugins@1.0.0_patch_hash=
|
|
358883
|
-
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})();';
|
|
358943
|
+
"node_modules/.pnpm/@popcraft+plugins@1.0.0_patch_hash=6826cb40a12857607fa1f7d7d102e5d8316bd483c1ff06865dac73139dfe709b/node_modules/@popcraft/plugins/dist/generated/runtime.js"() {
|
|
358944
|
+
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 /** Which record layers are about (one product, picked from a collection), and which of its fields a layer\'s words, picture or an instance\'s properties follow. */\n setRecord: (opts) => rpc.call("setRecord", opts || {}),\n bindField: (opts) => rpc.call("bindField", 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})();';
|
|
358884
358945
|
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})();';
|
|
358885
358946
|
}
|
|
358886
358947
|
});
|
|
358887
358948
|
|
|
358888
|
-
// node_modules/.pnpm/@popcraft+plugins@1.0.0_patch_hash=
|
|
358949
|
+
// node_modules/.pnpm/@popcraft+plugins@1.0.0_patch_hash=6826cb40a12857607fa1f7d7d102e5d8316bd483c1ff06865dac73139dfe709b/node_modules/@popcraft/plugins/dist/host.js
|
|
358889
358950
|
function csp(network) {
|
|
358890
358951
|
const connect2 = network ? "connect-src * data: blob:;" : "connect-src 'none';";
|
|
358891
358952
|
const img = network ? "img-src * data: blob:;" : "img-src data: blob:;";
|
|
@@ -358913,40 +358974,40 @@ function buildUIDocument(uiHtml, network) {
|
|
|
358913
358974
|
}
|
|
358914
358975
|
var escapeScript;
|
|
358915
358976
|
var init_host2 = __esm({
|
|
358916
|
-
"node_modules/.pnpm/@popcraft+plugins@1.0.0_patch_hash=
|
|
358977
|
+
"node_modules/.pnpm/@popcraft+plugins@1.0.0_patch_hash=6826cb40a12857607fa1f7d7d102e5d8316bd483c1ff06865dac73139dfe709b/node_modules/@popcraft/plugins/dist/host.js"() {
|
|
358917
358978
|
init_runtime4();
|
|
358918
358979
|
escapeScript = (code) => code.replace(/<\/script/gi, "<\\/script");
|
|
358919
358980
|
}
|
|
358920
358981
|
});
|
|
358921
358982
|
|
|
358922
|
-
// node_modules/.pnpm/@popcraft+plugins@1.0.0_patch_hash=
|
|
358983
|
+
// node_modules/.pnpm/@popcraft+plugins@1.0.0_patch_hash=6826cb40a12857607fa1f7d7d102e5d8316bd483c1ff06865dac73139dfe709b/node_modules/@popcraft/plugins/dist/runtime/rpc.js
|
|
358923
358984
|
var init_rpc = __esm({
|
|
358924
|
-
"node_modules/.pnpm/@popcraft+plugins@1.0.0_patch_hash=
|
|
358985
|
+
"node_modules/.pnpm/@popcraft+plugins@1.0.0_patch_hash=6826cb40a12857607fa1f7d7d102e5d8316bd483c1ff06865dac73139dfe709b/node_modules/@popcraft/plugins/dist/runtime/rpc.js"() {
|
|
358925
358986
|
}
|
|
358926
358987
|
});
|
|
358927
358988
|
|
|
358928
|
-
// node_modules/.pnpm/@popcraft+plugins@1.0.0_patch_hash=
|
|
358989
|
+
// node_modules/.pnpm/@popcraft+plugins@1.0.0_patch_hash=6826cb40a12857607fa1f7d7d102e5d8316bd483c1ff06865dac73139dfe709b/node_modules/@popcraft/plugins/dist/runtime/main.js
|
|
358929
358990
|
var init_main = __esm({
|
|
358930
|
-
"node_modules/.pnpm/@popcraft+plugins@1.0.0_patch_hash=
|
|
358991
|
+
"node_modules/.pnpm/@popcraft+plugins@1.0.0_patch_hash=6826cb40a12857607fa1f7d7d102e5d8316bd483c1ff06865dac73139dfe709b/node_modules/@popcraft/plugins/dist/runtime/main.js"() {
|
|
358931
358992
|
init_rpc();
|
|
358932
358993
|
}
|
|
358933
358994
|
});
|
|
358934
358995
|
|
|
358935
|
-
// node_modules/.pnpm/@popcraft+plugins@1.0.0_patch_hash=
|
|
358996
|
+
// node_modules/.pnpm/@popcraft+plugins@1.0.0_patch_hash=6826cb40a12857607fa1f7d7d102e5d8316bd483c1ff06865dac73139dfe709b/node_modules/@popcraft/plugins/dist/types.js
|
|
358936
358997
|
var init_types9 = __esm({
|
|
358937
|
-
"node_modules/.pnpm/@popcraft+plugins@1.0.0_patch_hash=
|
|
358998
|
+
"node_modules/.pnpm/@popcraft+plugins@1.0.0_patch_hash=6826cb40a12857607fa1f7d7d102e5d8316bd483c1ff06865dac73139dfe709b/node_modules/@popcraft/plugins/dist/types.js"() {
|
|
358938
358999
|
}
|
|
358939
359000
|
});
|
|
358940
359001
|
|
|
358941
|
-
// node_modules/.pnpm/@popcraft+plugins@1.0.0_patch_hash=
|
|
359002
|
+
// node_modules/.pnpm/@popcraft+plugins@1.0.0_patch_hash=6826cb40a12857607fa1f7d7d102e5d8316bd483c1ff06865dac73139dfe709b/node_modules/@popcraft/plugins/dist/widget.js
|
|
358942
359003
|
var init_widget = __esm({
|
|
358943
|
-
"node_modules/.pnpm/@popcraft+plugins@1.0.0_patch_hash=
|
|
359004
|
+
"node_modules/.pnpm/@popcraft+plugins@1.0.0_patch_hash=6826cb40a12857607fa1f7d7d102e5d8316bd483c1ff06865dac73139dfe709b/node_modules/@popcraft/plugins/dist/widget.js"() {
|
|
358944
359005
|
}
|
|
358945
359006
|
});
|
|
358946
359007
|
|
|
358947
|
-
// node_modules/.pnpm/@popcraft+plugins@1.0.0_patch_hash=
|
|
359008
|
+
// node_modules/.pnpm/@popcraft+plugins@1.0.0_patch_hash=6826cb40a12857607fa1f7d7d102e5d8316bd483c1ff06865dac73139dfe709b/node_modules/@popcraft/plugins/dist/index.js
|
|
358948
359009
|
var init_dist = __esm({
|
|
358949
|
-
"node_modules/.pnpm/@popcraft+plugins@1.0.0_patch_hash=
|
|
359010
|
+
"node_modules/.pnpm/@popcraft+plugins@1.0.0_patch_hash=6826cb40a12857607fa1f7d7d102e5d8316bd483c1ff06865dac73139dfe709b/node_modules/@popcraft/plugins/dist/index.js"() {
|
|
358950
359011
|
init_host2();
|
|
358951
359012
|
init_main();
|
|
358952
359013
|
init_runtime4();
|
|
@@ -390534,7 +390595,6 @@ function record(source, namespaces, globals, limits) {
|
|
|
390534
390595
|
var HELPER_NAMES;
|
|
390535
390596
|
var init_helper_names = __esm({
|
|
390536
390597
|
"lib/agent/design-script/helper-names.ts"() {
|
|
390537
|
-
"use strict";
|
|
390538
390598
|
HELPER_NAMES = ["draw", "marks", "fit", "motion", "captions", "overlays", "texture", "pointer", "windows", "devices", "type", "beat", "web", "social", "video", "site", "effects"];
|
|
390539
390599
|
}
|
|
390540
390600
|
});
|
|
@@ -390917,7 +390977,6 @@ function designRecorder() {
|
|
|
390917
390977
|
var installed;
|
|
390918
390978
|
var init_recorders = __esm({
|
|
390919
390979
|
"lib/agent/design-script/recorders.ts"() {
|
|
390920
|
-
"use strict";
|
|
390921
390980
|
installed = null;
|
|
390922
390981
|
}
|
|
390923
390982
|
});
|
|
@@ -394052,7 +394111,31 @@ function collectionOf(doc2, ref3) {
|
|
|
394052
394111
|
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."}`);
|
|
394053
394112
|
return c2;
|
|
394054
394113
|
}
|
|
394055
|
-
|
|
394114
|
+
function recordOf(doc2, c2, ref3) {
|
|
394115
|
+
const own2 = doc2.records?.[ref3];
|
|
394116
|
+
if (own2?.collectionId === c2.id) return own2;
|
|
394117
|
+
const slugs = recordSlugs(doc2, c2.id);
|
|
394118
|
+
const want = ref3.trim().toLowerCase();
|
|
394119
|
+
const found = recordsIn(doc2, c2.id).find((r) => slugs.get(r.id) === want || c2.fields.some((f2) => String(r.values[f2.id] ?? "").trim().toLowerCase() === want));
|
|
394120
|
+
if (!found) throw new ToolError(`${c2.name} has no record "${ref3}". Read them with get_records.`);
|
|
394121
|
+
return found;
|
|
394122
|
+
}
|
|
394123
|
+
function bindingKey(doc2, node2, property) {
|
|
394124
|
+
if (property === "text") {
|
|
394125
|
+
if (node2.type !== "TEXT") throw new ToolError(`"${node2.name}" is not a text.`);
|
|
394126
|
+
return "characters";
|
|
394127
|
+
}
|
|
394128
|
+
if (property === "picture") {
|
|
394129
|
+
if (node2.type !== "IMAGE") throw new ToolError(`"${node2.name}" is not an image layer: give its component an IMAGE property instead.`);
|
|
394130
|
+
return "imageUrl";
|
|
394131
|
+
}
|
|
394132
|
+
if (node2.type !== "INSTANCE") throw new ToolError(`"${node2.name}" has no property "${property}": say text, picture, or an instance's property.`);
|
|
394133
|
+
const defs = componentDefinitions(doc2.nodes, node2.mainComponentId);
|
|
394134
|
+
const def = defs[property];
|
|
394135
|
+
if (!def || !["TEXT", "IMAGE", "BOOLEAN"].includes(def.type)) throw new ToolError(`"${node2.name}" has no TEXT, IMAGE or BOOLEAN property "${property}". It has: ${Object.keys(defs).join(", ") || "none"}.`);
|
|
394136
|
+
return `${PROP_BINDING}${property}`;
|
|
394137
|
+
}
|
|
394138
|
+
var sizing2, padding2, overrides, nodeSetResponsive, link, nodeSetSemantics, nodeSetControl, siteSetRoute, breakpoint, siteSetBreakpoints, siteSetGpuTransitions, ENV_NAME, RESERVED_ENV, siteSetEnvironment, siteGetEnvironment, siteGetBreakpoints, described2, dataEditCollection, dataEditRecords, dataGetRecords, nodeSetRepeat, nodeSetRecord, nodeBindField, recordLabel;
|
|
394056
394139
|
var init_site3 = __esm({
|
|
394057
394140
|
"lib/commands/site.ts"() {
|
|
394058
394141
|
"use strict";
|
|
@@ -394061,6 +394144,7 @@ var init_site3 = __esm({
|
|
|
394061
394144
|
init_breakpoints();
|
|
394062
394145
|
init_collections();
|
|
394063
394146
|
init_semantics();
|
|
394147
|
+
init_instances();
|
|
394064
394148
|
init_controls();
|
|
394065
394149
|
init_types();
|
|
394066
394150
|
init_routes();
|
|
@@ -394659,6 +394743,83 @@ var init_site3 = __esm({
|
|
|
394659
394743
|
return { summary: c2 ? `Repeats for ${c2.name} (${shown2} records)` : "No longer repeats", data: { ids: ids2, collectionId: c2?.id ?? null } };
|
|
394660
394744
|
}
|
|
394661
394745
|
});
|
|
394746
|
+
nodeSetRecord = defineCommand({
|
|
394747
|
+
id: "node.setRecord",
|
|
394748
|
+
title: "Show a record",
|
|
394749
|
+
domain: "node",
|
|
394750
|
+
effect: "document",
|
|
394751
|
+
permission: "write",
|
|
394752
|
+
undoLabel: "Show a record",
|
|
394753
|
+
params: external_exports.object({
|
|
394754
|
+
ids: external_exports.array(external_exports.string()).min(1).max(50).optional().describe("Layers to edit (default: the selection)."),
|
|
394755
|
+
collection: external_exports.string().nullable().describe("The collection, by id or name; null: the layers show no record of their own again."),
|
|
394756
|
+
record: external_exports.string().optional().describe("The record, by id, page address, or the value of one of its fields (a product's handle or title).")
|
|
394757
|
+
}).strict(),
|
|
394758
|
+
expose: {
|
|
394759
|
+
plugin: { method: "setRecord" },
|
|
394760
|
+
ui: { label: "Show a record", keywords: ["record", "data", "bind", "product", "cms", "collection", "source"], enabled: needsSelection(1), palette: false },
|
|
394761
|
+
agent: {
|
|
394762
|
+
name: "set_record",
|
|
394763
|
+
description: "Make layers about one record of a collection (one product, one post): they and what they hold show its values wherever they follow a field \u2014 a text with {{item.<field key>}}, a picture or an instance property bound with bind_field. The nearest record wins: a layer's own, then a list it is in, then its page's."
|
|
394764
|
+
}
|
|
394765
|
+
},
|
|
394766
|
+
run: (args2, ctx2) => {
|
|
394767
|
+
const { doc: doc2, ids: ids2 } = resolveTargets(ctx2, args2.ids, "set_record");
|
|
394768
|
+
const c2 = args2.collection ? collectionOf(doc2, args2.collection) : null;
|
|
394769
|
+
if (c2 && !args2.record) throw new ToolError("Say which record.");
|
|
394770
|
+
const r = c2 ? recordOf(doc2, c2, args2.record) : null;
|
|
394771
|
+
const pin = c2 && r ? { collectionId: c2.id, recordId: r.id } : void 0;
|
|
394772
|
+
commitUpdates(ctx2, doc2, new Map(ids2.map((id3) => [id3, { record: pin }])));
|
|
394773
|
+
return { summary: pin ? `Shows ${c2.name}: ${recordLabel(c2, r)}` : "Shows no record of its own", data: { ids: ids2, record: pin ?? null } };
|
|
394774
|
+
}
|
|
394775
|
+
});
|
|
394776
|
+
nodeBindField = defineCommand({
|
|
394777
|
+
id: "node.bindField",
|
|
394778
|
+
title: "Bind to a field",
|
|
394779
|
+
domain: "node",
|
|
394780
|
+
effect: "document",
|
|
394781
|
+
permission: "write",
|
|
394782
|
+
undoLabel: "Bind to a field",
|
|
394783
|
+
params: external_exports.object({
|
|
394784
|
+
ids: external_exports.array(external_exports.string()).min(1).max(50).optional().describe("Layers to edit (default: the selection)."),
|
|
394785
|
+
property: external_exports.string().min(1).max(120).describe(`What follows the field: "text" (a text's words), "picture" (an image layer's picture), or the name of one of an instance's TEXT, IMAGE or BOOLEAN properties.`),
|
|
394786
|
+
field: external_exports.string().nullable().describe("The field, by name or key, of the record the layer is about (its own, its list's or its page's); null: it stops following one.")
|
|
394787
|
+
}).strict(),
|
|
394788
|
+
expose: {
|
|
394789
|
+
plugin: { method: "bindField" },
|
|
394790
|
+
ui: { label: "Bind to a field", keywords: ["bind", "field", "data", "source", "dynamic", "cms", "product"], enabled: needsSelection(1), palette: false },
|
|
394791
|
+
agent: {
|
|
394792
|
+
name: "bind_field",
|
|
394793
|
+
description: "Make a layer show a field of the record it is about (set_record, a list, or a collection page): a text's words, an image layer's picture, or an instance's TEXT / IMAGE / BOOLEAN property \u2014 so a product card component takes its title, price and photo from the record. null unbinds."
|
|
394794
|
+
}
|
|
394795
|
+
},
|
|
394796
|
+
run: (args2, ctx2) => {
|
|
394797
|
+
const { doc: doc2, ids: ids2 } = resolveTargets(ctx2, args2.ids, "bind_field");
|
|
394798
|
+
const updates = /* @__PURE__ */ new Map();
|
|
394799
|
+
for (const id3 of ids2) {
|
|
394800
|
+
const node2 = doc2.nodes[id3];
|
|
394801
|
+
const key5 = bindingKey(doc2, node2, args2.property);
|
|
394802
|
+
const bound = { ...node2.boundExpressions ?? {} };
|
|
394803
|
+
if (args2.field === null) delete bound[key5];
|
|
394804
|
+
else {
|
|
394805
|
+
const record2 = shownRecordOf(doc2.nodes, doc2, id3);
|
|
394806
|
+
const c2 = record2 && doc2.collections?.[record2.collectionId];
|
|
394807
|
+
if (!c2) throw new ToolError(`"${node2.name}" is about no record: pick one with set_record, or put it in a list (set_repeat).`);
|
|
394808
|
+
const want = fieldKey(args2.field);
|
|
394809
|
+
const f2 = c2.fields.find((x2) => x2.id === args2.field || fieldKey(x2.name) === want);
|
|
394810
|
+
if (!f2) throw new ToolError(`${c2.name} has no field "${args2.field}". It has: ${c2.fields.map((x2) => fieldKey(x2.name)).join(", ")}.`);
|
|
394811
|
+
bound[key5] = `item_${fieldKey(f2.name)}`;
|
|
394812
|
+
}
|
|
394813
|
+
updates.set(id3, { boundExpressions: Object.keys(bound).length ? bound : void 0 });
|
|
394814
|
+
}
|
|
394815
|
+
commitUpdates(ctx2, doc2, updates);
|
|
394816
|
+
return { summary: args2.field === null ? `${args2.property} follows no field` : `${args2.property} \u2190 ${args2.field}`, data: { ids: ids2 } };
|
|
394817
|
+
}
|
|
394818
|
+
});
|
|
394819
|
+
recordLabel = (c2, r) => {
|
|
394820
|
+
const f2 = c2.fields.find((x2) => x2.type === "TEXT") ?? c2.fields[0];
|
|
394821
|
+
return String((f2 && r.values[f2.id]) ?? r.id).slice(0, 80);
|
|
394822
|
+
};
|
|
394662
394823
|
}
|
|
394663
394824
|
});
|
|
394664
394825
|
|
|
@@ -395756,6 +395917,8 @@ var init_builtin4 = __esm({
|
|
|
395756
395917
|
siteSetRoute,
|
|
395757
395918
|
nodeSetControl,
|
|
395758
395919
|
nodeSetRepeat,
|
|
395920
|
+
nodeSetRecord,
|
|
395921
|
+
nodeBindField,
|
|
395759
395922
|
siteSetEnvironment,
|
|
395760
395923
|
siteGetEnvironment,
|
|
395761
395924
|
codeEditModule,
|
|
@@ -403062,7 +403225,7 @@ init_resources();
|
|
|
403062
403225
|
init_desktop();
|
|
403063
403226
|
init_hypery();
|
|
403064
403227
|
import { createInterface } from "node:readline";
|
|
403065
|
-
var VERSION2 = "0.
|
|
403228
|
+
var VERSION2 = "0.21.0";
|
|
403066
403229
|
var HELP = `popcraft ${VERSION2} \u2014 the PopCraft command line
|
|
403067
403230
|
|
|
403068
403231
|
Files (headless, on .popcraft files):
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@popcraft/cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.21.0",
|
|
4
4
|
"description": "The PopCraft command line: edit .popcraft files headlessly, call the REST API, publish to the marketplace and manage the desktop app's local plugins, themes, fonts, skills and agents.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"homepage": "https://popcraft.app/docs/api/cli",
|
|
@@ -34,7 +34,7 @@
|
|
|
34
34
|
"esbuild": "0.28.2"
|
|
35
35
|
},
|
|
36
36
|
"dependencies": {
|
|
37
|
-
"@popcraft/kit": "0.
|
|
37
|
+
"@popcraft/kit": "0.21.0"
|
|
38
38
|
},
|
|
39
39
|
"scripts": {
|
|
40
40
|
"build": "node build.mjs",
|