@popcraft/cli 0.20.2 → 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 -39
- 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();
|
|
@@ -305059,7 +305092,6 @@ function creditLine(c2) {
|
|
|
305059
305092
|
var MAX_PHOTO_PAGE, MAX_PHOTO_QUERY, UUID, isPhotoId, photoImagePath;
|
|
305060
305093
|
var init_stock = __esm({
|
|
305061
305094
|
"lib/photos/stock.ts"() {
|
|
305062
|
-
"use strict";
|
|
305063
305095
|
MAX_PHOTO_PAGE = 12;
|
|
305064
305096
|
MAX_PHOTO_QUERY = 200;
|
|
305065
305097
|
UUID = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
@@ -310996,7 +311028,6 @@ function agentToolList() {
|
|
|
310996
311028
|
var AGENT_CAPABILITIES, legacyCommandId, legacyTools, blobToDataUrl3, provided, legacyTool, legacyToolList;
|
|
310997
311029
|
var init_agent = __esm({
|
|
310998
311030
|
"lib/commands/agent.ts"() {
|
|
310999
|
-
"use strict";
|
|
311000
311031
|
init_types5();
|
|
311001
311032
|
init_registry();
|
|
311002
311033
|
init_errors();
|
|
@@ -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",
|
|
@@ -346268,7 +346321,8 @@ function componentPlan(doc2, screens) {
|
|
|
346268
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 });
|
|
346269
346322
|
}
|
|
346270
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 });
|
|
346271
|
-
|
|
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 } : {} };
|
|
346272
346326
|
});
|
|
346273
346327
|
}
|
|
346274
346328
|
function componentMedia(doc2, screens) {
|
|
@@ -346321,6 +346375,7 @@ function componentFiles(doc2, screens, o = {}) {
|
|
|
346321
346375
|
if (!p2) return null;
|
|
346322
346376
|
const c2 = doc2.collections[r.collectionId];
|
|
346323
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})`;
|
|
346324
346379
|
if (r.offset || r.limit) out += `.slice(${r.offset ?? 0}${r.limit ? `, ${(r.offset ?? 0) + r.limit}` : ""})`;
|
|
346325
346380
|
return out;
|
|
346326
346381
|
},
|
|
@@ -346495,6 +346550,10 @@ function shopifyThemeFiles(doc2, screens, o = {}) {
|
|
|
346495
346550
|
const schema = n.repeat && schemaOf(n.repeat.collectionId);
|
|
346496
346551
|
if (!schema || !n.repeat) return null;
|
|
346497
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
|
+
}
|
|
346498
346557
|
switch (schema) {
|
|
346499
346558
|
case "commerce.product":
|
|
346500
346559
|
return { open: `{% for p in ${source3}${range3} %}`, close: "{% endfor %}" };
|
|
@@ -346877,14 +346936,16 @@ function pageSource(plan2, kind) {
|
|
|
346877
346936
|
cart: 'getProducts({ sortKey: "CREATED_AT", reverse: true })',
|
|
346878
346937
|
page: 'getProducts({ sortKey: "CREATED_AT", reverse: true })'
|
|
346879
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];
|
|
346880
346941
|
const fetches = [
|
|
346881
346942
|
...kind === "collection" ? [["collection", "getCollection(handle)"]] : [],
|
|
346882
|
-
...uses("products") ? [["products",
|
|
346943
|
+
...uses("products") ? [["products", listed]] : [],
|
|
346883
346944
|
...uses("categories") ? [["categories", "storeCategories()"]] : [],
|
|
346884
346945
|
["frame", "storeFrame()"]
|
|
346885
346946
|
];
|
|
346886
346947
|
const shopify = [
|
|
346887
|
-
...kind === "product" ? ["getProduct"] : [],
|
|
346948
|
+
...kind === "product" || picks.length ? ["getProduct"] : [],
|
|
346888
346949
|
...kind === "collection" ? ["getCollection"] : [],
|
|
346889
346950
|
...uses("products") ? [productsFrom[kind].slice(0, productsFrom[kind].indexOf("("))] : []
|
|
346890
346951
|
];
|
|
@@ -347031,7 +347092,8 @@ function storefrontDesign(doc2, screens) {
|
|
|
347031
347092
|
const c2 = n.repeat && named(n.repeat.collectionId);
|
|
347032
347093
|
if (!c2 || !n.repeat) return null;
|
|
347033
347094
|
const range3 = `${n.repeat.limit ? ` limit="${n.repeat.limit}"` : ""}${n.repeat.offset ? ` offset="${n.repeat.offset}"` : ""}`;
|
|
347034
|
-
|
|
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 -->" };
|
|
347035
347097
|
},
|
|
347036
347098
|
form: (n) => n.action ? { attrs: { "data-pc-action": n.action } } : null
|
|
347037
347099
|
});
|
|
@@ -350974,7 +351036,7 @@ var init_motion_rich = __esm({
|
|
|
350974
351036
|
return { summary: `Playback on ${plural2(patches.size, "instance")}`, data: { ids: [...patches.keys()] } };
|
|
350975
351037
|
}
|
|
350976
351038
|
});
|
|
350977
|
-
PROP_TYPES = ["NUMBER", "COLOR", "MOTION", "BOOLEAN", "TEXT"];
|
|
351039
|
+
PROP_TYPES = ["NUMBER", "COLOR", "MOTION", "BOOLEAN", "TEXT", "IMAGE"];
|
|
350978
351040
|
componentPropOp = external_exports.discriminatedUnion("op", [
|
|
350979
351041
|
external_exports.object({
|
|
350980
351042
|
op: external_exports.literal("add"),
|
|
@@ -350991,8 +351053,8 @@ var init_motion_rich = __esm({
|
|
|
350991
351053
|
external_exports.object({
|
|
350992
351054
|
op: external_exports.literal("bindLayer"),
|
|
350993
351055
|
layer: external_exports.string().describe("A layer inside the component."),
|
|
350994
|
-
name: external_exports.string().describe("A NUMBER or
|
|
350995
|
-
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.")
|
|
350996
351058
|
}).describe("Make a layer property an input: each instance's value of the property plays there (a keyed path too).")
|
|
350997
351059
|
]);
|
|
350998
351060
|
motionEditComponentProperty = defineCommand({
|
|
@@ -351008,7 +351070,7 @@ var init_motion_rich = __esm({
|
|
|
351008
351070
|
ui: { label: "Edit component property", palette: false },
|
|
351009
351071
|
agent: {
|
|
351010
351072
|
name: "edit_component_property",
|
|
351011
|
-
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.`
|
|
351012
351074
|
}
|
|
351013
351075
|
},
|
|
351014
351076
|
run: (args2, ctx2) => {
|
|
@@ -351050,7 +351112,7 @@ var init_motion_rich = __esm({
|
|
|
351050
351112
|
}
|
|
351051
351113
|
case "bindLayer": {
|
|
351052
351114
|
const def = has(op4.name);
|
|
351053
|
-
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.");
|
|
351054
351116
|
const layer2 = nodeOrThrow(doc2, op4.layer);
|
|
351055
351117
|
const owner = target2.type === "COMPONENT_SET" ? target2.id : target2.id;
|
|
351056
351118
|
let inside2 = false;
|
|
@@ -356453,9 +356515,11 @@ are whole stores to begin from.
|
|
|
356453
356515
|
- \`commerce.menu\` for the store's menu, \`commerce.collection\` for its categories
|
|
356454
356516
|
Add a few real sample records with \`edit_records\`: the canvas is drawn with them. A store's real catalogue
|
|
356455
356517
|
comes from the Ecommerce plugin (Marketplace \u203A Plugins): it fills these collections from Shopify.
|
|
356456
|
-
3. **The lists.**
|
|
356457
|
-
|
|
356458
|
-
|
|
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.
|
|
356459
356523
|
4. **A page per product.** \`set_route\` on the product screen with the product collection's id: the route is
|
|
356460
356524
|
\`/product\` and each product's page is \`/product/<handle>\`. A card links to that screen.
|
|
356461
356525
|
5. **The forms.** \`set_control\` FORM with a storefront \`formAction\`:
|
|
@@ -358873,16 +358937,16 @@ var init_api5 = __esm({
|
|
|
358873
358937
|
}
|
|
358874
358938
|
});
|
|
358875
358939
|
|
|
358876
|
-
// 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
|
|
358877
358941
|
var MAIN_RUNTIME, UI_RUNTIME;
|
|
358878
358942
|
var init_runtime4 = __esm({
|
|
358879
|
-
"node_modules/.pnpm/@popcraft+plugins@1.0.0_patch_hash=
|
|
358880
|
-
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})();';
|
|
358881
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})();';
|
|
358882
358946
|
}
|
|
358883
358947
|
});
|
|
358884
358948
|
|
|
358885
|
-
// 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
|
|
358886
358950
|
function csp(network) {
|
|
358887
358951
|
const connect2 = network ? "connect-src * data: blob:;" : "connect-src 'none';";
|
|
358888
358952
|
const img = network ? "img-src * data: blob:;" : "img-src data: blob:;";
|
|
@@ -358910,40 +358974,40 @@ function buildUIDocument(uiHtml, network) {
|
|
|
358910
358974
|
}
|
|
358911
358975
|
var escapeScript;
|
|
358912
358976
|
var init_host2 = __esm({
|
|
358913
|
-
"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"() {
|
|
358914
358978
|
init_runtime4();
|
|
358915
358979
|
escapeScript = (code) => code.replace(/<\/script/gi, "<\\/script");
|
|
358916
358980
|
}
|
|
358917
358981
|
});
|
|
358918
358982
|
|
|
358919
|
-
// 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
|
|
358920
358984
|
var init_rpc = __esm({
|
|
358921
|
-
"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"() {
|
|
358922
358986
|
}
|
|
358923
358987
|
});
|
|
358924
358988
|
|
|
358925
|
-
// 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
|
|
358926
358990
|
var init_main = __esm({
|
|
358927
|
-
"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"() {
|
|
358928
358992
|
init_rpc();
|
|
358929
358993
|
}
|
|
358930
358994
|
});
|
|
358931
358995
|
|
|
358932
|
-
// 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
|
|
358933
358997
|
var init_types9 = __esm({
|
|
358934
|
-
"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"() {
|
|
358935
358999
|
}
|
|
358936
359000
|
});
|
|
358937
359001
|
|
|
358938
|
-
// 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
|
|
358939
359003
|
var init_widget = __esm({
|
|
358940
|
-
"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"() {
|
|
358941
359005
|
}
|
|
358942
359006
|
});
|
|
358943
359007
|
|
|
358944
|
-
// 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
|
|
358945
359009
|
var init_dist = __esm({
|
|
358946
|
-
"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"() {
|
|
358947
359011
|
init_host2();
|
|
358948
359012
|
init_main();
|
|
358949
359013
|
init_runtime4();
|
|
@@ -394047,7 +394111,31 @@ function collectionOf(doc2, ref3) {
|
|
|
394047
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."}`);
|
|
394048
394112
|
return c2;
|
|
394049
394113
|
}
|
|
394050
|
-
|
|
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;
|
|
394051
394139
|
var init_site3 = __esm({
|
|
394052
394140
|
"lib/commands/site.ts"() {
|
|
394053
394141
|
"use strict";
|
|
@@ -394056,6 +394144,7 @@ var init_site3 = __esm({
|
|
|
394056
394144
|
init_breakpoints();
|
|
394057
394145
|
init_collections();
|
|
394058
394146
|
init_semantics();
|
|
394147
|
+
init_instances();
|
|
394059
394148
|
init_controls();
|
|
394060
394149
|
init_types();
|
|
394061
394150
|
init_routes();
|
|
@@ -394654,6 +394743,83 @@ var init_site3 = __esm({
|
|
|
394654
394743
|
return { summary: c2 ? `Repeats for ${c2.name} (${shown2} records)` : "No longer repeats", data: { ids: ids2, collectionId: c2?.id ?? null } };
|
|
394655
394744
|
}
|
|
394656
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
|
+
};
|
|
394657
394823
|
}
|
|
394658
394824
|
});
|
|
394659
394825
|
|
|
@@ -395751,6 +395917,8 @@ var init_builtin4 = __esm({
|
|
|
395751
395917
|
siteSetRoute,
|
|
395752
395918
|
nodeSetControl,
|
|
395753
395919
|
nodeSetRepeat,
|
|
395920
|
+
nodeSetRecord,
|
|
395921
|
+
nodeBindField,
|
|
395754
395922
|
siteSetEnvironment,
|
|
395755
395923
|
siteGetEnvironment,
|
|
395756
395924
|
codeEditModule,
|
|
@@ -403057,7 +403225,7 @@ init_resources();
|
|
|
403057
403225
|
init_desktop();
|
|
403058
403226
|
init_hypery();
|
|
403059
403227
|
import { createInterface } from "node:readline";
|
|
403060
|
-
var VERSION2 = "0.
|
|
403228
|
+
var VERSION2 = "0.21.0";
|
|
403061
403229
|
var HELP = `popcraft ${VERSION2} \u2014 the PopCraft command line
|
|
403062
403230
|
|
|
403063
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",
|