@refactico/pages 0.1.0 → 0.2.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.cjs +2135 -875
- package/dist/index.d.ts +2 -2
- package/dist/index.js +2136 -876
- package/dist/style.css +46 -35
- package/package.json +12 -11
package/dist/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
|
|
2
|
-
import { useRef, useState,
|
|
2
|
+
import { useRef, useState, useEffect, useCallback, memo, createContext } from 'react';
|
|
3
3
|
|
|
4
4
|
const generateId = () => {
|
|
5
5
|
if (typeof crypto !== "undefined" && typeof crypto.randomUUID === "function") {
|
|
@@ -109,154 +109,914 @@ const moveArrayItem = (arr, fromIndex, toIndex) => {
|
|
|
109
109
|
return newArr;
|
|
110
110
|
};
|
|
111
111
|
|
|
112
|
-
const PlusIcon = ({ className = "", size = 20 }) => /* @__PURE__ */ jsxs(
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
112
|
+
const PlusIcon = ({ className = "", size = 20 }) => /* @__PURE__ */ jsxs(
|
|
113
|
+
"svg",
|
|
114
|
+
{
|
|
115
|
+
className,
|
|
116
|
+
width: size,
|
|
117
|
+
height: size,
|
|
118
|
+
viewBox: "0 0 24 24",
|
|
119
|
+
fill: "none",
|
|
120
|
+
stroke: "currentColor",
|
|
121
|
+
strokeWidth: "2",
|
|
122
|
+
strokeLinecap: "round",
|
|
123
|
+
strokeLinejoin: "round",
|
|
124
|
+
children: [
|
|
125
|
+
/* @__PURE__ */ jsx(
|
|
126
|
+
"line",
|
|
127
|
+
{
|
|
128
|
+
x1: "12",
|
|
129
|
+
y1: "5",
|
|
130
|
+
x2: "12",
|
|
131
|
+
y2: "19"
|
|
132
|
+
}
|
|
133
|
+
),
|
|
134
|
+
/* @__PURE__ */ jsx(
|
|
135
|
+
"line",
|
|
136
|
+
{
|
|
137
|
+
x1: "5",
|
|
138
|
+
y1: "12",
|
|
139
|
+
x2: "19",
|
|
140
|
+
y2: "12"
|
|
141
|
+
}
|
|
142
|
+
)
|
|
143
|
+
]
|
|
144
|
+
}
|
|
145
|
+
);
|
|
146
|
+
const TextIcon = ({ className = "", size = 20 }) => /* @__PURE__ */ jsxs(
|
|
147
|
+
"svg",
|
|
148
|
+
{
|
|
149
|
+
className,
|
|
150
|
+
width: size,
|
|
151
|
+
height: size,
|
|
152
|
+
viewBox: "0 0 24 24",
|
|
153
|
+
fill: "none",
|
|
154
|
+
stroke: "currentColor",
|
|
155
|
+
strokeWidth: "2",
|
|
156
|
+
strokeLinecap: "round",
|
|
157
|
+
strokeLinejoin: "round",
|
|
158
|
+
children: [
|
|
159
|
+
/* @__PURE__ */ jsx("polyline", { points: "4 7 4 4 20 4 20 7" }),
|
|
160
|
+
/* @__PURE__ */ jsx(
|
|
161
|
+
"line",
|
|
162
|
+
{
|
|
163
|
+
x1: "9",
|
|
164
|
+
y1: "20",
|
|
165
|
+
x2: "15",
|
|
166
|
+
y2: "20"
|
|
167
|
+
}
|
|
168
|
+
),
|
|
169
|
+
/* @__PURE__ */ jsx(
|
|
170
|
+
"line",
|
|
171
|
+
{
|
|
172
|
+
x1: "12",
|
|
173
|
+
y1: "4",
|
|
174
|
+
x2: "12",
|
|
175
|
+
y2: "20"
|
|
176
|
+
}
|
|
177
|
+
)
|
|
178
|
+
]
|
|
179
|
+
}
|
|
180
|
+
);
|
|
181
|
+
const HeadingIcon = ({ className = "", size = 20 }) => /* @__PURE__ */ jsxs(
|
|
182
|
+
"svg",
|
|
183
|
+
{
|
|
184
|
+
className,
|
|
185
|
+
width: size,
|
|
186
|
+
height: size,
|
|
187
|
+
viewBox: "0 0 24 24",
|
|
188
|
+
fill: "none",
|
|
189
|
+
stroke: "currentColor",
|
|
190
|
+
strokeWidth: "2",
|
|
191
|
+
strokeLinecap: "round",
|
|
192
|
+
strokeLinejoin: "round",
|
|
193
|
+
children: [
|
|
194
|
+
/* @__PURE__ */ jsx("path", { d: "M6 4v16" }),
|
|
195
|
+
/* @__PURE__ */ jsx("path", { d: "M18 4v16" }),
|
|
196
|
+
/* @__PURE__ */ jsx("path", { d: "M6 12h12" })
|
|
197
|
+
]
|
|
198
|
+
}
|
|
199
|
+
);
|
|
200
|
+
const ImageIcon = ({ className = "", size = 20 }) => /* @__PURE__ */ jsxs(
|
|
201
|
+
"svg",
|
|
202
|
+
{
|
|
203
|
+
className,
|
|
204
|
+
width: size,
|
|
205
|
+
height: size,
|
|
206
|
+
viewBox: "0 0 24 24",
|
|
207
|
+
fill: "none",
|
|
208
|
+
stroke: "currentColor",
|
|
209
|
+
strokeWidth: "2",
|
|
210
|
+
strokeLinecap: "round",
|
|
211
|
+
strokeLinejoin: "round",
|
|
212
|
+
children: [
|
|
213
|
+
/* @__PURE__ */ jsx(
|
|
214
|
+
"rect",
|
|
215
|
+
{
|
|
216
|
+
x: "3",
|
|
217
|
+
y: "3",
|
|
218
|
+
width: "18",
|
|
219
|
+
height: "18",
|
|
220
|
+
rx: "2",
|
|
221
|
+
ry: "2"
|
|
222
|
+
}
|
|
223
|
+
),
|
|
224
|
+
/* @__PURE__ */ jsx(
|
|
225
|
+
"circle",
|
|
226
|
+
{
|
|
227
|
+
cx: "8.5",
|
|
228
|
+
cy: "8.5",
|
|
229
|
+
r: "1.5"
|
|
230
|
+
}
|
|
231
|
+
),
|
|
232
|
+
/* @__PURE__ */ jsx("polyline", { points: "21 15 16 10 5 21" })
|
|
233
|
+
]
|
|
234
|
+
}
|
|
235
|
+
);
|
|
236
|
+
const CodeIcon = ({ className = "", size = 20 }) => /* @__PURE__ */ jsxs(
|
|
237
|
+
"svg",
|
|
238
|
+
{
|
|
239
|
+
className,
|
|
240
|
+
width: size,
|
|
241
|
+
height: size,
|
|
242
|
+
viewBox: "0 0 24 24",
|
|
243
|
+
fill: "none",
|
|
244
|
+
stroke: "currentColor",
|
|
245
|
+
strokeWidth: "2",
|
|
246
|
+
strokeLinecap: "round",
|
|
247
|
+
strokeLinejoin: "round",
|
|
248
|
+
children: [
|
|
249
|
+
/* @__PURE__ */ jsx("polyline", { points: "16 18 22 12 16 6" }),
|
|
250
|
+
/* @__PURE__ */ jsx("polyline", { points: "8 6 2 12 8 18" })
|
|
251
|
+
]
|
|
252
|
+
}
|
|
253
|
+
);
|
|
254
|
+
const TableIcon = ({ className = "", size = 20 }) => /* @__PURE__ */ jsxs(
|
|
255
|
+
"svg",
|
|
256
|
+
{
|
|
257
|
+
className,
|
|
258
|
+
width: size,
|
|
259
|
+
height: size,
|
|
260
|
+
viewBox: "0 0 24 24",
|
|
261
|
+
fill: "none",
|
|
262
|
+
stroke: "currentColor",
|
|
263
|
+
strokeWidth: "2",
|
|
264
|
+
strokeLinecap: "round",
|
|
265
|
+
strokeLinejoin: "round",
|
|
266
|
+
children: [
|
|
267
|
+
/* @__PURE__ */ jsx(
|
|
268
|
+
"rect",
|
|
269
|
+
{
|
|
270
|
+
x: "3",
|
|
271
|
+
y: "3",
|
|
272
|
+
width: "18",
|
|
273
|
+
height: "18",
|
|
274
|
+
rx: "2",
|
|
275
|
+
ry: "2"
|
|
276
|
+
}
|
|
277
|
+
),
|
|
278
|
+
/* @__PURE__ */ jsx(
|
|
279
|
+
"line",
|
|
280
|
+
{
|
|
281
|
+
x1: "3",
|
|
282
|
+
y1: "9",
|
|
283
|
+
x2: "21",
|
|
284
|
+
y2: "9"
|
|
285
|
+
}
|
|
286
|
+
),
|
|
287
|
+
/* @__PURE__ */ jsx(
|
|
288
|
+
"line",
|
|
289
|
+
{
|
|
290
|
+
x1: "3",
|
|
291
|
+
y1: "15",
|
|
292
|
+
x2: "21",
|
|
293
|
+
y2: "15"
|
|
294
|
+
}
|
|
295
|
+
),
|
|
296
|
+
/* @__PURE__ */ jsx(
|
|
297
|
+
"line",
|
|
298
|
+
{
|
|
299
|
+
x1: "9",
|
|
300
|
+
y1: "3",
|
|
301
|
+
x2: "9",
|
|
302
|
+
y2: "21"
|
|
303
|
+
}
|
|
304
|
+
),
|
|
305
|
+
/* @__PURE__ */ jsx(
|
|
306
|
+
"line",
|
|
307
|
+
{
|
|
308
|
+
x1: "15",
|
|
309
|
+
y1: "3",
|
|
310
|
+
x2: "15",
|
|
311
|
+
y2: "21"
|
|
312
|
+
}
|
|
313
|
+
)
|
|
314
|
+
]
|
|
315
|
+
}
|
|
316
|
+
);
|
|
317
|
+
const DividerIcon = ({ className = "", size = 20 }) => /* @__PURE__ */ jsx(
|
|
318
|
+
"svg",
|
|
319
|
+
{
|
|
320
|
+
className,
|
|
321
|
+
width: size,
|
|
322
|
+
height: size,
|
|
323
|
+
viewBox: "0 0 24 24",
|
|
324
|
+
fill: "none",
|
|
325
|
+
stroke: "currentColor",
|
|
326
|
+
strokeWidth: "2",
|
|
327
|
+
strokeLinecap: "round",
|
|
328
|
+
strokeLinejoin: "round",
|
|
329
|
+
children: /* @__PURE__ */ jsx(
|
|
330
|
+
"line",
|
|
331
|
+
{
|
|
332
|
+
x1: "3",
|
|
333
|
+
y1: "12",
|
|
334
|
+
x2: "21",
|
|
335
|
+
y2: "12"
|
|
336
|
+
}
|
|
337
|
+
)
|
|
338
|
+
}
|
|
339
|
+
);
|
|
340
|
+
const QuoteIcon = ({ className = "", size = 20 }) => /* @__PURE__ */ jsxs(
|
|
341
|
+
"svg",
|
|
342
|
+
{
|
|
343
|
+
className,
|
|
344
|
+
width: size,
|
|
345
|
+
height: size,
|
|
346
|
+
viewBox: "0 0 24 24",
|
|
347
|
+
fill: "none",
|
|
348
|
+
stroke: "currentColor",
|
|
349
|
+
strokeWidth: "2",
|
|
350
|
+
strokeLinecap: "round",
|
|
351
|
+
strokeLinejoin: "round",
|
|
352
|
+
children: [
|
|
353
|
+
/* @__PURE__ */ jsx("path", { d: "M3 21c3 0 7-1 7-8V5c0-1.25-.756-2.017-2-2H4c-1.25 0-2 .75-2 1.972V11c0 1.25.75 2 2 2 1 0 1 0 1 1v1c0 1-1 2-2 2s-1 .008-1 1.031V21c0 1 0 1 1 1z" }),
|
|
354
|
+
/* @__PURE__ */ jsx("path", { d: "M15 21c3 0 7-1 7-8V5c0-1.25-.757-2.017-2-2h-4c-1.25 0-2 .75-2 1.972V11c0 1.25.75 2 2 2h.75c0 2.25.25 4-2.75 4v3c0 1 0 1 1 1z" })
|
|
355
|
+
]
|
|
356
|
+
}
|
|
357
|
+
);
|
|
358
|
+
const ListIcon = ({ className = "", size = 20 }) => /* @__PURE__ */ jsxs(
|
|
359
|
+
"svg",
|
|
360
|
+
{
|
|
361
|
+
className,
|
|
362
|
+
width: size,
|
|
363
|
+
height: size,
|
|
364
|
+
viewBox: "0 0 24 24",
|
|
365
|
+
fill: "none",
|
|
366
|
+
stroke: "currentColor",
|
|
367
|
+
strokeWidth: "2",
|
|
368
|
+
strokeLinecap: "round",
|
|
369
|
+
strokeLinejoin: "round",
|
|
370
|
+
children: [
|
|
371
|
+
/* @__PURE__ */ jsx(
|
|
372
|
+
"line",
|
|
373
|
+
{
|
|
374
|
+
x1: "8",
|
|
375
|
+
y1: "6",
|
|
376
|
+
x2: "21",
|
|
377
|
+
y2: "6"
|
|
378
|
+
}
|
|
379
|
+
),
|
|
380
|
+
/* @__PURE__ */ jsx(
|
|
381
|
+
"line",
|
|
382
|
+
{
|
|
383
|
+
x1: "8",
|
|
384
|
+
y1: "12",
|
|
385
|
+
x2: "21",
|
|
386
|
+
y2: "12"
|
|
387
|
+
}
|
|
388
|
+
),
|
|
389
|
+
/* @__PURE__ */ jsx(
|
|
390
|
+
"line",
|
|
391
|
+
{
|
|
392
|
+
x1: "8",
|
|
393
|
+
y1: "18",
|
|
394
|
+
x2: "21",
|
|
395
|
+
y2: "18"
|
|
396
|
+
}
|
|
397
|
+
),
|
|
398
|
+
/* @__PURE__ */ jsx(
|
|
399
|
+
"line",
|
|
400
|
+
{
|
|
401
|
+
x1: "3",
|
|
402
|
+
y1: "6",
|
|
403
|
+
x2: "3.01",
|
|
404
|
+
y2: "6"
|
|
405
|
+
}
|
|
406
|
+
),
|
|
407
|
+
/* @__PURE__ */ jsx(
|
|
408
|
+
"line",
|
|
409
|
+
{
|
|
410
|
+
x1: "3",
|
|
411
|
+
y1: "12",
|
|
412
|
+
x2: "3.01",
|
|
413
|
+
y2: "12"
|
|
414
|
+
}
|
|
415
|
+
),
|
|
416
|
+
/* @__PURE__ */ jsx(
|
|
417
|
+
"line",
|
|
418
|
+
{
|
|
419
|
+
x1: "3",
|
|
420
|
+
y1: "18",
|
|
421
|
+
x2: "3.01",
|
|
422
|
+
y2: "18"
|
|
423
|
+
}
|
|
424
|
+
)
|
|
425
|
+
]
|
|
426
|
+
}
|
|
427
|
+
);
|
|
428
|
+
const CalloutIcon = ({ className = "", size = 20 }) => /* @__PURE__ */ jsxs(
|
|
429
|
+
"svg",
|
|
430
|
+
{
|
|
431
|
+
className,
|
|
432
|
+
width: size,
|
|
433
|
+
height: size,
|
|
434
|
+
viewBox: "0 0 24 24",
|
|
435
|
+
fill: "none",
|
|
436
|
+
stroke: "currentColor",
|
|
437
|
+
strokeWidth: "2",
|
|
438
|
+
strokeLinecap: "round",
|
|
439
|
+
strokeLinejoin: "round",
|
|
440
|
+
children: [
|
|
441
|
+
/* @__PURE__ */ jsx(
|
|
442
|
+
"circle",
|
|
443
|
+
{
|
|
444
|
+
cx: "12",
|
|
445
|
+
cy: "12",
|
|
446
|
+
r: "10"
|
|
447
|
+
}
|
|
448
|
+
),
|
|
449
|
+
/* @__PURE__ */ jsx(
|
|
450
|
+
"line",
|
|
451
|
+
{
|
|
452
|
+
x1: "12",
|
|
453
|
+
y1: "16",
|
|
454
|
+
x2: "12",
|
|
455
|
+
y2: "12"
|
|
456
|
+
}
|
|
457
|
+
),
|
|
458
|
+
/* @__PURE__ */ jsx(
|
|
459
|
+
"line",
|
|
460
|
+
{
|
|
461
|
+
x1: "12",
|
|
462
|
+
y1: "8",
|
|
463
|
+
x2: "12.01",
|
|
464
|
+
y2: "8"
|
|
465
|
+
}
|
|
466
|
+
)
|
|
467
|
+
]
|
|
468
|
+
}
|
|
469
|
+
);
|
|
470
|
+
const TrashIcon = ({ className = "", size = 20 }) => /* @__PURE__ */ jsxs(
|
|
471
|
+
"svg",
|
|
472
|
+
{
|
|
473
|
+
className,
|
|
474
|
+
width: size,
|
|
475
|
+
height: size,
|
|
476
|
+
viewBox: "0 0 24 24",
|
|
477
|
+
fill: "none",
|
|
478
|
+
stroke: "currentColor",
|
|
479
|
+
strokeWidth: "2",
|
|
480
|
+
strokeLinecap: "round",
|
|
481
|
+
strokeLinejoin: "round",
|
|
482
|
+
children: [
|
|
483
|
+
/* @__PURE__ */ jsx("polyline", { points: "3 6 5 6 21 6" }),
|
|
484
|
+
/* @__PURE__ */ jsx("path", { d: "M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2" })
|
|
485
|
+
]
|
|
486
|
+
}
|
|
487
|
+
);
|
|
488
|
+
const DragIcon = ({ className = "", size = 20 }) => /* @__PURE__ */ jsxs(
|
|
489
|
+
"svg",
|
|
490
|
+
{
|
|
491
|
+
className,
|
|
492
|
+
width: size,
|
|
493
|
+
height: size,
|
|
494
|
+
viewBox: "0 0 24 24",
|
|
495
|
+
fill: "none",
|
|
496
|
+
stroke: "currentColor",
|
|
497
|
+
strokeWidth: "2",
|
|
498
|
+
strokeLinecap: "round",
|
|
499
|
+
strokeLinejoin: "round",
|
|
500
|
+
children: [
|
|
501
|
+
/* @__PURE__ */ jsx(
|
|
502
|
+
"circle",
|
|
503
|
+
{
|
|
504
|
+
cx: "9",
|
|
505
|
+
cy: "5",
|
|
506
|
+
r: "1"
|
|
507
|
+
}
|
|
508
|
+
),
|
|
509
|
+
/* @__PURE__ */ jsx(
|
|
510
|
+
"circle",
|
|
511
|
+
{
|
|
512
|
+
cx: "9",
|
|
513
|
+
cy: "12",
|
|
514
|
+
r: "1"
|
|
515
|
+
}
|
|
516
|
+
),
|
|
517
|
+
/* @__PURE__ */ jsx(
|
|
518
|
+
"circle",
|
|
519
|
+
{
|
|
520
|
+
cx: "9",
|
|
521
|
+
cy: "19",
|
|
522
|
+
r: "1"
|
|
523
|
+
}
|
|
524
|
+
),
|
|
525
|
+
/* @__PURE__ */ jsx(
|
|
526
|
+
"circle",
|
|
527
|
+
{
|
|
528
|
+
cx: "15",
|
|
529
|
+
cy: "5",
|
|
530
|
+
r: "1"
|
|
531
|
+
}
|
|
532
|
+
),
|
|
533
|
+
/* @__PURE__ */ jsx(
|
|
534
|
+
"circle",
|
|
535
|
+
{
|
|
536
|
+
cx: "15",
|
|
537
|
+
cy: "12",
|
|
538
|
+
r: "1"
|
|
539
|
+
}
|
|
540
|
+
),
|
|
541
|
+
/* @__PURE__ */ jsx(
|
|
542
|
+
"circle",
|
|
543
|
+
{
|
|
544
|
+
cx: "15",
|
|
545
|
+
cy: "19",
|
|
546
|
+
r: "1"
|
|
547
|
+
}
|
|
548
|
+
)
|
|
549
|
+
]
|
|
550
|
+
}
|
|
551
|
+
);
|
|
552
|
+
const CopyIcon = ({ className = "", size = 20 }) => /* @__PURE__ */ jsxs(
|
|
553
|
+
"svg",
|
|
554
|
+
{
|
|
555
|
+
className,
|
|
556
|
+
width: size,
|
|
557
|
+
height: size,
|
|
558
|
+
viewBox: "0 0 24 24",
|
|
559
|
+
fill: "none",
|
|
560
|
+
stroke: "currentColor",
|
|
561
|
+
strokeWidth: "2",
|
|
562
|
+
strokeLinecap: "round",
|
|
563
|
+
strokeLinejoin: "round",
|
|
564
|
+
children: [
|
|
565
|
+
/* @__PURE__ */ jsx(
|
|
566
|
+
"rect",
|
|
567
|
+
{
|
|
568
|
+
x: "9",
|
|
569
|
+
y: "9",
|
|
570
|
+
width: "13",
|
|
571
|
+
height: "13",
|
|
572
|
+
rx: "2",
|
|
573
|
+
ry: "2"
|
|
574
|
+
}
|
|
575
|
+
),
|
|
576
|
+
/* @__PURE__ */ jsx("path", { d: "M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1" })
|
|
577
|
+
]
|
|
578
|
+
}
|
|
579
|
+
);
|
|
580
|
+
const ChevronUpIcon = ({ className = "", size = 20 }) => /* @__PURE__ */ jsx(
|
|
581
|
+
"svg",
|
|
582
|
+
{
|
|
583
|
+
className,
|
|
584
|
+
width: size,
|
|
585
|
+
height: size,
|
|
586
|
+
viewBox: "0 0 24 24",
|
|
587
|
+
fill: "none",
|
|
588
|
+
stroke: "currentColor",
|
|
589
|
+
strokeWidth: "2",
|
|
590
|
+
strokeLinecap: "round",
|
|
591
|
+
strokeLinejoin: "round",
|
|
592
|
+
children: /* @__PURE__ */ jsx("polyline", { points: "18 15 12 9 6 15" })
|
|
593
|
+
}
|
|
594
|
+
);
|
|
595
|
+
const ChevronDownIcon = ({ className = "", size = 20 }) => /* @__PURE__ */ jsx(
|
|
596
|
+
"svg",
|
|
597
|
+
{
|
|
598
|
+
className,
|
|
599
|
+
width: size,
|
|
600
|
+
height: size,
|
|
601
|
+
viewBox: "0 0 24 24",
|
|
602
|
+
fill: "none",
|
|
603
|
+
stroke: "currentColor",
|
|
604
|
+
strokeWidth: "2",
|
|
605
|
+
strokeLinecap: "round",
|
|
606
|
+
strokeLinejoin: "round",
|
|
607
|
+
children: /* @__PURE__ */ jsx("polyline", { points: "6 9 12 15 18 9" })
|
|
608
|
+
}
|
|
609
|
+
);
|
|
610
|
+
const ChevronLeftIcon = ({ className = "", size = 20 }) => /* @__PURE__ */ jsx(
|
|
611
|
+
"svg",
|
|
612
|
+
{
|
|
613
|
+
className,
|
|
614
|
+
width: size,
|
|
615
|
+
height: size,
|
|
616
|
+
viewBox: "0 0 24 24",
|
|
617
|
+
fill: "none",
|
|
618
|
+
stroke: "currentColor",
|
|
619
|
+
strokeWidth: "2",
|
|
620
|
+
strokeLinecap: "round",
|
|
621
|
+
strokeLinejoin: "round",
|
|
622
|
+
children: /* @__PURE__ */ jsx("polyline", { points: "15 18 9 12 15 6" })
|
|
623
|
+
}
|
|
624
|
+
);
|
|
625
|
+
const ChevronRightIcon = ({ className = "", size = 20 }) => /* @__PURE__ */ jsx(
|
|
626
|
+
"svg",
|
|
627
|
+
{
|
|
628
|
+
className,
|
|
629
|
+
width: size,
|
|
630
|
+
height: size,
|
|
631
|
+
viewBox: "0 0 24 24",
|
|
632
|
+
fill: "none",
|
|
633
|
+
stroke: "currentColor",
|
|
634
|
+
strokeWidth: "2",
|
|
635
|
+
strokeLinecap: "round",
|
|
636
|
+
strokeLinejoin: "round",
|
|
637
|
+
children: /* @__PURE__ */ jsx("polyline", { points: "9 18 15 12 9 6" })
|
|
638
|
+
}
|
|
639
|
+
);
|
|
640
|
+
const BoldIcon = ({ className = "", size = 20 }) => /* @__PURE__ */ jsxs(
|
|
641
|
+
"svg",
|
|
642
|
+
{
|
|
643
|
+
className,
|
|
644
|
+
width: size,
|
|
645
|
+
height: size,
|
|
646
|
+
viewBox: "0 0 24 24",
|
|
647
|
+
fill: "none",
|
|
648
|
+
stroke: "currentColor",
|
|
649
|
+
strokeWidth: "2",
|
|
650
|
+
strokeLinecap: "round",
|
|
651
|
+
strokeLinejoin: "round",
|
|
652
|
+
children: [
|
|
653
|
+
/* @__PURE__ */ jsx("path", { d: "M6 4h8a4 4 0 0 1 4 4 4 4 0 0 1-4 4H6z" }),
|
|
654
|
+
/* @__PURE__ */ jsx("path", { d: "M6 12h9a4 4 0 0 1 4 4 4 4 0 0 1-4 4H6z" })
|
|
655
|
+
]
|
|
656
|
+
}
|
|
657
|
+
);
|
|
658
|
+
const ItalicIcon = ({ className = "", size = 20 }) => /* @__PURE__ */ jsxs(
|
|
659
|
+
"svg",
|
|
660
|
+
{
|
|
661
|
+
className,
|
|
662
|
+
width: size,
|
|
663
|
+
height: size,
|
|
664
|
+
viewBox: "0 0 24 24",
|
|
665
|
+
fill: "none",
|
|
666
|
+
stroke: "currentColor",
|
|
667
|
+
strokeWidth: "2",
|
|
668
|
+
strokeLinecap: "round",
|
|
669
|
+
strokeLinejoin: "round",
|
|
670
|
+
children: [
|
|
671
|
+
/* @__PURE__ */ jsx(
|
|
672
|
+
"line",
|
|
673
|
+
{
|
|
674
|
+
x1: "19",
|
|
675
|
+
y1: "4",
|
|
676
|
+
x2: "10",
|
|
677
|
+
y2: "4"
|
|
678
|
+
}
|
|
679
|
+
),
|
|
680
|
+
/* @__PURE__ */ jsx(
|
|
681
|
+
"line",
|
|
682
|
+
{
|
|
683
|
+
x1: "14",
|
|
684
|
+
y1: "20",
|
|
685
|
+
x2: "5",
|
|
686
|
+
y2: "20"
|
|
687
|
+
}
|
|
688
|
+
),
|
|
689
|
+
/* @__PURE__ */ jsx(
|
|
690
|
+
"line",
|
|
691
|
+
{
|
|
692
|
+
x1: "15",
|
|
693
|
+
y1: "4",
|
|
694
|
+
x2: "9",
|
|
695
|
+
y2: "20"
|
|
696
|
+
}
|
|
697
|
+
)
|
|
698
|
+
]
|
|
699
|
+
}
|
|
700
|
+
);
|
|
701
|
+
const UnderlineIcon = ({ className = "", size = 20 }) => /* @__PURE__ */ jsxs(
|
|
702
|
+
"svg",
|
|
703
|
+
{
|
|
704
|
+
className,
|
|
705
|
+
width: size,
|
|
706
|
+
height: size,
|
|
707
|
+
viewBox: "0 0 24 24",
|
|
708
|
+
fill: "none",
|
|
709
|
+
stroke: "currentColor",
|
|
710
|
+
strokeWidth: "2",
|
|
711
|
+
strokeLinecap: "round",
|
|
712
|
+
strokeLinejoin: "round",
|
|
713
|
+
children: [
|
|
714
|
+
/* @__PURE__ */ jsx("path", { d: "M6 3v7a6 6 0 0 0 6 6 6 6 0 0 0 6-6V3" }),
|
|
715
|
+
/* @__PURE__ */ jsx(
|
|
716
|
+
"line",
|
|
717
|
+
{
|
|
718
|
+
x1: "4",
|
|
719
|
+
y1: "21",
|
|
720
|
+
x2: "20",
|
|
721
|
+
y2: "21"
|
|
722
|
+
}
|
|
723
|
+
)
|
|
724
|
+
]
|
|
725
|
+
}
|
|
726
|
+
);
|
|
727
|
+
const AlignLeftIcon = ({ className = "", size = 20 }) => /* @__PURE__ */ jsxs(
|
|
728
|
+
"svg",
|
|
729
|
+
{
|
|
730
|
+
className,
|
|
731
|
+
width: size,
|
|
732
|
+
height: size,
|
|
733
|
+
viewBox: "0 0 24 24",
|
|
734
|
+
fill: "none",
|
|
735
|
+
stroke: "currentColor",
|
|
736
|
+
strokeWidth: "2",
|
|
737
|
+
strokeLinecap: "round",
|
|
738
|
+
strokeLinejoin: "round",
|
|
739
|
+
children: [
|
|
740
|
+
/* @__PURE__ */ jsx(
|
|
741
|
+
"line",
|
|
742
|
+
{
|
|
743
|
+
x1: "17",
|
|
744
|
+
y1: "10",
|
|
745
|
+
x2: "3",
|
|
746
|
+
y2: "10"
|
|
747
|
+
}
|
|
748
|
+
),
|
|
749
|
+
/* @__PURE__ */ jsx(
|
|
750
|
+
"line",
|
|
751
|
+
{
|
|
752
|
+
x1: "21",
|
|
753
|
+
y1: "6",
|
|
754
|
+
x2: "3",
|
|
755
|
+
y2: "6"
|
|
756
|
+
}
|
|
757
|
+
),
|
|
758
|
+
/* @__PURE__ */ jsx(
|
|
759
|
+
"line",
|
|
760
|
+
{
|
|
761
|
+
x1: "21",
|
|
762
|
+
y1: "14",
|
|
763
|
+
x2: "3",
|
|
764
|
+
y2: "14"
|
|
765
|
+
}
|
|
766
|
+
),
|
|
767
|
+
/* @__PURE__ */ jsx(
|
|
768
|
+
"line",
|
|
769
|
+
{
|
|
770
|
+
x1: "17",
|
|
771
|
+
y1: "18",
|
|
772
|
+
x2: "3",
|
|
773
|
+
y2: "18"
|
|
774
|
+
}
|
|
775
|
+
)
|
|
776
|
+
]
|
|
777
|
+
}
|
|
778
|
+
);
|
|
779
|
+
const AlignCenterIcon = ({ className = "", size = 20 }) => /* @__PURE__ */ jsxs(
|
|
780
|
+
"svg",
|
|
781
|
+
{
|
|
782
|
+
className,
|
|
783
|
+
width: size,
|
|
784
|
+
height: size,
|
|
785
|
+
viewBox: "0 0 24 24",
|
|
786
|
+
fill: "none",
|
|
787
|
+
stroke: "currentColor",
|
|
788
|
+
strokeWidth: "2",
|
|
789
|
+
strokeLinecap: "round",
|
|
790
|
+
strokeLinejoin: "round",
|
|
791
|
+
children: [
|
|
792
|
+
/* @__PURE__ */ jsx(
|
|
793
|
+
"line",
|
|
794
|
+
{
|
|
795
|
+
x1: "18",
|
|
796
|
+
y1: "10",
|
|
797
|
+
x2: "6",
|
|
798
|
+
y2: "10"
|
|
799
|
+
}
|
|
800
|
+
),
|
|
801
|
+
/* @__PURE__ */ jsx(
|
|
802
|
+
"line",
|
|
803
|
+
{
|
|
804
|
+
x1: "21",
|
|
805
|
+
y1: "6",
|
|
806
|
+
x2: "3",
|
|
807
|
+
y2: "6"
|
|
808
|
+
}
|
|
809
|
+
),
|
|
810
|
+
/* @__PURE__ */ jsx(
|
|
811
|
+
"line",
|
|
812
|
+
{
|
|
813
|
+
x1: "21",
|
|
814
|
+
y1: "14",
|
|
815
|
+
x2: "3",
|
|
816
|
+
y2: "14"
|
|
817
|
+
}
|
|
818
|
+
),
|
|
819
|
+
/* @__PURE__ */ jsx(
|
|
820
|
+
"line",
|
|
821
|
+
{
|
|
822
|
+
x1: "18",
|
|
823
|
+
y1: "18",
|
|
824
|
+
x2: "6",
|
|
825
|
+
y2: "18"
|
|
826
|
+
}
|
|
827
|
+
)
|
|
828
|
+
]
|
|
829
|
+
}
|
|
830
|
+
);
|
|
831
|
+
const AlignRightIcon = ({ className = "", size = 20 }) => /* @__PURE__ */ jsxs(
|
|
832
|
+
"svg",
|
|
833
|
+
{
|
|
834
|
+
className,
|
|
835
|
+
width: size,
|
|
836
|
+
height: size,
|
|
837
|
+
viewBox: "0 0 24 24",
|
|
838
|
+
fill: "none",
|
|
839
|
+
stroke: "currentColor",
|
|
840
|
+
strokeWidth: "2",
|
|
841
|
+
strokeLinecap: "round",
|
|
842
|
+
strokeLinejoin: "round",
|
|
843
|
+
children: [
|
|
844
|
+
/* @__PURE__ */ jsx(
|
|
845
|
+
"line",
|
|
846
|
+
{
|
|
847
|
+
x1: "21",
|
|
848
|
+
y1: "10",
|
|
849
|
+
x2: "7",
|
|
850
|
+
y2: "10"
|
|
851
|
+
}
|
|
852
|
+
),
|
|
853
|
+
/* @__PURE__ */ jsx(
|
|
854
|
+
"line",
|
|
855
|
+
{
|
|
856
|
+
x1: "21",
|
|
857
|
+
y1: "6",
|
|
858
|
+
x2: "3",
|
|
859
|
+
y2: "6"
|
|
860
|
+
}
|
|
861
|
+
),
|
|
862
|
+
/* @__PURE__ */ jsx(
|
|
863
|
+
"line",
|
|
864
|
+
{
|
|
865
|
+
x1: "21",
|
|
866
|
+
y1: "14",
|
|
867
|
+
x2: "3",
|
|
868
|
+
y2: "14"
|
|
869
|
+
}
|
|
870
|
+
),
|
|
871
|
+
/* @__PURE__ */ jsx(
|
|
872
|
+
"line",
|
|
873
|
+
{
|
|
874
|
+
x1: "21",
|
|
875
|
+
y1: "18",
|
|
876
|
+
x2: "7",
|
|
877
|
+
y2: "18"
|
|
878
|
+
}
|
|
879
|
+
)
|
|
880
|
+
]
|
|
881
|
+
}
|
|
882
|
+
);
|
|
883
|
+
const CheckIcon = ({ className = "", size = 20 }) => /* @__PURE__ */ jsx(
|
|
884
|
+
"svg",
|
|
885
|
+
{
|
|
886
|
+
className,
|
|
887
|
+
width: size,
|
|
888
|
+
height: size,
|
|
889
|
+
viewBox: "0 0 24 24",
|
|
890
|
+
fill: "none",
|
|
891
|
+
stroke: "currentColor",
|
|
892
|
+
strokeWidth: "2",
|
|
893
|
+
strokeLinecap: "round",
|
|
894
|
+
strokeLinejoin: "round",
|
|
895
|
+
children: /* @__PURE__ */ jsx("polyline", { points: "20 6 9 17 4 12" })
|
|
896
|
+
}
|
|
897
|
+
);
|
|
898
|
+
const UploadIcon = ({ className = "", size = 20 }) => /* @__PURE__ */ jsxs(
|
|
899
|
+
"svg",
|
|
900
|
+
{
|
|
901
|
+
className,
|
|
902
|
+
width: size,
|
|
903
|
+
height: size,
|
|
904
|
+
viewBox: "0 0 24 24",
|
|
905
|
+
fill: "none",
|
|
906
|
+
stroke: "currentColor",
|
|
907
|
+
strokeWidth: "2",
|
|
908
|
+
strokeLinecap: "round",
|
|
909
|
+
strokeLinejoin: "round",
|
|
910
|
+
children: [
|
|
911
|
+
/* @__PURE__ */ jsx("path", { d: "M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4" }),
|
|
912
|
+
/* @__PURE__ */ jsx("polyline", { points: "17 8 12 3 7 8" }),
|
|
913
|
+
/* @__PURE__ */ jsx(
|
|
914
|
+
"line",
|
|
915
|
+
{
|
|
916
|
+
x1: "12",
|
|
917
|
+
y1: "3",
|
|
918
|
+
x2: "12",
|
|
919
|
+
y2: "15"
|
|
920
|
+
}
|
|
921
|
+
)
|
|
922
|
+
]
|
|
923
|
+
}
|
|
924
|
+
);
|
|
215
925
|
|
|
216
926
|
const blockOptions = [
|
|
217
927
|
{ type: "text", label: "Text", description: "Plain text paragraph", icon: TextIcon },
|
|
218
928
|
{ type: "heading", label: "Heading", description: "Section heading", icon: HeadingIcon },
|
|
219
929
|
{ type: "image", label: "Image", description: "Upload or embed image", icon: ImageIcon },
|
|
220
|
-
{
|
|
930
|
+
{
|
|
931
|
+
type: "code",
|
|
932
|
+
label: "Code",
|
|
933
|
+
description: "Code block with syntax highlighting",
|
|
934
|
+
icon: CodeIcon
|
|
935
|
+
},
|
|
221
936
|
{ type: "table", label: "Table", description: "Insert a table", icon: TableIcon },
|
|
222
937
|
{ type: "list", label: "List", description: "Bullet, numbered, or checklist", icon: ListIcon },
|
|
223
938
|
{ type: "quote", label: "Quote", description: "Blockquote", icon: QuoteIcon },
|
|
224
|
-
{
|
|
225
|
-
|
|
939
|
+
{
|
|
940
|
+
type: "callout",
|
|
941
|
+
label: "Callout",
|
|
942
|
+
description: "Info, warning, or tip box",
|
|
943
|
+
icon: CalloutIcon
|
|
944
|
+
},
|
|
945
|
+
{
|
|
946
|
+
type: "divider",
|
|
947
|
+
label: "Divider",
|
|
948
|
+
description: "Horizontal line separator",
|
|
949
|
+
icon: DividerIcon
|
|
950
|
+
}
|
|
226
951
|
];
|
|
227
952
|
const AddBlockMenu = ({ onAdd, onClose, theme = "light" }) => {
|
|
228
953
|
const menuRef = useRef(null);
|
|
229
954
|
const [focusedIndex, setFocusedIndex] = useState(0);
|
|
955
|
+
const [alignment, setAlignment] = useState("left");
|
|
230
956
|
const isDark = theme === "dark";
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
957
|
+
useEffect(() => {
|
|
958
|
+
const adjustPosition = () => {
|
|
959
|
+
if (!menuRef.current) return;
|
|
960
|
+
const menu = menuRef.current;
|
|
961
|
+
const rect = menu.getBoundingClientRect();
|
|
962
|
+
const viewportWidth = window.innerWidth;
|
|
963
|
+
const menuWidth = rect.width;
|
|
964
|
+
const padding = 8;
|
|
965
|
+
const parentRect = menu.parentElement?.getBoundingClientRect();
|
|
966
|
+
if (!parentRect) return;
|
|
967
|
+
const leftAlignedRight = parentRect.left + menuWidth;
|
|
968
|
+
const overflowsRight = leftAlignedRight > viewportWidth - padding;
|
|
969
|
+
const rightAlignedLeft = parentRect.right - menuWidth;
|
|
970
|
+
const overflowsLeft = rightAlignedLeft < padding;
|
|
971
|
+
if (overflowsRight && overflowsLeft) {
|
|
972
|
+
setAlignment("center");
|
|
973
|
+
} else if (overflowsRight) {
|
|
974
|
+
setAlignment("right");
|
|
975
|
+
} else {
|
|
976
|
+
setAlignment("left");
|
|
977
|
+
}
|
|
978
|
+
};
|
|
979
|
+
const timer = setTimeout(() => {
|
|
980
|
+
adjustPosition();
|
|
981
|
+
}, 0);
|
|
982
|
+
window.addEventListener("resize", adjustPosition);
|
|
983
|
+
return () => {
|
|
984
|
+
clearTimeout(timer);
|
|
985
|
+
window.removeEventListener("resize", adjustPosition);
|
|
986
|
+
};
|
|
987
|
+
}, []);
|
|
988
|
+
const handleKeyDown = useCallback(
|
|
989
|
+
(e) => {
|
|
990
|
+
switch (e.key) {
|
|
991
|
+
case "ArrowDown":
|
|
992
|
+
e.preventDefault();
|
|
993
|
+
setFocusedIndex((prev) => (prev + 1) % blockOptions.length);
|
|
994
|
+
break;
|
|
995
|
+
case "ArrowUp":
|
|
996
|
+
e.preventDefault();
|
|
997
|
+
setFocusedIndex((prev) => (prev - 1 + blockOptions.length) % blockOptions.length);
|
|
998
|
+
break;
|
|
999
|
+
case "Enter":
|
|
1000
|
+
case " ": {
|
|
1001
|
+
e.preventDefault();
|
|
1002
|
+
const option = blockOptions[focusedIndex];
|
|
1003
|
+
if (option) {
|
|
1004
|
+
onAdd(option.type);
|
|
1005
|
+
onClose();
|
|
1006
|
+
}
|
|
1007
|
+
break;
|
|
248
1008
|
}
|
|
249
|
-
|
|
1009
|
+
case "Escape":
|
|
1010
|
+
e.preventDefault();
|
|
1011
|
+
onClose();
|
|
1012
|
+
break;
|
|
1013
|
+
case "Tab":
|
|
1014
|
+
onClose();
|
|
1015
|
+
break;
|
|
250
1016
|
}
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
break;
|
|
255
|
-
case "Tab":
|
|
256
|
-
onClose();
|
|
257
|
-
break;
|
|
258
|
-
}
|
|
259
|
-
}, [focusedIndex, onAdd, onClose]);
|
|
1017
|
+
},
|
|
1018
|
+
[focusedIndex, onAdd, onClose]
|
|
1019
|
+
);
|
|
260
1020
|
useEffect(() => {
|
|
261
1021
|
const handleClickOutside = (event) => {
|
|
262
1022
|
if (menuRef.current && !menuRef.current.contains(event.target)) {
|
|
@@ -284,7 +1044,7 @@ const AddBlockMenu = ({ onAdd, onClose, theme = "light" }) => {
|
|
|
284
1044
|
"aria-label": "Add block menu",
|
|
285
1045
|
tabIndex: 0,
|
|
286
1046
|
onKeyDown: handleKeyDown,
|
|
287
|
-
className: `absolute z-50 mt-2 w-72 max-h-80 overflow-y-auto rounded-xl shadow-xl border animate-in fade-in slide-in-from-top-2 duration-200 focus:outline-none ${isDark ? "bg-slate-800 border-slate-700" : "bg-white border-slate-200"}`,
|
|
1047
|
+
className: `absolute z-50 top-full mt-2 w-72 max-w-[calc(100vw-16px)] max-h-80 overflow-y-auto rounded-xl shadow-xl border animate-in fade-in slide-in-from-top-2 duration-200 focus:outline-none ${alignment === "center" ? "left-1/2 -translate-x-1/2" : alignment === "right" ? "right-0" : "left-0"} ${isDark ? "bg-slate-800 border-slate-700" : "bg-white border-slate-200"}`,
|
|
288
1048
|
children: /* @__PURE__ */ jsxs("div", { className: "p-2", children: [
|
|
289
1049
|
/* @__PURE__ */ jsx(
|
|
290
1050
|
"p",
|
|
@@ -294,78 +1054,164 @@ const AddBlockMenu = ({ onAdd, onClose, theme = "light" }) => {
|
|
|
294
1054
|
children: "Add Block"
|
|
295
1055
|
}
|
|
296
1056
|
),
|
|
297
|
-
/* @__PURE__ */ jsx(
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
"
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
1057
|
+
/* @__PURE__ */ jsx(
|
|
1058
|
+
"div",
|
|
1059
|
+
{
|
|
1060
|
+
className: "space-y-1",
|
|
1061
|
+
role: "group",
|
|
1062
|
+
"aria-labelledby": "add-block-menu-label",
|
|
1063
|
+
children: blockOptions.map((option, index) => {
|
|
1064
|
+
const Icon = option.icon;
|
|
1065
|
+
const isFocused = index === focusedIndex;
|
|
1066
|
+
return /* @__PURE__ */ jsxs(
|
|
1067
|
+
"button",
|
|
1068
|
+
{
|
|
1069
|
+
role: "menuitem",
|
|
1070
|
+
type: "button",
|
|
1071
|
+
tabIndex: -1,
|
|
1072
|
+
onClick: () => {
|
|
1073
|
+
onAdd(option.type);
|
|
1074
|
+
onClose();
|
|
1075
|
+
},
|
|
1076
|
+
onMouseEnter: () => setFocusedIndex(index),
|
|
1077
|
+
"aria-label": `Add ${option.label} block: ${option.description}`,
|
|
1078
|
+
className: `w-full flex items-center gap-3 px-3 py-2.5 rounded-lg transition-colors text-left group ${isFocused ? isDark ? "bg-slate-700" : "bg-slate-100" : isDark ? "hover:bg-slate-700" : "hover:bg-slate-50"}`,
|
|
1079
|
+
children: [
|
|
1080
|
+
/* @__PURE__ */ jsx(
|
|
1081
|
+
"div",
|
|
1082
|
+
{
|
|
1083
|
+
className: `flex-shrink-0 w-10 h-10 flex items-center justify-center rounded-lg transition-colors ${isDark ? "bg-slate-700 group-hover:bg-slate-600" : "bg-slate-100 group-hover:bg-slate-200"}`,
|
|
1084
|
+
children: /* @__PURE__ */ jsx(
|
|
1085
|
+
Icon,
|
|
1086
|
+
{
|
|
1087
|
+
className: isDark ? "text-slate-300" : "text-slate-600",
|
|
1088
|
+
size: 20,
|
|
1089
|
+
"aria-hidden": "true"
|
|
1090
|
+
}
|
|
1091
|
+
)
|
|
1092
|
+
}
|
|
1093
|
+
),
|
|
1094
|
+
/* @__PURE__ */ jsxs("div", { className: "flex-1 min-w-0", children: [
|
|
1095
|
+
/* @__PURE__ */ jsx("p", { className: `text-sm font-medium ${isDark ? "text-white" : "text-slate-900"}`, children: option.label }),
|
|
1096
|
+
/* @__PURE__ */ jsx("p", { className: `text-xs truncate ${isDark ? "text-slate-400" : "text-slate-500"}`, children: option.description })
|
|
1097
|
+
] })
|
|
1098
|
+
]
|
|
1099
|
+
},
|
|
1100
|
+
option.type
|
|
1101
|
+
);
|
|
1102
|
+
})
|
|
1103
|
+
}
|
|
1104
|
+
)
|
|
324
1105
|
] })
|
|
325
1106
|
}
|
|
326
1107
|
);
|
|
327
1108
|
};
|
|
328
1109
|
|
|
1110
|
+
function useToolbarPosition({
|
|
1111
|
+
containerRef,
|
|
1112
|
+
isVisible,
|
|
1113
|
+
minSpaceAbove = 60,
|
|
1114
|
+
topOffset = 0
|
|
1115
|
+
}) {
|
|
1116
|
+
const [showBelow, setShowBelow] = useState(false);
|
|
1117
|
+
const recalculate = useCallback(() => {
|
|
1118
|
+
if (!containerRef.current || !isVisible) {
|
|
1119
|
+
return;
|
|
1120
|
+
}
|
|
1121
|
+
const rect = containerRef.current.getBoundingClientRect();
|
|
1122
|
+
const spaceAbove = rect.top - topOffset;
|
|
1123
|
+
setShowBelow(spaceAbove < minSpaceAbove);
|
|
1124
|
+
}, [containerRef, isVisible, minSpaceAbove, topOffset]);
|
|
1125
|
+
useEffect(() => {
|
|
1126
|
+
if (!isVisible) {
|
|
1127
|
+
return;
|
|
1128
|
+
}
|
|
1129
|
+
recalculate();
|
|
1130
|
+
const handleScroll = () => recalculate();
|
|
1131
|
+
const handleResize = () => recalculate();
|
|
1132
|
+
window.addEventListener("scroll", handleScroll, { passive: true });
|
|
1133
|
+
window.addEventListener("resize", handleResize, { passive: true });
|
|
1134
|
+
const scrollParents = [];
|
|
1135
|
+
let scrollParent = containerRef.current?.parentElement;
|
|
1136
|
+
while (scrollParent) {
|
|
1137
|
+
scrollParent.addEventListener("scroll", handleScroll, { passive: true });
|
|
1138
|
+
scrollParents.push(scrollParent);
|
|
1139
|
+
scrollParent = scrollParent.parentElement;
|
|
1140
|
+
}
|
|
1141
|
+
return () => {
|
|
1142
|
+
window.removeEventListener("scroll", handleScroll);
|
|
1143
|
+
window.removeEventListener("resize", handleResize);
|
|
1144
|
+
scrollParents.forEach((parent) => {
|
|
1145
|
+
parent.removeEventListener("scroll", handleScroll);
|
|
1146
|
+
});
|
|
1147
|
+
};
|
|
1148
|
+
}, [isVisible, recalculate, containerRef]);
|
|
1149
|
+
return { showBelow, recalculate };
|
|
1150
|
+
}
|
|
1151
|
+
|
|
329
1152
|
const fontSizeMap = {
|
|
330
1153
|
sm: "text-sm leading-relaxed",
|
|
331
1154
|
base: "text-base leading-relaxed",
|
|
332
1155
|
lg: "text-lg leading-relaxed",
|
|
333
1156
|
xl: "text-xl leading-relaxed"
|
|
334
1157
|
};
|
|
335
|
-
const alignmentMap$
|
|
1158
|
+
const alignmentMap$1 = {
|
|
336
1159
|
left: "text-left",
|
|
337
1160
|
center: "text-center",
|
|
338
1161
|
right: "text-right",
|
|
339
1162
|
justify: "text-justify"
|
|
340
1163
|
};
|
|
341
|
-
const TextBlockComponent = ({
|
|
1164
|
+
const TextBlockComponent = ({
|
|
1165
|
+
block,
|
|
1166
|
+
onUpdate,
|
|
1167
|
+
readOnly,
|
|
1168
|
+
theme = "light"
|
|
1169
|
+
}) => {
|
|
342
1170
|
const [showToolbar, setShowToolbar] = useState(false);
|
|
343
1171
|
const textareaRef = useRef(null);
|
|
1172
|
+
const containerRef = useRef(null);
|
|
344
1173
|
const isDark = theme === "dark";
|
|
1174
|
+
const { showBelow } = useToolbarPosition({
|
|
1175
|
+
containerRef,
|
|
1176
|
+
isVisible: showToolbar && !readOnly,
|
|
1177
|
+
minSpaceAbove: 60
|
|
1178
|
+
});
|
|
345
1179
|
useEffect(() => {
|
|
346
1180
|
if (textareaRef.current) {
|
|
347
1181
|
textareaRef.current.style.height = "auto";
|
|
348
1182
|
textareaRef.current.style.height = textareaRef.current.scrollHeight + "px";
|
|
349
1183
|
}
|
|
350
1184
|
}, [block.content]);
|
|
351
|
-
const handleChange = useCallback(
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
onUpdate
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
1185
|
+
const handleChange = useCallback(
|
|
1186
|
+
(e) => {
|
|
1187
|
+
onUpdate({ ...block, content: e.target.value });
|
|
1188
|
+
},
|
|
1189
|
+
[block, onUpdate]
|
|
1190
|
+
);
|
|
1191
|
+
const toggleStyle = useCallback(
|
|
1192
|
+
(style) => {
|
|
1193
|
+
onUpdate({
|
|
1194
|
+
...block,
|
|
1195
|
+
style: {
|
|
1196
|
+
...block.style,
|
|
1197
|
+
[style]: !block.style?.[style]
|
|
1198
|
+
}
|
|
1199
|
+
});
|
|
1200
|
+
},
|
|
1201
|
+
[block, onUpdate]
|
|
1202
|
+
);
|
|
1203
|
+
const setAlignment = useCallback(
|
|
1204
|
+
(alignment) => {
|
|
1205
|
+
onUpdate({ ...block, alignment });
|
|
1206
|
+
},
|
|
1207
|
+
[block, onUpdate]
|
|
1208
|
+
);
|
|
1209
|
+
const setFontSize = useCallback(
|
|
1210
|
+
(fontSize) => {
|
|
1211
|
+
onUpdate({ ...block, fontSize });
|
|
1212
|
+
},
|
|
1213
|
+
[block, onUpdate]
|
|
1214
|
+
);
|
|
369
1215
|
const handleFocus = useCallback(() => setShowToolbar(true), []);
|
|
370
1216
|
const handleBlur = useCallback((e) => {
|
|
371
1217
|
if (!e.currentTarget.contains(e.relatedTarget)) {
|
|
@@ -383,87 +1229,94 @@ const TextBlockComponent = ({ block, onUpdate, readOnly, theme = "light" }) => {
|
|
|
383
1229
|
return /* @__PURE__ */ jsxs(
|
|
384
1230
|
"div",
|
|
385
1231
|
{
|
|
1232
|
+
ref: containerRef,
|
|
386
1233
|
className: "group relative",
|
|
387
1234
|
onFocus: handleFocus,
|
|
388
1235
|
onBlur: handleBlur,
|
|
389
1236
|
children: [
|
|
390
|
-
showToolbar && !readOnly && /* @__PURE__ */ jsxs(
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
{
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
1237
|
+
showToolbar && !readOnly && /* @__PURE__ */ jsxs(
|
|
1238
|
+
"div",
|
|
1239
|
+
{
|
|
1240
|
+
className: `absolute left-0 flex items-center gap-1 p-1.5 rounded-xl shadow-lg border z-10 ${showBelow ? "top-full mt-2" : "-top-12"} ${isDark ? "bg-slate-800 border-slate-600" : "bg-white border-slate-200"}`,
|
|
1241
|
+
children: [
|
|
1242
|
+
/* @__PURE__ */ jsx(
|
|
1243
|
+
"button",
|
|
1244
|
+
{
|
|
1245
|
+
onClick: () => toggleStyle("bold"),
|
|
1246
|
+
className: toolbarBtnClass(block.style?.bold),
|
|
1247
|
+
title: "Bold",
|
|
1248
|
+
children: /* @__PURE__ */ jsx(BoldIcon, { size: 16 })
|
|
1249
|
+
}
|
|
1250
|
+
),
|
|
1251
|
+
/* @__PURE__ */ jsx(
|
|
1252
|
+
"button",
|
|
1253
|
+
{
|
|
1254
|
+
onClick: () => toggleStyle("italic"),
|
|
1255
|
+
className: toolbarBtnClass(block.style?.italic),
|
|
1256
|
+
title: "Italic",
|
|
1257
|
+
children: /* @__PURE__ */ jsx(ItalicIcon, { size: 16 })
|
|
1258
|
+
}
|
|
1259
|
+
),
|
|
1260
|
+
/* @__PURE__ */ jsx(
|
|
1261
|
+
"button",
|
|
1262
|
+
{
|
|
1263
|
+
onClick: () => toggleStyle("underline"),
|
|
1264
|
+
className: toolbarBtnClass(block.style?.underline),
|
|
1265
|
+
title: "Underline",
|
|
1266
|
+
children: /* @__PURE__ */ jsx(UnderlineIcon, { size: 16 })
|
|
1267
|
+
}
|
|
1268
|
+
),
|
|
1269
|
+
/* @__PURE__ */ jsx("div", { className: `w-px h-6 mx-1 ${isDark ? "bg-slate-600" : "bg-slate-200"}` }),
|
|
1270
|
+
/* @__PURE__ */ jsx(
|
|
1271
|
+
"button",
|
|
1272
|
+
{
|
|
1273
|
+
onClick: () => setAlignment("left"),
|
|
1274
|
+
className: toolbarBtnClass(block.alignment === "left"),
|
|
1275
|
+
title: "Align Left",
|
|
1276
|
+
children: /* @__PURE__ */ jsx(AlignLeftIcon, { size: 16 })
|
|
1277
|
+
}
|
|
1278
|
+
),
|
|
1279
|
+
/* @__PURE__ */ jsx(
|
|
1280
|
+
"button",
|
|
1281
|
+
{
|
|
1282
|
+
onClick: () => setAlignment("center"),
|
|
1283
|
+
className: toolbarBtnClass(block.alignment === "center"),
|
|
1284
|
+
title: "Align Center",
|
|
1285
|
+
children: /* @__PURE__ */ jsx(AlignCenterIcon, { size: 16 })
|
|
1286
|
+
}
|
|
1287
|
+
),
|
|
1288
|
+
/* @__PURE__ */ jsx(
|
|
1289
|
+
"button",
|
|
1290
|
+
{
|
|
1291
|
+
onClick: () => setAlignment("right"),
|
|
1292
|
+
className: toolbarBtnClass(block.alignment === "right"),
|
|
1293
|
+
title: "Align Right",
|
|
1294
|
+
children: /* @__PURE__ */ jsx(AlignRightIcon, { size: 16 })
|
|
1295
|
+
}
|
|
1296
|
+
),
|
|
1297
|
+
/* @__PURE__ */ jsx("div", { className: `w-px h-6 mx-1 ${isDark ? "bg-slate-600" : "bg-slate-200"}` }),
|
|
1298
|
+
/* @__PURE__ */ jsxs(
|
|
1299
|
+
"select",
|
|
1300
|
+
{
|
|
1301
|
+
value: block.fontSize || "base",
|
|
1302
|
+
onChange: (e) => setFontSize(e.target.value),
|
|
1303
|
+
className: `px-2 py-1.5 text-sm rounded-lg border ${isDark ? "bg-slate-700 border-slate-600 text-slate-200" : "bg-white border-slate-200 text-slate-700"}`,
|
|
1304
|
+
children: [
|
|
1305
|
+
/* @__PURE__ */ jsx("option", { value: "sm", children: "Small" }),
|
|
1306
|
+
/* @__PURE__ */ jsx("option", { value: "base", children: "Normal" }),
|
|
1307
|
+
/* @__PURE__ */ jsx("option", { value: "lg", children: "Large" }),
|
|
1308
|
+
/* @__PURE__ */ jsx("option", { value: "xl", children: "X-Large" })
|
|
1309
|
+
]
|
|
1310
|
+
}
|
|
1311
|
+
)
|
|
1312
|
+
]
|
|
1313
|
+
}
|
|
1314
|
+
),
|
|
462
1315
|
readOnly ? /* @__PURE__ */ jsx(
|
|
463
1316
|
"div",
|
|
464
1317
|
{
|
|
465
1318
|
style: textStyle,
|
|
466
|
-
className: `w-full whitespace-pre-wrap break-words ${fontSizeMap[block.fontSize || "base"]} ${alignmentMap$
|
|
1319
|
+
className: `w-full whitespace-pre-wrap break-words ${fontSizeMap[block.fontSize || "base"]} ${alignmentMap$1[block.alignment || "left"]} ${isDark ? "text-slate-200" : "text-slate-800"}`,
|
|
467
1320
|
children: block.content || /* @__PURE__ */ jsx("span", { className: isDark ? "text-slate-500" : "text-slate-400", children: "Empty text block" })
|
|
468
1321
|
}
|
|
469
1322
|
) : /* @__PURE__ */ jsx(
|
|
@@ -474,7 +1327,7 @@ const TextBlockComponent = ({ block, onUpdate, readOnly, theme = "light" }) => {
|
|
|
474
1327
|
onChange: handleChange,
|
|
475
1328
|
placeholder: "Start typing...",
|
|
476
1329
|
style: textStyle,
|
|
477
|
-
className: `w-full min-h-[2.5rem] p-2 resize-none outline-none bg-transparent ${fontSizeMap[block.fontSize || "base"]} ${alignmentMap$
|
|
1330
|
+
className: `w-full min-h-[2.5rem] p-2 resize-none outline-none bg-transparent ${fontSizeMap[block.fontSize || "base"]} ${alignmentMap$1[block.alignment || "left"]} ${isDark ? "text-slate-200 placeholder:text-slate-500" : "text-slate-800 placeholder:text-slate-400"}`,
|
|
478
1331
|
rows: 1
|
|
479
1332
|
}
|
|
480
1333
|
)
|
|
@@ -492,15 +1345,26 @@ const headingSizeMap = {
|
|
|
492
1345
|
5: "text-lg font-medium",
|
|
493
1346
|
6: "text-base font-medium"
|
|
494
1347
|
};
|
|
495
|
-
const alignmentMap
|
|
1348
|
+
const alignmentMap = {
|
|
496
1349
|
left: "text-left",
|
|
497
1350
|
center: "text-center",
|
|
498
1351
|
right: "text-right"
|
|
499
1352
|
};
|
|
500
|
-
const HeadingBlock = ({
|
|
1353
|
+
const HeadingBlock = ({
|
|
1354
|
+
block,
|
|
1355
|
+
onUpdate,
|
|
1356
|
+
readOnly,
|
|
1357
|
+
theme = "light"
|
|
1358
|
+
}) => {
|
|
501
1359
|
const [showToolbar, setShowToolbar] = useState(false);
|
|
502
1360
|
const inputRef = useRef(null);
|
|
1361
|
+
const containerRef = useRef(null);
|
|
503
1362
|
const isDark = theme === "dark";
|
|
1363
|
+
const { showBelow } = useToolbarPosition({
|
|
1364
|
+
containerRef,
|
|
1365
|
+
isVisible: showToolbar && !readOnly,
|
|
1366
|
+
minSpaceAbove: 60
|
|
1367
|
+
});
|
|
504
1368
|
const handleChange = (e) => {
|
|
505
1369
|
onUpdate({ ...block, content: e.target.value });
|
|
506
1370
|
};
|
|
@@ -514,6 +1378,7 @@ const HeadingBlock = ({ block, onUpdate, readOnly, theme = "light" }) => {
|
|
|
514
1378
|
return /* @__PURE__ */ jsxs(
|
|
515
1379
|
"div",
|
|
516
1380
|
{
|
|
1381
|
+
ref: containerRef,
|
|
517
1382
|
className: "group relative",
|
|
518
1383
|
onFocus: () => setShowToolbar(true),
|
|
519
1384
|
onBlur: (e) => {
|
|
@@ -522,56 +1387,62 @@ const HeadingBlock = ({ block, onUpdate, readOnly, theme = "light" }) => {
|
|
|
522
1387
|
}
|
|
523
1388
|
},
|
|
524
1389
|
children: [
|
|
525
|
-
showToolbar && !readOnly && /* @__PURE__ */ jsxs(
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
{
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
1390
|
+
showToolbar && !readOnly && /* @__PURE__ */ jsxs(
|
|
1391
|
+
"div",
|
|
1392
|
+
{
|
|
1393
|
+
className: `absolute left-0 flex items-center gap-1 p-1.5 rounded-xl shadow-lg border z-10 ${showBelow ? "top-full mt-2" : "-top-12"} ${isDark ? "bg-slate-800 border-slate-600" : "bg-white border-slate-200"}`,
|
|
1394
|
+
children: [
|
|
1395
|
+
/* @__PURE__ */ jsxs(
|
|
1396
|
+
"select",
|
|
1397
|
+
{
|
|
1398
|
+
value: block.level,
|
|
1399
|
+
onChange: (e) => setLevel(parseInt(e.target.value)),
|
|
1400
|
+
className: `px-2 py-1.5 text-sm rounded-lg border ${isDark ? "bg-slate-700 border-slate-600 text-slate-200" : "bg-white border-slate-200 text-slate-700"}`,
|
|
1401
|
+
children: [
|
|
1402
|
+
/* @__PURE__ */ jsx("option", { value: 1, children: "Heading 1" }),
|
|
1403
|
+
/* @__PURE__ */ jsx("option", { value: 2, children: "Heading 2" }),
|
|
1404
|
+
/* @__PURE__ */ jsx("option", { value: 3, children: "Heading 3" }),
|
|
1405
|
+
/* @__PURE__ */ jsx("option", { value: 4, children: "Heading 4" }),
|
|
1406
|
+
/* @__PURE__ */ jsx("option", { value: 5, children: "Heading 5" }),
|
|
1407
|
+
/* @__PURE__ */ jsx("option", { value: 6, children: "Heading 6" })
|
|
1408
|
+
]
|
|
1409
|
+
}
|
|
1410
|
+
),
|
|
1411
|
+
/* @__PURE__ */ jsx("div", { className: `w-px h-6 mx-1 ${isDark ? "bg-slate-600" : "bg-slate-200"}` }),
|
|
1412
|
+
/* @__PURE__ */ jsx(
|
|
1413
|
+
"button",
|
|
1414
|
+
{
|
|
1415
|
+
onClick: () => setAlignment("left"),
|
|
1416
|
+
className: toolbarBtnClass(block.alignment === "left"),
|
|
1417
|
+
title: "Align Left",
|
|
1418
|
+
children: /* @__PURE__ */ jsx(AlignLeftIcon, { size: 16 })
|
|
1419
|
+
}
|
|
1420
|
+
),
|
|
1421
|
+
/* @__PURE__ */ jsx(
|
|
1422
|
+
"button",
|
|
1423
|
+
{
|
|
1424
|
+
onClick: () => setAlignment("center"),
|
|
1425
|
+
className: toolbarBtnClass(block.alignment === "center"),
|
|
1426
|
+
title: "Align Center",
|
|
1427
|
+
children: /* @__PURE__ */ jsx(AlignCenterIcon, { size: 16 })
|
|
1428
|
+
}
|
|
1429
|
+
),
|
|
1430
|
+
/* @__PURE__ */ jsx(
|
|
1431
|
+
"button",
|
|
1432
|
+
{
|
|
1433
|
+
onClick: () => setAlignment("right"),
|
|
1434
|
+
className: toolbarBtnClass(block.alignment === "right"),
|
|
1435
|
+
title: "Align Right",
|
|
1436
|
+
children: /* @__PURE__ */ jsx(AlignRightIcon, { size: 16 })
|
|
1437
|
+
}
|
|
1438
|
+
)
|
|
1439
|
+
]
|
|
1440
|
+
}
|
|
1441
|
+
),
|
|
571
1442
|
readOnly ? /* @__PURE__ */ jsx(
|
|
572
1443
|
"div",
|
|
573
1444
|
{
|
|
574
|
-
className: `w-full p-2 ${headingSizeMap[block.level]} ${alignmentMap
|
|
1445
|
+
className: `w-full p-2 ${headingSizeMap[block.level]} ${alignmentMap[block.alignment || "left"]} ${isDark ? "text-white" : "text-slate-900"}`,
|
|
575
1446
|
children: block.content || /* @__PURE__ */ jsx("span", { className: isDark ? "text-slate-500" : "text-slate-400", children: "Empty heading" })
|
|
576
1447
|
}
|
|
577
1448
|
) : /* @__PURE__ */ jsx(
|
|
@@ -582,7 +1453,7 @@ const HeadingBlock = ({ block, onUpdate, readOnly, theme = "light" }) => {
|
|
|
582
1453
|
value: block.content,
|
|
583
1454
|
onChange: handleChange,
|
|
584
1455
|
placeholder: `Heading ${block.level}`,
|
|
585
|
-
className: `w-full p-2 outline-none bg-transparent ${headingSizeMap[block.level]} ${alignmentMap
|
|
1456
|
+
className: `w-full p-2 outline-none bg-transparent ${headingSizeMap[block.level]} ${alignmentMap[block.alignment || "left"]} ${isDark ? "text-white placeholder:text-slate-500" : "text-slate-900 placeholder:text-slate-400"}`
|
|
586
1457
|
}
|
|
587
1458
|
)
|
|
588
1459
|
]
|
|
@@ -590,16 +1461,22 @@ const HeadingBlock = ({ block, onUpdate, readOnly, theme = "light" }) => {
|
|
|
590
1461
|
);
|
|
591
1462
|
};
|
|
592
1463
|
|
|
593
|
-
const
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
1464
|
+
const ImageBlock = ({
|
|
1465
|
+
block,
|
|
1466
|
+
onUpdate,
|
|
1467
|
+
readOnly,
|
|
1468
|
+
theme = "light"
|
|
1469
|
+
}) => {
|
|
599
1470
|
const [showToolbar, setShowToolbar] = useState(false);
|
|
600
1471
|
const [isDragging, setIsDragging] = useState(false);
|
|
601
1472
|
const fileInputRef = useRef(null);
|
|
1473
|
+
const containerRef = useRef(null);
|
|
602
1474
|
const isDark = theme === "dark";
|
|
1475
|
+
const { showBelow } = useToolbarPosition({
|
|
1476
|
+
containerRef,
|
|
1477
|
+
isVisible: showToolbar && !readOnly && !!block.src,
|
|
1478
|
+
minSpaceAbove: 60
|
|
1479
|
+
});
|
|
603
1480
|
const handleFileChange = async (file) => {
|
|
604
1481
|
if (file && file.type.startsWith("image/")) {
|
|
605
1482
|
try {
|
|
@@ -668,7 +1545,12 @@ const ImageBlock = ({ block, onUpdate, readOnly, theme = "light" }) => {
|
|
|
668
1545
|
}
|
|
669
1546
|
),
|
|
670
1547
|
/* @__PURE__ */ jsxs("div", { className: "flex flex-col items-center justify-center text-center", children: [
|
|
671
|
-
/* @__PURE__ */ jsx(
|
|
1548
|
+
/* @__PURE__ */ jsx(
|
|
1549
|
+
UploadIcon,
|
|
1550
|
+
{
|
|
1551
|
+
className: `w-12 h-12 mb-4 ${isDark ? "text-slate-500" : "text-slate-400"}`
|
|
1552
|
+
}
|
|
1553
|
+
),
|
|
672
1554
|
/* @__PURE__ */ jsx("p", { className: `mb-2 ${isDark ? "text-slate-400" : "text-slate-600"}`, children: "Drag and drop an image here, or" }),
|
|
673
1555
|
/* @__PURE__ */ jsx(
|
|
674
1556
|
"button",
|
|
@@ -683,101 +1565,122 @@ const ImageBlock = ({ block, onUpdate, readOnly, theme = "light" }) => {
|
|
|
683
1565
|
] })
|
|
684
1566
|
]
|
|
685
1567
|
}
|
|
686
|
-
);
|
|
687
|
-
}
|
|
688
|
-
return /* @__PURE__ */ jsxs(
|
|
689
|
-
"div",
|
|
690
|
-
{
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
className: `
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
{
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
1568
|
+
);
|
|
1569
|
+
}
|
|
1570
|
+
return /* @__PURE__ */ jsxs(
|
|
1571
|
+
"div",
|
|
1572
|
+
{
|
|
1573
|
+
ref: containerRef,
|
|
1574
|
+
className: "group relative",
|
|
1575
|
+
onFocus: () => setShowToolbar(true),
|
|
1576
|
+
onBlur: (e) => {
|
|
1577
|
+
if (!e.currentTarget.contains(e.relatedTarget)) {
|
|
1578
|
+
setShowToolbar(false);
|
|
1579
|
+
}
|
|
1580
|
+
},
|
|
1581
|
+
children: [
|
|
1582
|
+
showToolbar && !readOnly && /* @__PURE__ */ jsxs(
|
|
1583
|
+
"div",
|
|
1584
|
+
{
|
|
1585
|
+
className: `absolute left-1/2 -translate-x-1/2 flex items-center gap-1 p-1.5 rounded-xl shadow-lg border z-10 ${showBelow ? "top-full mt-2" : "-top-12"} ${isDark ? "bg-slate-800 border-slate-600" : "bg-white border-slate-200"}`,
|
|
1586
|
+
children: [
|
|
1587
|
+
/* @__PURE__ */ jsx(
|
|
1588
|
+
"button",
|
|
1589
|
+
{
|
|
1590
|
+
onClick: () => setAlignment("left"),
|
|
1591
|
+
className: toolbarBtnClass(block.alignment === "left"),
|
|
1592
|
+
title: "Align Left",
|
|
1593
|
+
children: /* @__PURE__ */ jsx(AlignLeftIcon, { size: 16 })
|
|
1594
|
+
}
|
|
1595
|
+
),
|
|
1596
|
+
/* @__PURE__ */ jsx(
|
|
1597
|
+
"button",
|
|
1598
|
+
{
|
|
1599
|
+
onClick: () => setAlignment("center"),
|
|
1600
|
+
className: toolbarBtnClass(block.alignment === "center"),
|
|
1601
|
+
title: "Align Center",
|
|
1602
|
+
children: /* @__PURE__ */ jsx(AlignCenterIcon, { size: 16 })
|
|
1603
|
+
}
|
|
1604
|
+
),
|
|
1605
|
+
/* @__PURE__ */ jsx(
|
|
1606
|
+
"button",
|
|
1607
|
+
{
|
|
1608
|
+
onClick: () => setAlignment("right"),
|
|
1609
|
+
className: toolbarBtnClass(block.alignment === "right"),
|
|
1610
|
+
title: "Align Right",
|
|
1611
|
+
children: /* @__PURE__ */ jsx(AlignRightIcon, { size: 16 })
|
|
1612
|
+
}
|
|
1613
|
+
),
|
|
1614
|
+
/* @__PURE__ */ jsx("div", { className: `w-px h-6 mx-1 ${isDark ? "bg-slate-600" : "bg-slate-200"}` }),
|
|
1615
|
+
/* @__PURE__ */ jsx(
|
|
1616
|
+
"input",
|
|
1617
|
+
{
|
|
1618
|
+
type: "number",
|
|
1619
|
+
value: block.width || "",
|
|
1620
|
+
onChange: handleWidthChange,
|
|
1621
|
+
placeholder: "Width",
|
|
1622
|
+
className: `w-20 px-2 py-1.5 text-sm rounded-lg border ${isDark ? "bg-slate-700 border-slate-600 text-slate-200" : "bg-white border-slate-200 text-slate-700"}`
|
|
1623
|
+
}
|
|
1624
|
+
),
|
|
1625
|
+
/* @__PURE__ */ jsx("div", { className: `w-px h-6 mx-1 ${isDark ? "bg-slate-600" : "bg-slate-200"}` }),
|
|
1626
|
+
/* @__PURE__ */ jsx(
|
|
1627
|
+
"button",
|
|
1628
|
+
{
|
|
1629
|
+
onClick: clearImage,
|
|
1630
|
+
className: `p-2 rounded-lg hover:text-red-500 ${isDark ? "hover:bg-red-950/30 text-slate-400" : "hover:bg-red-50 text-slate-400"}`,
|
|
1631
|
+
title: "Remove Image",
|
|
1632
|
+
children: /* @__PURE__ */ jsx(TrashIcon, { size: 16 })
|
|
1633
|
+
}
|
|
1634
|
+
)
|
|
1635
|
+
]
|
|
1636
|
+
}
|
|
1637
|
+
),
|
|
1638
|
+
/* @__PURE__ */ jsxs(
|
|
1639
|
+
"figure",
|
|
1640
|
+
{
|
|
1641
|
+
className: "flex flex-col items-center w-full",
|
|
1642
|
+
style: { maxWidth: "100%" },
|
|
1643
|
+
children: [
|
|
1644
|
+
/* @__PURE__ */ jsx(
|
|
1645
|
+
"img",
|
|
1646
|
+
{
|
|
1647
|
+
src: block.src,
|
|
1648
|
+
alt: block.alt || "",
|
|
1649
|
+
className: "max-w-full h-auto rounded-xl shadow-sm",
|
|
1650
|
+
style: { maxWidth: block.width ? `${block.width}px` : "100%" }
|
|
1651
|
+
}
|
|
1652
|
+
),
|
|
1653
|
+
!readOnly ? /* @__PURE__ */ jsxs("div", { className: "mt-3 space-y-2", children: [
|
|
1654
|
+
/* @__PURE__ */ jsx(
|
|
1655
|
+
"input",
|
|
1656
|
+
{
|
|
1657
|
+
type: "text",
|
|
1658
|
+
value: block.caption || "",
|
|
1659
|
+
onChange: handleCaptionChange,
|
|
1660
|
+
placeholder: "Add a caption...",
|
|
1661
|
+
className: `w-full text-center text-sm bg-transparent outline-none ${isDark ? "text-slate-400 placeholder:text-slate-500" : "text-slate-600 placeholder:text-slate-400"}`
|
|
1662
|
+
}
|
|
1663
|
+
),
|
|
1664
|
+
/* @__PURE__ */ jsx(
|
|
1665
|
+
"input",
|
|
1666
|
+
{
|
|
1667
|
+
type: "text",
|
|
1668
|
+
value: block.alt || "",
|
|
1669
|
+
onChange: handleAltChange,
|
|
1670
|
+
placeholder: "Alt text for accessibility...",
|
|
1671
|
+
className: `w-full text-center text-xs bg-transparent outline-none ${isDark ? "text-slate-500 placeholder:text-slate-600" : "text-slate-500 placeholder:text-slate-400"}`
|
|
1672
|
+
}
|
|
1673
|
+
)
|
|
1674
|
+
] }) : block.caption ? /* @__PURE__ */ jsx(
|
|
1675
|
+
"figcaption",
|
|
1676
|
+
{
|
|
1677
|
+
className: `mt-3 text-center text-sm ${isDark ? "text-slate-400" : "text-slate-600"}`,
|
|
1678
|
+
children: block.caption
|
|
1679
|
+
}
|
|
1680
|
+
) : null
|
|
1681
|
+
]
|
|
1682
|
+
}
|
|
1683
|
+
)
|
|
781
1684
|
]
|
|
782
1685
|
}
|
|
783
1686
|
);
|
|
@@ -813,7 +1716,12 @@ const SUPPORTED_LANGUAGES = [
|
|
|
813
1716
|
"plaintext"
|
|
814
1717
|
];
|
|
815
1718
|
|
|
816
|
-
const CodeBlock = ({
|
|
1719
|
+
const CodeBlock = ({
|
|
1720
|
+
block,
|
|
1721
|
+
onUpdate,
|
|
1722
|
+
readOnly,
|
|
1723
|
+
theme = "light"
|
|
1724
|
+
}) => {
|
|
817
1725
|
const [copied, setCopied] = useState(false);
|
|
818
1726
|
const textareaRef = useRef(null);
|
|
819
1727
|
const isDark = theme === "dark";
|
|
@@ -849,58 +1757,78 @@ const CodeBlock = ({ block, onUpdate, readOnly, theme = "light" }) => {
|
|
|
849
1757
|
{
|
|
850
1758
|
className: `group relative rounded-xl overflow-hidden ${isDark ? "bg-slate-950" : "bg-slate-900"}`,
|
|
851
1759
|
children: [
|
|
852
|
-
/* @__PURE__ */ jsxs(
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
/* @__PURE__ */
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
1760
|
+
/* @__PURE__ */ jsxs(
|
|
1761
|
+
"div",
|
|
1762
|
+
{
|
|
1763
|
+
className: `flex items-center justify-between px-4 py-2.5 border-b ${isDark ? "bg-slate-900 border-slate-800" : "bg-slate-800 border-slate-700"}`,
|
|
1764
|
+
children: [
|
|
1765
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3", children: [
|
|
1766
|
+
/* @__PURE__ */ jsxs("div", { className: "flex gap-1.5", children: [
|
|
1767
|
+
/* @__PURE__ */ jsx("div", { className: "w-3 h-3 rounded-full bg-red-500/80" }),
|
|
1768
|
+
/* @__PURE__ */ jsx("div", { className: "w-3 h-3 rounded-full bg-yellow-500/80" }),
|
|
1769
|
+
/* @__PURE__ */ jsx("div", { className: "w-3 h-3 rounded-full bg-green-500/80" })
|
|
1770
|
+
] }),
|
|
1771
|
+
!readOnly ? /* @__PURE__ */ jsx(
|
|
1772
|
+
"input",
|
|
1773
|
+
{
|
|
1774
|
+
type: "text",
|
|
1775
|
+
value: block.filename || "",
|
|
1776
|
+
onChange: handleFilenameChange,
|
|
1777
|
+
placeholder: "filename.js",
|
|
1778
|
+
className: "text-sm text-slate-400 bg-transparent outline-none placeholder:text-slate-600 w-32"
|
|
1779
|
+
}
|
|
1780
|
+
) : block.filename ? /* @__PURE__ */ jsx("span", { className: "text-sm text-slate-400", children: block.filename }) : null
|
|
1781
|
+
] }),
|
|
1782
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
|
|
1783
|
+
!readOnly && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
1784
|
+
/* @__PURE__ */ jsx(
|
|
1785
|
+
"select",
|
|
1786
|
+
{
|
|
1787
|
+
value: block.language,
|
|
1788
|
+
onChange: handleLanguageChange,
|
|
1789
|
+
className: "text-xs px-2 py-1.5 bg-slate-700 text-slate-300 rounded-lg border border-slate-600 outline-none",
|
|
1790
|
+
children: SUPPORTED_LANGUAGES.map((lang) => /* @__PURE__ */ jsx(
|
|
1791
|
+
"option",
|
|
1792
|
+
{
|
|
1793
|
+
value: lang,
|
|
1794
|
+
children: lang
|
|
1795
|
+
},
|
|
1796
|
+
lang
|
|
1797
|
+
))
|
|
1798
|
+
}
|
|
1799
|
+
),
|
|
1800
|
+
/* @__PURE__ */ jsx(
|
|
1801
|
+
"button",
|
|
1802
|
+
{
|
|
1803
|
+
onClick: toggleLineNumbers,
|
|
1804
|
+
className: `text-xs px-2 py-1.5 rounded-lg transition-colors ${block.showLineNumbers ? "bg-indigo-600 text-white" : "bg-slate-700 text-slate-300 hover:bg-slate-600"}`,
|
|
1805
|
+
children: "#"
|
|
1806
|
+
}
|
|
1807
|
+
)
|
|
1808
|
+
] }),
|
|
1809
|
+
/* @__PURE__ */ jsx(
|
|
1810
|
+
"button",
|
|
1811
|
+
{
|
|
1812
|
+
onClick: copyToClipboard,
|
|
1813
|
+
className: "p-1.5 rounded-lg hover:bg-slate-700 text-slate-400 hover:text-white transition-colors",
|
|
1814
|
+
title: "Copy code",
|
|
1815
|
+
children: copied ? /* @__PURE__ */ jsx(CheckIcon, { size: 16 }) : /* @__PURE__ */ jsx(CopyIcon, { size: 16 })
|
|
1816
|
+
}
|
|
1817
|
+
)
|
|
1818
|
+
] })
|
|
1819
|
+
]
|
|
1820
|
+
}
|
|
1821
|
+
),
|
|
1822
|
+
/* @__PURE__ */ jsxs("div", { className: "relative flex", children: [
|
|
1823
|
+
block.showLineNumbers && /* @__PURE__ */ jsx("div", { className: "flex-shrink-0 py-4 pl-4 pr-3 text-right select-none border-r border-slate-800", children: lineNumbers.map((num) => /* @__PURE__ */ jsx(
|
|
1824
|
+
"div",
|
|
1825
|
+
{
|
|
1826
|
+
className: "text-xs text-slate-600 leading-6 font-mono",
|
|
1827
|
+
children: num
|
|
1828
|
+
},
|
|
1829
|
+
num
|
|
1830
|
+
)) }),
|
|
1831
|
+
/* @__PURE__ */ jsx("div", { className: "flex-1 p-4", children: readOnly ? /* @__PURE__ */ jsx("pre", { className: "text-sm text-slate-100 font-mono leading-6 whitespace-pre overflow-x-auto", children: /* @__PURE__ */ jsx("code", { children: block.code }) }) : /* @__PURE__ */ jsx(
|
|
904
1832
|
"textarea",
|
|
905
1833
|
{
|
|
906
1834
|
ref: textareaRef,
|
|
@@ -908,8 +1836,8 @@ const CodeBlock = ({ block, onUpdate, readOnly, theme = "light" }) => {
|
|
|
908
1836
|
onChange: handleCodeChange,
|
|
909
1837
|
placeholder: "// Write your code here...",
|
|
910
1838
|
spellCheck: false,
|
|
911
|
-
className: "w-full min-h-[100px] text-sm text-slate-100 font-mono leading-6 bg-transparent outline-none resize-none placeholder:text-slate-600",
|
|
912
|
-
style: { tabSize: 2 },
|
|
1839
|
+
className: "w-full min-h-[100px] text-sm text-slate-100 font-mono leading-6 bg-transparent outline-none resize-none placeholder:text-slate-600 overflow-hidden",
|
|
1840
|
+
style: { tabSize: 2, height: "auto" },
|
|
913
1841
|
onKeyDown: (e) => {
|
|
914
1842
|
if (e.key === "Tab") {
|
|
915
1843
|
e.preventDefault();
|
|
@@ -933,10 +1861,45 @@ const CodeBlock = ({ block, onUpdate, readOnly, theme = "light" }) => {
|
|
|
933
1861
|
);
|
|
934
1862
|
};
|
|
935
1863
|
|
|
936
|
-
const TableBlock = ({
|
|
1864
|
+
const TableBlock = ({
|
|
1865
|
+
block,
|
|
1866
|
+
onUpdate,
|
|
1867
|
+
readOnly,
|
|
1868
|
+
theme = "light"
|
|
1869
|
+
}) => {
|
|
937
1870
|
const [showToolbar, setShowToolbar] = useState(false);
|
|
938
|
-
const [
|
|
1871
|
+
const [activeCell, setActiveCell] = useState(null);
|
|
1872
|
+
const [toolbarPosition, setToolbarPosition] = useState(null);
|
|
1873
|
+
const containerRef = useRef(null);
|
|
1874
|
+
const toolbarRef = useRef(null);
|
|
1875
|
+
const cellRefs = useRef(/* @__PURE__ */ new Map());
|
|
939
1876
|
const isDark = theme === "dark";
|
|
1877
|
+
const updateToolbarPosition = (row, col) => {
|
|
1878
|
+
const cellKey = `${row}-${col}`;
|
|
1879
|
+
const cellEl = cellRefs.current.get(cellKey);
|
|
1880
|
+
const containerEl = containerRef.current;
|
|
1881
|
+
if (cellEl && containerEl) {
|
|
1882
|
+
const cellRect = cellEl.getBoundingClientRect();
|
|
1883
|
+
const containerRect = containerEl.getBoundingClientRect();
|
|
1884
|
+
const containerWidth = containerRect.width;
|
|
1885
|
+
let left = cellRect.left - containerRect.left;
|
|
1886
|
+
const toolbarWidth = 520;
|
|
1887
|
+
const availableRight = containerWidth - left;
|
|
1888
|
+
if (availableRight < toolbarWidth) {
|
|
1889
|
+
left = Math.max(0, containerWidth - toolbarWidth);
|
|
1890
|
+
}
|
|
1891
|
+
setToolbarPosition({
|
|
1892
|
+
top: cellRect.top - containerRect.top - 44,
|
|
1893
|
+
// 44px above cell
|
|
1894
|
+
left: Math.max(0, left)
|
|
1895
|
+
});
|
|
1896
|
+
}
|
|
1897
|
+
};
|
|
1898
|
+
const handleCellFocus = (row, col) => {
|
|
1899
|
+
setActiveCell({ row, col });
|
|
1900
|
+
setShowToolbar(true);
|
|
1901
|
+
setTimeout(() => updateToolbarPosition(row, col), 0);
|
|
1902
|
+
};
|
|
940
1903
|
const updateCell = (rowIndex, colIndex, content) => {
|
|
941
1904
|
const currentRow = block.rows[rowIndex];
|
|
942
1905
|
if (!currentRow) return;
|
|
@@ -969,6 +1932,44 @@ const TableBlock = ({ block, onUpdate, readOnly, theme = "light" }) => {
|
|
|
969
1932
|
const newRows = block.rows.map((row) => row.filter((_, i) => i !== colIndex));
|
|
970
1933
|
onUpdate({ ...block, rows: newRows });
|
|
971
1934
|
};
|
|
1935
|
+
const moveRowUp = (rowIndex) => {
|
|
1936
|
+
if (rowIndex === 0) return;
|
|
1937
|
+
const newRows = [...block.rows];
|
|
1938
|
+
const temp = newRows[rowIndex - 1];
|
|
1939
|
+
newRows[rowIndex - 1] = newRows[rowIndex];
|
|
1940
|
+
newRows[rowIndex] = temp;
|
|
1941
|
+
onUpdate({ ...block, rows: newRows });
|
|
1942
|
+
};
|
|
1943
|
+
const moveRowDown = (rowIndex) => {
|
|
1944
|
+
if (rowIndex >= block.rows.length - 1) return;
|
|
1945
|
+
const newRows = [...block.rows];
|
|
1946
|
+
const temp = newRows[rowIndex];
|
|
1947
|
+
newRows[rowIndex] = newRows[rowIndex + 1];
|
|
1948
|
+
newRows[rowIndex + 1] = temp;
|
|
1949
|
+
onUpdate({ ...block, rows: newRows });
|
|
1950
|
+
};
|
|
1951
|
+
const moveColumnLeft = (colIndex) => {
|
|
1952
|
+
if (colIndex === 0) return;
|
|
1953
|
+
const newRows = block.rows.map((row) => {
|
|
1954
|
+
const newRow = [...row];
|
|
1955
|
+
const temp = newRow[colIndex - 1];
|
|
1956
|
+
newRow[colIndex - 1] = newRow[colIndex];
|
|
1957
|
+
newRow[colIndex] = temp;
|
|
1958
|
+
return newRow;
|
|
1959
|
+
});
|
|
1960
|
+
onUpdate({ ...block, rows: newRows });
|
|
1961
|
+
};
|
|
1962
|
+
const moveColumnRight = (colIndex) => {
|
|
1963
|
+
if (colIndex >= (block.rows[0]?.length ?? 0) - 1) return;
|
|
1964
|
+
const newRows = block.rows.map((row) => {
|
|
1965
|
+
const newRow = [...row];
|
|
1966
|
+
const temp = newRow[colIndex];
|
|
1967
|
+
newRow[colIndex] = newRow[colIndex + 1];
|
|
1968
|
+
newRow[colIndex + 1] = temp;
|
|
1969
|
+
return newRow;
|
|
1970
|
+
});
|
|
1971
|
+
onUpdate({ ...block, rows: newRows });
|
|
1972
|
+
};
|
|
972
1973
|
const toggleHeader = () => {
|
|
973
1974
|
const newRows = block.rows.map(
|
|
974
1975
|
(row, rowIndex) => row.map((cell) => ({
|
|
@@ -978,26 +1979,14 @@ const TableBlock = ({ block, onUpdate, readOnly, theme = "light" }) => {
|
|
|
978
1979
|
);
|
|
979
1980
|
onUpdate({ ...block, rows: newRows, hasHeader: !block.hasHeader });
|
|
980
1981
|
};
|
|
981
|
-
const setCellAlignment = (alignment) => {
|
|
982
|
-
if (!selectedCell) return;
|
|
983
|
-
const currentRow = block.rows[selectedCell.row];
|
|
984
|
-
if (!currentRow) return;
|
|
985
|
-
const currentCell = currentRow[selectedCell.col];
|
|
986
|
-
if (!currentCell) return;
|
|
987
|
-
const newRows = [...block.rows];
|
|
988
|
-
const newRow = [...currentRow];
|
|
989
|
-
newRow[selectedCell.col] = {
|
|
990
|
-
...currentCell,
|
|
991
|
-
alignment
|
|
992
|
-
};
|
|
993
|
-
newRows[selectedCell.row] = newRow;
|
|
994
|
-
onUpdate({ ...block, rows: newRows });
|
|
995
|
-
};
|
|
996
1982
|
const toolbarBtnClass = (isActive) => `px-2 py-1 text-sm rounded-lg transition-colors ${isActive ? isDark ? "bg-indigo-900/50 text-indigo-400" : "bg-indigo-100 text-indigo-600" : isDark ? "hover:bg-slate-700 text-slate-300" : "hover:bg-slate-100 text-slate-700"}`;
|
|
997
1983
|
return /* @__PURE__ */ jsxs(
|
|
998
1984
|
"div",
|
|
999
1985
|
{
|
|
1986
|
+
ref: containerRef,
|
|
1000
1987
|
className: "group relative",
|
|
1988
|
+
tabIndex: 0,
|
|
1989
|
+
onClick: () => setShowToolbar(true),
|
|
1001
1990
|
onFocus: () => setShowToolbar(true),
|
|
1002
1991
|
onBlur: (e) => {
|
|
1003
1992
|
if (!e.currentTarget.contains(e.relatedTarget)) {
|
|
@@ -1005,114 +1994,194 @@ const TableBlock = ({ block, onUpdate, readOnly, theme = "light" }) => {
|
|
|
1005
1994
|
}
|
|
1006
1995
|
},
|
|
1007
1996
|
children: [
|
|
1008
|
-
showToolbar && !readOnly && /* @__PURE__ */ jsxs(
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
"
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
}
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1997
|
+
showToolbar && !readOnly && activeCell && toolbarPosition && /* @__PURE__ */ jsxs(
|
|
1998
|
+
"div",
|
|
1999
|
+
{
|
|
2000
|
+
ref: toolbarRef,
|
|
2001
|
+
style: { top: toolbarPosition.top, left: toolbarPosition.left },
|
|
2002
|
+
className: `absolute flex items-center gap-1 p-1.5 rounded-xl shadow-lg border z-50 whitespace-nowrap ${isDark ? "bg-slate-800 border-slate-600" : "bg-white border-slate-200"}`,
|
|
2003
|
+
children: [
|
|
2004
|
+
/* @__PURE__ */ jsxs(
|
|
2005
|
+
"button",
|
|
2006
|
+
{
|
|
2007
|
+
onMouseDown: (e) => {
|
|
2008
|
+
e.preventDefault();
|
|
2009
|
+
addRow();
|
|
2010
|
+
},
|
|
2011
|
+
className: `flex items-center gap-1 ${toolbarBtnClass()}`,
|
|
2012
|
+
title: "Add Row",
|
|
2013
|
+
children: [
|
|
2014
|
+
/* @__PURE__ */ jsx(PlusIcon, { size: 14 }),
|
|
2015
|
+
" Row"
|
|
2016
|
+
]
|
|
2017
|
+
}
|
|
2018
|
+
),
|
|
2019
|
+
/* @__PURE__ */ jsxs(
|
|
2020
|
+
"button",
|
|
2021
|
+
{
|
|
2022
|
+
onMouseDown: (e) => {
|
|
2023
|
+
e.preventDefault();
|
|
2024
|
+
addColumn();
|
|
2025
|
+
},
|
|
2026
|
+
className: `flex items-center gap-1 ${toolbarBtnClass()}`,
|
|
2027
|
+
title: "Add Column",
|
|
2028
|
+
children: [
|
|
2029
|
+
/* @__PURE__ */ jsx(PlusIcon, { size: 14 }),
|
|
2030
|
+
" Col"
|
|
2031
|
+
]
|
|
2032
|
+
}
|
|
2033
|
+
),
|
|
2034
|
+
/* @__PURE__ */ jsx("div", { className: `w-px h-6 mx-1 ${isDark ? "bg-slate-600" : "bg-slate-200"}` }),
|
|
2035
|
+
/* @__PURE__ */ jsx(
|
|
2036
|
+
"button",
|
|
2037
|
+
{
|
|
2038
|
+
onMouseDown: (e) => {
|
|
2039
|
+
e.preventDefault();
|
|
2040
|
+
toggleHeader();
|
|
2041
|
+
},
|
|
2042
|
+
className: toolbarBtnClass(block.hasHeader),
|
|
2043
|
+
children: "Header"
|
|
2044
|
+
}
|
|
2045
|
+
),
|
|
2046
|
+
/* @__PURE__ */ jsx("div", { className: `w-px h-6 mx-1 ${isDark ? "bg-slate-600" : "bg-slate-200"}` }),
|
|
2047
|
+
/* @__PURE__ */ jsx("span", { className: `text-xs ${isDark ? "text-slate-500" : "text-slate-400"}`, children: "Row:" }),
|
|
2048
|
+
/* @__PURE__ */ jsx(
|
|
2049
|
+
"button",
|
|
2050
|
+
{
|
|
2051
|
+
onMouseDown: (e) => {
|
|
2052
|
+
e.preventDefault();
|
|
2053
|
+
moveRowUp(activeCell.row);
|
|
2054
|
+
updateToolbarPosition(activeCell.row - 1, activeCell.col);
|
|
2055
|
+
},
|
|
2056
|
+
disabled: activeCell.row === 0,
|
|
2057
|
+
className: `p-1 rounded ${activeCell.row === 0 ? "opacity-30 cursor-not-allowed" : ""} ${toolbarBtnClass()}`,
|
|
2058
|
+
title: "Move Row Up",
|
|
2059
|
+
children: /* @__PURE__ */ jsx(ChevronUpIcon, { size: 14 })
|
|
2060
|
+
}
|
|
2061
|
+
),
|
|
2062
|
+
/* @__PURE__ */ jsx(
|
|
2063
|
+
"button",
|
|
2064
|
+
{
|
|
2065
|
+
onMouseDown: (e) => {
|
|
2066
|
+
e.preventDefault();
|
|
2067
|
+
moveRowDown(activeCell.row);
|
|
2068
|
+
updateToolbarPosition(activeCell.row + 1, activeCell.col);
|
|
2069
|
+
},
|
|
2070
|
+
disabled: activeCell.row >= block.rows.length - 1,
|
|
2071
|
+
className: `p-1 rounded ${activeCell.row >= block.rows.length - 1 ? "opacity-30 cursor-not-allowed" : ""} ${toolbarBtnClass()}`,
|
|
2072
|
+
title: "Move Row Down",
|
|
2073
|
+
children: /* @__PURE__ */ jsx(ChevronDownIcon, { size: 14 })
|
|
2074
|
+
}
|
|
2075
|
+
),
|
|
2076
|
+
/* @__PURE__ */ jsx(
|
|
2077
|
+
"button",
|
|
2078
|
+
{
|
|
2079
|
+
onMouseDown: (e) => {
|
|
2080
|
+
e.preventDefault();
|
|
2081
|
+
deleteRow(activeCell.row);
|
|
2082
|
+
setActiveCell(null);
|
|
2083
|
+
setShowToolbar(false);
|
|
2084
|
+
},
|
|
2085
|
+
disabled: block.rows.length <= 1,
|
|
2086
|
+
className: `p-1 rounded text-red-500 hover:bg-red-100 ${block.rows.length <= 1 ? "opacity-30 cursor-not-allowed" : ""}`,
|
|
2087
|
+
title: "Delete Row",
|
|
2088
|
+
children: /* @__PURE__ */ jsx(TrashIcon, { size: 14 })
|
|
2089
|
+
}
|
|
2090
|
+
),
|
|
2091
|
+
/* @__PURE__ */ jsx("div", { className: `w-px h-6 mx-1 ${isDark ? "bg-slate-600" : "bg-slate-200"}` }),
|
|
2092
|
+
/* @__PURE__ */ jsx("span", { className: `text-xs ${isDark ? "text-slate-500" : "text-slate-400"}`, children: "Col:" }),
|
|
2093
|
+
/* @__PURE__ */ jsx(
|
|
2094
|
+
"button",
|
|
2095
|
+
{
|
|
2096
|
+
onMouseDown: (e) => {
|
|
2097
|
+
e.preventDefault();
|
|
2098
|
+
moveColumnLeft(activeCell.col);
|
|
2099
|
+
updateToolbarPosition(activeCell.row, activeCell.col - 1);
|
|
2100
|
+
},
|
|
2101
|
+
disabled: activeCell.col === 0,
|
|
2102
|
+
className: `p-1 rounded ${activeCell.col === 0 ? "opacity-30 cursor-not-allowed" : ""} ${toolbarBtnClass()}`,
|
|
2103
|
+
title: "Move Column Left",
|
|
2104
|
+
children: /* @__PURE__ */ jsx(ChevronLeftIcon, { size: 14 })
|
|
2105
|
+
}
|
|
2106
|
+
),
|
|
2107
|
+
/* @__PURE__ */ jsx(
|
|
2108
|
+
"button",
|
|
2109
|
+
{
|
|
2110
|
+
onMouseDown: (e) => {
|
|
2111
|
+
e.preventDefault();
|
|
2112
|
+
moveColumnRight(activeCell.col);
|
|
2113
|
+
updateToolbarPosition(activeCell.row, activeCell.col + 1);
|
|
2114
|
+
},
|
|
2115
|
+
disabled: activeCell.col >= (block.rows[0]?.length ?? 0) - 1,
|
|
2116
|
+
className: `p-1 rounded ${activeCell.col >= (block.rows[0]?.length ?? 0) - 1 ? "opacity-30 cursor-not-allowed" : ""} ${toolbarBtnClass()}`,
|
|
2117
|
+
title: "Move Column Right",
|
|
2118
|
+
children: /* @__PURE__ */ jsx(ChevronRightIcon, { size: 14 })
|
|
2119
|
+
}
|
|
2120
|
+
),
|
|
2121
|
+
/* @__PURE__ */ jsx(
|
|
2122
|
+
"button",
|
|
2123
|
+
{
|
|
2124
|
+
onMouseDown: (e) => {
|
|
2125
|
+
e.preventDefault();
|
|
2126
|
+
deleteColumn(activeCell.col);
|
|
2127
|
+
setActiveCell(null);
|
|
2128
|
+
setShowToolbar(false);
|
|
2129
|
+
},
|
|
2130
|
+
disabled: (block.rows[0]?.length ?? 0) <= 1,
|
|
2131
|
+
className: `p-1 rounded text-red-500 hover:bg-red-100 ${(block.rows[0]?.length ?? 0) <= 1 ? "opacity-30 cursor-not-allowed" : ""}`,
|
|
2132
|
+
title: "Delete Column",
|
|
2133
|
+
children: /* @__PURE__ */ jsx(TrashIcon, { size: 14 })
|
|
2134
|
+
}
|
|
2135
|
+
)
|
|
2136
|
+
]
|
|
2137
|
+
}
|
|
2138
|
+
),
|
|
2139
|
+
/* @__PURE__ */ jsx("div", { className: "overflow-x-auto rounded-xl", children: /* @__PURE__ */ jsx(
|
|
2140
|
+
"table",
|
|
2141
|
+
{
|
|
2142
|
+
className: `w-full border-collapse border ${isDark ? "border-slate-600" : "border-slate-300"}`,
|
|
2143
|
+
children: /* @__PURE__ */ jsx("tbody", { children: block.rows.map((row, rowIndex) => /* @__PURE__ */ jsx(
|
|
2144
|
+
"tr",
|
|
1077
2145
|
{
|
|
1078
|
-
className:
|
|
1079
|
-
children:
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
onFocus: () => setSelectedCell({ row: rowIndex, col: colIndex }),
|
|
1087
|
-
onBlur: () => setSelectedCell(null),
|
|
1088
|
-
className: `w-full px-3 py-2 min-h-[40px] outline-none bg-transparent ${alignClass} ${isHeader ? "font-semibold" : ""} ${isDark ? "text-slate-200 placeholder:text-slate-500" : "text-slate-700 placeholder:text-slate-400"} focus:ring-2 focus:ring-indigo-500 focus:ring-inset`,
|
|
1089
|
-
placeholder: isHeader ? "Header" : ""
|
|
1090
|
-
}
|
|
1091
|
-
),
|
|
1092
|
-
!readOnly && rowIndex === 0 && showToolbar && /* @__PURE__ */ jsx(
|
|
1093
|
-
"button",
|
|
2146
|
+
className: "group/row",
|
|
2147
|
+
children: row.map((cell, colIndex) => {
|
|
2148
|
+
const isHeader = block.hasHeader && rowIndex === 0;
|
|
2149
|
+
const CellTag = isHeader ? "th" : "td";
|
|
2150
|
+
const isActive = activeCell?.row === rowIndex && activeCell?.col === colIndex;
|
|
2151
|
+
const alignClass = cell.alignment === "center" ? "text-center" : cell.alignment === "right" ? "text-right" : "text-left";
|
|
2152
|
+
return /* @__PURE__ */ jsx(
|
|
2153
|
+
CellTag,
|
|
1094
2154
|
{
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
2155
|
+
ref: (el) => {
|
|
2156
|
+
if (el) cellRefs.current.set(`${rowIndex}-${colIndex}`, el);
|
|
2157
|
+
},
|
|
2158
|
+
className: `relative border p-0 ${isDark ? "border-slate-600" : "border-slate-300"} ${isHeader ? isDark ? "bg-slate-800 font-semibold" : "bg-slate-100 font-semibold" : isDark ? "bg-slate-900" : "bg-white"} ${alignClass} ${isActive ? "ring-2 ring-indigo-500 ring-inset" : ""}`,
|
|
2159
|
+
children: readOnly ? /* @__PURE__ */ jsx(
|
|
2160
|
+
"div",
|
|
2161
|
+
{
|
|
2162
|
+
className: `px-3 py-2 min-h-[40px] ${isDark ? "text-slate-200" : "text-slate-700"}`,
|
|
2163
|
+
children: cell.content
|
|
2164
|
+
}
|
|
2165
|
+
) : /* @__PURE__ */ jsx(
|
|
2166
|
+
"input",
|
|
2167
|
+
{
|
|
2168
|
+
type: "text",
|
|
2169
|
+
value: cell.content,
|
|
2170
|
+
onChange: (e) => updateCell(rowIndex, colIndex, e.target.value),
|
|
2171
|
+
onFocus: () => handleCellFocus(rowIndex, colIndex),
|
|
2172
|
+
className: `w-full px-3 py-2 min-h-[40px] outline-none bg-transparent ${alignClass} ${isHeader ? "font-semibold" : ""} ${isDark ? "text-slate-200 placeholder:text-slate-500" : "text-slate-700 placeholder:text-slate-400"}`,
|
|
2173
|
+
placeholder: isHeader ? "Header" : ""
|
|
2174
|
+
}
|
|
2175
|
+
)
|
|
2176
|
+
},
|
|
2177
|
+
colIndex
|
|
2178
|
+
);
|
|
2179
|
+
})
|
|
1102
2180
|
},
|
|
1103
|
-
|
|
1104
|
-
)
|
|
1105
|
-
}
|
|
1106
|
-
|
|
1107
|
-
"button",
|
|
1108
|
-
{
|
|
1109
|
-
onClick: () => deleteRow(rowIndex),
|
|
1110
|
-
className: "p-1 rounded-lg bg-red-500 text-white opacity-0 group-hover/row:opacity-100 transition-opacity",
|
|
1111
|
-
title: "Delete Row",
|
|
1112
|
-
children: /* @__PURE__ */ jsx(TrashIcon, { size: 12 })
|
|
1113
|
-
}
|
|
1114
|
-
) })
|
|
1115
|
-
] }, rowIndex)) }) }) })
|
|
2181
|
+
rowIndex
|
|
2182
|
+
)) })
|
|
2183
|
+
}
|
|
2184
|
+
) })
|
|
1116
2185
|
]
|
|
1117
2186
|
}
|
|
1118
2187
|
);
|
|
@@ -1123,7 +2192,12 @@ const styleMap = {
|
|
|
1123
2192
|
dashed: "border-dashed",
|
|
1124
2193
|
dotted: "border-dotted"
|
|
1125
2194
|
};
|
|
1126
|
-
const DividerBlock = ({
|
|
2195
|
+
const DividerBlock = ({
|
|
2196
|
+
block,
|
|
2197
|
+
onUpdate,
|
|
2198
|
+
readOnly,
|
|
2199
|
+
theme = "light"
|
|
2200
|
+
}) => {
|
|
1127
2201
|
const isDark = theme === "dark";
|
|
1128
2202
|
const cycleStyle = () => {
|
|
1129
2203
|
if (readOnly) return;
|
|
@@ -1139,19 +2213,36 @@ const DividerBlock = ({ block, onUpdate, readOnly, theme = "light" }) => {
|
|
|
1139
2213
|
onClick: cycleStyle,
|
|
1140
2214
|
className: `border-t-2 ${styleMap[block.style || "solid"]} ${isDark ? "border-slate-700" + (!readOnly ? " hover:border-slate-500" : "") : "border-slate-200" + (!readOnly ? " hover:border-slate-400" : "")} ${!readOnly ? "cursor-pointer" : ""}`
|
|
1141
2215
|
}
|
|
1142
|
-
),
|
|
1143
|
-
!readOnly && /* @__PURE__ */ jsxs(
|
|
1144
|
-
"
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
2216
|
+
),
|
|
2217
|
+
!readOnly && /* @__PURE__ */ jsxs(
|
|
2218
|
+
"p",
|
|
2219
|
+
{
|
|
2220
|
+
className: `text-xs text-center mt-1 opacity-0 group-hover:opacity-100 transition-opacity ${isDark ? "text-slate-500" : "text-slate-400"}`,
|
|
2221
|
+
children: [
|
|
2222
|
+
"Click to change style (",
|
|
2223
|
+
block.style || "solid",
|
|
2224
|
+
")"
|
|
2225
|
+
]
|
|
2226
|
+
}
|
|
2227
|
+
)
|
|
1148
2228
|
] });
|
|
1149
2229
|
};
|
|
1150
2230
|
|
|
1151
|
-
const QuoteBlock = ({
|
|
2231
|
+
const QuoteBlock = ({
|
|
2232
|
+
block,
|
|
2233
|
+
onUpdate,
|
|
2234
|
+
readOnly,
|
|
2235
|
+
theme = "light"
|
|
2236
|
+
}) => {
|
|
1152
2237
|
const [showToolbar, setShowToolbar] = useState(false);
|
|
1153
2238
|
const textareaRef = useRef(null);
|
|
2239
|
+
const containerRef = useRef(null);
|
|
1154
2240
|
const isDark = theme === "dark";
|
|
2241
|
+
const { showBelow } = useToolbarPosition({
|
|
2242
|
+
containerRef,
|
|
2243
|
+
isVisible: showToolbar && !readOnly,
|
|
2244
|
+
minSpaceAbove: 60
|
|
2245
|
+
});
|
|
1155
2246
|
const styleClasses = {
|
|
1156
2247
|
default: `border-l-4 pl-4 italic ${isDark ? "border-slate-600" : "border-slate-300"}`,
|
|
1157
2248
|
bordered: `border-l-4 pl-4 py-3 rounded-r ${isDark ? "border-indigo-500 bg-indigo-950/30" : "border-indigo-500 bg-indigo-50"}`,
|
|
@@ -1176,6 +2267,7 @@ const QuoteBlock = ({ block, onUpdate, readOnly, theme = "light" }) => {
|
|
|
1176
2267
|
return /* @__PURE__ */ jsxs(
|
|
1177
2268
|
"div",
|
|
1178
2269
|
{
|
|
2270
|
+
ref: containerRef,
|
|
1179
2271
|
className: "group relative",
|
|
1180
2272
|
onFocus: () => setShowToolbar(true),
|
|
1181
2273
|
onBlur: (e) => {
|
|
@@ -1184,69 +2276,98 @@ const QuoteBlock = ({ block, onUpdate, readOnly, theme = "light" }) => {
|
|
|
1184
2276
|
}
|
|
1185
2277
|
},
|
|
1186
2278
|
children: [
|
|
1187
|
-
showToolbar && !readOnly && /* @__PURE__ */ jsxs(
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
{
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
{
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
2279
|
+
showToolbar && !readOnly && /* @__PURE__ */ jsxs(
|
|
2280
|
+
"div",
|
|
2281
|
+
{
|
|
2282
|
+
className: `absolute left-0 flex items-center gap-1 p-1.5 rounded-xl shadow-lg border z-10 ${showBelow ? "top-full mt-2" : "-top-12"} ${isDark ? "bg-slate-800 border-slate-600" : "bg-white border-slate-200"}`,
|
|
2283
|
+
children: [
|
|
2284
|
+
/* @__PURE__ */ jsx(
|
|
2285
|
+
"button",
|
|
2286
|
+
{
|
|
2287
|
+
onClick: () => setStyle("default"),
|
|
2288
|
+
className: toolbarBtnClass(block.style === "default" || !block.style),
|
|
2289
|
+
children: "Simple"
|
|
2290
|
+
}
|
|
2291
|
+
),
|
|
2292
|
+
/* @__PURE__ */ jsx(
|
|
2293
|
+
"button",
|
|
2294
|
+
{
|
|
2295
|
+
onClick: () => setStyle("bordered"),
|
|
2296
|
+
className: toolbarBtnClass(block.style === "bordered"),
|
|
2297
|
+
children: "Bordered"
|
|
2298
|
+
}
|
|
2299
|
+
),
|
|
2300
|
+
/* @__PURE__ */ jsx(
|
|
2301
|
+
"button",
|
|
2302
|
+
{
|
|
2303
|
+
onClick: () => setStyle("modern"),
|
|
2304
|
+
className: toolbarBtnClass(block.style === "modern"),
|
|
2305
|
+
children: "Modern"
|
|
2306
|
+
}
|
|
2307
|
+
)
|
|
2308
|
+
]
|
|
2309
|
+
}
|
|
2310
|
+
),
|
|
2311
|
+
/* @__PURE__ */ jsx(
|
|
2312
|
+
"blockquote",
|
|
2313
|
+
{
|
|
2314
|
+
className: `${styleClasses[block.style || "default"]} ${isDark ? "text-slate-300" : "text-slate-700"}`,
|
|
2315
|
+
children: readOnly ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
2316
|
+
/* @__PURE__ */ jsx("p", { className: "text-lg leading-relaxed whitespace-pre-wrap", children: block.content }),
|
|
2317
|
+
block.author && /* @__PURE__ */ jsxs(
|
|
2318
|
+
"cite",
|
|
2319
|
+
{
|
|
2320
|
+
className: `block mt-3 text-sm not-italic ${isDark ? "text-slate-400" : "text-slate-500"}`,
|
|
2321
|
+
children: [
|
|
2322
|
+
"— ",
|
|
2323
|
+
block.author
|
|
2324
|
+
]
|
|
2325
|
+
}
|
|
2326
|
+
)
|
|
2327
|
+
] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
2328
|
+
/* @__PURE__ */ jsx(
|
|
2329
|
+
"textarea",
|
|
2330
|
+
{
|
|
2331
|
+
ref: textareaRef,
|
|
2332
|
+
value: block.content,
|
|
2333
|
+
onChange: handleContentChange,
|
|
2334
|
+
placeholder: "Enter quote...",
|
|
2335
|
+
className: `w-full text-lg leading-relaxed bg-transparent outline-none resize-none ${isDark ? "placeholder:text-slate-500" : "placeholder:text-slate-400"}`,
|
|
2336
|
+
rows: 1
|
|
2337
|
+
}
|
|
2338
|
+
),
|
|
2339
|
+
/* @__PURE__ */ jsx(
|
|
2340
|
+
"input",
|
|
2341
|
+
{
|
|
2342
|
+
type: "text",
|
|
2343
|
+
value: block.author || "",
|
|
2344
|
+
onChange: handleAuthorChange,
|
|
2345
|
+
placeholder: "— Author name",
|
|
2346
|
+
className: `w-full mt-2 text-sm bg-transparent outline-none ${isDark ? "text-slate-400 placeholder:text-slate-500" : "text-slate-500 placeholder:text-slate-400"}`
|
|
2347
|
+
}
|
|
2348
|
+
)
|
|
2349
|
+
] })
|
|
2350
|
+
}
|
|
2351
|
+
)
|
|
1242
2352
|
]
|
|
1243
2353
|
}
|
|
1244
2354
|
);
|
|
1245
2355
|
};
|
|
1246
2356
|
|
|
1247
|
-
const ListBlock = ({
|
|
2357
|
+
const ListBlock = ({
|
|
2358
|
+
block,
|
|
2359
|
+
onUpdate,
|
|
2360
|
+
readOnly,
|
|
2361
|
+
theme = "light"
|
|
2362
|
+
}) => {
|
|
1248
2363
|
const [showToolbar, setShowToolbar] = useState(false);
|
|
2364
|
+
const containerRef = useRef(null);
|
|
1249
2365
|
const isDark = theme === "dark";
|
|
2366
|
+
const { showBelow } = useToolbarPosition({
|
|
2367
|
+
containerRef,
|
|
2368
|
+
isVisible: showToolbar && !readOnly,
|
|
2369
|
+
minSpaceAbove: 60
|
|
2370
|
+
});
|
|
1250
2371
|
const updateItem = (index, value) => {
|
|
1251
2372
|
const newItems = [...block.items];
|
|
1252
2373
|
newItems[index] = value;
|
|
@@ -1304,6 +2425,7 @@ const ListBlock = ({ block, onUpdate, readOnly, theme = "light" }) => {
|
|
|
1304
2425
|
return /* @__PURE__ */ jsxs(
|
|
1305
2426
|
"div",
|
|
1306
2427
|
{
|
|
2428
|
+
ref: containerRef,
|
|
1307
2429
|
className: "group relative",
|
|
1308
2430
|
onFocus: () => setShowToolbar(true),
|
|
1309
2431
|
onBlur: (e) => {
|
|
@@ -1312,65 +2434,90 @@ const ListBlock = ({ block, onUpdate, readOnly, theme = "light" }) => {
|
|
|
1312
2434
|
}
|
|
1313
2435
|
},
|
|
1314
2436
|
children: [
|
|
1315
|
-
showToolbar && !readOnly && /* @__PURE__ */ jsxs(
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
{
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
|
|
1327
|
-
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
|
|
1338
|
-
|
|
1339
|
-
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
|
|
1346
|
-
|
|
1347
|
-
|
|
1348
|
-
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
"input",
|
|
1354
|
-
{
|
|
1355
|
-
type: "text",
|
|
1356
|
-
"data-list-input": block.id,
|
|
1357
|
-
value: item,
|
|
1358
|
-
onChange: (e) => updateItem(index, e.target.value),
|
|
1359
|
-
onKeyDown: (e) => handleKeyDown(e, index),
|
|
1360
|
-
placeholder: "List item...",
|
|
1361
|
-
className: `flex-1 outline-none bg-transparent ${block.checkedItems?.[index] ? isDark ? "line-through text-slate-500" : "line-through text-slate-400" : ""} ${isDark ? "placeholder:text-slate-500" : "placeholder:text-slate-400"}`
|
|
1362
|
-
}
|
|
1363
|
-
),
|
|
1364
|
-
/* @__PURE__ */ jsx(
|
|
1365
|
-
"button",
|
|
2437
|
+
showToolbar && !readOnly && /* @__PURE__ */ jsxs(
|
|
2438
|
+
"div",
|
|
2439
|
+
{
|
|
2440
|
+
className: `absolute left-0 flex items-center gap-1 p-1.5 rounded-xl shadow-lg border z-10 ${showBelow ? "top-full mt-2" : "-top-12"} ${isDark ? "bg-slate-800 border-slate-600" : "bg-white border-slate-200"}`,
|
|
2441
|
+
children: [
|
|
2442
|
+
/* @__PURE__ */ jsx(
|
|
2443
|
+
"button",
|
|
2444
|
+
{
|
|
2445
|
+
onClick: () => setListType("bullet"),
|
|
2446
|
+
className: toolbarBtnClass(block.listType === "bullet"),
|
|
2447
|
+
children: "• Bullet"
|
|
2448
|
+
}
|
|
2449
|
+
),
|
|
2450
|
+
/* @__PURE__ */ jsx(
|
|
2451
|
+
"button",
|
|
2452
|
+
{
|
|
2453
|
+
onClick: () => setListType("numbered"),
|
|
2454
|
+
className: toolbarBtnClass(block.listType === "numbered"),
|
|
2455
|
+
children: "1. Numbered"
|
|
2456
|
+
}
|
|
2457
|
+
),
|
|
2458
|
+
/* @__PURE__ */ jsx(
|
|
2459
|
+
"button",
|
|
2460
|
+
{
|
|
2461
|
+
onClick: () => setListType("checklist"),
|
|
2462
|
+
className: toolbarBtnClass(block.listType === "checklist"),
|
|
2463
|
+
children: "☑ Checklist"
|
|
2464
|
+
}
|
|
2465
|
+
)
|
|
2466
|
+
]
|
|
2467
|
+
}
|
|
2468
|
+
),
|
|
2469
|
+
/* @__PURE__ */ jsx(
|
|
2470
|
+
ListWrapper,
|
|
2471
|
+
{
|
|
2472
|
+
className: `space-y-1 ${block.listType === "numbered" ? "list-decimal" : block.listType === "bullet" ? "list-disc" : "list-none"} ${block.listType !== "checklist" ? "pl-6" : ""} ${isDark ? "text-slate-200" : "text-slate-700"}`,
|
|
2473
|
+
children: block.items.map((item, index) => /* @__PURE__ */ jsxs(
|
|
2474
|
+
"li",
|
|
1366
2475
|
{
|
|
1367
|
-
|
|
1368
|
-
|
|
1369
|
-
|
|
1370
|
-
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
|
|
2476
|
+
className: "group/item flex items-center gap-2",
|
|
2477
|
+
children: [
|
|
2478
|
+
block.listType === "checklist" && /* @__PURE__ */ jsx(
|
|
2479
|
+
"button",
|
|
2480
|
+
{
|
|
2481
|
+
onClick: () => toggleChecked(index),
|
|
2482
|
+
disabled: readOnly,
|
|
2483
|
+
className: `flex-shrink-0 w-5 h-5 rounded border-2 flex items-center justify-center transition-colors ${block.checkedItems?.[index] ? "bg-indigo-500 border-indigo-500 text-white" : isDark ? "border-slate-500 hover:border-indigo-400" : "border-slate-300 hover:border-indigo-400"}`,
|
|
2484
|
+
children: block.checkedItems?.[index] && /* @__PURE__ */ jsx(CheckIcon, { size: 12 })
|
|
2485
|
+
}
|
|
2486
|
+
),
|
|
2487
|
+
readOnly ? /* @__PURE__ */ jsx(
|
|
2488
|
+
"span",
|
|
2489
|
+
{
|
|
2490
|
+
className: block.checkedItems?.[index] ? isDark ? "line-through text-slate-500" : "line-through text-slate-400" : "",
|
|
2491
|
+
children: item
|
|
2492
|
+
}
|
|
2493
|
+
) : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
2494
|
+
/* @__PURE__ */ jsx(
|
|
2495
|
+
"input",
|
|
2496
|
+
{
|
|
2497
|
+
type: "text",
|
|
2498
|
+
"data-list-input": block.id,
|
|
2499
|
+
value: item,
|
|
2500
|
+
onChange: (e) => updateItem(index, e.target.value),
|
|
2501
|
+
onKeyDown: (e) => handleKeyDown(e, index),
|
|
2502
|
+
placeholder: "List item...",
|
|
2503
|
+
className: `flex-1 outline-none bg-transparent ${block.checkedItems?.[index] ? isDark ? "line-through text-slate-500" : "line-through text-slate-400" : ""} ${isDark ? "placeholder:text-slate-500" : "placeholder:text-slate-400"}`
|
|
2504
|
+
}
|
|
2505
|
+
),
|
|
2506
|
+
/* @__PURE__ */ jsx(
|
|
2507
|
+
"button",
|
|
2508
|
+
{
|
|
2509
|
+
onClick: () => removeItem(index),
|
|
2510
|
+
className: `opacity-0 group-hover/item:opacity-100 p-1 transition-all ${isDark ? "text-slate-500 hover:text-red-400" : "text-slate-400 hover:text-red-500"}`,
|
|
2511
|
+
children: /* @__PURE__ */ jsx(TrashIcon, { size: 14 })
|
|
2512
|
+
}
|
|
2513
|
+
)
|
|
2514
|
+
] })
|
|
2515
|
+
]
|
|
2516
|
+
},
|
|
2517
|
+
index
|
|
2518
|
+
))
|
|
2519
|
+
}
|
|
2520
|
+
),
|
|
1374
2521
|
!readOnly && /* @__PURE__ */ jsxs(
|
|
1375
2522
|
"button",
|
|
1376
2523
|
{
|
|
@@ -1438,10 +2585,21 @@ const variantLabels = {
|
|
|
1438
2585
|
error: "Error",
|
|
1439
2586
|
tip: "Tip"
|
|
1440
2587
|
};
|
|
1441
|
-
const CalloutBlock = ({
|
|
2588
|
+
const CalloutBlock = ({
|
|
2589
|
+
block,
|
|
2590
|
+
onUpdate,
|
|
2591
|
+
readOnly,
|
|
2592
|
+
theme = "light"
|
|
2593
|
+
}) => {
|
|
1442
2594
|
const [showToolbar, setShowToolbar] = useState(false);
|
|
1443
2595
|
const textareaRef = useRef(null);
|
|
2596
|
+
const containerRef = useRef(null);
|
|
1444
2597
|
const isDark = theme === "dark";
|
|
2598
|
+
const { showBelow } = useToolbarPosition({
|
|
2599
|
+
containerRef,
|
|
2600
|
+
isVisible: showToolbar && !readOnly,
|
|
2601
|
+
minSpaceAbove: 60
|
|
2602
|
+
});
|
|
1445
2603
|
const handleContentChange = (e) => {
|
|
1446
2604
|
onUpdate({ ...block, content: e.target.value });
|
|
1447
2605
|
if (textareaRef.current) {
|
|
@@ -1461,6 +2619,7 @@ const CalloutBlock = ({ block, onUpdate, readOnly, theme = "light" }) => {
|
|
|
1461
2619
|
return /* @__PURE__ */ jsxs(
|
|
1462
2620
|
"div",
|
|
1463
2621
|
{
|
|
2622
|
+
ref: containerRef,
|
|
1464
2623
|
className: "group relative",
|
|
1465
2624
|
onFocus: () => setShowToolbar(true),
|
|
1466
2625
|
onBlur: (e) => {
|
|
@@ -1469,19 +2628,25 @@ const CalloutBlock = ({ block, onUpdate, readOnly, theme = "light" }) => {
|
|
|
1469
2628
|
}
|
|
1470
2629
|
},
|
|
1471
2630
|
children: [
|
|
1472
|
-
showToolbar && !readOnly && /* @__PURE__ */ jsx(
|
|
1473
|
-
"
|
|
2631
|
+
showToolbar && !readOnly && /* @__PURE__ */ jsx(
|
|
2632
|
+
"div",
|
|
1474
2633
|
{
|
|
1475
|
-
|
|
1476
|
-
|
|
1477
|
-
|
|
1478
|
-
|
|
1479
|
-
|
|
1480
|
-
|
|
1481
|
-
|
|
1482
|
-
|
|
1483
|
-
|
|
1484
|
-
|
|
2634
|
+
className: `absolute left-0 flex items-center gap-1 p-1.5 rounded-xl shadow-lg border z-10 ${showBelow ? "top-full mt-2" : "-top-12"} ${isDark ? "bg-slate-800 border-slate-600" : "bg-white border-slate-200"}`,
|
|
2635
|
+
children: Object.keys(variantStyles).map((variant) => /* @__PURE__ */ jsxs(
|
|
2636
|
+
"button",
|
|
2637
|
+
{
|
|
2638
|
+
onClick: () => setVariant(variant),
|
|
2639
|
+
className: toolbarBtnClass(block.variant === variant),
|
|
2640
|
+
children: [
|
|
2641
|
+
variantIcons[variant],
|
|
2642
|
+
" ",
|
|
2643
|
+
variantLabels[variant]
|
|
2644
|
+
]
|
|
2645
|
+
},
|
|
2646
|
+
variant
|
|
2647
|
+
))
|
|
2648
|
+
}
|
|
2649
|
+
),
|
|
1485
2650
|
/* @__PURE__ */ jsx("div", { className: `rounded-xl border ${styles.bg} ${styles.border} p-4`, children: /* @__PURE__ */ jsxs("div", { className: "flex gap-3", children: [
|
|
1486
2651
|
/* @__PURE__ */ jsx("span", { className: `text-xl flex-shrink-0 ${styles.icon}`, children: variantIcons[block.variant] }),
|
|
1487
2652
|
/* @__PURE__ */ jsx("div", { className: "flex-1 min-w-0", children: readOnly ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
@@ -1555,37 +2720,103 @@ const BlockWrapper = ({
|
|
|
1555
2720
|
}
|
|
1556
2721
|
return () => document.removeEventListener("mousedown", handleClickOutside);
|
|
1557
2722
|
}, [isSelected]);
|
|
1558
|
-
const handleBlockClick = useCallback(
|
|
1559
|
-
|
|
1560
|
-
|
|
1561
|
-
|
|
1562
|
-
|
|
1563
|
-
|
|
1564
|
-
|
|
1565
|
-
|
|
1566
|
-
|
|
1567
|
-
|
|
2723
|
+
const handleBlockClick = useCallback(
|
|
2724
|
+
(e) => {
|
|
2725
|
+
const target = e.target;
|
|
2726
|
+
const interactiveElements = ["INPUT", "TEXTAREA", "BUTTON", "SELECT"];
|
|
2727
|
+
if (interactiveElements.includes(target.tagName)) {
|
|
2728
|
+
return;
|
|
2729
|
+
}
|
|
2730
|
+
if (!readOnly) {
|
|
2731
|
+
setIsSelected(true);
|
|
2732
|
+
}
|
|
2733
|
+
},
|
|
2734
|
+
[readOnly]
|
|
2735
|
+
);
|
|
1568
2736
|
const renderBlock = useCallback(() => {
|
|
1569
2737
|
const commonProps = { readOnly, theme };
|
|
1570
2738
|
switch (block.type) {
|
|
1571
2739
|
case "text":
|
|
1572
|
-
return /* @__PURE__ */ jsx(
|
|
2740
|
+
return /* @__PURE__ */ jsx(
|
|
2741
|
+
TextBlock,
|
|
2742
|
+
{
|
|
2743
|
+
block,
|
|
2744
|
+
onUpdate: (b) => onUpdate(b),
|
|
2745
|
+
...commonProps
|
|
2746
|
+
}
|
|
2747
|
+
);
|
|
1573
2748
|
case "heading":
|
|
1574
|
-
return /* @__PURE__ */ jsx(
|
|
2749
|
+
return /* @__PURE__ */ jsx(
|
|
2750
|
+
HeadingBlock,
|
|
2751
|
+
{
|
|
2752
|
+
block,
|
|
2753
|
+
onUpdate: (b) => onUpdate(b),
|
|
2754
|
+
...commonProps
|
|
2755
|
+
}
|
|
2756
|
+
);
|
|
1575
2757
|
case "image":
|
|
1576
|
-
return /* @__PURE__ */ jsx(
|
|
2758
|
+
return /* @__PURE__ */ jsx(
|
|
2759
|
+
ImageBlock,
|
|
2760
|
+
{
|
|
2761
|
+
block,
|
|
2762
|
+
onUpdate: (b) => onUpdate(b),
|
|
2763
|
+
...commonProps
|
|
2764
|
+
}
|
|
2765
|
+
);
|
|
1577
2766
|
case "code":
|
|
1578
|
-
return /* @__PURE__ */ jsx(
|
|
2767
|
+
return /* @__PURE__ */ jsx(
|
|
2768
|
+
CodeBlock,
|
|
2769
|
+
{
|
|
2770
|
+
block,
|
|
2771
|
+
onUpdate: (b) => onUpdate(b),
|
|
2772
|
+
...commonProps
|
|
2773
|
+
}
|
|
2774
|
+
);
|
|
1579
2775
|
case "table":
|
|
1580
|
-
return /* @__PURE__ */ jsx(
|
|
2776
|
+
return /* @__PURE__ */ jsx(
|
|
2777
|
+
TableBlock,
|
|
2778
|
+
{
|
|
2779
|
+
block,
|
|
2780
|
+
onUpdate: (b) => onUpdate(b),
|
|
2781
|
+
...commonProps
|
|
2782
|
+
}
|
|
2783
|
+
);
|
|
1581
2784
|
case "divider":
|
|
1582
|
-
return /* @__PURE__ */ jsx(
|
|
2785
|
+
return /* @__PURE__ */ jsx(
|
|
2786
|
+
DividerBlock,
|
|
2787
|
+
{
|
|
2788
|
+
block,
|
|
2789
|
+
onUpdate: (b) => onUpdate(b),
|
|
2790
|
+
...commonProps
|
|
2791
|
+
}
|
|
2792
|
+
);
|
|
1583
2793
|
case "quote":
|
|
1584
|
-
return /* @__PURE__ */ jsx(
|
|
2794
|
+
return /* @__PURE__ */ jsx(
|
|
2795
|
+
QuoteBlock,
|
|
2796
|
+
{
|
|
2797
|
+
block,
|
|
2798
|
+
onUpdate: (b) => onUpdate(b),
|
|
2799
|
+
...commonProps
|
|
2800
|
+
}
|
|
2801
|
+
);
|
|
1585
2802
|
case "list":
|
|
1586
|
-
return /* @__PURE__ */ jsx(
|
|
2803
|
+
return /* @__PURE__ */ jsx(
|
|
2804
|
+
ListBlock,
|
|
2805
|
+
{
|
|
2806
|
+
block,
|
|
2807
|
+
onUpdate: (b) => onUpdate(b),
|
|
2808
|
+
...commonProps
|
|
2809
|
+
}
|
|
2810
|
+
);
|
|
1587
2811
|
case "callout":
|
|
1588
|
-
return /* @__PURE__ */ jsx(
|
|
2812
|
+
return /* @__PURE__ */ jsx(
|
|
2813
|
+
CalloutBlock,
|
|
2814
|
+
{
|
|
2815
|
+
block,
|
|
2816
|
+
onUpdate: (b) => onUpdate(b),
|
|
2817
|
+
...commonProps
|
|
2818
|
+
}
|
|
2819
|
+
);
|
|
1589
2820
|
default: {
|
|
1590
2821
|
const _exhaustiveCheck = block;
|
|
1591
2822
|
return /* @__PURE__ */ jsxs("div", { children: [
|
|
@@ -1596,43 +2827,53 @@ const BlockWrapper = ({
|
|
|
1596
2827
|
}
|
|
1597
2828
|
}, [block, onUpdate, readOnly, theme]);
|
|
1598
2829
|
const buttonBaseClass = `p-1.5 rounded-lg transition-all ${isDark ? "text-slate-400 hover:text-slate-200 hover:bg-slate-700" : "text-slate-500 hover:text-slate-700 hover:bg-slate-100"}`;
|
|
1599
|
-
const
|
|
1600
|
-
|
|
1601
|
-
|
|
1602
|
-
|
|
1603
|
-
|
|
1604
|
-
|
|
1605
|
-
|
|
1606
|
-
|
|
1607
|
-
|
|
1608
|
-
|
|
1609
|
-
|
|
1610
|
-
|
|
1611
|
-
|
|
1612
|
-
|
|
1613
|
-
|
|
1614
|
-
|
|
1615
|
-
|
|
1616
|
-
|
|
1617
|
-
|
|
1618
|
-
|
|
1619
|
-
|
|
1620
|
-
|
|
1621
|
-
|
|
1622
|
-
|
|
1623
|
-
|
|
1624
|
-
|
|
1625
|
-
|
|
1626
|
-
|
|
1627
|
-
|
|
1628
|
-
|
|
1629
|
-
|
|
1630
|
-
|
|
1631
|
-
|
|
1632
|
-
|
|
1633
|
-
|
|
2830
|
+
const handleKeyDown = useCallback(
|
|
2831
|
+
(e) => {
|
|
2832
|
+
if (readOnly || !isSelected) return;
|
|
2833
|
+
switch (e.key) {
|
|
2834
|
+
case "Escape":
|
|
2835
|
+
setIsSelected(false);
|
|
2836
|
+
setShowAddMenu(false);
|
|
2837
|
+
break;
|
|
2838
|
+
case "Delete":
|
|
2839
|
+
case "Backspace":
|
|
2840
|
+
if (!e.target.matches("input, textarea, [contenteditable]")) {
|
|
2841
|
+
e.preventDefault();
|
|
2842
|
+
onDelete();
|
|
2843
|
+
}
|
|
2844
|
+
break;
|
|
2845
|
+
case "ArrowUp":
|
|
2846
|
+
if (e.altKey) {
|
|
2847
|
+
e.preventDefault();
|
|
2848
|
+
onMoveUp();
|
|
2849
|
+
}
|
|
2850
|
+
break;
|
|
2851
|
+
case "ArrowDown":
|
|
2852
|
+
if (e.altKey) {
|
|
2853
|
+
e.preventDefault();
|
|
2854
|
+
onMoveDown();
|
|
2855
|
+
}
|
|
2856
|
+
break;
|
|
2857
|
+
case "d":
|
|
2858
|
+
if (e.ctrlKey || e.metaKey) {
|
|
2859
|
+
e.preventDefault();
|
|
2860
|
+
onDuplicate();
|
|
2861
|
+
}
|
|
2862
|
+
break;
|
|
2863
|
+
}
|
|
2864
|
+
},
|
|
2865
|
+
[readOnly, isSelected, onDelete, onMoveUp, onMoveDown, onDuplicate]
|
|
2866
|
+
);
|
|
1634
2867
|
const editModeBorderClass = !readOnly ? isSelected ? isDark ? "ring-2 ring-indigo-500 rounded-lg bg-slate-800/30" : "ring-2 ring-indigo-500 rounded-lg bg-indigo-50/30" : isDark ? "border border-slate-700 rounded-lg hover:border-slate-500" : "border border-slate-200 rounded-lg hover:border-slate-400" : "";
|
|
1635
2868
|
const blockTypeLabel = block.type.charAt(0).toUpperCase() + block.type.slice(1);
|
|
2869
|
+
const showControls = !readOnly;
|
|
2870
|
+
const handleAddBlock = useCallback(
|
|
2871
|
+
(type) => {
|
|
2872
|
+
onAddBlock(type, index);
|
|
2873
|
+
setShowAddMenu(false);
|
|
2874
|
+
},
|
|
2875
|
+
[onAddBlock, index]
|
|
2876
|
+
);
|
|
1636
2877
|
return /* @__PURE__ */ jsxs(
|
|
1637
2878
|
"div",
|
|
1638
2879
|
{
|
|
@@ -1657,109 +2898,126 @@ const BlockWrapper = ({
|
|
|
1657
2898
|
{
|
|
1658
2899
|
role: "toolbar",
|
|
1659
2900
|
"aria-label": "Block controls",
|
|
1660
|
-
className: `flex items-center justify-between gap-1 px-2 py-1.5 mb-1 rounded-t-lg border-b ${isDark ? "bg-slate-800 border-slate-700" : "bg-slate-50 border-slate-200"}`,
|
|
2901
|
+
className: `relative flex items-center justify-between gap-1 px-2 py-1.5 mb-1 rounded-t-lg border-b ${isDark ? "bg-slate-800 border-slate-700" : "bg-slate-50 border-slate-200"}`,
|
|
1661
2902
|
children: [
|
|
1662
|
-
/* @__PURE__ */ jsxs(
|
|
1663
|
-
|
|
1664
|
-
|
|
1665
|
-
|
|
1666
|
-
|
|
1667
|
-
|
|
1668
|
-
|
|
1669
|
-
|
|
1670
|
-
|
|
1671
|
-
|
|
1672
|
-
|
|
1673
|
-
|
|
1674
|
-
|
|
1675
|
-
|
|
1676
|
-
|
|
1677
|
-
|
|
1678
|
-
|
|
1679
|
-
|
|
1680
|
-
|
|
1681
|
-
|
|
1682
|
-
|
|
1683
|
-
|
|
1684
|
-
|
|
1685
|
-
|
|
1686
|
-
|
|
1687
|
-
|
|
1688
|
-
|
|
1689
|
-
|
|
1690
|
-
|
|
1691
|
-
|
|
1692
|
-
|
|
1693
|
-
|
|
1694
|
-
|
|
1695
|
-
|
|
1696
|
-
|
|
1697
|
-
|
|
1698
|
-
|
|
1699
|
-
|
|
1700
|
-
|
|
1701
|
-
|
|
1702
|
-
|
|
1703
|
-
|
|
1704
|
-
|
|
1705
|
-
|
|
1706
|
-
|
|
1707
|
-
|
|
1708
|
-
|
|
1709
|
-
|
|
1710
|
-
|
|
1711
|
-
|
|
1712
|
-
|
|
1713
|
-
|
|
1714
|
-
|
|
1715
|
-
|
|
1716
|
-
|
|
1717
|
-
|
|
1718
|
-
|
|
1719
|
-
|
|
1720
|
-
|
|
1721
|
-
|
|
1722
|
-
|
|
1723
|
-
|
|
1724
|
-
|
|
1725
|
-
|
|
1726
|
-
|
|
1727
|
-
|
|
1728
|
-
|
|
1729
|
-
|
|
1730
|
-
|
|
1731
|
-
|
|
1732
|
-
|
|
1733
|
-
|
|
1734
|
-
|
|
1735
|
-
|
|
1736
|
-
|
|
1737
|
-
|
|
1738
|
-
|
|
1739
|
-
|
|
1740
|
-
|
|
1741
|
-
|
|
1742
|
-
|
|
1743
|
-
|
|
1744
|
-
|
|
1745
|
-
|
|
1746
|
-
|
|
1747
|
-
|
|
1748
|
-
|
|
1749
|
-
|
|
1750
|
-
|
|
1751
|
-
|
|
1752
|
-
|
|
2903
|
+
/* @__PURE__ */ jsxs(
|
|
2904
|
+
"div",
|
|
2905
|
+
{
|
|
2906
|
+
className: "flex items-center gap-1",
|
|
2907
|
+
role: "group",
|
|
2908
|
+
"aria-label": "Reorder controls",
|
|
2909
|
+
children: [
|
|
2910
|
+
/* @__PURE__ */ jsx(
|
|
2911
|
+
"button",
|
|
2912
|
+
{
|
|
2913
|
+
type: "button",
|
|
2914
|
+
className: `${buttonBaseClass} cursor-grab active:cursor-grabbing`,
|
|
2915
|
+
title: "Drag to reorder",
|
|
2916
|
+
"aria-label": "Drag to reorder block",
|
|
2917
|
+
onClick: (e) => {
|
|
2918
|
+
e.stopPropagation();
|
|
2919
|
+
setIsSelected(true);
|
|
2920
|
+
},
|
|
2921
|
+
children: /* @__PURE__ */ jsx(DragIcon, { size: 16 })
|
|
2922
|
+
}
|
|
2923
|
+
),
|
|
2924
|
+
/* @__PURE__ */ jsx(
|
|
2925
|
+
"button",
|
|
2926
|
+
{
|
|
2927
|
+
type: "button",
|
|
2928
|
+
onClick: (e) => {
|
|
2929
|
+
e.stopPropagation();
|
|
2930
|
+
onMoveUp();
|
|
2931
|
+
},
|
|
2932
|
+
disabled: index === 0,
|
|
2933
|
+
className: `${buttonBaseClass} disabled:opacity-30 disabled:cursor-not-allowed`,
|
|
2934
|
+
title: "Move up (Alt+↑)",
|
|
2935
|
+
"aria-label": "Move block up",
|
|
2936
|
+
"aria-disabled": index === 0,
|
|
2937
|
+
children: /* @__PURE__ */ jsx(ChevronUpIcon, { size: 16 })
|
|
2938
|
+
}
|
|
2939
|
+
),
|
|
2940
|
+
/* @__PURE__ */ jsx(
|
|
2941
|
+
"button",
|
|
2942
|
+
{
|
|
2943
|
+
type: "button",
|
|
2944
|
+
onClick: (e) => {
|
|
2945
|
+
e.stopPropagation();
|
|
2946
|
+
onMoveDown();
|
|
2947
|
+
},
|
|
2948
|
+
disabled: index === totalBlocks - 1,
|
|
2949
|
+
className: `${buttonBaseClass} disabled:opacity-30 disabled:cursor-not-allowed`,
|
|
2950
|
+
title: "Move down (Alt+↓)",
|
|
2951
|
+
"aria-label": "Move block down",
|
|
2952
|
+
"aria-disabled": index === totalBlocks - 1,
|
|
2953
|
+
children: /* @__PURE__ */ jsx(ChevronDownIcon, { size: 16 })
|
|
2954
|
+
}
|
|
2955
|
+
)
|
|
2956
|
+
]
|
|
2957
|
+
}
|
|
2958
|
+
),
|
|
2959
|
+
/* @__PURE__ */ jsxs(
|
|
2960
|
+
"div",
|
|
2961
|
+
{
|
|
2962
|
+
className: "flex items-center gap-1",
|
|
2963
|
+
role: "group",
|
|
2964
|
+
"aria-label": "Block actions",
|
|
2965
|
+
children: [
|
|
2966
|
+
/* @__PURE__ */ jsx(
|
|
2967
|
+
"button",
|
|
2968
|
+
{
|
|
2969
|
+
type: "button",
|
|
2970
|
+
onClick: (e) => {
|
|
2971
|
+
e.stopPropagation();
|
|
2972
|
+
setShowAddMenu(!showAddMenu);
|
|
2973
|
+
},
|
|
2974
|
+
className: `${buttonBaseClass} hover:!text-indigo-500`,
|
|
2975
|
+
title: "Add block below",
|
|
2976
|
+
"aria-label": "Add new block below",
|
|
2977
|
+
"aria-expanded": showAddMenu,
|
|
2978
|
+
"aria-haspopup": "menu",
|
|
2979
|
+
children: /* @__PURE__ */ jsx(PlusIcon, { size: 16 })
|
|
2980
|
+
}
|
|
2981
|
+
),
|
|
2982
|
+
/* @__PURE__ */ jsx(
|
|
2983
|
+
"button",
|
|
2984
|
+
{
|
|
2985
|
+
type: "button",
|
|
2986
|
+
onClick: (e) => {
|
|
2987
|
+
e.stopPropagation();
|
|
2988
|
+
onDuplicate();
|
|
2989
|
+
},
|
|
2990
|
+
className: `${buttonBaseClass} hover:!text-indigo-500`,
|
|
2991
|
+
title: "Duplicate (Ctrl+D)",
|
|
2992
|
+
"aria-label": "Duplicate block",
|
|
2993
|
+
children: /* @__PURE__ */ jsx(CopyIcon, { size: 16 })
|
|
2994
|
+
}
|
|
2995
|
+
),
|
|
2996
|
+
/* @__PURE__ */ jsx(
|
|
2997
|
+
"button",
|
|
2998
|
+
{
|
|
2999
|
+
type: "button",
|
|
3000
|
+
onClick: (e) => {
|
|
3001
|
+
e.stopPropagation();
|
|
3002
|
+
onDelete();
|
|
3003
|
+
},
|
|
3004
|
+
className: `${buttonBaseClass} hover:!text-red-500`,
|
|
3005
|
+
title: "Delete",
|
|
3006
|
+
"aria-label": "Delete block",
|
|
3007
|
+
children: /* @__PURE__ */ jsx(TrashIcon, { size: 16 })
|
|
3008
|
+
}
|
|
3009
|
+
)
|
|
3010
|
+
]
|
|
3011
|
+
}
|
|
3012
|
+
),
|
|
3013
|
+
showAddMenu && /* @__PURE__ */ jsx(
|
|
1753
3014
|
AddBlockMenu,
|
|
1754
3015
|
{
|
|
1755
|
-
onAdd:
|
|
1756
|
-
onAddBlock(type, index);
|
|
1757
|
-
setShowAddMenu(false);
|
|
1758
|
-
},
|
|
3016
|
+
onAdd: handleAddBlock,
|
|
1759
3017
|
onClose: () => setShowAddMenu(false),
|
|
1760
3018
|
theme
|
|
1761
3019
|
}
|
|
1762
|
-
)
|
|
3020
|
+
)
|
|
1763
3021
|
]
|
|
1764
3022
|
}
|
|
1765
3023
|
),
|
|
@@ -1942,14 +3200,14 @@ const PagesEditor = ({
|
|
|
1942
3200
|
]
|
|
1943
3201
|
}
|
|
1944
3202
|
),
|
|
1945
|
-
showInitialAddMenu && /* @__PURE__ */ jsx(
|
|
3203
|
+
showInitialAddMenu && /* @__PURE__ */ jsx(
|
|
1946
3204
|
AddBlockMenu,
|
|
1947
3205
|
{
|
|
1948
3206
|
onAdd: (type) => addBlock(type),
|
|
1949
3207
|
onClose: () => setShowInitialAddMenu(false),
|
|
1950
3208
|
theme
|
|
1951
3209
|
}
|
|
1952
|
-
)
|
|
3210
|
+
)
|
|
1953
3211
|
] })
|
|
1954
3212
|
] })
|
|
1955
3213
|
) : (
|
|
@@ -1995,19 +3253,21 @@ const PagesEditor = ({
|
|
|
1995
3253
|
]
|
|
1996
3254
|
}
|
|
1997
3255
|
),
|
|
1998
|
-
showInitialAddMenu && /* @__PURE__ */ jsx(
|
|
3256
|
+
showInitialAddMenu && /* @__PURE__ */ jsx(
|
|
1999
3257
|
AddBlockMenu,
|
|
2000
3258
|
{
|
|
2001
3259
|
onAdd: (type) => addBlock(type),
|
|
2002
3260
|
onClose: () => setShowInitialAddMenu(false),
|
|
2003
3261
|
theme
|
|
2004
3262
|
}
|
|
2005
|
-
)
|
|
3263
|
+
)
|
|
2006
3264
|
] }) }) })
|
|
2007
3265
|
] }) }) });
|
|
2008
3266
|
};
|
|
2009
3267
|
|
|
2010
|
-
function useBlockToolbar({
|
|
3268
|
+
function useBlockToolbar({
|
|
3269
|
+
readOnly = false
|
|
3270
|
+
} = {}) {
|
|
2011
3271
|
const [showToolbar, setShowToolbar] = useState(false);
|
|
2012
3272
|
const handleFocus = useCallback(() => {
|
|
2013
3273
|
if (!readOnly) {
|