@puckeditor/plugin-ai 0.8.3-canary.fcc3f680 → 0.8.4-canary.1fe661a8
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/index.js +488 -218
- package/dist/index.mjs +488 -218
- package/package.json +8 -8
package/dist/index.js
CHANGED
|
@@ -2490,7 +2490,6 @@ function ExamplePrompt({
|
|
|
2490
2490
|
// src/components/Chat/index.tsx
|
|
2491
2491
|
var import_qler = __toESM(require("qler"));
|
|
2492
2492
|
var import_reducer = __toESM(require_dist());
|
|
2493
|
-
var import_html2canvas_pro = __toESM(require("html2canvas-pro"));
|
|
2494
2493
|
var import_use_debounce = require("use-debounce");
|
|
2495
2494
|
|
|
2496
2495
|
// src/lib/scroll-tracking-events.ts
|
|
@@ -2550,147 +2549,16 @@ var import_react24 = require("react");
|
|
|
2550
2549
|
|
|
2551
2550
|
// src/lib/morph-html.ts
|
|
2552
2551
|
init_react_import();
|
|
2553
|
-
var PROTECTED_ATTRS = /* @__PURE__ */ new Set([
|
|
2554
|
-
"contenteditable",
|
|
2555
|
-
"data-puck-overlay-portal"
|
|
2556
|
-
]);
|
|
2557
|
-
var SLOT_OWNED_ATTRS = /* @__PURE__ */ new Set(["style", "class"]);
|
|
2558
|
-
var isEventHandlerAttr = (name) => /^on/i.test(name);
|
|
2559
|
-
var cssEscape = (value) => typeof CSS !== "undefined" && CSS.escape ? CSS.escape(value) : value.replace(/["\\]/g, "\\$&");
|
|
2560
|
-
var FIELD_ATTR_PREFIX = "data-puck-field-";
|
|
2561
|
-
var hasJsonFieldBinding = (el) => {
|
|
2562
|
-
const attrBoundNames = /* @__PURE__ */ new Set();
|
|
2563
|
-
const jsonFieldNames = [];
|
|
2564
|
-
for (const attr of Array.from(el.attributes)) {
|
|
2565
|
-
if (!attr.name.startsWith(FIELD_ATTR_PREFIX)) continue;
|
|
2566
|
-
if (attr.name.startsWith("data-puck-field-value-")) continue;
|
|
2567
|
-
if (attr.value.trimStart().startsWith("{")) {
|
|
2568
|
-
const fieldName = attr.name.slice(FIELD_ATTR_PREFIX.length);
|
|
2569
|
-
if (fieldName && fieldName !== "name") {
|
|
2570
|
-
jsonFieldNames.push(fieldName);
|
|
2571
|
-
}
|
|
2572
|
-
} else {
|
|
2573
|
-
const fieldName = attr.value.trim();
|
|
2574
|
-
if (fieldName) attrBoundNames.add(fieldName);
|
|
2575
|
-
}
|
|
2576
|
-
}
|
|
2577
|
-
return jsonFieldNames.some((name) => !attrBoundNames.has(name));
|
|
2578
|
-
};
|
|
2579
|
-
var ownsItsChildren = (el) => el.hasAttribute("data-puck-slot") || el.hasAttribute("data-puck-field-name") || el.hasAttribute("data-puck-array") || hasJsonFieldBinding(el);
|
|
2580
|
-
var syncAttributes = (target, source) => {
|
|
2581
|
-
const isSlot = target.hasAttribute("data-puck-slot");
|
|
2582
|
-
for (const attr of Array.from(target.attributes)) {
|
|
2583
|
-
if (PROTECTED_ATTRS.has(attr.name)) continue;
|
|
2584
|
-
if (isSlot && SLOT_OWNED_ATTRS.has(attr.name)) continue;
|
|
2585
|
-
if (isEventHandlerAttr(attr.name) || !source.hasAttribute(attr.name)) {
|
|
2586
|
-
target.removeAttribute(attr.name);
|
|
2587
|
-
}
|
|
2588
|
-
}
|
|
2589
|
-
for (const attr of Array.from(source.attributes)) {
|
|
2590
|
-
if (PROTECTED_ATTRS.has(attr.name)) continue;
|
|
2591
|
-
if (isSlot && SLOT_OWNED_ATTRS.has(attr.name)) continue;
|
|
2592
|
-
if (isEventHandlerAttr(attr.name)) continue;
|
|
2593
|
-
if (target.getAttribute(attr.name) !== attr.value) {
|
|
2594
|
-
target.setAttribute(attr.name, attr.value);
|
|
2595
|
-
}
|
|
2596
|
-
}
|
|
2597
|
-
};
|
|
2598
|
-
var isSameKind = (a, b) => a.nodeType === b.nodeType && (a.nodeType !== Node.ELEMENT_NODE || a.tagName === b.tagName);
|
|
2599
|
-
var isIncompleteTagArtifact = (node) => node.nodeType === Node.TEXT_NODE && /^<\/?[a-zA-Z]*$/.test(node.nodeValue ?? "");
|
|
2600
|
-
var stripIncompleteTagArtifacts = (root) => {
|
|
2601
|
-
for (const child of Array.from(root.childNodes)) {
|
|
2602
|
-
if (isIncompleteTagArtifact(child)) {
|
|
2603
|
-
root.removeChild(child);
|
|
2604
|
-
} else if (child.nodeType === Node.ELEMENT_NODE) {
|
|
2605
|
-
stripIncompleteTagArtifacts(child);
|
|
2606
|
-
}
|
|
2607
|
-
}
|
|
2608
|
-
};
|
|
2609
|
-
var stripEventHandlerAttrs = (root) => {
|
|
2610
|
-
root.querySelectorAll("*").forEach((el) => {
|
|
2611
|
-
for (const attr of Array.from(el.attributes)) {
|
|
2612
|
-
if (isEventHandlerAttr(attr.name)) el.removeAttribute(attr.name);
|
|
2613
|
-
}
|
|
2614
|
-
});
|
|
2615
|
-
};
|
|
2616
|
-
var morphChildren = (target, source, skipChildrenOf = ownsItsChildren) => {
|
|
2617
|
-
const sourceChildren = Array.from(source.childNodes);
|
|
2618
|
-
for (let i = 0; i < sourceChildren.length; i++) {
|
|
2619
|
-
const sourceChild = sourceChildren[i];
|
|
2620
|
-
const targetChild = target.childNodes[i];
|
|
2621
|
-
if (!targetChild) {
|
|
2622
|
-
target.appendChild(sourceChild);
|
|
2623
|
-
continue;
|
|
2624
|
-
}
|
|
2625
|
-
if (!isSameKind(targetChild, sourceChild)) {
|
|
2626
|
-
target.replaceChild(sourceChild, targetChild);
|
|
2627
|
-
continue;
|
|
2628
|
-
}
|
|
2629
|
-
if (sourceChild.nodeType !== Node.ELEMENT_NODE) {
|
|
2630
|
-
if (targetChild.nodeValue !== sourceChild.nodeValue) {
|
|
2631
|
-
targetChild.nodeValue = sourceChild.nodeValue;
|
|
2632
|
-
}
|
|
2633
|
-
continue;
|
|
2634
|
-
}
|
|
2635
|
-
const targetEl = targetChild;
|
|
2636
|
-
syncAttributes(targetEl, sourceChild);
|
|
2637
|
-
if (!skipChildrenOf(targetEl)) {
|
|
2638
|
-
morphChildren(targetEl, sourceChild, skipChildrenOf);
|
|
2639
|
-
}
|
|
2640
|
-
}
|
|
2641
|
-
while (target.childNodes.length > sourceChildren.length) {
|
|
2642
|
-
target.removeChild(target.lastChild);
|
|
2643
|
-
}
|
|
2644
|
-
};
|
|
2645
|
-
function morphHtml(container, html, attrOverrides = [], skipChildrenOf = ownsItsChildren) {
|
|
2646
|
-
const template = container.ownerDocument.createElement("template");
|
|
2647
|
-
template.innerHTML = html;
|
|
2648
|
-
stripIncompleteTagArtifacts(template.content);
|
|
2649
|
-
stripEventHandlerAttrs(template.content);
|
|
2650
|
-
for (const { name, attr, value } of attrOverrides) {
|
|
2651
|
-
template.content.querySelectorAll(`[data-puck-field-${attr}="${cssEscape(name)}"]`).forEach((el) => {
|
|
2652
|
-
if (el.closest("[data-puck-array]")) return;
|
|
2653
|
-
el.setAttribute(attr, value);
|
|
2654
|
-
});
|
|
2655
|
-
}
|
|
2656
|
-
morphChildren(container, template.content, skipChildrenOf);
|
|
2657
|
-
}
|
|
2658
2552
|
|
|
2659
|
-
// src/lib/design/
|
|
2553
|
+
// src/lib/design/annotations.ts
|
|
2660
2554
|
init_react_import();
|
|
2661
|
-
var wrapScriptWithObserverGuard = (script) => {
|
|
2662
|
-
if (!script.includes("MutationObserver")) return script;
|
|
2663
|
-
return `(function () {
|
|
2664
|
-
var __NativeMutationObserver = window.MutationObserver;
|
|
2665
|
-
function MutationObserver(callback) {
|
|
2666
|
-
var observed = [];
|
|
2667
|
-
var inner = new __NativeMutationObserver(function (records) {
|
|
2668
|
-
inner.disconnect();
|
|
2669
|
-
try {
|
|
2670
|
-
callback(records, inner);
|
|
2671
|
-
} finally {
|
|
2672
|
-
for (var i = 0; i < observed.length; i++) {
|
|
2673
|
-
__nativeObserve.call(inner, observed[i][0], observed[i][1]);
|
|
2674
|
-
}
|
|
2675
|
-
}
|
|
2676
|
-
});
|
|
2677
|
-
var __nativeObserve = inner.observe;
|
|
2678
|
-
inner.observe = function (target, options) {
|
|
2679
|
-
observed.push([target, options]);
|
|
2680
|
-
return __nativeObserve.call(inner, target, options);
|
|
2681
|
-
};
|
|
2682
|
-
return inner;
|
|
2683
|
-
}
|
|
2684
|
-
${script}
|
|
2685
|
-
})();`;
|
|
2686
|
-
};
|
|
2687
2555
|
|
|
2688
2556
|
// src/lib/html-annotations.ts
|
|
2689
2557
|
init_react_import();
|
|
2690
2558
|
var import_htmlparser2 = require("htmlparser2");
|
|
2691
2559
|
var import_domutils = require("domutils");
|
|
2692
2560
|
var import_domhandler = require("domhandler");
|
|
2693
|
-
var
|
|
2561
|
+
var FIELD_ATTR_PREFIX = "data-puck-field-";
|
|
2694
2562
|
var OPTIONS_ATTR_PREFIX = "data-puck-options-";
|
|
2695
2563
|
var BIND_ATTR_PREFIX = "data-puck-bind-";
|
|
2696
2564
|
var BIND_INPUT_ATTR_PREFIX = "data-puck-bind-input-";
|
|
@@ -2738,6 +2606,19 @@ var textContentWithBreaks = (node) => {
|
|
|
2738
2606
|
var isRecord = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
2739
2607
|
var FIELD_NAME_RE = /^[A-Za-z0-9_]+(?:[-.][A-Za-z0-9_]+)*$/;
|
|
2740
2608
|
var isValidFieldName = (name) => FIELD_NAME_RE.test(name);
|
|
2609
|
+
var isFieldNameClaimed = (name, claimed, includeExact = true) => {
|
|
2610
|
+
for (const entry of claimed) {
|
|
2611
|
+
if (includeExact && entry === name || entry.startsWith(`${name}.`) || name.startsWith(`${entry}.`)) {
|
|
2612
|
+
return true;
|
|
2613
|
+
}
|
|
2614
|
+
}
|
|
2615
|
+
return false;
|
|
2616
|
+
};
|
|
2617
|
+
var attrBoundFieldNames = (attribs) => new Set(
|
|
2618
|
+
Object.entries(attribs).filter(
|
|
2619
|
+
([name, value]) => name.startsWith(FIELD_ATTR_PREFIX) && name !== `${FIELD_ATTR_PREFIX}name` && !name.startsWith(`${FIELD_ATTR_PREFIX}value-`) && !tryParseFieldShape(value)
|
|
2620
|
+
).map(([, value]) => value.trim()).filter(isValidFieldName)
|
|
2621
|
+
);
|
|
2741
2622
|
var getDeepValue = (source, path) => {
|
|
2742
2623
|
if (!path.includes(".")) return source[path];
|
|
2743
2624
|
let current = source;
|
|
@@ -2838,6 +2719,7 @@ var collectElementFields = (element, acc) => {
|
|
|
2838
2719
|
return true;
|
|
2839
2720
|
}
|
|
2840
2721
|
let skipChildren = false;
|
|
2722
|
+
const attrBound = attrBoundFieldNames(attribs);
|
|
2841
2723
|
for (const [attrName, attrValue] of Object.entries(attribs)) {
|
|
2842
2724
|
if (attrName.startsWith(OPTIONS_ATTR_PREFIX)) {
|
|
2843
2725
|
const fieldName = attrName.slice(OPTIONS_ATTR_PREFIX.length);
|
|
@@ -2866,8 +2748,8 @@ var collectElementFields = (element, acc) => {
|
|
|
2866
2748
|
}
|
|
2867
2749
|
continue;
|
|
2868
2750
|
}
|
|
2869
|
-
if (!attrName.startsWith(
|
|
2870
|
-
const target = attrName.slice(
|
|
2751
|
+
if (!attrName.startsWith(FIELD_ATTR_PREFIX)) continue;
|
|
2752
|
+
const target = attrName.slice(FIELD_ATTR_PREFIX.length);
|
|
2871
2753
|
if (!target) continue;
|
|
2872
2754
|
const shape = tryParseFieldShape(attrValue);
|
|
2873
2755
|
if (shape) {
|
|
@@ -2881,6 +2763,9 @@ var collectElementFields = (element, acc) => {
|
|
|
2881
2763
|
if (existing) existing.shape = shape;
|
|
2882
2764
|
continue;
|
|
2883
2765
|
}
|
|
2766
|
+
if (isFieldNameClaimed(name2, attrBound, false) || isFieldNameClaimed(name2, acc.seenFields)) {
|
|
2767
|
+
continue;
|
|
2768
|
+
}
|
|
2884
2769
|
acc.seenFields.add(name2);
|
|
2885
2770
|
if (shape.type === "richtext") {
|
|
2886
2771
|
acc.fields.push({ name: name2, binding: "text", shape, format: "json" });
|
|
@@ -2935,6 +2820,9 @@ var collectElementFields = (element, acc) => {
|
|
|
2935
2820
|
}
|
|
2936
2821
|
continue;
|
|
2937
2822
|
}
|
|
2823
|
+
if (target === "name" && isFieldNameClaimed(name, attrBound) || isFieldNameClaimed(name, acc.seenFields)) {
|
|
2824
|
+
continue;
|
|
2825
|
+
}
|
|
2938
2826
|
acc.seenFields.add(name);
|
|
2939
2827
|
const fieldType = getTypeModifier(attribs, name);
|
|
2940
2828
|
const constraints = fieldType === "number" ? getNumberConstraints(attribs, name) : {};
|
|
@@ -3028,7 +2916,7 @@ var parseHtmlAnnotations = (html) => {
|
|
|
3028
2916
|
if (slotName && isValidFieldName(slotName) && !seenSlots.has(slotName)) {
|
|
3029
2917
|
seenSlots.add(slotName);
|
|
3030
2918
|
const shape = tryParseFieldShape(
|
|
3031
|
-
attribs[
|
|
2919
|
+
attribs[FIELD_ATTR_PREFIX + slotName.toLowerCase()] ?? ""
|
|
3032
2920
|
);
|
|
3033
2921
|
const allow = shape?.type === "slot" ? sanitizeStringArray(shape.allow) : void 0;
|
|
3034
2922
|
const disallow = shape?.type === "slot" ? sanitizeStringArray(shape.disallow) : void 0;
|
|
@@ -3177,21 +3065,16 @@ var patchElement = (element, props) => {
|
|
|
3177
3065
|
}
|
|
3178
3066
|
return { didPatch, skipChildren: true };
|
|
3179
3067
|
}
|
|
3180
|
-
const attrBoundFields =
|
|
3181
|
-
for (const [an, av] of Object.entries(attribs)) {
|
|
3182
|
-
if (an.startsWith(FIELD_ATTR_PREFIX2) && an !== `${FIELD_ATTR_PREFIX2}name` && !tryParseFieldShape(av)) {
|
|
3183
|
-
attrBoundFields.add(av.trim());
|
|
3184
|
-
}
|
|
3185
|
-
}
|
|
3068
|
+
const attrBoundFields = attrBoundFieldNames(attribs);
|
|
3186
3069
|
for (const [attrName, attrValue] of Object.entries(attribs)) {
|
|
3187
|
-
if (!attrName.startsWith(
|
|
3188
|
-
const target = attrName.slice(
|
|
3070
|
+
if (!attrName.startsWith(FIELD_ATTR_PREFIX)) continue;
|
|
3071
|
+
const target = attrName.slice(FIELD_ATTR_PREFIX.length);
|
|
3189
3072
|
if (!target) continue;
|
|
3190
3073
|
const shape = tryParseFieldShape(attrValue);
|
|
3191
3074
|
if (shape) {
|
|
3192
3075
|
if (shape.type === "slot") continue;
|
|
3193
3076
|
const name2 = target;
|
|
3194
|
-
if (
|
|
3077
|
+
if (isFieldNameClaimed(name2, attrBoundFields)) continue;
|
|
3195
3078
|
const value2 = getDeepValue(props, name2);
|
|
3196
3079
|
if (shape.type === "richtext") {
|
|
3197
3080
|
if (typeof value2 !== "string") continue;
|
|
@@ -3209,6 +3092,9 @@ var patchElement = (element, props) => {
|
|
|
3209
3092
|
}
|
|
3210
3093
|
const name = attrValue.trim();
|
|
3211
3094
|
if (!name) continue;
|
|
3095
|
+
if (target === "name" && isFieldNameClaimed(name, attrBoundFields)) {
|
|
3096
|
+
continue;
|
|
3097
|
+
}
|
|
3212
3098
|
const value = getDeepValue(props, name);
|
|
3213
3099
|
if (target === "name" && getTypeModifier(attribs, name) === "richtext") {
|
|
3214
3100
|
if (typeof value !== "string") continue;
|
|
@@ -3281,7 +3167,6 @@ var renderHtmlArrayItems = (html, arrayName, items) => {
|
|
|
3281
3167
|
};
|
|
3282
3168
|
|
|
3283
3169
|
// src/lib/design/annotations.ts
|
|
3284
|
-
init_react_import();
|
|
3285
3170
|
var cache = /* @__PURE__ */ new Map();
|
|
3286
3171
|
var MAX_CACHE_ENTRIES = 32;
|
|
3287
3172
|
var getAnnotations = (html) => {
|
|
@@ -3298,6 +3183,160 @@ var getSlotFields = (html) => Object.fromEntries(
|
|
|
3298
3183
|
getAnnotations(html).slots.map((slot) => [slot.name, toSlotField(slot)])
|
|
3299
3184
|
);
|
|
3300
3185
|
|
|
3186
|
+
// src/lib/morph-html.ts
|
|
3187
|
+
var PROTECTED_ATTRS = /* @__PURE__ */ new Set([
|
|
3188
|
+
"contenteditable",
|
|
3189
|
+
"data-puck-overlay-portal"
|
|
3190
|
+
]);
|
|
3191
|
+
var SLOT_OWNED_ATTRS = /* @__PURE__ */ new Set(["style", "class"]);
|
|
3192
|
+
var isEventHandlerAttr = (name) => /^on/i.test(name);
|
|
3193
|
+
var FIELD_ATTR_PREFIX2 = "data-puck-field-";
|
|
3194
|
+
var LEGACY_TEXT_ATTR = `${FIELD_ATTR_PREFIX2}name`;
|
|
3195
|
+
var VALUE_ATTR_PREFIX = `${FIELD_ATTR_PREFIX2}value-`;
|
|
3196
|
+
var hasTextBinding = (el, parsedTextFields) => {
|
|
3197
|
+
for (const attr of Array.from(el.attributes)) {
|
|
3198
|
+
if (!attr.name.startsWith(FIELD_ATTR_PREFIX2)) continue;
|
|
3199
|
+
if (attr.name.startsWith(VALUE_ATTR_PREFIX)) continue;
|
|
3200
|
+
const isShape = attr.value.trimStart().startsWith("{");
|
|
3201
|
+
const fieldName = isShape ? attr.name.slice(FIELD_ATTR_PREFIX2.length) : attr.value.trim();
|
|
3202
|
+
if (isValidFieldName(fieldName) && (attr.name === LEGACY_TEXT_ATTR || isShape) && (!parsedTextFields || parsedTextFields.has(fieldName))) {
|
|
3203
|
+
return true;
|
|
3204
|
+
}
|
|
3205
|
+
}
|
|
3206
|
+
return false;
|
|
3207
|
+
};
|
|
3208
|
+
var ownsItsChildren = (el, parsedTextFields) => el.hasAttribute("data-puck-slot") || el.hasAttribute("data-puck-array") || hasTextBinding(el, parsedTextFields);
|
|
3209
|
+
var syncAttributes = (target, source) => {
|
|
3210
|
+
const isSlot = target.hasAttribute("data-puck-slot");
|
|
3211
|
+
for (const attr of Array.from(target.attributes)) {
|
|
3212
|
+
if (PROTECTED_ATTRS.has(attr.name)) continue;
|
|
3213
|
+
if (isSlot && SLOT_OWNED_ATTRS.has(attr.name)) continue;
|
|
3214
|
+
if (isEventHandlerAttr(attr.name) || !source.hasAttribute(attr.name)) {
|
|
3215
|
+
target.removeAttribute(attr.name);
|
|
3216
|
+
}
|
|
3217
|
+
}
|
|
3218
|
+
for (const attr of Array.from(source.attributes)) {
|
|
3219
|
+
if (PROTECTED_ATTRS.has(attr.name)) continue;
|
|
3220
|
+
if (isSlot && SLOT_OWNED_ATTRS.has(attr.name)) continue;
|
|
3221
|
+
if (isEventHandlerAttr(attr.name)) continue;
|
|
3222
|
+
if (target.getAttribute(attr.name) !== attr.value) {
|
|
3223
|
+
target.setAttribute(attr.name, attr.value);
|
|
3224
|
+
}
|
|
3225
|
+
}
|
|
3226
|
+
};
|
|
3227
|
+
var isSameKind = (a, b) => a.nodeType === b.nodeType && (a.nodeType !== Node.ELEMENT_NODE || a.tagName === b.tagName);
|
|
3228
|
+
var isIncompleteTagArtifact = (node) => node.nodeType === Node.TEXT_NODE && /^<\/?[a-zA-Z]*$/.test(node.nodeValue ?? "");
|
|
3229
|
+
var stripIncompleteTagArtifacts = (root) => {
|
|
3230
|
+
for (const child of Array.from(root.childNodes)) {
|
|
3231
|
+
if (isIncompleteTagArtifact(child)) {
|
|
3232
|
+
root.removeChild(child);
|
|
3233
|
+
} else if (child.nodeType === Node.ELEMENT_NODE) {
|
|
3234
|
+
stripIncompleteTagArtifacts(child);
|
|
3235
|
+
}
|
|
3236
|
+
}
|
|
3237
|
+
};
|
|
3238
|
+
var stripEventHandlerAttrs = (root) => {
|
|
3239
|
+
root.querySelectorAll("*").forEach((el) => {
|
|
3240
|
+
for (const attr of Array.from(el.attributes)) {
|
|
3241
|
+
if (isEventHandlerAttr(attr.name)) el.removeAttribute(attr.name);
|
|
3242
|
+
}
|
|
3243
|
+
});
|
|
3244
|
+
};
|
|
3245
|
+
var morphChildren = (target, source, skipChildrenOf = ownsItsChildren) => {
|
|
3246
|
+
const sourceChildren = Array.from(source.childNodes);
|
|
3247
|
+
for (let i = 0; i < sourceChildren.length; i++) {
|
|
3248
|
+
const sourceChild = sourceChildren[i];
|
|
3249
|
+
const targetChild = target.childNodes[i];
|
|
3250
|
+
if (!targetChild) {
|
|
3251
|
+
target.appendChild(sourceChild);
|
|
3252
|
+
continue;
|
|
3253
|
+
}
|
|
3254
|
+
if (!isSameKind(targetChild, sourceChild)) {
|
|
3255
|
+
target.replaceChild(sourceChild, targetChild);
|
|
3256
|
+
continue;
|
|
3257
|
+
}
|
|
3258
|
+
if (sourceChild.nodeType !== Node.ELEMENT_NODE) {
|
|
3259
|
+
if (targetChild.nodeValue !== sourceChild.nodeValue) {
|
|
3260
|
+
targetChild.nodeValue = sourceChild.nodeValue;
|
|
3261
|
+
}
|
|
3262
|
+
continue;
|
|
3263
|
+
}
|
|
3264
|
+
const targetEl = targetChild;
|
|
3265
|
+
syncAttributes(targetEl, sourceChild);
|
|
3266
|
+
if (!skipChildrenOf(targetEl)) {
|
|
3267
|
+
morphChildren(targetEl, sourceChild, skipChildrenOf);
|
|
3268
|
+
}
|
|
3269
|
+
}
|
|
3270
|
+
while (target.childNodes.length > sourceChildren.length) {
|
|
3271
|
+
target.removeChild(target.lastChild);
|
|
3272
|
+
}
|
|
3273
|
+
};
|
|
3274
|
+
function morphHtml(container, html, attrOverrides = [], skipChildrenOf) {
|
|
3275
|
+
const template = container.ownerDocument.createElement("template");
|
|
3276
|
+
template.innerHTML = html;
|
|
3277
|
+
stripIncompleteTagArtifacts(template.content);
|
|
3278
|
+
stripEventHandlerAttrs(template.content);
|
|
3279
|
+
if (attrOverrides.length > 0) {
|
|
3280
|
+
const overridesByAttr = /* @__PURE__ */ new Map();
|
|
3281
|
+
for (const override of attrOverrides) {
|
|
3282
|
+
if (isEventHandlerAttr(override.attr)) continue;
|
|
3283
|
+
const bindingAttr = `${FIELD_ATTR_PREFIX2}${override.attr}`;
|
|
3284
|
+
const fields = overridesByAttr.get(bindingAttr) ?? /* @__PURE__ */ new Map();
|
|
3285
|
+
fields.set(override.name, override);
|
|
3286
|
+
overridesByAttr.set(bindingAttr, fields);
|
|
3287
|
+
}
|
|
3288
|
+
template.content.querySelectorAll("*").forEach((el) => {
|
|
3289
|
+
for (const attr of Array.from(el.attributes)) {
|
|
3290
|
+
const override = overridesByAttr.get(attr.name)?.get(attr.value.trim());
|
|
3291
|
+
if (!override) continue;
|
|
3292
|
+
if (el.closest("[data-puck-array]")) return;
|
|
3293
|
+
el.setAttribute(override.attr, override.value);
|
|
3294
|
+
}
|
|
3295
|
+
});
|
|
3296
|
+
}
|
|
3297
|
+
if (skipChildrenOf) {
|
|
3298
|
+
morphChildren(container, template.content, skipChildrenOf);
|
|
3299
|
+
return;
|
|
3300
|
+
}
|
|
3301
|
+
const parsedTextFields = new Set(
|
|
3302
|
+
getAnnotations(html).fields.filter((field) => field.binding === "text").map((field) => field.name)
|
|
3303
|
+
);
|
|
3304
|
+
morphChildren(
|
|
3305
|
+
container,
|
|
3306
|
+
template.content,
|
|
3307
|
+
(el) => ownsItsChildren(el, parsedTextFields)
|
|
3308
|
+
);
|
|
3309
|
+
}
|
|
3310
|
+
|
|
3311
|
+
// src/lib/design/observer-guard.ts
|
|
3312
|
+
init_react_import();
|
|
3313
|
+
var wrapScriptWithObserverGuard = (script) => {
|
|
3314
|
+
if (!script.includes("MutationObserver")) return script;
|
|
3315
|
+
return `(function () {
|
|
3316
|
+
var __NativeMutationObserver = window.MutationObserver;
|
|
3317
|
+
function MutationObserver(callback) {
|
|
3318
|
+
var observed = [];
|
|
3319
|
+
var inner = new __NativeMutationObserver(function (records) {
|
|
3320
|
+
inner.disconnect();
|
|
3321
|
+
try {
|
|
3322
|
+
callback(records, inner);
|
|
3323
|
+
} finally {
|
|
3324
|
+
for (var i = 0; i < observed.length; i++) {
|
|
3325
|
+
__nativeObserve.call(inner, observed[i][0], observed[i][1]);
|
|
3326
|
+
}
|
|
3327
|
+
}
|
|
3328
|
+
});
|
|
3329
|
+
var __nativeObserve = inner.observe;
|
|
3330
|
+
inner.observe = function (target, options) {
|
|
3331
|
+
observed.push([target, options]);
|
|
3332
|
+
return __nativeObserve.call(inner, target, options);
|
|
3333
|
+
};
|
|
3334
|
+
return inner;
|
|
3335
|
+
}
|
|
3336
|
+
${script}
|
|
3337
|
+
})();`;
|
|
3338
|
+
};
|
|
3339
|
+
|
|
3301
3340
|
// src/lib/design/registration-store.ts
|
|
3302
3341
|
init_react_import();
|
|
3303
3342
|
var RegistrationStore = class {
|
|
@@ -3371,7 +3410,7 @@ init_react_import();
|
|
|
3371
3410
|
var import_core2 = require("@puckeditor/core");
|
|
3372
3411
|
var CONTENT_EDITABLE_ATTR = "data-puck-content-editable";
|
|
3373
3412
|
var isInlineEditingDisabled = (el) => el.closest(`[${CONTENT_EDITABLE_ATTR}="false"]`) !== null;
|
|
3374
|
-
var
|
|
3413
|
+
var cssEscape = (value) => typeof CSS !== "undefined" && CSS.escape ? CSS.escape(value) : value.replace(/["\\]/g, "\\$&");
|
|
3375
3414
|
var queryScopedFields = (entry, selector) => Array.from(entry.querySelectorAll(selector)).filter((el) => {
|
|
3376
3415
|
if (el.closest("[data-puck-array]")) return false;
|
|
3377
3416
|
const closestSlot = el.closest("[data-puck-slot]");
|
|
@@ -3379,7 +3418,7 @@ var queryScopedFields = (entry, selector) => Array.from(entry.querySelectorAll(s
|
|
|
3379
3418
|
return true;
|
|
3380
3419
|
});
|
|
3381
3420
|
var findOwnArrayContainer = (entry, arrayName) => {
|
|
3382
|
-
const selector = `[data-puck-array="${
|
|
3421
|
+
const selector = `[data-puck-array="${cssEscape(arrayName)}"]`;
|
|
3383
3422
|
for (const el of entry.querySelectorAll(selector)) {
|
|
3384
3423
|
const closestSlot = el.closest("[data-puck-slot]");
|
|
3385
3424
|
if (!closestSlot || !entry.contains(closestSlot)) return el;
|
|
@@ -3394,7 +3433,7 @@ var inlineEditModeFor = (field) => {
|
|
|
3394
3433
|
const type = field.shape?.type ?? field.fieldType;
|
|
3395
3434
|
return type === "richtext" ? "richtext" : type === "number" ? "number" : "text";
|
|
3396
3435
|
};
|
|
3397
|
-
var textFieldSelector = (field) => field.format === "json" ? `[${
|
|
3436
|
+
var textFieldSelector = (field) => field.format === "json" ? `[${cssEscape(`data-puck-field-${field.name}`)}]` : `[data-puck-field-name="${cssEscape(field.name)}"]`;
|
|
3398
3437
|
var isHTMLElement = (el) => {
|
|
3399
3438
|
const HTMLElementCtor = el.ownerDocument.defaultView?.HTMLElement;
|
|
3400
3439
|
return !!HTMLElementCtor && el instanceof HTMLElementCtor;
|
|
@@ -3420,6 +3459,29 @@ var syncFieldValues = (entry, fields, props) => {
|
|
|
3420
3459
|
});
|
|
3421
3460
|
}
|
|
3422
3461
|
};
|
|
3462
|
+
var claimedHostStyles = /* @__PURE__ */ new WeakMap();
|
|
3463
|
+
var claimHostStyles = (el, applyWhiteSpace) => {
|
|
3464
|
+
if (!claimedHostStyles.has(el)) {
|
|
3465
|
+
claimedHostStyles.set(el, {
|
|
3466
|
+
cursor: el.style.cursor,
|
|
3467
|
+
whiteSpace: applyWhiteSpace ? el.style.whiteSpace : null
|
|
3468
|
+
});
|
|
3469
|
+
}
|
|
3470
|
+
applyHostStyles(el);
|
|
3471
|
+
};
|
|
3472
|
+
var applyHostStyles = (el) => {
|
|
3473
|
+
const claimed = claimedHostStyles.get(el);
|
|
3474
|
+
if (!claimed) return;
|
|
3475
|
+
el.style.cursor = "text";
|
|
3476
|
+
if (claimed.whiteSpace !== null) el.style.whiteSpace = "pre-wrap";
|
|
3477
|
+
};
|
|
3478
|
+
var releaseHostStyles = (el) => {
|
|
3479
|
+
const claimed = claimedHostStyles.get(el);
|
|
3480
|
+
if (!claimed) return;
|
|
3481
|
+
el.style.cursor = claimed.cursor;
|
|
3482
|
+
if (claimed.whiteSpace !== null) el.style.whiteSpace = claimed.whiteSpace;
|
|
3483
|
+
claimedHostStyles.delete(el);
|
|
3484
|
+
};
|
|
3423
3485
|
var attachInlineEditing = (el, {
|
|
3424
3486
|
componentId,
|
|
3425
3487
|
propPath,
|
|
@@ -3432,8 +3494,7 @@ var attachInlineEditing = (el, {
|
|
|
3432
3494
|
const syncEditable = () => {
|
|
3433
3495
|
el.contentEditable = hovering || focused ? mode === "richtext" ? "true" : "plaintext-only" : "false";
|
|
3434
3496
|
};
|
|
3435
|
-
|
|
3436
|
-
el.style.cursor = "text";
|
|
3497
|
+
claimHostStyles(el, mode !== "richtext");
|
|
3437
3498
|
syncEditable();
|
|
3438
3499
|
let lastValidNumberText = el.innerText.replaceAll(/\n/gm, "");
|
|
3439
3500
|
const handleInput = () => {
|
|
@@ -3511,7 +3572,7 @@ var attachInlineEditing = (el, {
|
|
|
3511
3572
|
el.removeEventListener("mouseout", handleMouseOut, true);
|
|
3512
3573
|
el.removeEventListener("focus", handleFocus);
|
|
3513
3574
|
el.removeEventListener("blur", handleBlur);
|
|
3514
|
-
el
|
|
3575
|
+
releaseHostStyles(el);
|
|
3515
3576
|
el.removeAttribute("contenteditable");
|
|
3516
3577
|
cleanupPortal?.();
|
|
3517
3578
|
};
|
|
@@ -3577,7 +3638,7 @@ var wireArrayItemEditing = ({
|
|
|
3577
3638
|
const mode = inlineEditModeFor(field);
|
|
3578
3639
|
const registration = wiring.get(target);
|
|
3579
3640
|
if (registration?.propPath === propPath && registration.mode === mode) {
|
|
3580
|
-
target
|
|
3641
|
+
applyHostStyles(target);
|
|
3581
3642
|
continue;
|
|
3582
3643
|
}
|
|
3583
3644
|
registration?.cleanup();
|
|
@@ -3719,7 +3780,7 @@ var SlotPortal = ({
|
|
|
3719
3780
|
[slotStyle]
|
|
3720
3781
|
);
|
|
3721
3782
|
(0, import_react23.useEffect)(() => {
|
|
3722
|
-
const el = entry.querySelector(`[data-puck-slot="${
|
|
3783
|
+
const el = entry.querySelector(`[data-puck-slot="${cssEscape(slotName)}"]`);
|
|
3723
3784
|
if (el !== lastTarget.current) {
|
|
3724
3785
|
el?.replaceChildren();
|
|
3725
3786
|
lastTarget.current = el;
|
|
@@ -3739,6 +3800,8 @@ var SlotPortal = ({
|
|
|
3739
3800
|
|
|
3740
3801
|
// src/lib/design/component.tsx
|
|
3741
3802
|
var import_jsx_runtime32 = require("react/jsx-runtime");
|
|
3803
|
+
var DESIGN_COMPONENT = Symbol("puck-ai.designComponent");
|
|
3804
|
+
var isDesignComponent = (config) => !!config?.[DESIGN_COMPONENT];
|
|
3742
3805
|
var streamingValues = /* @__PURE__ */ new Map();
|
|
3743
3806
|
var instanceKey = (name, instanceId) => `${name}:${typeof instanceId === "string" ? instanceId : ""}`;
|
|
3744
3807
|
var getRegistrationSlotFields = (reg) => {
|
|
@@ -3763,7 +3826,7 @@ function createDesignComponentConfig(registration) {
|
|
|
3763
3826
|
registrationStore.apply(registration);
|
|
3764
3827
|
}
|
|
3765
3828
|
const slotFields = getRegistrationSlotFields(registration);
|
|
3766
|
-
|
|
3829
|
+
const componentConfig = {
|
|
3767
3830
|
...registration.label ? { label: registration.label } : {},
|
|
3768
3831
|
fields: { ...slotFields },
|
|
3769
3832
|
defaultProps: { ...registration.defaultProps ?? {} },
|
|
@@ -3824,6 +3887,8 @@ function createDesignComponentConfig(registration) {
|
|
|
3824
3887
|
},
|
|
3825
3888
|
render: (renderProps) => renderProps.puck?.isEditing ? /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(EditorEntry, { ...renderProps }) : /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(Entry, { ...renderProps, getPuck: null })
|
|
3826
3889
|
};
|
|
3890
|
+
componentConfig[DESIGN_COMPONENT] = true;
|
|
3891
|
+
return componentConfig;
|
|
3827
3892
|
function EditorEntry(renderProps) {
|
|
3828
3893
|
const getPuck = (0, import_core3.useGetPuck)();
|
|
3829
3894
|
return /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(Entry, { ...renderProps, getPuck });
|
|
@@ -3903,7 +3968,7 @@ function createDesignComponentConfig(registration) {
|
|
|
3903
3968
|
morphed.current = { el: entryEl, html, attrSig };
|
|
3904
3969
|
morphHtml(entryEl, html, attrFields);
|
|
3905
3970
|
for (const el of fieldWiring.current.keys()) {
|
|
3906
|
-
if (el.isConnected) el
|
|
3971
|
+
if (el.isConnected) applyHostStyles(el);
|
|
3907
3972
|
}
|
|
3908
3973
|
}
|
|
3909
3974
|
syncFieldValues(entryEl, annotations.fields, props);
|
|
@@ -4062,9 +4127,11 @@ function getDynamicConfigGlobals(dynamicConfig) {
|
|
|
4062
4127
|
...typeof script === "string" ? { script } : {}
|
|
4063
4128
|
};
|
|
4064
4129
|
}
|
|
4130
|
+
var INLINE_EDIT_RESET = ":where([data-puck-design] [contenteditable]){overflow-wrap:inherit;line-break:inherit;-webkit-nbsp-mode:inherit}";
|
|
4065
4131
|
function DesignGlobals({
|
|
4066
4132
|
styles,
|
|
4067
|
-
script
|
|
4133
|
+
script,
|
|
4134
|
+
isEditing
|
|
4068
4135
|
}) {
|
|
4069
4136
|
const scriptRef = (0, import_react25.useRef)(null);
|
|
4070
4137
|
const hostRef = (0, import_react25.useRef)(null);
|
|
@@ -4082,6 +4149,7 @@ function DesignGlobals({
|
|
|
4082
4149
|
};
|
|
4083
4150
|
}, [script]);
|
|
4084
4151
|
return /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)(import_jsx_runtime33.Fragment, { children: [
|
|
4152
|
+
isEditing && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("style", { children: INLINE_EDIT_RESET }),
|
|
4085
4153
|
styles && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("style", { children: styles }),
|
|
4086
4154
|
script && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("div", { ref: hostRef, style: { display: "none" } })
|
|
4087
4155
|
] });
|
|
@@ -4094,7 +4162,14 @@ function withDesignGlobals(root) {
|
|
|
4094
4162
|
const render = (props) => {
|
|
4095
4163
|
const { styles, script } = getDynamicConfigGlobals(props._dynamicConfig);
|
|
4096
4164
|
return /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)(import_jsx_runtime33.Fragment, { children: [
|
|
4097
|
-
/* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
|
|
4165
|
+
/* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
|
|
4166
|
+
DesignGlobals,
|
|
4167
|
+
{
|
|
4168
|
+
styles,
|
|
4169
|
+
script,
|
|
4170
|
+
isEditing: props.puck?.isEditing
|
|
4171
|
+
}
|
|
4172
|
+
),
|
|
4098
4173
|
userRender ? userRender(props) : props.children
|
|
4099
4174
|
] });
|
|
4100
4175
|
};
|
|
@@ -4208,7 +4283,7 @@ function syncDesignComponents(getPuck) {
|
|
|
4208
4283
|
ensureDynamicConfigField(config);
|
|
4209
4284
|
for (const [name, persistedReg] of Object.entries(persisted)) {
|
|
4210
4285
|
const prev = lastSynced.get(name);
|
|
4211
|
-
if (registrationStore.has(name) && (prev === persistedReg || registrationContentEqual(prev, persistedReg))) {
|
|
4286
|
+
if (registrationStore.has(name) && config.components[name] && (prev === persistedReg || registrationContentEqual(prev, persistedReg))) {
|
|
4212
4287
|
lastSynced.set(name, persistedReg);
|
|
4213
4288
|
continue;
|
|
4214
4289
|
}
|
|
@@ -4239,8 +4314,10 @@ function syncDesignComponents(getPuck) {
|
|
|
4239
4314
|
if (!(name in persisted)) {
|
|
4240
4315
|
registrationStore.delete(name);
|
|
4241
4316
|
lastSynced.delete(name);
|
|
4242
|
-
|
|
4243
|
-
|
|
4317
|
+
if (isDesignComponent(config.components[name])) {
|
|
4318
|
+
delete config.components[name];
|
|
4319
|
+
hasRemovals = true;
|
|
4320
|
+
}
|
|
4244
4321
|
}
|
|
4245
4322
|
}
|
|
4246
4323
|
if (createdSettled) {
|
|
@@ -4360,12 +4437,145 @@ var waitForIframeReady = async (root, imageTimeout = 1e4) => {
|
|
|
4360
4437
|
await waitForNextPaint(document2);
|
|
4361
4438
|
};
|
|
4362
4439
|
|
|
4440
|
+
// src/lib/capture-screenshot.ts
|
|
4441
|
+
init_react_import();
|
|
4442
|
+
var import_html2canvas_pro = __toESM(require("html2canvas-pro"));
|
|
4443
|
+
|
|
4444
|
+
// src/lib/screenshot-size.ts
|
|
4445
|
+
init_react_import();
|
|
4446
|
+
var MAX_WEBP_DIMENSION = 16383;
|
|
4447
|
+
var CAPTURE_SCALE = 2;
|
|
4448
|
+
var getFitRatio = (width, height, dimensionLimit = MAX_WEBP_DIMENSION) => {
|
|
4449
|
+
if (width <= 0 || height <= 0) return 1;
|
|
4450
|
+
return Math.min(1, dimensionLimit / Math.max(width, height));
|
|
4451
|
+
};
|
|
4452
|
+
var getCaptureScale = (width, height, scale) => scale * getFitRatio(width * scale, height * scale);
|
|
4453
|
+
var scaleDimension = (value, ratio) => Math.max(1, Math.floor(value * ratio));
|
|
4454
|
+
var getDocumentSize = (root) => {
|
|
4455
|
+
const { body, documentElement } = root.ownerDocument;
|
|
4456
|
+
return {
|
|
4457
|
+
width: Math.max(
|
|
4458
|
+
body?.scrollWidth ?? 0,
|
|
4459
|
+
body?.offsetWidth ?? 0,
|
|
4460
|
+
body?.clientWidth ?? 0,
|
|
4461
|
+
documentElement?.scrollWidth ?? 0,
|
|
4462
|
+
documentElement?.offsetWidth ?? 0,
|
|
4463
|
+
documentElement?.clientWidth ?? 0
|
|
4464
|
+
),
|
|
4465
|
+
height: Math.max(
|
|
4466
|
+
body?.scrollHeight ?? 0,
|
|
4467
|
+
body?.offsetHeight ?? 0,
|
|
4468
|
+
body?.clientHeight ?? 0,
|
|
4469
|
+
documentElement?.scrollHeight ?? 0,
|
|
4470
|
+
documentElement?.offsetHeight ?? 0,
|
|
4471
|
+
documentElement?.clientHeight ?? 0
|
|
4472
|
+
)
|
|
4473
|
+
};
|
|
4474
|
+
};
|
|
4475
|
+
|
|
4476
|
+
// src/lib/capture-screenshot.ts
|
|
4477
|
+
var editorOnlyClassPrefixes = ["_DraggableComponent--hover", "_ActionBar"];
|
|
4478
|
+
var releaseCanvas = (canvas) => {
|
|
4479
|
+
canvas.width = 0;
|
|
4480
|
+
canvas.height = 0;
|
|
4481
|
+
};
|
|
4482
|
+
var drawScaled = (source, ratio) => {
|
|
4483
|
+
const target = document.createElement("canvas");
|
|
4484
|
+
target.width = scaleDimension(source.width, ratio);
|
|
4485
|
+
target.height = scaleDimension(source.height, ratio);
|
|
4486
|
+
const ctx2 = target.getContext("2d");
|
|
4487
|
+
if (!ctx2) {
|
|
4488
|
+
releaseCanvas(target);
|
|
4489
|
+
return source;
|
|
4490
|
+
}
|
|
4491
|
+
ctx2.imageSmoothingEnabled = true;
|
|
4492
|
+
ctx2.imageSmoothingQuality = "high";
|
|
4493
|
+
ctx2.drawImage(source, 0, 0, target.width, target.height);
|
|
4494
|
+
return target;
|
|
4495
|
+
};
|
|
4496
|
+
var fitCanvas = (canvas) => {
|
|
4497
|
+
let remaining = getFitRatio(canvas.width, canvas.height);
|
|
4498
|
+
if (remaining >= 1) return canvas;
|
|
4499
|
+
let current = canvas;
|
|
4500
|
+
while (remaining < 0.5) {
|
|
4501
|
+
const next = drawScaled(current, 0.5);
|
|
4502
|
+
if (current !== canvas) releaseCanvas(current);
|
|
4503
|
+
current = next;
|
|
4504
|
+
remaining *= 2;
|
|
4505
|
+
}
|
|
4506
|
+
const fitted = drawScaled(current, remaining);
|
|
4507
|
+
if (current !== canvas) releaseCanvas(current);
|
|
4508
|
+
return fitted;
|
|
4509
|
+
};
|
|
4510
|
+
var toWebp = (canvas, quality) => new Promise((resolve, reject) => {
|
|
4511
|
+
canvas.toBlob(
|
|
4512
|
+
(blob) => {
|
|
4513
|
+
if (blob && blob.size > 0) {
|
|
4514
|
+
resolve(blob);
|
|
4515
|
+
return;
|
|
4516
|
+
}
|
|
4517
|
+
reject(
|
|
4518
|
+
new Error(
|
|
4519
|
+
`Could not encode a ${canvas.width}x${canvas.height} canvas as WebP`
|
|
4520
|
+
)
|
|
4521
|
+
);
|
|
4522
|
+
},
|
|
4523
|
+
"image/webp",
|
|
4524
|
+
quality
|
|
4525
|
+
);
|
|
4526
|
+
});
|
|
4527
|
+
var captureScreenshot = async (root, { scale = CAPTURE_SCALE, quality = 0.8, width } = {}) => {
|
|
4528
|
+
const documentSize = getDocumentSize(root);
|
|
4529
|
+
const safeWebPScale = getCaptureScale(
|
|
4530
|
+
width ?? documentSize.width,
|
|
4531
|
+
documentSize.height,
|
|
4532
|
+
scale
|
|
4533
|
+
);
|
|
4534
|
+
const canvas = await (0, import_html2canvas_pro.default)(root, {
|
|
4535
|
+
scale: safeWebPScale,
|
|
4536
|
+
backgroundColor: "#ffffff",
|
|
4537
|
+
...width === void 0 ? {} : { width, windowWidth: width },
|
|
4538
|
+
foreignObjectRendering: false,
|
|
4539
|
+
imageTimeout: 3e4,
|
|
4540
|
+
logging: false,
|
|
4541
|
+
allowTaint: false,
|
|
4542
|
+
useCORS: true,
|
|
4543
|
+
scrollY: 0,
|
|
4544
|
+
ignoreElements: (el) => Array.from(el.classList).some(
|
|
4545
|
+
(c) => editorOnlyClassPrefixes.some((prefix) => c.startsWith(prefix))
|
|
4546
|
+
)
|
|
4547
|
+
});
|
|
4548
|
+
const fitted = fitCanvas(canvas);
|
|
4549
|
+
try {
|
|
4550
|
+
return await toWebp(fitted, quality);
|
|
4551
|
+
} finally {
|
|
4552
|
+
if (fitted !== canvas) releaseCanvas(fitted);
|
|
4553
|
+
releaseCanvas(canvas);
|
|
4554
|
+
}
|
|
4555
|
+
};
|
|
4556
|
+
|
|
4557
|
+
// src/lib/client-tool-response.ts
|
|
4558
|
+
init_react_import();
|
|
4559
|
+
async function postClientToolResponse(host, body) {
|
|
4560
|
+
const response = await fetch(`${host.replace(/\/+$/, "")}/tool`, {
|
|
4561
|
+
method: "POST",
|
|
4562
|
+
headers: { "Content-Type": "application/json" },
|
|
4563
|
+
body: JSON.stringify(body)
|
|
4564
|
+
});
|
|
4565
|
+
if (!response.ok) {
|
|
4566
|
+
throw new Error(
|
|
4567
|
+
`Client tool endpoint returned ${response.status} ${response.statusText}`.trim()
|
|
4568
|
+
);
|
|
4569
|
+
}
|
|
4570
|
+
}
|
|
4571
|
+
|
|
4363
4572
|
// src/components/Chat/index.tsx
|
|
4364
4573
|
var import_jsx_runtime35 = require("react/jsx-runtime");
|
|
4365
4574
|
var q = (0, import_qler.default)();
|
|
4366
4575
|
var DEFAULT_API_VERSION = "v2";
|
|
4367
4576
|
var BUILD_OP_DEBOUNCE_MS = 1e3 / 60;
|
|
4368
|
-
var
|
|
4577
|
+
var CLIENT_TOOL_ENDPOINT_UNAVAILABLE_ERROR_MESSAGE = "Unable to verify the page data. Please enable the `/chat/tool` endpoint on the server and try again.";
|
|
4578
|
+
var PLUGIN_AI_VERSION = true ? "0.8.4-canary.1fe661a8" : "unknown";
|
|
4369
4579
|
var BENCHMARK = false;
|
|
4370
4580
|
var prefixedUlid = (prefix = "") => `${prefix ? `${prefix}_` : ""}${(0, import_ulid.ulid)()}`;
|
|
4371
4581
|
var getClassName18 = getClassNameFactory("Chat", styles_module_default);
|
|
@@ -4403,10 +4613,14 @@ function Chat2(props) {
|
|
|
4403
4613
|
}, [puckData, getPuck]);
|
|
4404
4614
|
const [error, setError] = (0, import_react27.useState)();
|
|
4405
4615
|
const [userError, setUserError] = (0, import_react27.useState)();
|
|
4616
|
+
const clientToolEndpointUnavailableRef = (0, import_react27.useRef)(false);
|
|
4617
|
+
const stopChatRef = (0, import_react27.useRef)(null);
|
|
4406
4618
|
const [composerAttachments, setComposerAttachments] = (0, import_react27.useState)([]);
|
|
4407
4619
|
const removedAttachmentClientIdsRef = (0, import_react27.useRef)(/* @__PURE__ */ new Set());
|
|
4408
4620
|
const uploadControllersRef = (0, import_react27.useRef)(/* @__PURE__ */ new Map());
|
|
4409
4621
|
const pendingBuildOpsRef = (0, import_react27.useRef)([]);
|
|
4622
|
+
const lastStreamActivityRef = (0, import_react27.useRef)(0);
|
|
4623
|
+
const hiddenSinceRef = (0, import_react27.useRef)(null);
|
|
4410
4624
|
const [toolStatus, setToolStatus] = (0, import_react27.useState)({});
|
|
4411
4625
|
const [subagentState, setSubagentState] = (0, import_react27.useState)({});
|
|
4412
4626
|
const attachmentConfig = (0, import_react27.useMemo)(
|
|
@@ -4446,24 +4660,7 @@ function Chat2(props) {
|
|
|
4446
4660
|
throw new Error("Preview frame not found");
|
|
4447
4661
|
}
|
|
4448
4662
|
await waitForIframeReady(iframeDocument);
|
|
4449
|
-
const
|
|
4450
|
-
scale: 2,
|
|
4451
|
-
backgroundColor: "#ffffff",
|
|
4452
|
-
width,
|
|
4453
|
-
windowWidth: width,
|
|
4454
|
-
foreignObjectRendering: false,
|
|
4455
|
-
imageTimeout: 3e4,
|
|
4456
|
-
logging: false,
|
|
4457
|
-
allowTaint: false,
|
|
4458
|
-
useCORS: true,
|
|
4459
|
-
scrollY: 0,
|
|
4460
|
-
ignoreElements: (el) => Array.from(el.classList).some(
|
|
4461
|
-
(c) => c.startsWith("_DraggableComponent--hover") || c.startsWith("_ActionBar")
|
|
4462
|
-
)
|
|
4463
|
-
});
|
|
4464
|
-
const image = canvas.toDataURL("image/webp", 0.8);
|
|
4465
|
-
const imageResponse = await fetch(image);
|
|
4466
|
-
const blob = await imageResponse.blob();
|
|
4663
|
+
const blob = await captureScreenshot(iframeDocument, { width });
|
|
4467
4664
|
const uploadResponse = await fetch(bucketUrl, {
|
|
4468
4665
|
method: "PUT",
|
|
4469
4666
|
body: blob
|
|
@@ -4517,8 +4714,43 @@ function Chat2(props) {
|
|
|
4517
4714
|
},
|
|
4518
4715
|
[debouncedFlushBuildOps]
|
|
4519
4716
|
);
|
|
4717
|
+
const handleClientToolEndpointUnavailable = (0, import_react27.useCallback)(() => {
|
|
4718
|
+
if (clientToolEndpointUnavailableRef.current) return;
|
|
4719
|
+
clientToolEndpointUnavailableRef.current = true;
|
|
4720
|
+
setError(CLIENT_TOOL_ENDPOINT_UNAVAILABLE_ERROR_MESSAGE);
|
|
4721
|
+
console.error(CLIENT_TOOL_ENDPOINT_UNAVAILABLE_ERROR_MESSAGE);
|
|
4722
|
+
setToolStatus((current) => {
|
|
4723
|
+
let changed = false;
|
|
4724
|
+
const next = {};
|
|
4725
|
+
for (const [id, toolState] of Object.entries(current)) {
|
|
4726
|
+
if (toolState.loading) {
|
|
4727
|
+
changed = true;
|
|
4728
|
+
next[id] = {
|
|
4729
|
+
...toolState,
|
|
4730
|
+
loading: false,
|
|
4731
|
+
label: "Verification unavailable"
|
|
4732
|
+
};
|
|
4733
|
+
} else {
|
|
4734
|
+
next[id] = toolState;
|
|
4735
|
+
}
|
|
4736
|
+
}
|
|
4737
|
+
return changed ? next : current;
|
|
4738
|
+
});
|
|
4739
|
+
stopChatRef.current?.();
|
|
4740
|
+
}, []);
|
|
4741
|
+
const sendClientToolResponse = (0, import_react27.useCallback)(
|
|
4742
|
+
async (body) => {
|
|
4743
|
+
try {
|
|
4744
|
+
await postClientToolResponse(host, body);
|
|
4745
|
+
} catch {
|
|
4746
|
+
handleClientToolEndpointUnavailable();
|
|
4747
|
+
}
|
|
4748
|
+
},
|
|
4749
|
+
[handleClientToolEndpointUnavailable, host]
|
|
4750
|
+
);
|
|
4520
4751
|
const processData = (0, import_react27.useCallback)(
|
|
4521
4752
|
(dataPart) => {
|
|
4753
|
+
lastStreamActivityRef.current = Date.now();
|
|
4522
4754
|
switch (dataPart.type) {
|
|
4523
4755
|
case "data-new-chat-created": {
|
|
4524
4756
|
localChatId.current = dataPart.data.chatId;
|
|
@@ -4549,13 +4781,9 @@ function Chat2(props) {
|
|
|
4549
4781
|
debouncedFlushBuildOps.flush();
|
|
4550
4782
|
q.wait().then(() => {
|
|
4551
4783
|
const { appState } = getPuck();
|
|
4552
|
-
return
|
|
4553
|
-
|
|
4554
|
-
|
|
4555
|
-
body: JSON.stringify({
|
|
4556
|
-
id: requestId,
|
|
4557
|
-
responses: [{ action, output: appState.data }]
|
|
4558
|
-
})
|
|
4784
|
+
return sendClientToolResponse({
|
|
4785
|
+
id: requestId,
|
|
4786
|
+
responses: [{ action, output: appState.data }]
|
|
4559
4787
|
});
|
|
4560
4788
|
}).catch((e) => {
|
|
4561
4789
|
console.error("Failed to respond to client request:", e);
|
|
@@ -4572,22 +4800,7 @@ function Chat2(props) {
|
|
|
4572
4800
|
throw new Error("Preview frame not found");
|
|
4573
4801
|
}
|
|
4574
4802
|
await waitForIframeReady(iframeDocument);
|
|
4575
|
-
const
|
|
4576
|
-
scale: 2,
|
|
4577
|
-
backgroundColor: "#ffffff",
|
|
4578
|
-
foreignObjectRendering: false,
|
|
4579
|
-
imageTimeout: 3e4,
|
|
4580
|
-
logging: false,
|
|
4581
|
-
allowTaint: false,
|
|
4582
|
-
useCORS: true,
|
|
4583
|
-
scrollY: 0,
|
|
4584
|
-
ignoreElements: (el) => Array.from(el.classList).some(
|
|
4585
|
-
(c) => c.startsWith("_DraggableComponent--hover") || c.startsWith("_ActionBar")
|
|
4586
|
-
)
|
|
4587
|
-
});
|
|
4588
|
-
const image = canvas.toDataURL("image/webp", 0.8);
|
|
4589
|
-
const imageResponse = await fetch(image);
|
|
4590
|
-
const blob = await imageResponse.blob();
|
|
4803
|
+
const blob = await captureScreenshot(iframeDocument);
|
|
4591
4804
|
const uploadResponse = await fetch(putUrl, {
|
|
4592
4805
|
method: "PUT",
|
|
4593
4806
|
body: blob
|
|
@@ -4597,16 +4810,16 @@ function Chat2(props) {
|
|
|
4597
4810
|
`Upload failed with status ${uploadResponse.status}`
|
|
4598
4811
|
);
|
|
4599
4812
|
}
|
|
4600
|
-
return
|
|
4601
|
-
|
|
4602
|
-
|
|
4603
|
-
body: JSON.stringify({
|
|
4604
|
-
id: requestId,
|
|
4605
|
-
responses: [{ action, output: { sizeBytes: blob.size } }]
|
|
4606
|
-
})
|
|
4813
|
+
return sendClientToolResponse({
|
|
4814
|
+
id: requestId,
|
|
4815
|
+
responses: [{ action, output: { sizeBytes: blob.size } }]
|
|
4607
4816
|
});
|
|
4608
4817
|
}).catch((e) => {
|
|
4609
4818
|
console.error("Failed to respond to client request:", e);
|
|
4819
|
+
return sendClientToolResponse({
|
|
4820
|
+
id: requestId,
|
|
4821
|
+
responses: [{ action, output: { sizeBytes: 0 } }]
|
|
4822
|
+
});
|
|
4610
4823
|
});
|
|
4611
4824
|
}
|
|
4612
4825
|
return;
|
|
@@ -4650,6 +4863,7 @@ function Chat2(props) {
|
|
|
4650
4863
|
getPuck,
|
|
4651
4864
|
puckDispatch,
|
|
4652
4865
|
queueBuildOp,
|
|
4866
|
+
sendClientToolResponse,
|
|
4653
4867
|
uploadScreenshot
|
|
4654
4868
|
]
|
|
4655
4869
|
);
|
|
@@ -4719,12 +4933,14 @@ function Chat2(props) {
|
|
|
4719
4933
|
if (BENCHMARK) {
|
|
4720
4934
|
console.timeEnd("chat");
|
|
4721
4935
|
}
|
|
4722
|
-
|
|
4936
|
+
if (!clientToolEndpointUnavailableRef.current) {
|
|
4937
|
+
setError(e.message);
|
|
4938
|
+
}
|
|
4723
4939
|
},
|
|
4724
4940
|
onFinish: (options) => {
|
|
4725
4941
|
debouncedFlushBuildOps.flush();
|
|
4726
4942
|
q.wait().then(() => {
|
|
4727
|
-
if (!options.isAbort) {
|
|
4943
|
+
if (!options.isAbort || clientToolEndpointUnavailableRef.current) {
|
|
4728
4944
|
puckDispatch({
|
|
4729
4945
|
type: "set",
|
|
4730
4946
|
state: getPuck().appState,
|
|
@@ -4739,12 +4955,63 @@ function Chat2(props) {
|
|
|
4739
4955
|
});
|
|
4740
4956
|
}
|
|
4741
4957
|
});
|
|
4742
|
-
(0, import_react27.useEffect)(
|
|
4743
|
-
|
|
4958
|
+
(0, import_react27.useEffect)(() => {
|
|
4959
|
+
stopChatRef.current = stop;
|
|
4960
|
+
return () => {
|
|
4961
|
+
stopChatRef.current = null;
|
|
4744
4962
|
stop();
|
|
4745
|
-
}
|
|
4746
|
-
|
|
4747
|
-
);
|
|
4963
|
+
};
|
|
4964
|
+
}, [stop]);
|
|
4965
|
+
const statusRef = (0, import_react27.useRef)(status);
|
|
4966
|
+
(0, import_react27.useEffect)(() => {
|
|
4967
|
+
statusRef.current = status;
|
|
4968
|
+
}, [status]);
|
|
4969
|
+
(0, import_react27.useEffect)(() => {
|
|
4970
|
+
lastStreamActivityRef.current = Date.now();
|
|
4971
|
+
}, [messages]);
|
|
4972
|
+
(0, import_react27.useEffect)(() => {
|
|
4973
|
+
const FROZEN_HIDDEN_MS = 3 * 6e4;
|
|
4974
|
+
const RESUME_GRACE_MS = 12e3;
|
|
4975
|
+
const isStreaming = () => statusRef.current === "streaming" || statusRef.current === "submitted";
|
|
4976
|
+
let graceTimer;
|
|
4977
|
+
const recoverIfSevered = () => {
|
|
4978
|
+
if (!isStreaming()) return;
|
|
4979
|
+
if (Date.now() - lastStreamActivityRef.current < RESUME_GRACE_MS) return;
|
|
4980
|
+
stop();
|
|
4981
|
+
setToolStatus((current) => {
|
|
4982
|
+
let changed = false;
|
|
4983
|
+
const next = {};
|
|
4984
|
+
for (const [id, toolState] of Object.entries(current)) {
|
|
4985
|
+
if (toolState.loading) {
|
|
4986
|
+
changed = true;
|
|
4987
|
+
next[id] = { ...toolState, loading: false, label: "Interrupted" };
|
|
4988
|
+
} else {
|
|
4989
|
+
next[id] = toolState;
|
|
4990
|
+
}
|
|
4991
|
+
}
|
|
4992
|
+
return changed ? next : current;
|
|
4993
|
+
});
|
|
4994
|
+
};
|
|
4995
|
+
const onVisibilityChange = () => {
|
|
4996
|
+
if (document.hidden) {
|
|
4997
|
+
hiddenSinceRef.current = isStreaming() ? Date.now() : null;
|
|
4998
|
+
return;
|
|
4999
|
+
}
|
|
5000
|
+
const hiddenSince = hiddenSinceRef.current;
|
|
5001
|
+
hiddenSinceRef.current = null;
|
|
5002
|
+
if (graceTimer) clearTimeout(graceTimer);
|
|
5003
|
+
if (hiddenSince === null || Date.now() - hiddenSince < FROZEN_HIDDEN_MS) {
|
|
5004
|
+
return;
|
|
5005
|
+
}
|
|
5006
|
+
lastStreamActivityRef.current = 0;
|
|
5007
|
+
graceTimer = setTimeout(recoverIfSevered, RESUME_GRACE_MS);
|
|
5008
|
+
};
|
|
5009
|
+
document.addEventListener("visibilitychange", onVisibilityChange);
|
|
5010
|
+
return () => {
|
|
5011
|
+
document.removeEventListener("visibilitychange", onVisibilityChange);
|
|
5012
|
+
if (graceTimer) clearTimeout(graceTimer);
|
|
5013
|
+
};
|
|
5014
|
+
}, [stop]);
|
|
4748
5015
|
const [forcedStatus, setForcedStatus] = (0, import_react27.useState)();
|
|
4749
5016
|
const resolvedStatus = (0, import_react27.useMemo)(
|
|
4750
5017
|
() => forcedStatus ?? status,
|
|
@@ -4795,6 +5062,8 @@ function Chat2(props) {
|
|
|
4795
5062
|
if (!text && readyAttachments.length === 0) {
|
|
4796
5063
|
return false;
|
|
4797
5064
|
}
|
|
5065
|
+
clientToolEndpointUnavailableRef.current = false;
|
|
5066
|
+
setError("");
|
|
4798
5067
|
setUserError("");
|
|
4799
5068
|
if (chat?.onSubmit) {
|
|
4800
5069
|
try {
|
|
@@ -5034,6 +5303,7 @@ function Chat2(props) {
|
|
|
5034
5303
|
),
|
|
5035
5304
|
error,
|
|
5036
5305
|
handleRetry: () => {
|
|
5306
|
+
clientToolEndpointUnavailableRef.current = false;
|
|
5037
5307
|
setError("");
|
|
5038
5308
|
regenerate();
|
|
5039
5309
|
},
|