puckeditor-plugin-ai 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.css +584 -0
- package/dist/index.css.map +1 -0
- package/dist/index.d.mts +237 -0
- package/dist/index.d.ts +237 -0
- package/dist/index.js +1148 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +1123 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +59 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,1148 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
"use client";
|
|
3
|
+
var __create = Object.create;
|
|
4
|
+
var __defProp = Object.defineProperty;
|
|
5
|
+
var __defProps = Object.defineProperties;
|
|
6
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
7
|
+
var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
|
|
8
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
9
|
+
var __getOwnPropSymbols = Object.getOwnPropertySymbols;
|
|
10
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
11
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
12
|
+
var __propIsEnum = Object.prototype.propertyIsEnumerable;
|
|
13
|
+
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
14
|
+
var __spreadValues = (a, b) => {
|
|
15
|
+
for (var prop in b || (b = {}))
|
|
16
|
+
if (__hasOwnProp.call(b, prop))
|
|
17
|
+
__defNormalProp(a, prop, b[prop]);
|
|
18
|
+
if (__getOwnPropSymbols)
|
|
19
|
+
for (var prop of __getOwnPropSymbols(b)) {
|
|
20
|
+
if (__propIsEnum.call(b, prop))
|
|
21
|
+
__defNormalProp(a, prop, b[prop]);
|
|
22
|
+
}
|
|
23
|
+
return a;
|
|
24
|
+
};
|
|
25
|
+
var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
|
|
26
|
+
var __objRest = (source, exclude) => {
|
|
27
|
+
var target = {};
|
|
28
|
+
for (var prop in source)
|
|
29
|
+
if (__hasOwnProp.call(source, prop) && exclude.indexOf(prop) < 0)
|
|
30
|
+
target[prop] = source[prop];
|
|
31
|
+
if (source != null && __getOwnPropSymbols)
|
|
32
|
+
for (var prop of __getOwnPropSymbols(source)) {
|
|
33
|
+
if (exclude.indexOf(prop) < 0 && __propIsEnum.call(source, prop))
|
|
34
|
+
target[prop] = source[prop];
|
|
35
|
+
}
|
|
36
|
+
return target;
|
|
37
|
+
};
|
|
38
|
+
var __export = (target, all) => {
|
|
39
|
+
for (var name in all)
|
|
40
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
41
|
+
};
|
|
42
|
+
var __copyProps = (to, from, except, desc) => {
|
|
43
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
44
|
+
for (let key of __getOwnPropNames(from))
|
|
45
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
46
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
47
|
+
}
|
|
48
|
+
return to;
|
|
49
|
+
};
|
|
50
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
51
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
52
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
53
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
54
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
55
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
56
|
+
mod
|
|
57
|
+
));
|
|
58
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
59
|
+
var __async = (__this, __arguments, generator) => {
|
|
60
|
+
return new Promise((resolve, reject) => {
|
|
61
|
+
var fulfilled = (value) => {
|
|
62
|
+
try {
|
|
63
|
+
step(generator.next(value));
|
|
64
|
+
} catch (e) {
|
|
65
|
+
reject(e);
|
|
66
|
+
}
|
|
67
|
+
};
|
|
68
|
+
var rejected = (value) => {
|
|
69
|
+
try {
|
|
70
|
+
step(generator.throw(value));
|
|
71
|
+
} catch (e) {
|
|
72
|
+
reject(e);
|
|
73
|
+
}
|
|
74
|
+
};
|
|
75
|
+
var step = (x) => x.done ? resolve(x.value) : Promise.resolve(x.value).then(fulfilled, rejected);
|
|
76
|
+
step((generator = generator.apply(__this, __arguments)).next());
|
|
77
|
+
});
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
// index.tsx
|
|
81
|
+
var index_exports = {};
|
|
82
|
+
__export(index_exports, {
|
|
83
|
+
Chat: () => Chat,
|
|
84
|
+
createAiPlugin: () => createAiPlugin,
|
|
85
|
+
default: () => index_default
|
|
86
|
+
});
|
|
87
|
+
module.exports = __toCommonJS(index_exports);
|
|
88
|
+
|
|
89
|
+
// ../tsup-config/react-import.js
|
|
90
|
+
var import_react = __toESM(require("react"));
|
|
91
|
+
|
|
92
|
+
// index.tsx
|
|
93
|
+
var import_react4 = require("react");
|
|
94
|
+
var import_core = require("@puckeditor/core");
|
|
95
|
+
var import_react5 = require("@ai-sdk/react");
|
|
96
|
+
var import_ai = require("ai");
|
|
97
|
+
var import_react_markdown = __toESM(require("react-markdown"));
|
|
98
|
+
var import_react_textarea_autosize = __toESM(require("react-textarea-autosize"));
|
|
99
|
+
var import_use_stick_to_bottom = require("use-stick-to-bottom");
|
|
100
|
+
|
|
101
|
+
// ../../node_modules/.pnpm/lucide-react@0.452.0_react@19.2.4/node_modules/lucide-react/dist/esm/createLucideIcon.js
|
|
102
|
+
var import_react3 = require("react");
|
|
103
|
+
|
|
104
|
+
// ../../node_modules/.pnpm/lucide-react@0.452.0_react@19.2.4/node_modules/lucide-react/dist/esm/shared/src/utils.js
|
|
105
|
+
var toKebabCase = (string) => string.replace(/([a-z0-9])([A-Z])/g, "$1-$2").toLowerCase();
|
|
106
|
+
var mergeClasses = (...classes) => classes.filter((className, index, array) => {
|
|
107
|
+
return Boolean(className) && array.indexOf(className) === index;
|
|
108
|
+
}).join(" ");
|
|
109
|
+
|
|
110
|
+
// ../../node_modules/.pnpm/lucide-react@0.452.0_react@19.2.4/node_modules/lucide-react/dist/esm/Icon.js
|
|
111
|
+
var import_react2 = require("react");
|
|
112
|
+
|
|
113
|
+
// ../../node_modules/.pnpm/lucide-react@0.452.0_react@19.2.4/node_modules/lucide-react/dist/esm/defaultAttributes.js
|
|
114
|
+
var defaultAttributes = {
|
|
115
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
116
|
+
width: 24,
|
|
117
|
+
height: 24,
|
|
118
|
+
viewBox: "0 0 24 24",
|
|
119
|
+
fill: "none",
|
|
120
|
+
stroke: "currentColor",
|
|
121
|
+
strokeWidth: 2,
|
|
122
|
+
strokeLinecap: "round",
|
|
123
|
+
strokeLinejoin: "round"
|
|
124
|
+
};
|
|
125
|
+
|
|
126
|
+
// ../../node_modules/.pnpm/lucide-react@0.452.0_react@19.2.4/node_modules/lucide-react/dist/esm/Icon.js
|
|
127
|
+
var Icon = (0, import_react2.forwardRef)(
|
|
128
|
+
(_a, ref) => {
|
|
129
|
+
var _b = _a, {
|
|
130
|
+
color = "currentColor",
|
|
131
|
+
size = 24,
|
|
132
|
+
strokeWidth = 2,
|
|
133
|
+
absoluteStrokeWidth,
|
|
134
|
+
className = "",
|
|
135
|
+
children,
|
|
136
|
+
iconNode
|
|
137
|
+
} = _b, rest = __objRest(_b, [
|
|
138
|
+
"color",
|
|
139
|
+
"size",
|
|
140
|
+
"strokeWidth",
|
|
141
|
+
"absoluteStrokeWidth",
|
|
142
|
+
"className",
|
|
143
|
+
"children",
|
|
144
|
+
"iconNode"
|
|
145
|
+
]);
|
|
146
|
+
return (0, import_react2.createElement)(
|
|
147
|
+
"svg",
|
|
148
|
+
__spreadValues(__spreadProps(__spreadValues({
|
|
149
|
+
ref
|
|
150
|
+
}, defaultAttributes), {
|
|
151
|
+
width: size,
|
|
152
|
+
height: size,
|
|
153
|
+
stroke: color,
|
|
154
|
+
strokeWidth: absoluteStrokeWidth ? Number(strokeWidth) * 24 / Number(size) : strokeWidth,
|
|
155
|
+
className: mergeClasses("lucide", className)
|
|
156
|
+
}), rest),
|
|
157
|
+
[
|
|
158
|
+
...iconNode.map(([tag, attrs]) => (0, import_react2.createElement)(tag, attrs)),
|
|
159
|
+
...Array.isArray(children) ? children : [children]
|
|
160
|
+
]
|
|
161
|
+
);
|
|
162
|
+
}
|
|
163
|
+
);
|
|
164
|
+
|
|
165
|
+
// ../../node_modules/.pnpm/lucide-react@0.452.0_react@19.2.4/node_modules/lucide-react/dist/esm/createLucideIcon.js
|
|
166
|
+
var createLucideIcon = (iconName, iconNode) => {
|
|
167
|
+
const Component = (0, import_react3.forwardRef)(
|
|
168
|
+
(_a, ref) => {
|
|
169
|
+
var _b = _a, { className } = _b, props = __objRest(_b, ["className"]);
|
|
170
|
+
return (0, import_react3.createElement)(Icon, __spreadValues({
|
|
171
|
+
ref,
|
|
172
|
+
iconNode,
|
|
173
|
+
className: mergeClasses(`lucide-${toKebabCase(iconName)}`, className)
|
|
174
|
+
}, props));
|
|
175
|
+
}
|
|
176
|
+
);
|
|
177
|
+
Component.displayName = `${iconName}`;
|
|
178
|
+
return Component;
|
|
179
|
+
};
|
|
180
|
+
|
|
181
|
+
// ../../node_modules/.pnpm/lucide-react@0.452.0_react@19.2.4/node_modules/lucide-react/dist/esm/icons/arrow-up.js
|
|
182
|
+
var ArrowUp = createLucideIcon("ArrowUp", [
|
|
183
|
+
["path", { d: "m5 12 7-7 7 7", key: "hav0vg" }],
|
|
184
|
+
["path", { d: "M12 19V5", key: "x0mq9r" }]
|
|
185
|
+
]);
|
|
186
|
+
|
|
187
|
+
// ../../node_modules/.pnpm/lucide-react@0.452.0_react@19.2.4/node_modules/lucide-react/dist/esm/icons/bot.js
|
|
188
|
+
var Bot = createLucideIcon("Bot", [
|
|
189
|
+
["path", { d: "M12 8V4H8", key: "hb8ula" }],
|
|
190
|
+
["rect", { width: "16", height: "12", x: "4", y: "8", rx: "2", key: "enze0r" }],
|
|
191
|
+
["path", { d: "M2 14h2", key: "vft8re" }],
|
|
192
|
+
["path", { d: "M20 14h2", key: "4cs60a" }],
|
|
193
|
+
["path", { d: "M15 13v2", key: "1xurst" }],
|
|
194
|
+
["path", { d: "M9 13v2", key: "rq6x2g" }]
|
|
195
|
+
]);
|
|
196
|
+
|
|
197
|
+
// ../../node_modules/.pnpm/lucide-react@0.452.0_react@19.2.4/node_modules/lucide-react/dist/esm/icons/check.js
|
|
198
|
+
var Check = createLucideIcon("Check", [["path", { d: "M20 6 9 17l-5-5", key: "1gmf2c" }]]);
|
|
199
|
+
|
|
200
|
+
// ../../node_modules/.pnpm/lucide-react@0.452.0_react@19.2.4/node_modules/lucide-react/dist/esm/icons/image.js
|
|
201
|
+
var Image = createLucideIcon("Image", [
|
|
202
|
+
["rect", { width: "18", height: "18", x: "3", y: "3", rx: "2", ry: "2", key: "1m3agn" }],
|
|
203
|
+
["circle", { cx: "9", cy: "9", r: "2", key: "af1f0g" }],
|
|
204
|
+
["path", { d: "m21 15-3.086-3.086a2 2 0 0 0-2.828 0L6 21", key: "1xmnt7" }]
|
|
205
|
+
]);
|
|
206
|
+
|
|
207
|
+
// ../../node_modules/.pnpm/lucide-react@0.452.0_react@19.2.4/node_modules/lucide-react/dist/esm/icons/rotate-ccw.js
|
|
208
|
+
var RotateCcw = createLucideIcon("RotateCcw", [
|
|
209
|
+
["path", { d: "M3 12a9 9 0 1 0 9-9 9.75 9.75 0 0 0-6.74 2.74L3 8", key: "1357e3" }],
|
|
210
|
+
["path", { d: "M3 3v5h5", key: "1xhq8a" }]
|
|
211
|
+
]);
|
|
212
|
+
|
|
213
|
+
// ../../node_modules/.pnpm/lucide-react@0.452.0_react@19.2.4/node_modules/lucide-react/dist/esm/icons/triangle-alert.js
|
|
214
|
+
var TriangleAlert = createLucideIcon("TriangleAlert", [
|
|
215
|
+
[
|
|
216
|
+
"path",
|
|
217
|
+
{
|
|
218
|
+
d: "m21.73 18-8-14a2 2 0 0 0-3.48 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.73-3",
|
|
219
|
+
key: "wmoenq"
|
|
220
|
+
}
|
|
221
|
+
],
|
|
222
|
+
["path", { d: "M12 9v4", key: "juzpu7" }],
|
|
223
|
+
["path", { d: "M12 17h.01", key: "p32p05" }]
|
|
224
|
+
]);
|
|
225
|
+
|
|
226
|
+
// ../../node_modules/.pnpm/lucide-react@0.452.0_react@19.2.4/node_modules/lucide-react/dist/esm/icons/x.js
|
|
227
|
+
var X = createLucideIcon("X", [
|
|
228
|
+
["path", { d: "M18 6 6 18", key: "1bl5f8" }],
|
|
229
|
+
["path", { d: "m6 6 12 12", key: "d8bk6v" }]
|
|
230
|
+
]);
|
|
231
|
+
|
|
232
|
+
// index.tsx
|
|
233
|
+
var import_qler = __toESM(require("qler"));
|
|
234
|
+
var import_ulid = require("ulid");
|
|
235
|
+
var import_html2canvas_pro = __toESM(require("html2canvas-pro"));
|
|
236
|
+
var import_jsx_runtime = require("react/jsx-runtime");
|
|
237
|
+
function readFileAsDataURL(file) {
|
|
238
|
+
return new Promise((resolve, reject) => {
|
|
239
|
+
const reader = new FileReader();
|
|
240
|
+
reader.onload = () => resolve(reader.result);
|
|
241
|
+
reader.onerror = reject;
|
|
242
|
+
reader.readAsDataURL(file);
|
|
243
|
+
});
|
|
244
|
+
}
|
|
245
|
+
function filesToAttachedImages(files) {
|
|
246
|
+
return __async(this, null, function* () {
|
|
247
|
+
const results = [];
|
|
248
|
+
for (const file of Array.from(files)) {
|
|
249
|
+
if (!file.type.startsWith("image/")) continue;
|
|
250
|
+
const dataUrl = yield readFileAsDataURL(file);
|
|
251
|
+
results.push({ id: prefixedUlid("img"), dataUrl, name: file.name });
|
|
252
|
+
}
|
|
253
|
+
return results;
|
|
254
|
+
});
|
|
255
|
+
}
|
|
256
|
+
var prefixedUlid = (prefix = "") => `${prefix ? `${prefix}_` : ""}${(0, import_ulid.ulid)()}`;
|
|
257
|
+
var q = (0, import_qler.default)();
|
|
258
|
+
var getSelectorForId = (state, id) => {
|
|
259
|
+
var _a, _b, _c, _d;
|
|
260
|
+
const node = (_b = (_a = state == null ? void 0 : state.indexes) == null ? void 0 : _a.nodes) == null ? void 0 : _b[id];
|
|
261
|
+
if (!node) return void 0;
|
|
262
|
+
const zoneCompound = `${node.parentId}:${node.zone}`;
|
|
263
|
+
const index = (_d = (_c = state.indexes.zones[zoneCompound]) == null ? void 0 : _c.contentIds) == null ? void 0 : _d.indexOf(id);
|
|
264
|
+
return { zone: zoneCompound, index };
|
|
265
|
+
};
|
|
266
|
+
var getItemById = (state, id) => {
|
|
267
|
+
var _a, _b, _c;
|
|
268
|
+
return (_c = (_b = (_a = state == null ? void 0 : state.indexes) == null ? void 0 : _a.nodes) == null ? void 0 : _b[id]) == null ? void 0 : _c.data;
|
|
269
|
+
};
|
|
270
|
+
var applyArrayDefaults = (oldProps, newProps, fields) => {
|
|
271
|
+
const updatedProps = __spreadValues(__spreadValues({}, oldProps), newProps);
|
|
272
|
+
for (const fieldName in fields) {
|
|
273
|
+
const field = fields[fieldName];
|
|
274
|
+
if (field.type === "array") {
|
|
275
|
+
const arrayField = field;
|
|
276
|
+
const arrayFields = arrayField.arrayFields;
|
|
277
|
+
updatedProps[fieldName] = (updatedProps[fieldName] || []).map((item, index) => {
|
|
278
|
+
var _a, _b, _c, _d, _e;
|
|
279
|
+
const newItem = {};
|
|
280
|
+
const defaultValue = typeof arrayField.defaultItemProps === "function" ? arrayField.defaultItemProps(index) : arrayField.defaultItemProps;
|
|
281
|
+
for (const arrayFieldName in arrayFields) {
|
|
282
|
+
const subField = arrayFields[arrayFieldName];
|
|
283
|
+
if (subField.type === "slot") {
|
|
284
|
+
newItem[arrayFieldName] = (_d = (_c = item[arrayFieldName]) != null ? _c : (_b = (_a = oldProps[fieldName]) == null ? void 0 : _a[index]) == null ? void 0 : _b[arrayFieldName]) != null ? _d : defaultValue == null ? void 0 : defaultValue[arrayFieldName];
|
|
285
|
+
} else {
|
|
286
|
+
newItem[arrayFieldName] = (_e = item[arrayFieldName]) != null ? _e : defaultValue == null ? void 0 : defaultValue[arrayFieldName];
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
return newItem;
|
|
290
|
+
});
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
return updatedProps;
|
|
294
|
+
};
|
|
295
|
+
var dispatchOp = (operation, { getState, dispatchAction, config }) => {
|
|
296
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _i;
|
|
297
|
+
const state = getState();
|
|
298
|
+
try {
|
|
299
|
+
if (operation.op === "add") {
|
|
300
|
+
if (operation.zone) {
|
|
301
|
+
dispatchAction({
|
|
302
|
+
type: "insert",
|
|
303
|
+
destinationIndex: operation.index,
|
|
304
|
+
destinationZone: operation.zone,
|
|
305
|
+
componentType: operation.type,
|
|
306
|
+
id: operation.id,
|
|
307
|
+
recordHistory: false
|
|
308
|
+
});
|
|
309
|
+
const existing = getItemById(getState(), operation.id);
|
|
310
|
+
if (!existing) {
|
|
311
|
+
throw new Error(`Tried to update an item that doesn't exist: ${operation.id}`);
|
|
312
|
+
}
|
|
313
|
+
const newData = __spreadProps(__spreadValues({}, existing), {
|
|
314
|
+
props: applyArrayDefaults(
|
|
315
|
+
existing.props,
|
|
316
|
+
operation.props,
|
|
317
|
+
(_b = (_a = config.components[existing.type]) == null ? void 0 : _a.fields) != null ? _b : {}
|
|
318
|
+
)
|
|
319
|
+
});
|
|
320
|
+
dispatchAction({
|
|
321
|
+
type: "replace",
|
|
322
|
+
destinationIndex: operation.index,
|
|
323
|
+
destinationZone: operation.zone,
|
|
324
|
+
data: newData,
|
|
325
|
+
recordHistory: false
|
|
326
|
+
});
|
|
327
|
+
}
|
|
328
|
+
} else if (operation.op === "update") {
|
|
329
|
+
const selector = getSelectorForId(state, operation.id);
|
|
330
|
+
const existing = getItemById(state, operation.id);
|
|
331
|
+
if (!selector || !existing) {
|
|
332
|
+
throw new Error(`Tried to update an item that doesn't exist: ${operation.id}`);
|
|
333
|
+
}
|
|
334
|
+
const newData = __spreadProps(__spreadValues({}, existing), {
|
|
335
|
+
props: applyArrayDefaults(
|
|
336
|
+
existing.props,
|
|
337
|
+
operation.props,
|
|
338
|
+
(_d = (_c = config.components[existing.type]) == null ? void 0 : _c.fields) != null ? _d : {}
|
|
339
|
+
)
|
|
340
|
+
});
|
|
341
|
+
dispatchAction({
|
|
342
|
+
type: "replace",
|
|
343
|
+
destinationIndex: selector.index,
|
|
344
|
+
destinationZone: selector.zone,
|
|
345
|
+
data: newData,
|
|
346
|
+
recordHistory: false
|
|
347
|
+
});
|
|
348
|
+
} else if (operation.op === "updateRoot") {
|
|
349
|
+
const existing = (_e = state == null ? void 0 : state.data) == null ? void 0 : _e.root;
|
|
350
|
+
const defaultProps = (_g = (_f = config.root) == null ? void 0 : _f.defaultProps) != null ? _g : {};
|
|
351
|
+
dispatchAction({
|
|
352
|
+
type: "replaceRoot",
|
|
353
|
+
root: __spreadProps(__spreadValues({}, existing), {
|
|
354
|
+
props: __spreadValues(__spreadValues(__spreadValues({}, defaultProps), existing == null ? void 0 : existing.props), operation.props)
|
|
355
|
+
}),
|
|
356
|
+
recordHistory: false
|
|
357
|
+
});
|
|
358
|
+
} else if (operation.op === "delete") {
|
|
359
|
+
const selector = getSelectorForId(state, operation.id);
|
|
360
|
+
if (!selector) {
|
|
361
|
+
throw new Error(`Tried to delete an item that doesn't exist: ${operation.id}`);
|
|
362
|
+
}
|
|
363
|
+
dispatchAction({
|
|
364
|
+
type: "remove",
|
|
365
|
+
zone: selector.zone,
|
|
366
|
+
index: selector.index,
|
|
367
|
+
recordHistory: false
|
|
368
|
+
});
|
|
369
|
+
} else if (operation.op === "duplicate") {
|
|
370
|
+
const selector = getSelectorForId(state, operation.id);
|
|
371
|
+
if (!selector) {
|
|
372
|
+
throw new Error(`Tried to duplicate an item that doesn't exist: ${operation.id}`);
|
|
373
|
+
}
|
|
374
|
+
dispatchAction({
|
|
375
|
+
type: "duplicate",
|
|
376
|
+
sourceZone: selector.zone,
|
|
377
|
+
sourceIndex: selector.index,
|
|
378
|
+
recordHistory: false
|
|
379
|
+
});
|
|
380
|
+
} else if (operation.op === "move") {
|
|
381
|
+
const selector = getSelectorForId(state, operation.id);
|
|
382
|
+
if (!selector) {
|
|
383
|
+
throw new Error(`Tried to move an item that doesn't exist: ${operation.id}`);
|
|
384
|
+
}
|
|
385
|
+
dispatchAction({
|
|
386
|
+
type: "move",
|
|
387
|
+
sourceZone: selector.zone,
|
|
388
|
+
sourceIndex: selector.index,
|
|
389
|
+
destinationIndex: operation.index,
|
|
390
|
+
destinationZone: operation.zone,
|
|
391
|
+
recordHistory: false
|
|
392
|
+
});
|
|
393
|
+
} else if (operation.op === "reset") {
|
|
394
|
+
const defaultRootProps = (_i = (_h = config.root) == null ? void 0 : _h.defaultProps) != null ? _i : {};
|
|
395
|
+
dispatchAction({
|
|
396
|
+
type: "setData",
|
|
397
|
+
data: { content: [], root: defaultRootProps },
|
|
398
|
+
recordHistory: false
|
|
399
|
+
});
|
|
400
|
+
} else {
|
|
401
|
+
throw new Error(`Unknown operation: ${operation.op}`);
|
|
402
|
+
}
|
|
403
|
+
} catch (e) {
|
|
404
|
+
console.error("Error applying operation, skipping...", operation, e);
|
|
405
|
+
}
|
|
406
|
+
};
|
|
407
|
+
var toolStatusContext = (0, import_react4.createContext)({});
|
|
408
|
+
var ToolStatusProvider = toolStatusContext.Provider;
|
|
409
|
+
function Loader({ size = 16 }) {
|
|
410
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
411
|
+
"span",
|
|
412
|
+
{
|
|
413
|
+
className: "puck-ai-loader",
|
|
414
|
+
style: { width: size, height: size },
|
|
415
|
+
"aria-label": "loading"
|
|
416
|
+
}
|
|
417
|
+
);
|
|
418
|
+
}
|
|
419
|
+
function ToolStatusDisplay({ status }) {
|
|
420
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "puck-ai-chat-message-data", children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "puck-ai-chat-message-data-inner", children: [
|
|
421
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "puck-ai-chat-message-data-icon", children: status.error ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(TriangleAlert, { size: 18 }) : status.loading ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Loader, { size: 16 }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Check, { size: 18 }) }),
|
|
422
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { children: status.label })
|
|
423
|
+
] }) });
|
|
424
|
+
}
|
|
425
|
+
function PuckTool({
|
|
426
|
+
toolCallId,
|
|
427
|
+
output,
|
|
428
|
+
defaultLabel = "Thinking..."
|
|
429
|
+
}) {
|
|
430
|
+
const toolStatusMap = (0, import_react4.useContext)(toolStatusContext);
|
|
431
|
+
const contextStatus = toolStatusMap[toolCallId];
|
|
432
|
+
const outputObj = output;
|
|
433
|
+
const status = outputObj && "status" in outputObj ? outputObj.status : contextStatus != null ? contextStatus : { loading: true, label: defaultLabel };
|
|
434
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ToolStatusDisplay, { status });
|
|
435
|
+
}
|
|
436
|
+
function ChatMessagePart({ part, role }) {
|
|
437
|
+
if (part.type === "text") {
|
|
438
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "puck-ai-chat-message-text", children: role === "assistant" || role === "user" ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_markdown.default, { children: part.text }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { children: part.text }) });
|
|
439
|
+
}
|
|
440
|
+
if (part.type === "tool-createPage" || part.type === "tool-updatePage" || part.type === "tool-userTool") {
|
|
441
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(PuckTool, __spreadValues({}, part));
|
|
442
|
+
}
|
|
443
|
+
return null;
|
|
444
|
+
}
|
|
445
|
+
function ChatMessage({ message }) {
|
|
446
|
+
const { role, parts } = message;
|
|
447
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
448
|
+
"div",
|
|
449
|
+
{
|
|
450
|
+
className: `puck-ai-chat-message${role === "user" ? " puck-ai-chat-message--user-role" : ""}`,
|
|
451
|
+
"data-message-id": message.id,
|
|
452
|
+
children: parts.map((part, i) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
453
|
+
ChatMessagePart,
|
|
454
|
+
{
|
|
455
|
+
part,
|
|
456
|
+
role
|
|
457
|
+
},
|
|
458
|
+
`${message.id}-${part.type}-${i}`
|
|
459
|
+
))
|
|
460
|
+
}
|
|
461
|
+
);
|
|
462
|
+
}
|
|
463
|
+
function ExamplePrompt({
|
|
464
|
+
label,
|
|
465
|
+
href,
|
|
466
|
+
onClick
|
|
467
|
+
}) {
|
|
468
|
+
const El = href ? "a" : "button";
|
|
469
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(El, { className: "puck-ai-chatbody-example-prompt", href, onClick, children: [
|
|
470
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { children: label }),
|
|
471
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "puck-ai-chatbody-example-prompt-arrow", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ArrowUp, { size: 16 }) })
|
|
472
|
+
] });
|
|
473
|
+
}
|
|
474
|
+
function PromptForm({
|
|
475
|
+
handleSubmit,
|
|
476
|
+
inputRef,
|
|
477
|
+
isLoading,
|
|
478
|
+
glow,
|
|
479
|
+
placeholder = "What do you want to build?",
|
|
480
|
+
minRows = 2,
|
|
481
|
+
maxRows = 5,
|
|
482
|
+
value = "",
|
|
483
|
+
images = [],
|
|
484
|
+
onImagesChange
|
|
485
|
+
}) {
|
|
486
|
+
const [prompt, setPrompt] = (0, import_react4.useState)(value);
|
|
487
|
+
const [isDragOver, setIsDragOver] = (0, import_react4.useState)(false);
|
|
488
|
+
const hasSetInitialPrompt = (0, import_react4.useRef)(false);
|
|
489
|
+
const internalRef = (0, import_react4.useRef)(null);
|
|
490
|
+
const fileInputRef = (0, import_react4.useRef)(null);
|
|
491
|
+
(0, import_react4.useEffect)(() => {
|
|
492
|
+
setPrompt(value);
|
|
493
|
+
}, [value]);
|
|
494
|
+
(0, import_react4.useEffect)(() => {
|
|
495
|
+
const currentUrl = new URL(location.href);
|
|
496
|
+
const initialPrompt = currentUrl.searchParams.get("initialPrompt");
|
|
497
|
+
if (!hasSetInitialPrompt.current && initialPrompt && prompt === "") {
|
|
498
|
+
hasSetInitialPrompt.current = true;
|
|
499
|
+
setPrompt(initialPrompt);
|
|
500
|
+
}
|
|
501
|
+
}, []);
|
|
502
|
+
const addImages = (0, import_react4.useCallback)((files) => __async(null, null, function* () {
|
|
503
|
+
const newImgs = yield filesToAttachedImages(files);
|
|
504
|
+
if (newImgs.length > 0) {
|
|
505
|
+
onImagesChange == null ? void 0 : onImagesChange([...images, ...newImgs]);
|
|
506
|
+
}
|
|
507
|
+
}), [images, onImagesChange]);
|
|
508
|
+
const removeImage = (0, import_react4.useCallback)((id) => {
|
|
509
|
+
onImagesChange == null ? void 0 : onImagesChange(images.filter((img) => img.id !== id));
|
|
510
|
+
}, [images, onImagesChange]);
|
|
511
|
+
const sendPrompt = () => {
|
|
512
|
+
if (isLoading) return;
|
|
513
|
+
if (prompt.trim() || images.length > 0) {
|
|
514
|
+
handleSubmit(prompt);
|
|
515
|
+
}
|
|
516
|
+
setPrompt("");
|
|
517
|
+
};
|
|
518
|
+
const handleDragOver = (e) => {
|
|
519
|
+
e.preventDefault();
|
|
520
|
+
if (e.dataTransfer.types.some((t) => t === "Files")) {
|
|
521
|
+
setIsDragOver(true);
|
|
522
|
+
}
|
|
523
|
+
};
|
|
524
|
+
const handleDragLeave = (e) => {
|
|
525
|
+
if (!e.currentTarget.contains(e.relatedTarget)) {
|
|
526
|
+
setIsDragOver(false);
|
|
527
|
+
}
|
|
528
|
+
};
|
|
529
|
+
const handleDrop = (e) => __async(null, null, function* () {
|
|
530
|
+
e.preventDefault();
|
|
531
|
+
setIsDragOver(false);
|
|
532
|
+
if (e.dataTransfer.files.length > 0) {
|
|
533
|
+
yield addImages(e.dataTransfer.files);
|
|
534
|
+
}
|
|
535
|
+
});
|
|
536
|
+
const classNames = [
|
|
537
|
+
"puck-ai-prompt-form",
|
|
538
|
+
glow ? "puck-ai-prompt-form--glow" : "",
|
|
539
|
+
isLoading ? "puck-ai-prompt-form--is-loading" : "",
|
|
540
|
+
isDragOver ? "puck-ai-prompt-form--drag-over" : ""
|
|
541
|
+
].filter(Boolean).join(" ");
|
|
542
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
543
|
+
"div",
|
|
544
|
+
{
|
|
545
|
+
className: classNames,
|
|
546
|
+
onDragOver: handleDragOver,
|
|
547
|
+
onDragEnter: handleDragOver,
|
|
548
|
+
onDragLeave: handleDragLeave,
|
|
549
|
+
onDrop: handleDrop,
|
|
550
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "puck-ai-prompt-form-inner", children: [
|
|
551
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "puck-ai-prompt-form-glow" }),
|
|
552
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
553
|
+
"input",
|
|
554
|
+
{
|
|
555
|
+
ref: fileInputRef,
|
|
556
|
+
type: "file",
|
|
557
|
+
accept: "image/*",
|
|
558
|
+
multiple: true,
|
|
559
|
+
style: { display: "none" },
|
|
560
|
+
onChange: (e) => __async(null, null, function* () {
|
|
561
|
+
if (e.target.files) {
|
|
562
|
+
yield addImages(e.target.files);
|
|
563
|
+
e.target.value = "";
|
|
564
|
+
}
|
|
565
|
+
})
|
|
566
|
+
}
|
|
567
|
+
),
|
|
568
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
569
|
+
"form",
|
|
570
|
+
{
|
|
571
|
+
onSubmit: (e) => {
|
|
572
|
+
e.preventDefault();
|
|
573
|
+
sendPrompt();
|
|
574
|
+
},
|
|
575
|
+
children: [
|
|
576
|
+
images.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "puck-ai-image-thumbnails", children: images.map((img) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "puck-ai-image-thumbnail", children: [
|
|
577
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("img", { src: img.dataUrl, alt: img.name }),
|
|
578
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
579
|
+
"button",
|
|
580
|
+
{
|
|
581
|
+
type: "button",
|
|
582
|
+
className: "puck-ai-image-thumbnail-remove",
|
|
583
|
+
onClick: () => removeImage(img.id),
|
|
584
|
+
title: "Remove image",
|
|
585
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(X, { size: 10 })
|
|
586
|
+
}
|
|
587
|
+
)
|
|
588
|
+
] }, img.id)) }),
|
|
589
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "puck-ai-prompt-form-form-inner", children: [
|
|
590
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
591
|
+
import_react_textarea_autosize.default,
|
|
592
|
+
{
|
|
593
|
+
className: "puck-ai-prompt-form-input",
|
|
594
|
+
name: "prompt",
|
|
595
|
+
minRows,
|
|
596
|
+
maxRows,
|
|
597
|
+
placeholder: isDragOver ? "Drop images here\u2026" : placeholder,
|
|
598
|
+
disabled: isLoading,
|
|
599
|
+
value: prompt,
|
|
600
|
+
ref: (node) => {
|
|
601
|
+
if (inputRef) {
|
|
602
|
+
inputRef.current = node;
|
|
603
|
+
}
|
|
604
|
+
internalRef.current = node;
|
|
605
|
+
},
|
|
606
|
+
onChange: (e) => setPrompt(e.target.value),
|
|
607
|
+
onKeyDown: (e) => {
|
|
608
|
+
if (!e.shiftKey && e.key === "Enter") {
|
|
609
|
+
e.preventDefault();
|
|
610
|
+
}
|
|
611
|
+
},
|
|
612
|
+
onKeyUp: (e) => {
|
|
613
|
+
if (!e.shiftKey && e.key === "Enter") {
|
|
614
|
+
e.preventDefault();
|
|
615
|
+
sendPrompt();
|
|
616
|
+
}
|
|
617
|
+
}
|
|
618
|
+
}
|
|
619
|
+
),
|
|
620
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
621
|
+
"div",
|
|
622
|
+
{
|
|
623
|
+
className: "puck-ai-prompt-form-actions",
|
|
624
|
+
onClick: () => {
|
|
625
|
+
var _a;
|
|
626
|
+
return (_a = internalRef.current) == null ? void 0 : _a.focus();
|
|
627
|
+
},
|
|
628
|
+
children: [
|
|
629
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
630
|
+
"div",
|
|
631
|
+
{
|
|
632
|
+
className: "puck-ai-prompt-form-actions-left",
|
|
633
|
+
onClick: (e) => e.stopPropagation(),
|
|
634
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
635
|
+
"button",
|
|
636
|
+
{
|
|
637
|
+
type: "button",
|
|
638
|
+
className: "puck-ai-image-attach-btn",
|
|
639
|
+
title: "Attach image",
|
|
640
|
+
onClick: () => {
|
|
641
|
+
var _a;
|
|
642
|
+
return (_a = fileInputRef.current) == null ? void 0 : _a.click();
|
|
643
|
+
},
|
|
644
|
+
disabled: isLoading,
|
|
645
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Image, { size: 15 })
|
|
646
|
+
}
|
|
647
|
+
)
|
|
648
|
+
}
|
|
649
|
+
),
|
|
650
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
651
|
+
"div",
|
|
652
|
+
{
|
|
653
|
+
className: "puck-ai-prompt-form-actions-right",
|
|
654
|
+
onClick: (e) => e.stopPropagation(),
|
|
655
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
656
|
+
"button",
|
|
657
|
+
{
|
|
658
|
+
className: "puck-ai-prompt-form-action-submit",
|
|
659
|
+
type: "submit",
|
|
660
|
+
disabled: isLoading,
|
|
661
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ArrowUp, { size: 24 })
|
|
662
|
+
}
|
|
663
|
+
)
|
|
664
|
+
}
|
|
665
|
+
)
|
|
666
|
+
]
|
|
667
|
+
}
|
|
668
|
+
)
|
|
669
|
+
] })
|
|
670
|
+
]
|
|
671
|
+
}
|
|
672
|
+
)
|
|
673
|
+
] })
|
|
674
|
+
}
|
|
675
|
+
);
|
|
676
|
+
}
|
|
677
|
+
function ChatBody({
|
|
678
|
+
children,
|
|
679
|
+
examplePrompts,
|
|
680
|
+
handleSubmit,
|
|
681
|
+
hideInput,
|
|
682
|
+
inputRef,
|
|
683
|
+
messages = [],
|
|
684
|
+
status,
|
|
685
|
+
error,
|
|
686
|
+
handleRetry,
|
|
687
|
+
promptValue,
|
|
688
|
+
targetComponent,
|
|
689
|
+
onClearTarget,
|
|
690
|
+
images,
|
|
691
|
+
onImagesChange
|
|
692
|
+
}) {
|
|
693
|
+
const { scrollRef, contentRef } = (0, import_use_stick_to_bottom.useStickToBottom)();
|
|
694
|
+
const hasMessages = messages && messages.length > 0;
|
|
695
|
+
const classNames = [
|
|
696
|
+
"puck-ai-chatbody",
|
|
697
|
+
hasMessages ? "puck-ai-chatbody--has-messages" : "",
|
|
698
|
+
children ? "puck-ai-chatbody--has-children" : "",
|
|
699
|
+
hideInput ? "puck-ai-chatbody--hide-input" : ""
|
|
700
|
+
].filter(Boolean).join(" ");
|
|
701
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: classNames, children: [
|
|
702
|
+
children ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "puck-ai-chatbody-default", children }) : null,
|
|
703
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "puck-ai-chatbody-inner", ref: scrollRef, children: [
|
|
704
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "puck-ai-chatbody-messages", ref: contentRef, children: [...messages].reverse().map((message) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ChatMessage, { message }, message.id)) }),
|
|
705
|
+
status === "submitted" && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "puck-ai-chatbody-loader", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Loader, { size: 14 }) }),
|
|
706
|
+
error && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "puck-ai-chatbody-error", children: [
|
|
707
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "puck-ai-chatbody-error-label", children: "Something went wrong." }),
|
|
708
|
+
handleRetry && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "puck-ai-chatbody-error-action", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
709
|
+
"button",
|
|
710
|
+
{
|
|
711
|
+
className: "puck-ai-icon-button",
|
|
712
|
+
title: "Retry",
|
|
713
|
+
onClick: handleRetry,
|
|
714
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(RotateCcw, { size: 14 })
|
|
715
|
+
}
|
|
716
|
+
) })
|
|
717
|
+
] }),
|
|
718
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "puck-ai-chatbody-form", children: [
|
|
719
|
+
targetComponent && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "puck-ai-target-banner", children: [
|
|
720
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "puck-ai-target-banner-label", children: "Targeting:" }),
|
|
721
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "puck-ai-target-banner-name", children: targetComponent.label || targetComponent.type }),
|
|
722
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("code", { className: "puck-ai-target-banner-id", children: targetComponent.id }),
|
|
723
|
+
onClearTarget && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
724
|
+
"button",
|
|
725
|
+
{
|
|
726
|
+
className: "puck-ai-target-banner-clear",
|
|
727
|
+
onClick: onClearTarget,
|
|
728
|
+
title: "Clear target",
|
|
729
|
+
type: "button",
|
|
730
|
+
children: "\xD7"
|
|
731
|
+
}
|
|
732
|
+
)
|
|
733
|
+
] }),
|
|
734
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
735
|
+
PromptForm,
|
|
736
|
+
{
|
|
737
|
+
glow: !hasMessages && !targetComponent,
|
|
738
|
+
handleSubmit,
|
|
739
|
+
inputRef,
|
|
740
|
+
isLoading: status === "submitted" || status === "streaming",
|
|
741
|
+
placeholder: targetComponent ? `What should I do with the ${targetComponent.label || targetComponent.type}?` : "What do you want to build?",
|
|
742
|
+
value: promptValue,
|
|
743
|
+
images,
|
|
744
|
+
onImagesChange
|
|
745
|
+
}
|
|
746
|
+
),
|
|
747
|
+
examplePrompts ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "puck-ai-chatbody-example-prompts", children: examplePrompts }) : null
|
|
748
|
+
] })
|
|
749
|
+
] })
|
|
750
|
+
] });
|
|
751
|
+
}
|
|
752
|
+
function isScrolledIntoView(el) {
|
|
753
|
+
const rect = el.getBoundingClientRect();
|
|
754
|
+
return rect.top >= 0 && rect.bottom <= window.innerHeight;
|
|
755
|
+
}
|
|
756
|
+
function Placeholder({
|
|
757
|
+
dispatch,
|
|
758
|
+
inputRef,
|
|
759
|
+
pluginRef
|
|
760
|
+
}) {
|
|
761
|
+
const handleEnterPromptClick = () => {
|
|
762
|
+
var _a;
|
|
763
|
+
(_a = inputRef.current) == null ? void 0 : _a.focus({ preventScroll: true });
|
|
764
|
+
setTimeout(() => {
|
|
765
|
+
if (pluginRef.current && inputRef.current && !isScrolledIntoView(inputRef.current)) {
|
|
766
|
+
const box = pluginRef.current.getBoundingClientRect();
|
|
767
|
+
const top = box.top - (window.innerHeight - box.height) / 2;
|
|
768
|
+
window.scrollTo({ behavior: "smooth", top });
|
|
769
|
+
}
|
|
770
|
+
}, 10);
|
|
771
|
+
};
|
|
772
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "puck-ai-chat-placeholder", children: [
|
|
773
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Bot, { size: 24 }),
|
|
774
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { children: "Use AI to build a page using the available blocks" }),
|
|
775
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "puck-ai-chat-actions", children: [
|
|
776
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { className: "puck-ai-chat-action", onClick: handleEnterPromptClick, children: "Enter prompt" }),
|
|
777
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
778
|
+
"button",
|
|
779
|
+
{
|
|
780
|
+
className: "puck-ai-chat-action-outlined",
|
|
781
|
+
onClick: () => {
|
|
782
|
+
dispatch({ type: "setUi", ui: { plugin: { current: "blocks" } } });
|
|
783
|
+
},
|
|
784
|
+
children: "Build manually"
|
|
785
|
+
}
|
|
786
|
+
)
|
|
787
|
+
] })
|
|
788
|
+
] });
|
|
789
|
+
}
|
|
790
|
+
function scrollIntoViewLocal(el, win, behavior = "smooth") {
|
|
791
|
+
var _a, _b;
|
|
792
|
+
const scroller = ((_a = el.ownerDocument) == null ? void 0 : _a.scrollingElement) || ((_b = el.ownerDocument) == null ? void 0 : _b.documentElement);
|
|
793
|
+
const rect = el.getBoundingClientRect();
|
|
794
|
+
const vpH = win.innerHeight;
|
|
795
|
+
const current = scroller.scrollTop;
|
|
796
|
+
const offset = win.innerHeight / 2;
|
|
797
|
+
let targetTop = current;
|
|
798
|
+
if (rect.top < 0) {
|
|
799
|
+
targetTop = current + rect.top;
|
|
800
|
+
} else if (rect.bottom > vpH) {
|
|
801
|
+
targetTop = current + (rect.bottom - vpH);
|
|
802
|
+
}
|
|
803
|
+
if (targetTop !== current) {
|
|
804
|
+
scroller.scrollTo({ top: targetTop + offset, behavior });
|
|
805
|
+
}
|
|
806
|
+
}
|
|
807
|
+
function useFrameMutationObserver(callback) {
|
|
808
|
+
return (0, import_react4.useCallback)(() => {
|
|
809
|
+
var _a;
|
|
810
|
+
const frame = document == null ? void 0 : document.getElementById("preview-frame");
|
|
811
|
+
if (!frame) return;
|
|
812
|
+
let observer = null;
|
|
813
|
+
const win = frame.contentWindow;
|
|
814
|
+
let enabled = true;
|
|
815
|
+
const disable = () => {
|
|
816
|
+
enabled = false;
|
|
817
|
+
};
|
|
818
|
+
const attachObserver = () => {
|
|
819
|
+
const win2 = frame.contentWindow;
|
|
820
|
+
const doc = frame.contentDocument || (win2 == null ? void 0 : win2.document);
|
|
821
|
+
if (!win2 || !doc) return;
|
|
822
|
+
const target = doc.querySelector("#frame-root > div");
|
|
823
|
+
if (!target) return;
|
|
824
|
+
observer = new MutationObserver((entries) => {
|
|
825
|
+
if (enabled) callback(entries, win2);
|
|
826
|
+
});
|
|
827
|
+
observer.observe(target, { childList: true, subtree: true });
|
|
828
|
+
win2.addEventListener("pointerdown", disable);
|
|
829
|
+
win2.addEventListener("wheel", disable);
|
|
830
|
+
};
|
|
831
|
+
if (((_a = frame.contentDocument) == null ? void 0 : _a.readyState) === "complete") {
|
|
832
|
+
attachObserver();
|
|
833
|
+
} else {
|
|
834
|
+
frame.addEventListener("load", attachObserver, { once: true });
|
|
835
|
+
}
|
|
836
|
+
return () => {
|
|
837
|
+
frame.removeEventListener("load", attachObserver);
|
|
838
|
+
win == null ? void 0 : win.removeEventListener("pointerdown", disable);
|
|
839
|
+
win == null ? void 0 : win.removeEventListener("wheel", disable);
|
|
840
|
+
observer == null ? void 0 : observer.disconnect();
|
|
841
|
+
};
|
|
842
|
+
}, [callback]);
|
|
843
|
+
}
|
|
844
|
+
function ScrollTracking({ children }) {
|
|
845
|
+
const followedRefs = (0, import_react4.useRef)([]);
|
|
846
|
+
const follow = useFrameMutationObserver((records, win) => {
|
|
847
|
+
if (records.length > 0) {
|
|
848
|
+
const lastRecord = records[records.length - 1];
|
|
849
|
+
if (followedRefs.current.includes(lastRecord.target)) return;
|
|
850
|
+
followedRefs.current.push(lastRecord.target);
|
|
851
|
+
requestAnimationFrame(() => {
|
|
852
|
+
const el = lastRecord.target;
|
|
853
|
+
scrollIntoViewLocal(el, win);
|
|
854
|
+
});
|
|
855
|
+
}
|
|
856
|
+
});
|
|
857
|
+
(0, import_react4.useEffect)(() => {
|
|
858
|
+
const cleanup = follow();
|
|
859
|
+
return cleanup;
|
|
860
|
+
}, [follow]);
|
|
861
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_jsx_runtime.Fragment, { children });
|
|
862
|
+
}
|
|
863
|
+
var usePuck = (0, import_core.createUsePuck)();
|
|
864
|
+
function Chat({
|
|
865
|
+
chat,
|
|
866
|
+
host = "/api/puck/chat",
|
|
867
|
+
prepareRequest
|
|
868
|
+
}) {
|
|
869
|
+
const { examplePrompts } = chat != null ? chat : {};
|
|
870
|
+
const puckDispatch = usePuck((s) => s.dispatch);
|
|
871
|
+
const getPuck = (0, import_core.useGetPuck)();
|
|
872
|
+
const localChatId = (0, import_react4.useRef)("");
|
|
873
|
+
const inputRef = (0, import_react4.useRef)(null);
|
|
874
|
+
const pluginRef = (0, import_react4.useRef)(null);
|
|
875
|
+
const [error, setError] = (0, import_react4.useState)();
|
|
876
|
+
const [toolStatus, setToolStatus] = (0, import_react4.useState)({});
|
|
877
|
+
const uploadScreenshot = (0, import_react4.useCallback)(
|
|
878
|
+
(width, bucketUrl) => __async(null, null, function* () {
|
|
879
|
+
var _a, _b, _c;
|
|
880
|
+
const iframeDocument = (_c = (_b = (_a = document == null ? void 0 : document.getElementById("preview-frame")) == null ? void 0 : _a.contentDocument) == null ? void 0 : _b.documentElement) != null ? _c : null;
|
|
881
|
+
if (!iframeDocument) return;
|
|
882
|
+
const canvas = yield (0, import_html2canvas_pro.default)(iframeDocument, {
|
|
883
|
+
scale: 2,
|
|
884
|
+
backgroundColor: "#ffffff",
|
|
885
|
+
width,
|
|
886
|
+
windowWidth: width,
|
|
887
|
+
foreignObjectRendering: false,
|
|
888
|
+
imageTimeout: 3e4,
|
|
889
|
+
logging: false,
|
|
890
|
+
allowTaint: false,
|
|
891
|
+
useCORS: true,
|
|
892
|
+
scrollY: 0,
|
|
893
|
+
ignoreElements: (el) => Array.from(el.classList).some(
|
|
894
|
+
(c) => c.startsWith("_DraggableComponent--hover") || c.startsWith("_ActionBar")
|
|
895
|
+
)
|
|
896
|
+
});
|
|
897
|
+
const image = canvas.toDataURL("image/webp", 0.8);
|
|
898
|
+
const blob = yield (yield fetch(image)).blob();
|
|
899
|
+
yield fetch(bucketUrl, { method: "PUT", body: blob });
|
|
900
|
+
}),
|
|
901
|
+
[]
|
|
902
|
+
);
|
|
903
|
+
const processData = (0, import_react4.useCallback)(
|
|
904
|
+
(dataPart) => {
|
|
905
|
+
switch (dataPart.type) {
|
|
906
|
+
case "data-new-chat-created": {
|
|
907
|
+
localChatId.current = dataPart.data.chatId;
|
|
908
|
+
return;
|
|
909
|
+
}
|
|
910
|
+
case "data-puck-actions": {
|
|
911
|
+
dataPart.data.forEach((action) => {
|
|
912
|
+
try {
|
|
913
|
+
puckDispatch(action);
|
|
914
|
+
} catch (e) {
|
|
915
|
+
console.error("Bad action: ", action);
|
|
916
|
+
console.error(e);
|
|
917
|
+
}
|
|
918
|
+
});
|
|
919
|
+
return;
|
|
920
|
+
}
|
|
921
|
+
case "data-build-op": {
|
|
922
|
+
const data = dataPart.data;
|
|
923
|
+
q.queue(() => {
|
|
924
|
+
const puck = getPuck();
|
|
925
|
+
if (!puck) return;
|
|
926
|
+
dispatchOp(data, {
|
|
927
|
+
getState: () => {
|
|
928
|
+
var _a;
|
|
929
|
+
return (_a = puck.__private) == null ? void 0 : _a.appState;
|
|
930
|
+
},
|
|
931
|
+
dispatchAction: puck.dispatch,
|
|
932
|
+
config: puck.config
|
|
933
|
+
});
|
|
934
|
+
});
|
|
935
|
+
return;
|
|
936
|
+
}
|
|
937
|
+
case "data-tool-status": {
|
|
938
|
+
const { toolCallId, status: toolSt } = dataPart.data;
|
|
939
|
+
setToolStatus((s) => __spreadProps(__spreadValues({}, s), { [toolCallId]: toolSt }));
|
|
940
|
+
return;
|
|
941
|
+
}
|
|
942
|
+
case "data-send-screenshot": {
|
|
943
|
+
const { urls } = dataPart.data;
|
|
944
|
+
urls.forEach((obj) => {
|
|
945
|
+
const entries = Object.entries(obj);
|
|
946
|
+
if (entries.length === 0) return;
|
|
947
|
+
const [key, value] = entries[0];
|
|
948
|
+
const breakpoint = Number(key);
|
|
949
|
+
uploadScreenshot(breakpoint, value);
|
|
950
|
+
});
|
|
951
|
+
return;
|
|
952
|
+
}
|
|
953
|
+
default:
|
|
954
|
+
console.warn("dataPart without case:", dataPart);
|
|
955
|
+
return;
|
|
956
|
+
}
|
|
957
|
+
},
|
|
958
|
+
[getPuck, puckDispatch, uploadScreenshot]
|
|
959
|
+
);
|
|
960
|
+
const { messages, status, sendMessage, regenerate, setMessages } = (0, import_react5.useChat)({
|
|
961
|
+
generateId: () => prefixedUlid("msg"),
|
|
962
|
+
messages: [],
|
|
963
|
+
transport: new import_ai.DefaultChatTransport({
|
|
964
|
+
api: host,
|
|
965
|
+
prepareSendMessagesRequest: (opts) => __async(null, null, function* () {
|
|
966
|
+
var _a, _b, _c, _d;
|
|
967
|
+
const puck = getPuck();
|
|
968
|
+
const config = (_a = puck == null ? void 0 : puck.config) != null ? _a : { components: {} };
|
|
969
|
+
const appState = (_b = puck == null ? void 0 : puck.appState) != null ? _b : { data: { root: { props: {} }, content: [], zones: {} } };
|
|
970
|
+
const root = (_c = config.root) != null ? _c : {
|
|
971
|
+
fields: {
|
|
972
|
+
title: {
|
|
973
|
+
type: "text",
|
|
974
|
+
ai: { instructions: "The title for the page" }
|
|
975
|
+
}
|
|
976
|
+
}
|
|
977
|
+
};
|
|
978
|
+
const configWithRoot = __spreadProps(__spreadValues({}, config), { root });
|
|
979
|
+
const defaultBody = __spreadValues(__spreadValues(__spreadProps(__spreadValues({}, opts.body), {
|
|
980
|
+
chatId: localChatId.current,
|
|
981
|
+
trigger: opts.trigger,
|
|
982
|
+
messages: opts.messages,
|
|
983
|
+
pageData: appState.data,
|
|
984
|
+
config: configWithRoot
|
|
985
|
+
}), targetComponentRef.current ? { selectedComponentId: targetComponentRef.current.id } : {}), pendingSendImagesRef.current.length > 0 ? (() => {
|
|
986
|
+
const imgs = pendingSendImagesRef.current;
|
|
987
|
+
pendingSendImagesRef.current = [];
|
|
988
|
+
return { images: imgs };
|
|
989
|
+
})() : {});
|
|
990
|
+
const defaultOptions = {
|
|
991
|
+
headers: opts.headers,
|
|
992
|
+
credentials: opts.credentials,
|
|
993
|
+
body: defaultBody
|
|
994
|
+
};
|
|
995
|
+
if (prepareRequest) {
|
|
996
|
+
const userOptions = yield prepareRequest(defaultOptions);
|
|
997
|
+
return {
|
|
998
|
+
headers: __spreadValues(__spreadValues({}, defaultOptions.headers), userOptions.headers),
|
|
999
|
+
credentials: (_d = userOptions.credentials) != null ? _d : defaultOptions.credentials,
|
|
1000
|
+
body: __spreadValues(__spreadValues({}, defaultBody), userOptions.body)
|
|
1001
|
+
};
|
|
1002
|
+
}
|
|
1003
|
+
return {
|
|
1004
|
+
headers: defaultOptions.headers,
|
|
1005
|
+
credentials: defaultOptions.credentials,
|
|
1006
|
+
body: defaultBody
|
|
1007
|
+
};
|
|
1008
|
+
})
|
|
1009
|
+
}),
|
|
1010
|
+
onData: processData,
|
|
1011
|
+
onError: (e) => {
|
|
1012
|
+
console.error(e);
|
|
1013
|
+
setError(e.message);
|
|
1014
|
+
},
|
|
1015
|
+
onFinish: () => {
|
|
1016
|
+
const puck = getPuck();
|
|
1017
|
+
if (puck == null ? void 0 : puck.appState) {
|
|
1018
|
+
puckDispatch({ type: "set", state: puck.appState, recordHistory: true });
|
|
1019
|
+
}
|
|
1020
|
+
}
|
|
1021
|
+
});
|
|
1022
|
+
const [forcedStatus, setForcedStatus] = (0, import_react4.useState)();
|
|
1023
|
+
const resolvedStatus = (0, import_react4.useMemo)(
|
|
1024
|
+
() => forcedStatus != null ? forcedStatus : status,
|
|
1025
|
+
[status, forcedStatus]
|
|
1026
|
+
);
|
|
1027
|
+
const [promptValue, setPromptValue] = (0, import_react4.useState)("");
|
|
1028
|
+
const [attachedImages, setAttachedImages] = (0, import_react4.useState)([]);
|
|
1029
|
+
const pendingSendImagesRef = (0, import_react4.useRef)([]);
|
|
1030
|
+
const [targetComponent, setTargetComponent] = (0, import_react4.useState)(null);
|
|
1031
|
+
const targetComponentRef = (0, import_react4.useRef)(null);
|
|
1032
|
+
(0, import_react4.useEffect)(() => {
|
|
1033
|
+
targetComponentRef.current = targetComponent;
|
|
1034
|
+
}, [targetComponent]);
|
|
1035
|
+
(0, import_react4.useEffect)(() => {
|
|
1036
|
+
window.__PUCK_AI = {
|
|
1037
|
+
processData,
|
|
1038
|
+
setMessages,
|
|
1039
|
+
setStatus: setForcedStatus,
|
|
1040
|
+
sendMessage,
|
|
1041
|
+
setPrompt: (value) => {
|
|
1042
|
+
var _a;
|
|
1043
|
+
setPromptValue(value);
|
|
1044
|
+
(_a = inputRef.current) == null ? void 0 : _a.focus();
|
|
1045
|
+
},
|
|
1046
|
+
setTargetComponent: (target) => {
|
|
1047
|
+
var _a;
|
|
1048
|
+
setTargetComponent(target);
|
|
1049
|
+
(_a = inputRef.current) == null ? void 0 : _a.focus();
|
|
1050
|
+
}
|
|
1051
|
+
};
|
|
1052
|
+
}, [processData, setMessages, sendMessage]);
|
|
1053
|
+
const handleSubmit = (prompt) => {
|
|
1054
|
+
const text = prompt.trim();
|
|
1055
|
+
if (chat == null ? void 0 : chat.onSubmit) {
|
|
1056
|
+
chat.onSubmit(text);
|
|
1057
|
+
return;
|
|
1058
|
+
}
|
|
1059
|
+
if (!text && attachedImages.length === 0) return;
|
|
1060
|
+
setError("");
|
|
1061
|
+
setPromptValue("");
|
|
1062
|
+
pendingSendImagesRef.current = attachedImages.map((img) => img.dataUrl);
|
|
1063
|
+
setAttachedImages([]);
|
|
1064
|
+
sendMessage({ text }).catch((e) => {
|
|
1065
|
+
console.error(e);
|
|
1066
|
+
});
|
|
1067
|
+
};
|
|
1068
|
+
const messagesWithStatuses = (0, import_react4.useMemo)(() => {
|
|
1069
|
+
return messages.map((msg) => __spreadProps(__spreadValues({}, msg), {
|
|
1070
|
+
parts: msg.parts.map((part) => {
|
|
1071
|
+
if ("toolCallId" in part) {
|
|
1072
|
+
return __spreadProps(__spreadValues({}, part), { status: toolStatus[part.toolCallId] });
|
|
1073
|
+
}
|
|
1074
|
+
return part;
|
|
1075
|
+
})
|
|
1076
|
+
}));
|
|
1077
|
+
}, [messages, toolStatus]);
|
|
1078
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "puck-ai-chat", ref: pluginRef, children: [
|
|
1079
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "puck-ai-chat-header", children: "AI page builder" }),
|
|
1080
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(ToolStatusProvider, { value: toolStatus, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1081
|
+
ChatBody,
|
|
1082
|
+
{
|
|
1083
|
+
messages: messagesWithStatuses,
|
|
1084
|
+
handleSubmit,
|
|
1085
|
+
inputRef,
|
|
1086
|
+
status: resolvedStatus,
|
|
1087
|
+
examplePrompts: examplePrompts == null ? void 0 : examplePrompts.map(({ label, href, onClick }) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ExamplePrompt, { label, href, onClick }, label)),
|
|
1088
|
+
error,
|
|
1089
|
+
handleRetry: () => {
|
|
1090
|
+
setError("");
|
|
1091
|
+
regenerate();
|
|
1092
|
+
},
|
|
1093
|
+
promptValue,
|
|
1094
|
+
targetComponent,
|
|
1095
|
+
onClearTarget: () => setTargetComponent(null),
|
|
1096
|
+
images: attachedImages,
|
|
1097
|
+
onImagesChange: setAttachedImages,
|
|
1098
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Placeholder, { dispatch: puckDispatch, inputRef, pluginRef })
|
|
1099
|
+
}
|
|
1100
|
+
) })
|
|
1101
|
+
] });
|
|
1102
|
+
}
|
|
1103
|
+
function createAiPlugin(opts = {}) {
|
|
1104
|
+
const { scrollTracking = true, host, chat, prepareRequest } = opts;
|
|
1105
|
+
return {
|
|
1106
|
+
label: "AI",
|
|
1107
|
+
name: "ai",
|
|
1108
|
+
icon: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Bot, {}),
|
|
1109
|
+
mobilePanelHeight: "min-content",
|
|
1110
|
+
render: () => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Chat, { host, chat, prepareRequest }),
|
|
1111
|
+
overrides: {
|
|
1112
|
+
preview: ({ children }) => {
|
|
1113
|
+
if (scrollTracking) {
|
|
1114
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ScrollTracking, { children });
|
|
1115
|
+
}
|
|
1116
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_jsx_runtime.Fragment, { children });
|
|
1117
|
+
}
|
|
1118
|
+
}
|
|
1119
|
+
};
|
|
1120
|
+
}
|
|
1121
|
+
var index_default = createAiPlugin;
|
|
1122
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
1123
|
+
0 && (module.exports = {
|
|
1124
|
+
Chat,
|
|
1125
|
+
createAiPlugin
|
|
1126
|
+
});
|
|
1127
|
+
/*! Bundled license information:
|
|
1128
|
+
|
|
1129
|
+
lucide-react/dist/esm/shared/src/utils.js:
|
|
1130
|
+
lucide-react/dist/esm/defaultAttributes.js:
|
|
1131
|
+
lucide-react/dist/esm/Icon.js:
|
|
1132
|
+
lucide-react/dist/esm/createLucideIcon.js:
|
|
1133
|
+
lucide-react/dist/esm/icons/arrow-up.js:
|
|
1134
|
+
lucide-react/dist/esm/icons/bot.js:
|
|
1135
|
+
lucide-react/dist/esm/icons/check.js:
|
|
1136
|
+
lucide-react/dist/esm/icons/image.js:
|
|
1137
|
+
lucide-react/dist/esm/icons/rotate-ccw.js:
|
|
1138
|
+
lucide-react/dist/esm/icons/triangle-alert.js:
|
|
1139
|
+
lucide-react/dist/esm/icons/x.js:
|
|
1140
|
+
lucide-react/dist/esm/lucide-react.js:
|
|
1141
|
+
(**
|
|
1142
|
+
* @license lucide-react v0.452.0 - ISC
|
|
1143
|
+
*
|
|
1144
|
+
* This source code is licensed under the ISC license.
|
|
1145
|
+
* See the LICENSE file in the root directory of this source tree.
|
|
1146
|
+
*)
|
|
1147
|
+
*/
|
|
1148
|
+
//# sourceMappingURL=index.js.map
|