@puckeditor/plugin-ai 0.8.3-canary.fcc3f680 → 0.8.3
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 +478 -214
- package/dist/index.mjs +478 -214
- package/package.json +7 -7
package/dist/index.mjs
CHANGED
|
@@ -2510,7 +2510,6 @@ function ExamplePrompt({
|
|
|
2510
2510
|
// src/components/Chat/index.tsx
|
|
2511
2511
|
var import_reducer = __toESM(require_dist());
|
|
2512
2512
|
import qler from "qler";
|
|
2513
|
-
import html2canvas from "html2canvas-pro";
|
|
2514
2513
|
import { useDebouncedCallback } from "use-debounce";
|
|
2515
2514
|
|
|
2516
2515
|
// src/lib/scroll-tracking-events.ts
|
|
@@ -2582,147 +2581,16 @@ import {
|
|
|
2582
2581
|
|
|
2583
2582
|
// src/lib/morph-html.ts
|
|
2584
2583
|
init_react_import();
|
|
2585
|
-
var PROTECTED_ATTRS = /* @__PURE__ */ new Set([
|
|
2586
|
-
"contenteditable",
|
|
2587
|
-
"data-puck-overlay-portal"
|
|
2588
|
-
]);
|
|
2589
|
-
var SLOT_OWNED_ATTRS = /* @__PURE__ */ new Set(["style", "class"]);
|
|
2590
|
-
var isEventHandlerAttr = (name) => /^on/i.test(name);
|
|
2591
|
-
var cssEscape = (value) => typeof CSS !== "undefined" && CSS.escape ? CSS.escape(value) : value.replace(/["\\]/g, "\\$&");
|
|
2592
|
-
var FIELD_ATTR_PREFIX = "data-puck-field-";
|
|
2593
|
-
var hasJsonFieldBinding = (el) => {
|
|
2594
|
-
const attrBoundNames = /* @__PURE__ */ new Set();
|
|
2595
|
-
const jsonFieldNames = [];
|
|
2596
|
-
for (const attr of Array.from(el.attributes)) {
|
|
2597
|
-
if (!attr.name.startsWith(FIELD_ATTR_PREFIX)) continue;
|
|
2598
|
-
if (attr.name.startsWith("data-puck-field-value-")) continue;
|
|
2599
|
-
if (attr.value.trimStart().startsWith("{")) {
|
|
2600
|
-
const fieldName = attr.name.slice(FIELD_ATTR_PREFIX.length);
|
|
2601
|
-
if (fieldName && fieldName !== "name") {
|
|
2602
|
-
jsonFieldNames.push(fieldName);
|
|
2603
|
-
}
|
|
2604
|
-
} else {
|
|
2605
|
-
const fieldName = attr.value.trim();
|
|
2606
|
-
if (fieldName) attrBoundNames.add(fieldName);
|
|
2607
|
-
}
|
|
2608
|
-
}
|
|
2609
|
-
return jsonFieldNames.some((name) => !attrBoundNames.has(name));
|
|
2610
|
-
};
|
|
2611
|
-
var ownsItsChildren = (el) => el.hasAttribute("data-puck-slot") || el.hasAttribute("data-puck-field-name") || el.hasAttribute("data-puck-array") || hasJsonFieldBinding(el);
|
|
2612
|
-
var syncAttributes = (target, source) => {
|
|
2613
|
-
const isSlot = target.hasAttribute("data-puck-slot");
|
|
2614
|
-
for (const attr of Array.from(target.attributes)) {
|
|
2615
|
-
if (PROTECTED_ATTRS.has(attr.name)) continue;
|
|
2616
|
-
if (isSlot && SLOT_OWNED_ATTRS.has(attr.name)) continue;
|
|
2617
|
-
if (isEventHandlerAttr(attr.name) || !source.hasAttribute(attr.name)) {
|
|
2618
|
-
target.removeAttribute(attr.name);
|
|
2619
|
-
}
|
|
2620
|
-
}
|
|
2621
|
-
for (const attr of Array.from(source.attributes)) {
|
|
2622
|
-
if (PROTECTED_ATTRS.has(attr.name)) continue;
|
|
2623
|
-
if (isSlot && SLOT_OWNED_ATTRS.has(attr.name)) continue;
|
|
2624
|
-
if (isEventHandlerAttr(attr.name)) continue;
|
|
2625
|
-
if (target.getAttribute(attr.name) !== attr.value) {
|
|
2626
|
-
target.setAttribute(attr.name, attr.value);
|
|
2627
|
-
}
|
|
2628
|
-
}
|
|
2629
|
-
};
|
|
2630
|
-
var isSameKind = (a, b) => a.nodeType === b.nodeType && (a.nodeType !== Node.ELEMENT_NODE || a.tagName === b.tagName);
|
|
2631
|
-
var isIncompleteTagArtifact = (node) => node.nodeType === Node.TEXT_NODE && /^<\/?[a-zA-Z]*$/.test(node.nodeValue ?? "");
|
|
2632
|
-
var stripIncompleteTagArtifacts = (root) => {
|
|
2633
|
-
for (const child of Array.from(root.childNodes)) {
|
|
2634
|
-
if (isIncompleteTagArtifact(child)) {
|
|
2635
|
-
root.removeChild(child);
|
|
2636
|
-
} else if (child.nodeType === Node.ELEMENT_NODE) {
|
|
2637
|
-
stripIncompleteTagArtifacts(child);
|
|
2638
|
-
}
|
|
2639
|
-
}
|
|
2640
|
-
};
|
|
2641
|
-
var stripEventHandlerAttrs = (root) => {
|
|
2642
|
-
root.querySelectorAll("*").forEach((el) => {
|
|
2643
|
-
for (const attr of Array.from(el.attributes)) {
|
|
2644
|
-
if (isEventHandlerAttr(attr.name)) el.removeAttribute(attr.name);
|
|
2645
|
-
}
|
|
2646
|
-
});
|
|
2647
|
-
};
|
|
2648
|
-
var morphChildren = (target, source, skipChildrenOf = ownsItsChildren) => {
|
|
2649
|
-
const sourceChildren = Array.from(source.childNodes);
|
|
2650
|
-
for (let i = 0; i < sourceChildren.length; i++) {
|
|
2651
|
-
const sourceChild = sourceChildren[i];
|
|
2652
|
-
const targetChild = target.childNodes[i];
|
|
2653
|
-
if (!targetChild) {
|
|
2654
|
-
target.appendChild(sourceChild);
|
|
2655
|
-
continue;
|
|
2656
|
-
}
|
|
2657
|
-
if (!isSameKind(targetChild, sourceChild)) {
|
|
2658
|
-
target.replaceChild(sourceChild, targetChild);
|
|
2659
|
-
continue;
|
|
2660
|
-
}
|
|
2661
|
-
if (sourceChild.nodeType !== Node.ELEMENT_NODE) {
|
|
2662
|
-
if (targetChild.nodeValue !== sourceChild.nodeValue) {
|
|
2663
|
-
targetChild.nodeValue = sourceChild.nodeValue;
|
|
2664
|
-
}
|
|
2665
|
-
continue;
|
|
2666
|
-
}
|
|
2667
|
-
const targetEl = targetChild;
|
|
2668
|
-
syncAttributes(targetEl, sourceChild);
|
|
2669
|
-
if (!skipChildrenOf(targetEl)) {
|
|
2670
|
-
morphChildren(targetEl, sourceChild, skipChildrenOf);
|
|
2671
|
-
}
|
|
2672
|
-
}
|
|
2673
|
-
while (target.childNodes.length > sourceChildren.length) {
|
|
2674
|
-
target.removeChild(target.lastChild);
|
|
2675
|
-
}
|
|
2676
|
-
};
|
|
2677
|
-
function morphHtml(container, html, attrOverrides = [], skipChildrenOf = ownsItsChildren) {
|
|
2678
|
-
const template = container.ownerDocument.createElement("template");
|
|
2679
|
-
template.innerHTML = html;
|
|
2680
|
-
stripIncompleteTagArtifacts(template.content);
|
|
2681
|
-
stripEventHandlerAttrs(template.content);
|
|
2682
|
-
for (const { name, attr, value } of attrOverrides) {
|
|
2683
|
-
template.content.querySelectorAll(`[data-puck-field-${attr}="${cssEscape(name)}"]`).forEach((el) => {
|
|
2684
|
-
if (el.closest("[data-puck-array]")) return;
|
|
2685
|
-
el.setAttribute(attr, value);
|
|
2686
|
-
});
|
|
2687
|
-
}
|
|
2688
|
-
morphChildren(container, template.content, skipChildrenOf);
|
|
2689
|
-
}
|
|
2690
2584
|
|
|
2691
|
-
// src/lib/design/
|
|
2585
|
+
// src/lib/design/annotations.ts
|
|
2692
2586
|
init_react_import();
|
|
2693
|
-
var wrapScriptWithObserverGuard = (script) => {
|
|
2694
|
-
if (!script.includes("MutationObserver")) return script;
|
|
2695
|
-
return `(function () {
|
|
2696
|
-
var __NativeMutationObserver = window.MutationObserver;
|
|
2697
|
-
function MutationObserver(callback) {
|
|
2698
|
-
var observed = [];
|
|
2699
|
-
var inner = new __NativeMutationObserver(function (records) {
|
|
2700
|
-
inner.disconnect();
|
|
2701
|
-
try {
|
|
2702
|
-
callback(records, inner);
|
|
2703
|
-
} finally {
|
|
2704
|
-
for (var i = 0; i < observed.length; i++) {
|
|
2705
|
-
__nativeObserve.call(inner, observed[i][0], observed[i][1]);
|
|
2706
|
-
}
|
|
2707
|
-
}
|
|
2708
|
-
});
|
|
2709
|
-
var __nativeObserve = inner.observe;
|
|
2710
|
-
inner.observe = function (target, options) {
|
|
2711
|
-
observed.push([target, options]);
|
|
2712
|
-
return __nativeObserve.call(inner, target, options);
|
|
2713
|
-
};
|
|
2714
|
-
return inner;
|
|
2715
|
-
}
|
|
2716
|
-
${script}
|
|
2717
|
-
})();`;
|
|
2718
|
-
};
|
|
2719
2587
|
|
|
2720
2588
|
// src/lib/html-annotations.ts
|
|
2721
2589
|
init_react_import();
|
|
2722
2590
|
import { parseDocument } from "htmlparser2";
|
|
2723
2591
|
import { appendChild, getInnerHTML, getOuterHTML, textContent } from "domutils";
|
|
2724
2592
|
import { Text } from "domhandler";
|
|
2725
|
-
var
|
|
2593
|
+
var FIELD_ATTR_PREFIX = "data-puck-field-";
|
|
2726
2594
|
var OPTIONS_ATTR_PREFIX = "data-puck-options-";
|
|
2727
2595
|
var BIND_ATTR_PREFIX = "data-puck-bind-";
|
|
2728
2596
|
var BIND_INPUT_ATTR_PREFIX = "data-puck-bind-input-";
|
|
@@ -2770,6 +2638,19 @@ var textContentWithBreaks = (node) => {
|
|
|
2770
2638
|
var isRecord = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
2771
2639
|
var FIELD_NAME_RE = /^[A-Za-z0-9_]+(?:[-.][A-Za-z0-9_]+)*$/;
|
|
2772
2640
|
var isValidFieldName = (name) => FIELD_NAME_RE.test(name);
|
|
2641
|
+
var isFieldNameClaimed = (name, claimed, includeExact = true) => {
|
|
2642
|
+
for (const entry of claimed) {
|
|
2643
|
+
if (includeExact && entry === name || entry.startsWith(`${name}.`) || name.startsWith(`${entry}.`)) {
|
|
2644
|
+
return true;
|
|
2645
|
+
}
|
|
2646
|
+
}
|
|
2647
|
+
return false;
|
|
2648
|
+
};
|
|
2649
|
+
var attrBoundFieldNames = (attribs) => new Set(
|
|
2650
|
+
Object.entries(attribs).filter(
|
|
2651
|
+
([name, value]) => name.startsWith(FIELD_ATTR_PREFIX) && name !== `${FIELD_ATTR_PREFIX}name` && !name.startsWith(`${FIELD_ATTR_PREFIX}value-`) && !tryParseFieldShape(value)
|
|
2652
|
+
).map(([, value]) => value.trim()).filter(isValidFieldName)
|
|
2653
|
+
);
|
|
2773
2654
|
var getDeepValue = (source, path) => {
|
|
2774
2655
|
if (!path.includes(".")) return source[path];
|
|
2775
2656
|
let current = source;
|
|
@@ -2870,6 +2751,7 @@ var collectElementFields = (element, acc) => {
|
|
|
2870
2751
|
return true;
|
|
2871
2752
|
}
|
|
2872
2753
|
let skipChildren = false;
|
|
2754
|
+
const attrBound = attrBoundFieldNames(attribs);
|
|
2873
2755
|
for (const [attrName, attrValue] of Object.entries(attribs)) {
|
|
2874
2756
|
if (attrName.startsWith(OPTIONS_ATTR_PREFIX)) {
|
|
2875
2757
|
const fieldName = attrName.slice(OPTIONS_ATTR_PREFIX.length);
|
|
@@ -2898,8 +2780,8 @@ var collectElementFields = (element, acc) => {
|
|
|
2898
2780
|
}
|
|
2899
2781
|
continue;
|
|
2900
2782
|
}
|
|
2901
|
-
if (!attrName.startsWith(
|
|
2902
|
-
const target = attrName.slice(
|
|
2783
|
+
if (!attrName.startsWith(FIELD_ATTR_PREFIX)) continue;
|
|
2784
|
+
const target = attrName.slice(FIELD_ATTR_PREFIX.length);
|
|
2903
2785
|
if (!target) continue;
|
|
2904
2786
|
const shape = tryParseFieldShape(attrValue);
|
|
2905
2787
|
if (shape) {
|
|
@@ -2913,6 +2795,9 @@ var collectElementFields = (element, acc) => {
|
|
|
2913
2795
|
if (existing) existing.shape = shape;
|
|
2914
2796
|
continue;
|
|
2915
2797
|
}
|
|
2798
|
+
if (isFieldNameClaimed(name2, attrBound, false) || isFieldNameClaimed(name2, acc.seenFields)) {
|
|
2799
|
+
continue;
|
|
2800
|
+
}
|
|
2916
2801
|
acc.seenFields.add(name2);
|
|
2917
2802
|
if (shape.type === "richtext") {
|
|
2918
2803
|
acc.fields.push({ name: name2, binding: "text", shape, format: "json" });
|
|
@@ -2967,6 +2852,9 @@ var collectElementFields = (element, acc) => {
|
|
|
2967
2852
|
}
|
|
2968
2853
|
continue;
|
|
2969
2854
|
}
|
|
2855
|
+
if (target === "name" && isFieldNameClaimed(name, attrBound) || isFieldNameClaimed(name, acc.seenFields)) {
|
|
2856
|
+
continue;
|
|
2857
|
+
}
|
|
2970
2858
|
acc.seenFields.add(name);
|
|
2971
2859
|
const fieldType = getTypeModifier(attribs, name);
|
|
2972
2860
|
const constraints = fieldType === "number" ? getNumberConstraints(attribs, name) : {};
|
|
@@ -3060,7 +2948,7 @@ var parseHtmlAnnotations = (html) => {
|
|
|
3060
2948
|
if (slotName && isValidFieldName(slotName) && !seenSlots.has(slotName)) {
|
|
3061
2949
|
seenSlots.add(slotName);
|
|
3062
2950
|
const shape = tryParseFieldShape(
|
|
3063
|
-
attribs[
|
|
2951
|
+
attribs[FIELD_ATTR_PREFIX + slotName.toLowerCase()] ?? ""
|
|
3064
2952
|
);
|
|
3065
2953
|
const allow = shape?.type === "slot" ? sanitizeStringArray(shape.allow) : void 0;
|
|
3066
2954
|
const disallow = shape?.type === "slot" ? sanitizeStringArray(shape.disallow) : void 0;
|
|
@@ -3209,21 +3097,16 @@ var patchElement = (element, props) => {
|
|
|
3209
3097
|
}
|
|
3210
3098
|
return { didPatch, skipChildren: true };
|
|
3211
3099
|
}
|
|
3212
|
-
const attrBoundFields =
|
|
3213
|
-
for (const [an, av] of Object.entries(attribs)) {
|
|
3214
|
-
if (an.startsWith(FIELD_ATTR_PREFIX2) && an !== `${FIELD_ATTR_PREFIX2}name` && !tryParseFieldShape(av)) {
|
|
3215
|
-
attrBoundFields.add(av.trim());
|
|
3216
|
-
}
|
|
3217
|
-
}
|
|
3100
|
+
const attrBoundFields = attrBoundFieldNames(attribs);
|
|
3218
3101
|
for (const [attrName, attrValue] of Object.entries(attribs)) {
|
|
3219
|
-
if (!attrName.startsWith(
|
|
3220
|
-
const target = attrName.slice(
|
|
3102
|
+
if (!attrName.startsWith(FIELD_ATTR_PREFIX)) continue;
|
|
3103
|
+
const target = attrName.slice(FIELD_ATTR_PREFIX.length);
|
|
3221
3104
|
if (!target) continue;
|
|
3222
3105
|
const shape = tryParseFieldShape(attrValue);
|
|
3223
3106
|
if (shape) {
|
|
3224
3107
|
if (shape.type === "slot") continue;
|
|
3225
3108
|
const name2 = target;
|
|
3226
|
-
if (
|
|
3109
|
+
if (isFieldNameClaimed(name2, attrBoundFields)) continue;
|
|
3227
3110
|
const value2 = getDeepValue(props, name2);
|
|
3228
3111
|
if (shape.type === "richtext") {
|
|
3229
3112
|
if (typeof value2 !== "string") continue;
|
|
@@ -3241,6 +3124,9 @@ var patchElement = (element, props) => {
|
|
|
3241
3124
|
}
|
|
3242
3125
|
const name = attrValue.trim();
|
|
3243
3126
|
if (!name) continue;
|
|
3127
|
+
if (target === "name" && isFieldNameClaimed(name, attrBoundFields)) {
|
|
3128
|
+
continue;
|
|
3129
|
+
}
|
|
3244
3130
|
const value = getDeepValue(props, name);
|
|
3245
3131
|
if (target === "name" && getTypeModifier(attribs, name) === "richtext") {
|
|
3246
3132
|
if (typeof value !== "string") continue;
|
|
@@ -3313,7 +3199,6 @@ var renderHtmlArrayItems = (html, arrayName, items) => {
|
|
|
3313
3199
|
};
|
|
3314
3200
|
|
|
3315
3201
|
// src/lib/design/annotations.ts
|
|
3316
|
-
init_react_import();
|
|
3317
3202
|
var cache = /* @__PURE__ */ new Map();
|
|
3318
3203
|
var MAX_CACHE_ENTRIES = 32;
|
|
3319
3204
|
var getAnnotations = (html) => {
|
|
@@ -3330,6 +3215,160 @@ var getSlotFields = (html) => Object.fromEntries(
|
|
|
3330
3215
|
getAnnotations(html).slots.map((slot) => [slot.name, toSlotField(slot)])
|
|
3331
3216
|
);
|
|
3332
3217
|
|
|
3218
|
+
// src/lib/morph-html.ts
|
|
3219
|
+
var PROTECTED_ATTRS = /* @__PURE__ */ new Set([
|
|
3220
|
+
"contenteditable",
|
|
3221
|
+
"data-puck-overlay-portal"
|
|
3222
|
+
]);
|
|
3223
|
+
var SLOT_OWNED_ATTRS = /* @__PURE__ */ new Set(["style", "class"]);
|
|
3224
|
+
var isEventHandlerAttr = (name) => /^on/i.test(name);
|
|
3225
|
+
var FIELD_ATTR_PREFIX2 = "data-puck-field-";
|
|
3226
|
+
var LEGACY_TEXT_ATTR = `${FIELD_ATTR_PREFIX2}name`;
|
|
3227
|
+
var VALUE_ATTR_PREFIX = `${FIELD_ATTR_PREFIX2}value-`;
|
|
3228
|
+
var hasTextBinding = (el, parsedTextFields) => {
|
|
3229
|
+
for (const attr of Array.from(el.attributes)) {
|
|
3230
|
+
if (!attr.name.startsWith(FIELD_ATTR_PREFIX2)) continue;
|
|
3231
|
+
if (attr.name.startsWith(VALUE_ATTR_PREFIX)) continue;
|
|
3232
|
+
const isShape = attr.value.trimStart().startsWith("{");
|
|
3233
|
+
const fieldName = isShape ? attr.name.slice(FIELD_ATTR_PREFIX2.length) : attr.value.trim();
|
|
3234
|
+
if (isValidFieldName(fieldName) && (attr.name === LEGACY_TEXT_ATTR || isShape) && (!parsedTextFields || parsedTextFields.has(fieldName))) {
|
|
3235
|
+
return true;
|
|
3236
|
+
}
|
|
3237
|
+
}
|
|
3238
|
+
return false;
|
|
3239
|
+
};
|
|
3240
|
+
var ownsItsChildren = (el, parsedTextFields) => el.hasAttribute("data-puck-slot") || el.hasAttribute("data-puck-array") || hasTextBinding(el, parsedTextFields);
|
|
3241
|
+
var syncAttributes = (target, source) => {
|
|
3242
|
+
const isSlot = target.hasAttribute("data-puck-slot");
|
|
3243
|
+
for (const attr of Array.from(target.attributes)) {
|
|
3244
|
+
if (PROTECTED_ATTRS.has(attr.name)) continue;
|
|
3245
|
+
if (isSlot && SLOT_OWNED_ATTRS.has(attr.name)) continue;
|
|
3246
|
+
if (isEventHandlerAttr(attr.name) || !source.hasAttribute(attr.name)) {
|
|
3247
|
+
target.removeAttribute(attr.name);
|
|
3248
|
+
}
|
|
3249
|
+
}
|
|
3250
|
+
for (const attr of Array.from(source.attributes)) {
|
|
3251
|
+
if (PROTECTED_ATTRS.has(attr.name)) continue;
|
|
3252
|
+
if (isSlot && SLOT_OWNED_ATTRS.has(attr.name)) continue;
|
|
3253
|
+
if (isEventHandlerAttr(attr.name)) continue;
|
|
3254
|
+
if (target.getAttribute(attr.name) !== attr.value) {
|
|
3255
|
+
target.setAttribute(attr.name, attr.value);
|
|
3256
|
+
}
|
|
3257
|
+
}
|
|
3258
|
+
};
|
|
3259
|
+
var isSameKind = (a, b) => a.nodeType === b.nodeType && (a.nodeType !== Node.ELEMENT_NODE || a.tagName === b.tagName);
|
|
3260
|
+
var isIncompleteTagArtifact = (node) => node.nodeType === Node.TEXT_NODE && /^<\/?[a-zA-Z]*$/.test(node.nodeValue ?? "");
|
|
3261
|
+
var stripIncompleteTagArtifacts = (root) => {
|
|
3262
|
+
for (const child of Array.from(root.childNodes)) {
|
|
3263
|
+
if (isIncompleteTagArtifact(child)) {
|
|
3264
|
+
root.removeChild(child);
|
|
3265
|
+
} else if (child.nodeType === Node.ELEMENT_NODE) {
|
|
3266
|
+
stripIncompleteTagArtifacts(child);
|
|
3267
|
+
}
|
|
3268
|
+
}
|
|
3269
|
+
};
|
|
3270
|
+
var stripEventHandlerAttrs = (root) => {
|
|
3271
|
+
root.querySelectorAll("*").forEach((el) => {
|
|
3272
|
+
for (const attr of Array.from(el.attributes)) {
|
|
3273
|
+
if (isEventHandlerAttr(attr.name)) el.removeAttribute(attr.name);
|
|
3274
|
+
}
|
|
3275
|
+
});
|
|
3276
|
+
};
|
|
3277
|
+
var morphChildren = (target, source, skipChildrenOf = ownsItsChildren) => {
|
|
3278
|
+
const sourceChildren = Array.from(source.childNodes);
|
|
3279
|
+
for (let i = 0; i < sourceChildren.length; i++) {
|
|
3280
|
+
const sourceChild = sourceChildren[i];
|
|
3281
|
+
const targetChild = target.childNodes[i];
|
|
3282
|
+
if (!targetChild) {
|
|
3283
|
+
target.appendChild(sourceChild);
|
|
3284
|
+
continue;
|
|
3285
|
+
}
|
|
3286
|
+
if (!isSameKind(targetChild, sourceChild)) {
|
|
3287
|
+
target.replaceChild(sourceChild, targetChild);
|
|
3288
|
+
continue;
|
|
3289
|
+
}
|
|
3290
|
+
if (sourceChild.nodeType !== Node.ELEMENT_NODE) {
|
|
3291
|
+
if (targetChild.nodeValue !== sourceChild.nodeValue) {
|
|
3292
|
+
targetChild.nodeValue = sourceChild.nodeValue;
|
|
3293
|
+
}
|
|
3294
|
+
continue;
|
|
3295
|
+
}
|
|
3296
|
+
const targetEl = targetChild;
|
|
3297
|
+
syncAttributes(targetEl, sourceChild);
|
|
3298
|
+
if (!skipChildrenOf(targetEl)) {
|
|
3299
|
+
morphChildren(targetEl, sourceChild, skipChildrenOf);
|
|
3300
|
+
}
|
|
3301
|
+
}
|
|
3302
|
+
while (target.childNodes.length > sourceChildren.length) {
|
|
3303
|
+
target.removeChild(target.lastChild);
|
|
3304
|
+
}
|
|
3305
|
+
};
|
|
3306
|
+
function morphHtml(container, html, attrOverrides = [], skipChildrenOf) {
|
|
3307
|
+
const template = container.ownerDocument.createElement("template");
|
|
3308
|
+
template.innerHTML = html;
|
|
3309
|
+
stripIncompleteTagArtifacts(template.content);
|
|
3310
|
+
stripEventHandlerAttrs(template.content);
|
|
3311
|
+
if (attrOverrides.length > 0) {
|
|
3312
|
+
const overridesByAttr = /* @__PURE__ */ new Map();
|
|
3313
|
+
for (const override of attrOverrides) {
|
|
3314
|
+
if (isEventHandlerAttr(override.attr)) continue;
|
|
3315
|
+
const bindingAttr = `${FIELD_ATTR_PREFIX2}${override.attr}`;
|
|
3316
|
+
const fields = overridesByAttr.get(bindingAttr) ?? /* @__PURE__ */ new Map();
|
|
3317
|
+
fields.set(override.name, override);
|
|
3318
|
+
overridesByAttr.set(bindingAttr, fields);
|
|
3319
|
+
}
|
|
3320
|
+
template.content.querySelectorAll("*").forEach((el) => {
|
|
3321
|
+
for (const attr of Array.from(el.attributes)) {
|
|
3322
|
+
const override = overridesByAttr.get(attr.name)?.get(attr.value.trim());
|
|
3323
|
+
if (!override) continue;
|
|
3324
|
+
if (el.closest("[data-puck-array]")) return;
|
|
3325
|
+
el.setAttribute(override.attr, override.value);
|
|
3326
|
+
}
|
|
3327
|
+
});
|
|
3328
|
+
}
|
|
3329
|
+
if (skipChildrenOf) {
|
|
3330
|
+
morphChildren(container, template.content, skipChildrenOf);
|
|
3331
|
+
return;
|
|
3332
|
+
}
|
|
3333
|
+
const parsedTextFields = new Set(
|
|
3334
|
+
getAnnotations(html).fields.filter((field) => field.binding === "text").map((field) => field.name)
|
|
3335
|
+
);
|
|
3336
|
+
morphChildren(
|
|
3337
|
+
container,
|
|
3338
|
+
template.content,
|
|
3339
|
+
(el) => ownsItsChildren(el, parsedTextFields)
|
|
3340
|
+
);
|
|
3341
|
+
}
|
|
3342
|
+
|
|
3343
|
+
// src/lib/design/observer-guard.ts
|
|
3344
|
+
init_react_import();
|
|
3345
|
+
var wrapScriptWithObserverGuard = (script) => {
|
|
3346
|
+
if (!script.includes("MutationObserver")) return script;
|
|
3347
|
+
return `(function () {
|
|
3348
|
+
var __NativeMutationObserver = window.MutationObserver;
|
|
3349
|
+
function MutationObserver(callback) {
|
|
3350
|
+
var observed = [];
|
|
3351
|
+
var inner = new __NativeMutationObserver(function (records) {
|
|
3352
|
+
inner.disconnect();
|
|
3353
|
+
try {
|
|
3354
|
+
callback(records, inner);
|
|
3355
|
+
} finally {
|
|
3356
|
+
for (var i = 0; i < observed.length; i++) {
|
|
3357
|
+
__nativeObserve.call(inner, observed[i][0], observed[i][1]);
|
|
3358
|
+
}
|
|
3359
|
+
}
|
|
3360
|
+
});
|
|
3361
|
+
var __nativeObserve = inner.observe;
|
|
3362
|
+
inner.observe = function (target, options) {
|
|
3363
|
+
observed.push([target, options]);
|
|
3364
|
+
return __nativeObserve.call(inner, target, options);
|
|
3365
|
+
};
|
|
3366
|
+
return inner;
|
|
3367
|
+
}
|
|
3368
|
+
${script}
|
|
3369
|
+
})();`;
|
|
3370
|
+
};
|
|
3371
|
+
|
|
3333
3372
|
// src/lib/design/registration-store.ts
|
|
3334
3373
|
init_react_import();
|
|
3335
3374
|
var RegistrationStore = class {
|
|
@@ -3403,7 +3442,7 @@ init_react_import();
|
|
|
3403
3442
|
import { registerOverlayPortal, setDeep } from "@puckeditor/core";
|
|
3404
3443
|
var CONTENT_EDITABLE_ATTR = "data-puck-content-editable";
|
|
3405
3444
|
var isInlineEditingDisabled = (el) => el.closest(`[${CONTENT_EDITABLE_ATTR}="false"]`) !== null;
|
|
3406
|
-
var
|
|
3445
|
+
var cssEscape = (value) => typeof CSS !== "undefined" && CSS.escape ? CSS.escape(value) : value.replace(/["\\]/g, "\\$&");
|
|
3407
3446
|
var queryScopedFields = (entry, selector) => Array.from(entry.querySelectorAll(selector)).filter((el) => {
|
|
3408
3447
|
if (el.closest("[data-puck-array]")) return false;
|
|
3409
3448
|
const closestSlot = el.closest("[data-puck-slot]");
|
|
@@ -3411,7 +3450,7 @@ var queryScopedFields = (entry, selector) => Array.from(entry.querySelectorAll(s
|
|
|
3411
3450
|
return true;
|
|
3412
3451
|
});
|
|
3413
3452
|
var findOwnArrayContainer = (entry, arrayName) => {
|
|
3414
|
-
const selector = `[data-puck-array="${
|
|
3453
|
+
const selector = `[data-puck-array="${cssEscape(arrayName)}"]`;
|
|
3415
3454
|
for (const el of entry.querySelectorAll(selector)) {
|
|
3416
3455
|
const closestSlot = el.closest("[data-puck-slot]");
|
|
3417
3456
|
if (!closestSlot || !entry.contains(closestSlot)) return el;
|
|
@@ -3426,7 +3465,7 @@ var inlineEditModeFor = (field) => {
|
|
|
3426
3465
|
const type = field.shape?.type ?? field.fieldType;
|
|
3427
3466
|
return type === "richtext" ? "richtext" : type === "number" ? "number" : "text";
|
|
3428
3467
|
};
|
|
3429
|
-
var textFieldSelector = (field) => field.format === "json" ? `[${
|
|
3468
|
+
var textFieldSelector = (field) => field.format === "json" ? `[${cssEscape(`data-puck-field-${field.name}`)}]` : `[data-puck-field-name="${cssEscape(field.name)}"]`;
|
|
3430
3469
|
var isHTMLElement = (el) => {
|
|
3431
3470
|
const HTMLElementCtor = el.ownerDocument.defaultView?.HTMLElement;
|
|
3432
3471
|
return !!HTMLElementCtor && el instanceof HTMLElementCtor;
|
|
@@ -3452,6 +3491,29 @@ var syncFieldValues = (entry, fields, props) => {
|
|
|
3452
3491
|
});
|
|
3453
3492
|
}
|
|
3454
3493
|
};
|
|
3494
|
+
var claimedHostStyles = /* @__PURE__ */ new WeakMap();
|
|
3495
|
+
var claimHostStyles = (el, applyWhiteSpace) => {
|
|
3496
|
+
if (!claimedHostStyles.has(el)) {
|
|
3497
|
+
claimedHostStyles.set(el, {
|
|
3498
|
+
cursor: el.style.cursor,
|
|
3499
|
+
whiteSpace: applyWhiteSpace ? el.style.whiteSpace : null
|
|
3500
|
+
});
|
|
3501
|
+
}
|
|
3502
|
+
applyHostStyles(el);
|
|
3503
|
+
};
|
|
3504
|
+
var applyHostStyles = (el) => {
|
|
3505
|
+
const claimed = claimedHostStyles.get(el);
|
|
3506
|
+
if (!claimed) return;
|
|
3507
|
+
el.style.cursor = "text";
|
|
3508
|
+
if (claimed.whiteSpace !== null) el.style.whiteSpace = "pre-wrap";
|
|
3509
|
+
};
|
|
3510
|
+
var releaseHostStyles = (el) => {
|
|
3511
|
+
const claimed = claimedHostStyles.get(el);
|
|
3512
|
+
if (!claimed) return;
|
|
3513
|
+
el.style.cursor = claimed.cursor;
|
|
3514
|
+
if (claimed.whiteSpace !== null) el.style.whiteSpace = claimed.whiteSpace;
|
|
3515
|
+
claimedHostStyles.delete(el);
|
|
3516
|
+
};
|
|
3455
3517
|
var attachInlineEditing = (el, {
|
|
3456
3518
|
componentId,
|
|
3457
3519
|
propPath,
|
|
@@ -3464,8 +3526,7 @@ var attachInlineEditing = (el, {
|
|
|
3464
3526
|
const syncEditable = () => {
|
|
3465
3527
|
el.contentEditable = hovering || focused ? mode === "richtext" ? "true" : "plaintext-only" : "false";
|
|
3466
3528
|
};
|
|
3467
|
-
|
|
3468
|
-
el.style.cursor = "text";
|
|
3529
|
+
claimHostStyles(el, mode !== "richtext");
|
|
3469
3530
|
syncEditable();
|
|
3470
3531
|
let lastValidNumberText = el.innerText.replaceAll(/\n/gm, "");
|
|
3471
3532
|
const handleInput = () => {
|
|
@@ -3543,7 +3604,7 @@ var attachInlineEditing = (el, {
|
|
|
3543
3604
|
el.removeEventListener("mouseout", handleMouseOut, true);
|
|
3544
3605
|
el.removeEventListener("focus", handleFocus);
|
|
3545
3606
|
el.removeEventListener("blur", handleBlur);
|
|
3546
|
-
el
|
|
3607
|
+
releaseHostStyles(el);
|
|
3547
3608
|
el.removeAttribute("contenteditable");
|
|
3548
3609
|
cleanupPortal?.();
|
|
3549
3610
|
};
|
|
@@ -3609,7 +3670,7 @@ var wireArrayItemEditing = ({
|
|
|
3609
3670
|
const mode = inlineEditModeFor(field);
|
|
3610
3671
|
const registration = wiring.get(target);
|
|
3611
3672
|
if (registration?.propPath === propPath && registration.mode === mode) {
|
|
3612
|
-
target
|
|
3673
|
+
applyHostStyles(target);
|
|
3613
3674
|
continue;
|
|
3614
3675
|
}
|
|
3615
3676
|
registration?.cleanup();
|
|
@@ -3751,7 +3812,7 @@ var SlotPortal = ({
|
|
|
3751
3812
|
[slotStyle]
|
|
3752
3813
|
);
|
|
3753
3814
|
useEffect10(() => {
|
|
3754
|
-
const el = entry.querySelector(`[data-puck-slot="${
|
|
3815
|
+
const el = entry.querySelector(`[data-puck-slot="${cssEscape(slotName)}"]`);
|
|
3755
3816
|
if (el !== lastTarget.current) {
|
|
3756
3817
|
el?.replaceChildren();
|
|
3757
3818
|
lastTarget.current = el;
|
|
@@ -3935,7 +3996,7 @@ function createDesignComponentConfig(registration) {
|
|
|
3935
3996
|
morphed.current = { el: entryEl, html, attrSig };
|
|
3936
3997
|
morphHtml(entryEl, html, attrFields);
|
|
3937
3998
|
for (const el of fieldWiring.current.keys()) {
|
|
3938
|
-
if (el.isConnected) el
|
|
3999
|
+
if (el.isConnected) applyHostStyles(el);
|
|
3939
4000
|
}
|
|
3940
4001
|
}
|
|
3941
4002
|
syncFieldValues(entryEl, annotations.fields, props);
|
|
@@ -4094,9 +4155,11 @@ function getDynamicConfigGlobals(dynamicConfig) {
|
|
|
4094
4155
|
...typeof script === "string" ? { script } : {}
|
|
4095
4156
|
};
|
|
4096
4157
|
}
|
|
4158
|
+
var INLINE_EDIT_RESET = ":where([data-puck-design] [contenteditable]){overflow-wrap:inherit;line-break:inherit;-webkit-nbsp-mode:inherit}";
|
|
4097
4159
|
function DesignGlobals({
|
|
4098
4160
|
styles,
|
|
4099
|
-
script
|
|
4161
|
+
script,
|
|
4162
|
+
isEditing
|
|
4100
4163
|
}) {
|
|
4101
4164
|
const scriptRef = useRef12(null);
|
|
4102
4165
|
const hostRef = useRef12(null);
|
|
@@ -4114,6 +4177,7 @@ function DesignGlobals({
|
|
|
4114
4177
|
};
|
|
4115
4178
|
}, [script]);
|
|
4116
4179
|
return /* @__PURE__ */ jsxs19(Fragment8, { children: [
|
|
4180
|
+
isEditing && /* @__PURE__ */ jsx33("style", { children: INLINE_EDIT_RESET }),
|
|
4117
4181
|
styles && /* @__PURE__ */ jsx33("style", { children: styles }),
|
|
4118
4182
|
script && /* @__PURE__ */ jsx33("div", { ref: hostRef, style: { display: "none" } })
|
|
4119
4183
|
] });
|
|
@@ -4126,7 +4190,14 @@ function withDesignGlobals(root) {
|
|
|
4126
4190
|
const render = (props) => {
|
|
4127
4191
|
const { styles, script } = getDynamicConfigGlobals(props._dynamicConfig);
|
|
4128
4192
|
return /* @__PURE__ */ jsxs19(Fragment8, { children: [
|
|
4129
|
-
/* @__PURE__ */ jsx33(
|
|
4193
|
+
/* @__PURE__ */ jsx33(
|
|
4194
|
+
DesignGlobals,
|
|
4195
|
+
{
|
|
4196
|
+
styles,
|
|
4197
|
+
script,
|
|
4198
|
+
isEditing: props.puck?.isEditing
|
|
4199
|
+
}
|
|
4200
|
+
),
|
|
4130
4201
|
userRender ? userRender(props) : props.children
|
|
4131
4202
|
] });
|
|
4132
4203
|
};
|
|
@@ -4392,12 +4463,145 @@ var waitForIframeReady = async (root, imageTimeout = 1e4) => {
|
|
|
4392
4463
|
await waitForNextPaint(document2);
|
|
4393
4464
|
};
|
|
4394
4465
|
|
|
4466
|
+
// src/lib/capture-screenshot.ts
|
|
4467
|
+
init_react_import();
|
|
4468
|
+
import html2canvas from "html2canvas-pro";
|
|
4469
|
+
|
|
4470
|
+
// src/lib/screenshot-size.ts
|
|
4471
|
+
init_react_import();
|
|
4472
|
+
var MAX_WEBP_DIMENSION = 16383;
|
|
4473
|
+
var CAPTURE_SCALE = 2;
|
|
4474
|
+
var getFitRatio = (width, height, dimensionLimit = MAX_WEBP_DIMENSION) => {
|
|
4475
|
+
if (width <= 0 || height <= 0) return 1;
|
|
4476
|
+
return Math.min(1, dimensionLimit / Math.max(width, height));
|
|
4477
|
+
};
|
|
4478
|
+
var getCaptureScale = (width, height, scale) => scale * getFitRatio(width * scale, height * scale);
|
|
4479
|
+
var scaleDimension = (value, ratio) => Math.max(1, Math.floor(value * ratio));
|
|
4480
|
+
var getDocumentSize = (root) => {
|
|
4481
|
+
const { body, documentElement } = root.ownerDocument;
|
|
4482
|
+
return {
|
|
4483
|
+
width: Math.max(
|
|
4484
|
+
body?.scrollWidth ?? 0,
|
|
4485
|
+
body?.offsetWidth ?? 0,
|
|
4486
|
+
body?.clientWidth ?? 0,
|
|
4487
|
+
documentElement?.scrollWidth ?? 0,
|
|
4488
|
+
documentElement?.offsetWidth ?? 0,
|
|
4489
|
+
documentElement?.clientWidth ?? 0
|
|
4490
|
+
),
|
|
4491
|
+
height: Math.max(
|
|
4492
|
+
body?.scrollHeight ?? 0,
|
|
4493
|
+
body?.offsetHeight ?? 0,
|
|
4494
|
+
body?.clientHeight ?? 0,
|
|
4495
|
+
documentElement?.scrollHeight ?? 0,
|
|
4496
|
+
documentElement?.offsetHeight ?? 0,
|
|
4497
|
+
documentElement?.clientHeight ?? 0
|
|
4498
|
+
)
|
|
4499
|
+
};
|
|
4500
|
+
};
|
|
4501
|
+
|
|
4502
|
+
// src/lib/capture-screenshot.ts
|
|
4503
|
+
var editorOnlyClassPrefixes = ["_DraggableComponent--hover", "_ActionBar"];
|
|
4504
|
+
var releaseCanvas = (canvas) => {
|
|
4505
|
+
canvas.width = 0;
|
|
4506
|
+
canvas.height = 0;
|
|
4507
|
+
};
|
|
4508
|
+
var drawScaled = (source, ratio) => {
|
|
4509
|
+
const target = document.createElement("canvas");
|
|
4510
|
+
target.width = scaleDimension(source.width, ratio);
|
|
4511
|
+
target.height = scaleDimension(source.height, ratio);
|
|
4512
|
+
const ctx2 = target.getContext("2d");
|
|
4513
|
+
if (!ctx2) {
|
|
4514
|
+
releaseCanvas(target);
|
|
4515
|
+
return source;
|
|
4516
|
+
}
|
|
4517
|
+
ctx2.imageSmoothingEnabled = true;
|
|
4518
|
+
ctx2.imageSmoothingQuality = "high";
|
|
4519
|
+
ctx2.drawImage(source, 0, 0, target.width, target.height);
|
|
4520
|
+
return target;
|
|
4521
|
+
};
|
|
4522
|
+
var fitCanvas = (canvas) => {
|
|
4523
|
+
let remaining = getFitRatio(canvas.width, canvas.height);
|
|
4524
|
+
if (remaining >= 1) return canvas;
|
|
4525
|
+
let current = canvas;
|
|
4526
|
+
while (remaining < 0.5) {
|
|
4527
|
+
const next = drawScaled(current, 0.5);
|
|
4528
|
+
if (current !== canvas) releaseCanvas(current);
|
|
4529
|
+
current = next;
|
|
4530
|
+
remaining *= 2;
|
|
4531
|
+
}
|
|
4532
|
+
const fitted = drawScaled(current, remaining);
|
|
4533
|
+
if (current !== canvas) releaseCanvas(current);
|
|
4534
|
+
return fitted;
|
|
4535
|
+
};
|
|
4536
|
+
var toWebp = (canvas, quality) => new Promise((resolve, reject) => {
|
|
4537
|
+
canvas.toBlob(
|
|
4538
|
+
(blob) => {
|
|
4539
|
+
if (blob && blob.size > 0) {
|
|
4540
|
+
resolve(blob);
|
|
4541
|
+
return;
|
|
4542
|
+
}
|
|
4543
|
+
reject(
|
|
4544
|
+
new Error(
|
|
4545
|
+
`Could not encode a ${canvas.width}x${canvas.height} canvas as WebP`
|
|
4546
|
+
)
|
|
4547
|
+
);
|
|
4548
|
+
},
|
|
4549
|
+
"image/webp",
|
|
4550
|
+
quality
|
|
4551
|
+
);
|
|
4552
|
+
});
|
|
4553
|
+
var captureScreenshot = async (root, { scale = CAPTURE_SCALE, quality = 0.8, width } = {}) => {
|
|
4554
|
+
const documentSize = getDocumentSize(root);
|
|
4555
|
+
const safeWebPScale = getCaptureScale(
|
|
4556
|
+
width ?? documentSize.width,
|
|
4557
|
+
documentSize.height,
|
|
4558
|
+
scale
|
|
4559
|
+
);
|
|
4560
|
+
const canvas = await html2canvas(root, {
|
|
4561
|
+
scale: safeWebPScale,
|
|
4562
|
+
backgroundColor: "#ffffff",
|
|
4563
|
+
...width === void 0 ? {} : { width, windowWidth: width },
|
|
4564
|
+
foreignObjectRendering: false,
|
|
4565
|
+
imageTimeout: 3e4,
|
|
4566
|
+
logging: false,
|
|
4567
|
+
allowTaint: false,
|
|
4568
|
+
useCORS: true,
|
|
4569
|
+
scrollY: 0,
|
|
4570
|
+
ignoreElements: (el) => Array.from(el.classList).some(
|
|
4571
|
+
(c) => editorOnlyClassPrefixes.some((prefix) => c.startsWith(prefix))
|
|
4572
|
+
)
|
|
4573
|
+
});
|
|
4574
|
+
const fitted = fitCanvas(canvas);
|
|
4575
|
+
try {
|
|
4576
|
+
return await toWebp(fitted, quality);
|
|
4577
|
+
} finally {
|
|
4578
|
+
if (fitted !== canvas) releaseCanvas(fitted);
|
|
4579
|
+
releaseCanvas(canvas);
|
|
4580
|
+
}
|
|
4581
|
+
};
|
|
4582
|
+
|
|
4583
|
+
// src/lib/client-tool-response.ts
|
|
4584
|
+
init_react_import();
|
|
4585
|
+
async function postClientToolResponse(host, body) {
|
|
4586
|
+
const response = await fetch(`${host.replace(/\/+$/, "")}/tool`, {
|
|
4587
|
+
method: "POST",
|
|
4588
|
+
headers: { "Content-Type": "application/json" },
|
|
4589
|
+
body: JSON.stringify(body)
|
|
4590
|
+
});
|
|
4591
|
+
if (!response.ok) {
|
|
4592
|
+
throw new Error(
|
|
4593
|
+
`Client tool endpoint returned ${response.status} ${response.statusText}`.trim()
|
|
4594
|
+
);
|
|
4595
|
+
}
|
|
4596
|
+
}
|
|
4597
|
+
|
|
4395
4598
|
// src/components/Chat/index.tsx
|
|
4396
4599
|
import { Fragment as Fragment9, jsx as jsx35, jsxs as jsxs20 } from "react/jsx-runtime";
|
|
4397
4600
|
var q = qler();
|
|
4398
4601
|
var DEFAULT_API_VERSION = "v2";
|
|
4399
4602
|
var BUILD_OP_DEBOUNCE_MS = 1e3 / 60;
|
|
4400
|
-
var
|
|
4603
|
+
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.";
|
|
4604
|
+
var PLUGIN_AI_VERSION = true ? "0.8.3" : "unknown";
|
|
4401
4605
|
var BENCHMARK = false;
|
|
4402
4606
|
var prefixedUlid = (prefix = "") => `${prefix ? `${prefix}_` : ""}${ulid()}`;
|
|
4403
4607
|
var getClassName18 = getClassNameFactory("Chat", styles_module_default);
|
|
@@ -4435,10 +4639,14 @@ function Chat2(props) {
|
|
|
4435
4639
|
}, [puckData, getPuck]);
|
|
4436
4640
|
const [error, setError] = useState16();
|
|
4437
4641
|
const [userError, setUserError] = useState16();
|
|
4642
|
+
const clientToolEndpointUnavailableRef = useRef13(false);
|
|
4643
|
+
const stopChatRef = useRef13(null);
|
|
4438
4644
|
const [composerAttachments, setComposerAttachments] = useState16([]);
|
|
4439
4645
|
const removedAttachmentClientIdsRef = useRef13(/* @__PURE__ */ new Set());
|
|
4440
4646
|
const uploadControllersRef = useRef13(/* @__PURE__ */ new Map());
|
|
4441
4647
|
const pendingBuildOpsRef = useRef13([]);
|
|
4648
|
+
const lastStreamActivityRef = useRef13(0);
|
|
4649
|
+
const hiddenSinceRef = useRef13(null);
|
|
4442
4650
|
const [toolStatus, setToolStatus] = useState16({});
|
|
4443
4651
|
const [subagentState, setSubagentState] = useState16({});
|
|
4444
4652
|
const attachmentConfig = useMemo6(
|
|
@@ -4478,24 +4686,7 @@ function Chat2(props) {
|
|
|
4478
4686
|
throw new Error("Preview frame not found");
|
|
4479
4687
|
}
|
|
4480
4688
|
await waitForIframeReady(iframeDocument);
|
|
4481
|
-
const
|
|
4482
|
-
scale: 2,
|
|
4483
|
-
backgroundColor: "#ffffff",
|
|
4484
|
-
width,
|
|
4485
|
-
windowWidth: width,
|
|
4486
|
-
foreignObjectRendering: false,
|
|
4487
|
-
imageTimeout: 3e4,
|
|
4488
|
-
logging: false,
|
|
4489
|
-
allowTaint: false,
|
|
4490
|
-
useCORS: true,
|
|
4491
|
-
scrollY: 0,
|
|
4492
|
-
ignoreElements: (el) => Array.from(el.classList).some(
|
|
4493
|
-
(c) => c.startsWith("_DraggableComponent--hover") || c.startsWith("_ActionBar")
|
|
4494
|
-
)
|
|
4495
|
-
});
|
|
4496
|
-
const image = canvas.toDataURL("image/webp", 0.8);
|
|
4497
|
-
const imageResponse = await fetch(image);
|
|
4498
|
-
const blob = await imageResponse.blob();
|
|
4689
|
+
const blob = await captureScreenshot(iframeDocument, { width });
|
|
4499
4690
|
const uploadResponse = await fetch(bucketUrl, {
|
|
4500
4691
|
method: "PUT",
|
|
4501
4692
|
body: blob
|
|
@@ -4549,8 +4740,43 @@ function Chat2(props) {
|
|
|
4549
4740
|
},
|
|
4550
4741
|
[debouncedFlushBuildOps]
|
|
4551
4742
|
);
|
|
4743
|
+
const handleClientToolEndpointUnavailable = useCallback6(() => {
|
|
4744
|
+
if (clientToolEndpointUnavailableRef.current) return;
|
|
4745
|
+
clientToolEndpointUnavailableRef.current = true;
|
|
4746
|
+
setError(CLIENT_TOOL_ENDPOINT_UNAVAILABLE_ERROR_MESSAGE);
|
|
4747
|
+
console.error(CLIENT_TOOL_ENDPOINT_UNAVAILABLE_ERROR_MESSAGE);
|
|
4748
|
+
setToolStatus((current) => {
|
|
4749
|
+
let changed = false;
|
|
4750
|
+
const next = {};
|
|
4751
|
+
for (const [id, toolState] of Object.entries(current)) {
|
|
4752
|
+
if (toolState.loading) {
|
|
4753
|
+
changed = true;
|
|
4754
|
+
next[id] = {
|
|
4755
|
+
...toolState,
|
|
4756
|
+
loading: false,
|
|
4757
|
+
label: "Verification unavailable"
|
|
4758
|
+
};
|
|
4759
|
+
} else {
|
|
4760
|
+
next[id] = toolState;
|
|
4761
|
+
}
|
|
4762
|
+
}
|
|
4763
|
+
return changed ? next : current;
|
|
4764
|
+
});
|
|
4765
|
+
stopChatRef.current?.();
|
|
4766
|
+
}, []);
|
|
4767
|
+
const sendClientToolResponse = useCallback6(
|
|
4768
|
+
async (body) => {
|
|
4769
|
+
try {
|
|
4770
|
+
await postClientToolResponse(host, body);
|
|
4771
|
+
} catch {
|
|
4772
|
+
handleClientToolEndpointUnavailable();
|
|
4773
|
+
}
|
|
4774
|
+
},
|
|
4775
|
+
[handleClientToolEndpointUnavailable, host]
|
|
4776
|
+
);
|
|
4552
4777
|
const processData = useCallback6(
|
|
4553
4778
|
(dataPart) => {
|
|
4779
|
+
lastStreamActivityRef.current = Date.now();
|
|
4554
4780
|
switch (dataPart.type) {
|
|
4555
4781
|
case "data-new-chat-created": {
|
|
4556
4782
|
localChatId.current = dataPart.data.chatId;
|
|
@@ -4581,13 +4807,9 @@ function Chat2(props) {
|
|
|
4581
4807
|
debouncedFlushBuildOps.flush();
|
|
4582
4808
|
q.wait().then(() => {
|
|
4583
4809
|
const { appState } = getPuck();
|
|
4584
|
-
return
|
|
4585
|
-
|
|
4586
|
-
|
|
4587
|
-
body: JSON.stringify({
|
|
4588
|
-
id: requestId,
|
|
4589
|
-
responses: [{ action, output: appState.data }]
|
|
4590
|
-
})
|
|
4810
|
+
return sendClientToolResponse({
|
|
4811
|
+
id: requestId,
|
|
4812
|
+
responses: [{ action, output: appState.data }]
|
|
4591
4813
|
});
|
|
4592
4814
|
}).catch((e) => {
|
|
4593
4815
|
console.error("Failed to respond to client request:", e);
|
|
@@ -4604,22 +4826,7 @@ function Chat2(props) {
|
|
|
4604
4826
|
throw new Error("Preview frame not found");
|
|
4605
4827
|
}
|
|
4606
4828
|
await waitForIframeReady(iframeDocument);
|
|
4607
|
-
const
|
|
4608
|
-
scale: 2,
|
|
4609
|
-
backgroundColor: "#ffffff",
|
|
4610
|
-
foreignObjectRendering: false,
|
|
4611
|
-
imageTimeout: 3e4,
|
|
4612
|
-
logging: false,
|
|
4613
|
-
allowTaint: false,
|
|
4614
|
-
useCORS: true,
|
|
4615
|
-
scrollY: 0,
|
|
4616
|
-
ignoreElements: (el) => Array.from(el.classList).some(
|
|
4617
|
-
(c) => c.startsWith("_DraggableComponent--hover") || c.startsWith("_ActionBar")
|
|
4618
|
-
)
|
|
4619
|
-
});
|
|
4620
|
-
const image = canvas.toDataURL("image/webp", 0.8);
|
|
4621
|
-
const imageResponse = await fetch(image);
|
|
4622
|
-
const blob = await imageResponse.blob();
|
|
4829
|
+
const blob = await captureScreenshot(iframeDocument);
|
|
4623
4830
|
const uploadResponse = await fetch(putUrl, {
|
|
4624
4831
|
method: "PUT",
|
|
4625
4832
|
body: blob
|
|
@@ -4629,16 +4836,16 @@ function Chat2(props) {
|
|
|
4629
4836
|
`Upload failed with status ${uploadResponse.status}`
|
|
4630
4837
|
);
|
|
4631
4838
|
}
|
|
4632
|
-
return
|
|
4633
|
-
|
|
4634
|
-
|
|
4635
|
-
body: JSON.stringify({
|
|
4636
|
-
id: requestId,
|
|
4637
|
-
responses: [{ action, output: { sizeBytes: blob.size } }]
|
|
4638
|
-
})
|
|
4839
|
+
return sendClientToolResponse({
|
|
4840
|
+
id: requestId,
|
|
4841
|
+
responses: [{ action, output: { sizeBytes: blob.size } }]
|
|
4639
4842
|
});
|
|
4640
4843
|
}).catch((e) => {
|
|
4641
4844
|
console.error("Failed to respond to client request:", e);
|
|
4845
|
+
return sendClientToolResponse({
|
|
4846
|
+
id: requestId,
|
|
4847
|
+
responses: [{ action, output: { sizeBytes: 0 } }]
|
|
4848
|
+
});
|
|
4642
4849
|
});
|
|
4643
4850
|
}
|
|
4644
4851
|
return;
|
|
@@ -4682,6 +4889,7 @@ function Chat2(props) {
|
|
|
4682
4889
|
getPuck,
|
|
4683
4890
|
puckDispatch,
|
|
4684
4891
|
queueBuildOp,
|
|
4892
|
+
sendClientToolResponse,
|
|
4685
4893
|
uploadScreenshot
|
|
4686
4894
|
]
|
|
4687
4895
|
);
|
|
@@ -4751,12 +4959,14 @@ function Chat2(props) {
|
|
|
4751
4959
|
if (BENCHMARK) {
|
|
4752
4960
|
console.timeEnd("chat");
|
|
4753
4961
|
}
|
|
4754
|
-
|
|
4962
|
+
if (!clientToolEndpointUnavailableRef.current) {
|
|
4963
|
+
setError(e.message);
|
|
4964
|
+
}
|
|
4755
4965
|
},
|
|
4756
4966
|
onFinish: (options) => {
|
|
4757
4967
|
debouncedFlushBuildOps.flush();
|
|
4758
4968
|
q.wait().then(() => {
|
|
4759
|
-
if (!options.isAbort) {
|
|
4969
|
+
if (!options.isAbort || clientToolEndpointUnavailableRef.current) {
|
|
4760
4970
|
puckDispatch({
|
|
4761
4971
|
type: "set",
|
|
4762
4972
|
state: getPuck().appState,
|
|
@@ -4771,12 +4981,63 @@ function Chat2(props) {
|
|
|
4771
4981
|
});
|
|
4772
4982
|
}
|
|
4773
4983
|
});
|
|
4774
|
-
useEffect13(
|
|
4775
|
-
|
|
4984
|
+
useEffect13(() => {
|
|
4985
|
+
stopChatRef.current = stop;
|
|
4986
|
+
return () => {
|
|
4987
|
+
stopChatRef.current = null;
|
|
4776
4988
|
stop();
|
|
4777
|
-
}
|
|
4778
|
-
|
|
4779
|
-
);
|
|
4989
|
+
};
|
|
4990
|
+
}, [stop]);
|
|
4991
|
+
const statusRef = useRef13(status);
|
|
4992
|
+
useEffect13(() => {
|
|
4993
|
+
statusRef.current = status;
|
|
4994
|
+
}, [status]);
|
|
4995
|
+
useEffect13(() => {
|
|
4996
|
+
lastStreamActivityRef.current = Date.now();
|
|
4997
|
+
}, [messages]);
|
|
4998
|
+
useEffect13(() => {
|
|
4999
|
+
const FROZEN_HIDDEN_MS = 3 * 6e4;
|
|
5000
|
+
const RESUME_GRACE_MS = 12e3;
|
|
5001
|
+
const isStreaming = () => statusRef.current === "streaming" || statusRef.current === "submitted";
|
|
5002
|
+
let graceTimer;
|
|
5003
|
+
const recoverIfSevered = () => {
|
|
5004
|
+
if (!isStreaming()) return;
|
|
5005
|
+
if (Date.now() - lastStreamActivityRef.current < RESUME_GRACE_MS) return;
|
|
5006
|
+
stop();
|
|
5007
|
+
setToolStatus((current) => {
|
|
5008
|
+
let changed = false;
|
|
5009
|
+
const next = {};
|
|
5010
|
+
for (const [id, toolState] of Object.entries(current)) {
|
|
5011
|
+
if (toolState.loading) {
|
|
5012
|
+
changed = true;
|
|
5013
|
+
next[id] = { ...toolState, loading: false, label: "Interrupted" };
|
|
5014
|
+
} else {
|
|
5015
|
+
next[id] = toolState;
|
|
5016
|
+
}
|
|
5017
|
+
}
|
|
5018
|
+
return changed ? next : current;
|
|
5019
|
+
});
|
|
5020
|
+
};
|
|
5021
|
+
const onVisibilityChange = () => {
|
|
5022
|
+
if (document.hidden) {
|
|
5023
|
+
hiddenSinceRef.current = isStreaming() ? Date.now() : null;
|
|
5024
|
+
return;
|
|
5025
|
+
}
|
|
5026
|
+
const hiddenSince = hiddenSinceRef.current;
|
|
5027
|
+
hiddenSinceRef.current = null;
|
|
5028
|
+
if (graceTimer) clearTimeout(graceTimer);
|
|
5029
|
+
if (hiddenSince === null || Date.now() - hiddenSince < FROZEN_HIDDEN_MS) {
|
|
5030
|
+
return;
|
|
5031
|
+
}
|
|
5032
|
+
lastStreamActivityRef.current = 0;
|
|
5033
|
+
graceTimer = setTimeout(recoverIfSevered, RESUME_GRACE_MS);
|
|
5034
|
+
};
|
|
5035
|
+
document.addEventListener("visibilitychange", onVisibilityChange);
|
|
5036
|
+
return () => {
|
|
5037
|
+
document.removeEventListener("visibilitychange", onVisibilityChange);
|
|
5038
|
+
if (graceTimer) clearTimeout(graceTimer);
|
|
5039
|
+
};
|
|
5040
|
+
}, [stop]);
|
|
4780
5041
|
const [forcedStatus, setForcedStatus] = useState16();
|
|
4781
5042
|
const resolvedStatus = useMemo6(
|
|
4782
5043
|
() => forcedStatus ?? status,
|
|
@@ -4827,6 +5088,8 @@ function Chat2(props) {
|
|
|
4827
5088
|
if (!text && readyAttachments.length === 0) {
|
|
4828
5089
|
return false;
|
|
4829
5090
|
}
|
|
5091
|
+
clientToolEndpointUnavailableRef.current = false;
|
|
5092
|
+
setError("");
|
|
4830
5093
|
setUserError("");
|
|
4831
5094
|
if (chat?.onSubmit) {
|
|
4832
5095
|
try {
|
|
@@ -5066,6 +5329,7 @@ function Chat2(props) {
|
|
|
5066
5329
|
),
|
|
5067
5330
|
error,
|
|
5068
5331
|
handleRetry: () => {
|
|
5332
|
+
clientToolEndpointUnavailableRef.current = false;
|
|
5069
5333
|
setError("");
|
|
5070
5334
|
regenerate();
|
|
5071
5335
|
},
|