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.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