@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.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
2
- import { useRef, useState, useCallback, useEffect, memo, createContext } from 'react';
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("svg", { className, width: size, height: size, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
113
- /* @__PURE__ */ jsx("line", { x1: "12", y1: "5", x2: "12", y2: "19" }),
114
- /* @__PURE__ */ jsx("line", { x1: "5", y1: "12", x2: "19", y2: "12" })
115
- ] });
116
- const TextIcon = ({ className = "", size = 20 }) => /* @__PURE__ */ jsxs("svg", { className, width: size, height: size, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
117
- /* @__PURE__ */ jsx("polyline", { points: "4 7 4 4 20 4 20 7" }),
118
- /* @__PURE__ */ jsx("line", { x1: "9", y1: "20", x2: "15", y2: "20" }),
119
- /* @__PURE__ */ jsx("line", { x1: "12", y1: "4", x2: "12", y2: "20" })
120
- ] });
121
- const HeadingIcon = ({ className = "", size = 20 }) => /* @__PURE__ */ jsxs("svg", { className, width: size, height: size, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
122
- /* @__PURE__ */ jsx("path", { d: "M6 4v16" }),
123
- /* @__PURE__ */ jsx("path", { d: "M18 4v16" }),
124
- /* @__PURE__ */ jsx("path", { d: "M6 12h12" })
125
- ] });
126
- const ImageIcon = ({ className = "", size = 20 }) => /* @__PURE__ */ jsxs("svg", { className, width: size, height: size, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
127
- /* @__PURE__ */ jsx("rect", { x: "3", y: "3", width: "18", height: "18", rx: "2", ry: "2" }),
128
- /* @__PURE__ */ jsx("circle", { cx: "8.5", cy: "8.5", r: "1.5" }),
129
- /* @__PURE__ */ jsx("polyline", { points: "21 15 16 10 5 21" })
130
- ] });
131
- const CodeIcon = ({ className = "", size = 20 }) => /* @__PURE__ */ jsxs("svg", { className, width: size, height: size, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
132
- /* @__PURE__ */ jsx("polyline", { points: "16 18 22 12 16 6" }),
133
- /* @__PURE__ */ jsx("polyline", { points: "8 6 2 12 8 18" })
134
- ] });
135
- const TableIcon = ({ className = "", size = 20 }) => /* @__PURE__ */ jsxs("svg", { className, width: size, height: size, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
136
- /* @__PURE__ */ jsx("rect", { x: "3", y: "3", width: "18", height: "18", rx: "2", ry: "2" }),
137
- /* @__PURE__ */ jsx("line", { x1: "3", y1: "9", x2: "21", y2: "9" }),
138
- /* @__PURE__ */ jsx("line", { x1: "3", y1: "15", x2: "21", y2: "15" }),
139
- /* @__PURE__ */ jsx("line", { x1: "9", y1: "3", x2: "9", y2: "21" }),
140
- /* @__PURE__ */ jsx("line", { x1: "15", y1: "3", x2: "15", y2: "21" })
141
- ] });
142
- const DividerIcon = ({ className = "", size = 20 }) => /* @__PURE__ */ jsx("svg", { className, width: size, height: size, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ jsx("line", { x1: "3", y1: "12", x2: "21", y2: "12" }) });
143
- const QuoteIcon = ({ className = "", size = 20 }) => /* @__PURE__ */ jsxs("svg", { className, width: size, height: size, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
144
- /* @__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" }),
145
- /* @__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" })
146
- ] });
147
- const ListIcon = ({ className = "", size = 20 }) => /* @__PURE__ */ jsxs("svg", { className, width: size, height: size, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
148
- /* @__PURE__ */ jsx("line", { x1: "8", y1: "6", x2: "21", y2: "6" }),
149
- /* @__PURE__ */ jsx("line", { x1: "8", y1: "12", x2: "21", y2: "12" }),
150
- /* @__PURE__ */ jsx("line", { x1: "8", y1: "18", x2: "21", y2: "18" }),
151
- /* @__PURE__ */ jsx("line", { x1: "3", y1: "6", x2: "3.01", y2: "6" }),
152
- /* @__PURE__ */ jsx("line", { x1: "3", y1: "12", x2: "3.01", y2: "12" }),
153
- /* @__PURE__ */ jsx("line", { x1: "3", y1: "18", x2: "3.01", y2: "18" })
154
- ] });
155
- const CalloutIcon = ({ className = "", size = 20 }) => /* @__PURE__ */ jsxs("svg", { className, width: size, height: size, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
156
- /* @__PURE__ */ jsx("circle", { cx: "12", cy: "12", r: "10" }),
157
- /* @__PURE__ */ jsx("line", { x1: "12", y1: "16", x2: "12", y2: "12" }),
158
- /* @__PURE__ */ jsx("line", { x1: "12", y1: "8", x2: "12.01", y2: "8" })
159
- ] });
160
- const TrashIcon = ({ className = "", size = 20 }) => /* @__PURE__ */ jsxs("svg", { className, width: size, height: size, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
161
- /* @__PURE__ */ jsx("polyline", { points: "3 6 5 6 21 6" }),
162
- /* @__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" })
163
- ] });
164
- const DragIcon = ({ className = "", size = 20 }) => /* @__PURE__ */ jsxs("svg", { className, width: size, height: size, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
165
- /* @__PURE__ */ jsx("circle", { cx: "9", cy: "5", r: "1" }),
166
- /* @__PURE__ */ jsx("circle", { cx: "9", cy: "12", r: "1" }),
167
- /* @__PURE__ */ jsx("circle", { cx: "9", cy: "19", r: "1" }),
168
- /* @__PURE__ */ jsx("circle", { cx: "15", cy: "5", r: "1" }),
169
- /* @__PURE__ */ jsx("circle", { cx: "15", cy: "12", r: "1" }),
170
- /* @__PURE__ */ jsx("circle", { cx: "15", cy: "19", r: "1" })
171
- ] });
172
- const CopyIcon = ({ className = "", size = 20 }) => /* @__PURE__ */ jsxs("svg", { className, width: size, height: size, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
173
- /* @__PURE__ */ jsx("rect", { x: "9", y: "9", width: "13", height: "13", rx: "2", ry: "2" }),
174
- /* @__PURE__ */ jsx("path", { d: "M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1" })
175
- ] });
176
- const ChevronUpIcon = ({ className = "", size = 20 }) => /* @__PURE__ */ jsx("svg", { className, width: size, height: size, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ jsx("polyline", { points: "18 15 12 9 6 15" }) });
177
- const ChevronDownIcon = ({ className = "", size = 20 }) => /* @__PURE__ */ jsx("svg", { className, width: size, height: size, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ jsx("polyline", { points: "6 9 12 15 18 9" }) });
178
- const BoldIcon = ({ className = "", size = 20 }) => /* @__PURE__ */ jsxs("svg", { className, width: size, height: size, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
179
- /* @__PURE__ */ jsx("path", { d: "M6 4h8a4 4 0 0 1 4 4 4 4 0 0 1-4 4H6z" }),
180
- /* @__PURE__ */ jsx("path", { d: "M6 12h9a4 4 0 0 1 4 4 4 4 0 0 1-4 4H6z" })
181
- ] });
182
- const ItalicIcon = ({ className = "", size = 20 }) => /* @__PURE__ */ jsxs("svg", { className, width: size, height: size, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
183
- /* @__PURE__ */ jsx("line", { x1: "19", y1: "4", x2: "10", y2: "4" }),
184
- /* @__PURE__ */ jsx("line", { x1: "14", y1: "20", x2: "5", y2: "20" }),
185
- /* @__PURE__ */ jsx("line", { x1: "15", y1: "4", x2: "9", y2: "20" })
186
- ] });
187
- const UnderlineIcon = ({ className = "", size = 20 }) => /* @__PURE__ */ jsxs("svg", { className, width: size, height: size, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
188
- /* @__PURE__ */ jsx("path", { d: "M6 3v7a6 6 0 0 0 6 6 6 6 0 0 0 6-6V3" }),
189
- /* @__PURE__ */ jsx("line", { x1: "4", y1: "21", x2: "20", y2: "21" })
190
- ] });
191
- const AlignLeftIcon = ({ className = "", size = 20 }) => /* @__PURE__ */ jsxs("svg", { className, width: size, height: size, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
192
- /* @__PURE__ */ jsx("line", { x1: "17", y1: "10", x2: "3", y2: "10" }),
193
- /* @__PURE__ */ jsx("line", { x1: "21", y1: "6", x2: "3", y2: "6" }),
194
- /* @__PURE__ */ jsx("line", { x1: "21", y1: "14", x2: "3", y2: "14" }),
195
- /* @__PURE__ */ jsx("line", { x1: "17", y1: "18", x2: "3", y2: "18" })
196
- ] });
197
- const AlignCenterIcon = ({ className = "", size = 20 }) => /* @__PURE__ */ jsxs("svg", { className, width: size, height: size, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
198
- /* @__PURE__ */ jsx("line", { x1: "18", y1: "10", x2: "6", y2: "10" }),
199
- /* @__PURE__ */ jsx("line", { x1: "21", y1: "6", x2: "3", y2: "6" }),
200
- /* @__PURE__ */ jsx("line", { x1: "21", y1: "14", x2: "3", y2: "14" }),
201
- /* @__PURE__ */ jsx("line", { x1: "18", y1: "18", x2: "6", y2: "18" })
202
- ] });
203
- const AlignRightIcon = ({ className = "", size = 20 }) => /* @__PURE__ */ jsxs("svg", { className, width: size, height: size, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
204
- /* @__PURE__ */ jsx("line", { x1: "21", y1: "10", x2: "7", y2: "10" }),
205
- /* @__PURE__ */ jsx("line", { x1: "21", y1: "6", x2: "3", y2: "6" }),
206
- /* @__PURE__ */ jsx("line", { x1: "21", y1: "14", x2: "3", y2: "14" }),
207
- /* @__PURE__ */ jsx("line", { x1: "21", y1: "18", x2: "7", y2: "18" })
208
- ] });
209
- const CheckIcon = ({ className = "", size = 20 }) => /* @__PURE__ */ jsx("svg", { className, width: size, height: size, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ jsx("polyline", { points: "20 6 9 17 4 12" }) });
210
- const UploadIcon = ({ className = "", size = 20 }) => /* @__PURE__ */ jsxs("svg", { className, width: size, height: size, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
211
- /* @__PURE__ */ jsx("path", { d: "M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4" }),
212
- /* @__PURE__ */ jsx("polyline", { points: "17 8 12 3 7 8" }),
213
- /* @__PURE__ */ jsx("line", { x1: "12", y1: "3", x2: "12", y2: "15" })
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
- { type: "code", label: "Code", description: "Code block with syntax highlighting", icon: CodeIcon },
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
- { type: "callout", label: "Callout", description: "Info, warning, or tip box", icon: CalloutIcon },
225
- { type: "divider", label: "Divider", description: "Horizontal line separator", icon: DividerIcon }
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
- const handleKeyDown = useCallback((e) => {
232
- switch (e.key) {
233
- case "ArrowDown":
234
- e.preventDefault();
235
- setFocusedIndex((prev) => (prev + 1) % blockOptions.length);
236
- break;
237
- case "ArrowUp":
238
- e.preventDefault();
239
- setFocusedIndex((prev) => (prev - 1 + blockOptions.length) % blockOptions.length);
240
- break;
241
- case "Enter":
242
- case " ": {
243
- e.preventDefault();
244
- const option = blockOptions[focusedIndex];
245
- if (option) {
246
- onAdd(option.type);
247
- onClose();
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
- break;
1009
+ case "Escape":
1010
+ e.preventDefault();
1011
+ onClose();
1012
+ break;
1013
+ case "Tab":
1014
+ onClose();
1015
+ break;
250
1016
  }
251
- case "Escape":
252
- e.preventDefault();
253
- onClose();
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("div", { className: "space-y-1", role: "group", "aria-labelledby": "add-block-menu-label", children: blockOptions.map((option, index) => {
298
- const Icon = option.icon;
299
- const isFocused = index === focusedIndex;
300
- return /* @__PURE__ */ jsxs(
301
- "button",
302
- {
303
- role: "menuitem",
304
- type: "button",
305
- tabIndex: -1,
306
- onClick: () => {
307
- onAdd(option.type);
308
- onClose();
309
- },
310
- onMouseEnter: () => setFocusedIndex(index),
311
- "aria-label": `Add ${option.label} block: ${option.description}`,
312
- 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"}`,
313
- children: [
314
- /* @__PURE__ */ jsx("div", { 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"}`, children: /* @__PURE__ */ jsx(Icon, { className: isDark ? "text-slate-300" : "text-slate-600", size: 20, "aria-hidden": "true" }) }),
315
- /* @__PURE__ */ jsxs("div", { className: "flex-1 min-w-0", children: [
316
- /* @__PURE__ */ jsx("p", { className: `text-sm font-medium ${isDark ? "text-white" : "text-slate-900"}`, children: option.label }),
317
- /* @__PURE__ */ jsx("p", { className: `text-xs truncate ${isDark ? "text-slate-400" : "text-slate-500"}`, children: option.description })
318
- ] })
319
- ]
320
- },
321
- option.type
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$2 = {
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 = ({ block, onUpdate, readOnly, theme = "light" }) => {
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((e) => {
352
- onUpdate({ ...block, content: e.target.value });
353
- }, [block, onUpdate]);
354
- const toggleStyle = useCallback((style) => {
355
- onUpdate({
356
- ...block,
357
- style: {
358
- ...block.style,
359
- [style]: !block.style?.[style]
360
- }
361
- });
362
- }, [block, onUpdate]);
363
- const setAlignment = useCallback((alignment) => {
364
- onUpdate({ ...block, alignment });
365
- }, [block, onUpdate]);
366
- const setFontSize = useCallback((fontSize) => {
367
- onUpdate({ ...block, fontSize });
368
- }, [block, onUpdate]);
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("div", { className: `absolute -top-12 left-0 flex items-center gap-1 p-1.5 rounded-xl shadow-lg border z-10 ${isDark ? "bg-slate-800 border-slate-600" : "bg-white border-slate-200"}`, children: [
391
- /* @__PURE__ */ jsx(
392
- "button",
393
- {
394
- onClick: () => toggleStyle("bold"),
395
- className: toolbarBtnClass(block.style?.bold),
396
- title: "Bold",
397
- children: /* @__PURE__ */ jsx(BoldIcon, { size: 16 })
398
- }
399
- ),
400
- /* @__PURE__ */ jsx(
401
- "button",
402
- {
403
- onClick: () => toggleStyle("italic"),
404
- className: toolbarBtnClass(block.style?.italic),
405
- title: "Italic",
406
- children: /* @__PURE__ */ jsx(ItalicIcon, { size: 16 })
407
- }
408
- ),
409
- /* @__PURE__ */ jsx(
410
- "button",
411
- {
412
- onClick: () => toggleStyle("underline"),
413
- className: toolbarBtnClass(block.style?.underline),
414
- title: "Underline",
415
- children: /* @__PURE__ */ jsx(UnderlineIcon, { size: 16 })
416
- }
417
- ),
418
- /* @__PURE__ */ jsx("div", { className: `w-px h-6 mx-1 ${isDark ? "bg-slate-600" : "bg-slate-200"}` }),
419
- /* @__PURE__ */ jsx(
420
- "button",
421
- {
422
- onClick: () => setAlignment("left"),
423
- className: toolbarBtnClass(block.alignment === "left"),
424
- title: "Align Left",
425
- children: /* @__PURE__ */ jsx(AlignLeftIcon, { size: 16 })
426
- }
427
- ),
428
- /* @__PURE__ */ jsx(
429
- "button",
430
- {
431
- onClick: () => setAlignment("center"),
432
- className: toolbarBtnClass(block.alignment === "center"),
433
- title: "Align Center",
434
- children: /* @__PURE__ */ jsx(AlignCenterIcon, { size: 16 })
435
- }
436
- ),
437
- /* @__PURE__ */ jsx(
438
- "button",
439
- {
440
- onClick: () => setAlignment("right"),
441
- className: toolbarBtnClass(block.alignment === "right"),
442
- title: "Align Right",
443
- children: /* @__PURE__ */ jsx(AlignRightIcon, { size: 16 })
444
- }
445
- ),
446
- /* @__PURE__ */ jsx("div", { className: `w-px h-6 mx-1 ${isDark ? "bg-slate-600" : "bg-slate-200"}` }),
447
- /* @__PURE__ */ jsxs(
448
- "select",
449
- {
450
- value: block.fontSize || "base",
451
- onChange: (e) => setFontSize(e.target.value),
452
- 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"}`,
453
- children: [
454
- /* @__PURE__ */ jsx("option", { value: "sm", children: "Small" }),
455
- /* @__PURE__ */ jsx("option", { value: "base", children: "Normal" }),
456
- /* @__PURE__ */ jsx("option", { value: "lg", children: "Large" }),
457
- /* @__PURE__ */ jsx("option", { value: "xl", children: "X-Large" })
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$2[block.alignment || "left"]} ${isDark ? "text-slate-200" : "text-slate-800"}`,
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$2[block.alignment || "left"]} ${isDark ? "text-slate-200 placeholder:text-slate-500" : "text-slate-800 placeholder:text-slate-400"}`,
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$1 = {
1348
+ const alignmentMap = {
496
1349
  left: "text-left",
497
1350
  center: "text-center",
498
1351
  right: "text-right"
499
1352
  };
500
- const HeadingBlock = ({ block, onUpdate, readOnly, theme = "light" }) => {
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("div", { className: `absolute -top-12 left-0 flex items-center gap-1 p-1.5 rounded-xl shadow-lg border z-10 ${isDark ? "bg-slate-800 border-slate-600" : "bg-white border-slate-200"}`, children: [
526
- /* @__PURE__ */ jsxs(
527
- "select",
528
- {
529
- value: block.level,
530
- onChange: (e) => setLevel(parseInt(e.target.value)),
531
- 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"}`,
532
- children: [
533
- /* @__PURE__ */ jsx("option", { value: 1, children: "Heading 1" }),
534
- /* @__PURE__ */ jsx("option", { value: 2, children: "Heading 2" }),
535
- /* @__PURE__ */ jsx("option", { value: 3, children: "Heading 3" }),
536
- /* @__PURE__ */ jsx("option", { value: 4, children: "Heading 4" }),
537
- /* @__PURE__ */ jsx("option", { value: 5, children: "Heading 5" }),
538
- /* @__PURE__ */ jsx("option", { value: 6, children: "Heading 6" })
539
- ]
540
- }
541
- ),
542
- /* @__PURE__ */ jsx("div", { className: `w-px h-6 mx-1 ${isDark ? "bg-slate-600" : "bg-slate-200"}` }),
543
- /* @__PURE__ */ jsx(
544
- "button",
545
- {
546
- onClick: () => setAlignment("left"),
547
- className: toolbarBtnClass(block.alignment === "left"),
548
- title: "Align Left",
549
- children: /* @__PURE__ */ jsx(AlignLeftIcon, { size: 16 })
550
- }
551
- ),
552
- /* @__PURE__ */ jsx(
553
- "button",
554
- {
555
- onClick: () => setAlignment("center"),
556
- className: toolbarBtnClass(block.alignment === "center"),
557
- title: "Align Center",
558
- children: /* @__PURE__ */ jsx(AlignCenterIcon, { size: 16 })
559
- }
560
- ),
561
- /* @__PURE__ */ jsx(
562
- "button",
563
- {
564
- onClick: () => setAlignment("right"),
565
- className: toolbarBtnClass(block.alignment === "right"),
566
- title: "Align Right",
567
- children: /* @__PURE__ */ jsx(AlignRightIcon, { size: 16 })
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$1[block.alignment || "left"]} ${isDark ? "text-white" : "text-slate-900"}`,
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$1[block.alignment || "left"]} ${isDark ? "text-white placeholder:text-slate-500" : "text-slate-900 placeholder:text-slate-400"}`
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 alignmentMap = {
594
- left: "mr-auto",
595
- center: "mx-auto",
596
- right: "ml-auto"
597
- };
598
- const ImageBlock = ({ block, onUpdate, readOnly, theme = "light" }) => {
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(UploadIcon, { className: `w-12 h-12 mb-4 ${isDark ? "text-slate-500" : "text-slate-400"}` }),
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
- className: "group relative",
692
- onFocus: () => setShowToolbar(true),
693
- onBlur: (e) => {
694
- if (!e.currentTarget.contains(e.relatedTarget)) {
695
- setShowToolbar(false);
696
- }
697
- },
698
- children: [
699
- showToolbar && !readOnly && /* @__PURE__ */ jsxs("div", { className: `absolute -top-12 left-1/2 -translate-x-1/2 flex items-center gap-1 p-1.5 rounded-xl shadow-lg border z-10 ${isDark ? "bg-slate-800 border-slate-600" : "bg-white border-slate-200"}`, children: [
700
- /* @__PURE__ */ jsx(
701
- "button",
702
- {
703
- onClick: () => setAlignment("left"),
704
- className: toolbarBtnClass(block.alignment === "left"),
705
- title: "Align Left",
706
- children: /* @__PURE__ */ jsx(AlignLeftIcon, { size: 16 })
707
- }
708
- ),
709
- /* @__PURE__ */ jsx(
710
- "button",
711
- {
712
- onClick: () => setAlignment("center"),
713
- className: toolbarBtnClass(block.alignment === "center"),
714
- title: "Align Center",
715
- children: /* @__PURE__ */ jsx(AlignCenterIcon, { size: 16 })
716
- }
717
- ),
718
- /* @__PURE__ */ jsx(
719
- "button",
720
- {
721
- onClick: () => setAlignment("right"),
722
- className: toolbarBtnClass(block.alignment === "right"),
723
- title: "Align Right",
724
- children: /* @__PURE__ */ jsx(AlignRightIcon, { size: 16 })
725
- }
726
- ),
727
- /* @__PURE__ */ jsx("div", { className: `w-px h-6 mx-1 ${isDark ? "bg-slate-600" : "bg-slate-200"}` }),
728
- /* @__PURE__ */ jsx(
729
- "input",
730
- {
731
- type: "number",
732
- value: block.width || "",
733
- onChange: handleWidthChange,
734
- placeholder: "Width",
735
- 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"}`
736
- }
737
- ),
738
- /* @__PURE__ */ jsx("div", { className: `w-px h-6 mx-1 ${isDark ? "bg-slate-600" : "bg-slate-200"}` }),
739
- /* @__PURE__ */ jsx(
740
- "button",
741
- {
742
- onClick: clearImage,
743
- 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"}`,
744
- title: "Remove Image",
745
- children: /* @__PURE__ */ jsx(TrashIcon, { size: 16 })
746
- }
747
- )
748
- ] }),
749
- /* @__PURE__ */ jsxs("figure", { className: `${alignmentMap[block.alignment || "center"]}`, style: { maxWidth: block.width ? `${block.width}px` : "100%" }, children: [
750
- /* @__PURE__ */ jsx(
751
- "img",
752
- {
753
- src: block.src,
754
- alt: block.alt || "",
755
- className: "max-w-full h-auto rounded-xl shadow-sm"
756
- }
757
- ),
758
- !readOnly ? /* @__PURE__ */ jsxs("div", { className: "mt-3 space-y-2", children: [
759
- /* @__PURE__ */ jsx(
760
- "input",
761
- {
762
- type: "text",
763
- value: block.caption || "",
764
- onChange: handleCaptionChange,
765
- placeholder: "Add a caption...",
766
- 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"}`
767
- }
768
- ),
769
- /* @__PURE__ */ jsx(
770
- "input",
771
- {
772
- type: "text",
773
- value: block.alt || "",
774
- onChange: handleAltChange,
775
- placeholder: "Alt text for accessibility...",
776
- 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"}`
777
- }
778
- )
779
- ] }) : block.caption ? /* @__PURE__ */ jsx("figcaption", { className: `mt-3 text-center text-sm ${isDark ? "text-slate-400" : "text-slate-600"}`, children: block.caption }) : null
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 = ({ block, onUpdate, readOnly, theme = "light" }) => {
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("div", { 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"}`, children: [
853
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3", children: [
854
- /* @__PURE__ */ jsxs("div", { className: "flex gap-1.5", children: [
855
- /* @__PURE__ */ jsx("div", { className: "w-3 h-3 rounded-full bg-red-500/80" }),
856
- /* @__PURE__ */ jsx("div", { className: "w-3 h-3 rounded-full bg-yellow-500/80" }),
857
- /* @__PURE__ */ jsx("div", { className: "w-3 h-3 rounded-full bg-green-500/80" })
858
- ] }),
859
- !readOnly ? /* @__PURE__ */ jsx(
860
- "input",
861
- {
862
- type: "text",
863
- value: block.filename || "",
864
- onChange: handleFilenameChange,
865
- placeholder: "filename.js",
866
- className: "text-sm text-slate-400 bg-transparent outline-none placeholder:text-slate-600 w-32"
867
- }
868
- ) : block.filename ? /* @__PURE__ */ jsx("span", { className: "text-sm text-slate-400", children: block.filename }) : null
869
- ] }),
870
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
871
- !readOnly && /* @__PURE__ */ jsxs(Fragment, { children: [
872
- /* @__PURE__ */ jsx(
873
- "select",
874
- {
875
- value: block.language,
876
- onChange: handleLanguageChange,
877
- className: "text-xs px-2 py-1.5 bg-slate-700 text-slate-300 rounded-lg border border-slate-600 outline-none",
878
- children: SUPPORTED_LANGUAGES.map((lang) => /* @__PURE__ */ jsx("option", { value: lang, children: lang }, lang))
879
- }
880
- ),
881
- /* @__PURE__ */ jsx(
882
- "button",
883
- {
884
- onClick: toggleLineNumbers,
885
- 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"}`,
886
- children: "#"
887
- }
888
- )
889
- ] }),
890
- /* @__PURE__ */ jsx(
891
- "button",
892
- {
893
- onClick: copyToClipboard,
894
- className: "p-1.5 rounded-lg hover:bg-slate-700 text-slate-400 hover:text-white transition-colors",
895
- title: "Copy code",
896
- children: copied ? /* @__PURE__ */ jsx(CheckIcon, { size: 16 }) : /* @__PURE__ */ jsx(CopyIcon, { size: 16 })
897
- }
898
- )
899
- ] })
900
- ] }),
901
- /* @__PURE__ */ jsxs("div", { className: "relative flex overflow-x-auto", children: [
902
- 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("div", { className: "text-xs text-slate-600 leading-6 font-mono", children: num }, num)) }),
903
- /* @__PURE__ */ jsx("div", { className: "flex-1 p-4 overflow-x-auto", children: readOnly ? /* @__PURE__ */ jsx("pre", { className: "text-sm text-slate-100 font-mono leading-6 whitespace-pre", children: /* @__PURE__ */ jsx("code", { children: block.code }) }) : /* @__PURE__ */ jsx(
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 = ({ block, onUpdate, readOnly, theme = "light" }) => {
1864
+ const TableBlock = ({
1865
+ block,
1866
+ onUpdate,
1867
+ readOnly,
1868
+ theme = "light"
1869
+ }) => {
937
1870
  const [showToolbar, setShowToolbar] = useState(false);
938
- const [selectedCell, setSelectedCell] = useState(null);
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("div", { className: `absolute -top-12 left-0 flex items-center gap-1 p-1.5 rounded-xl shadow-lg border z-10 ${isDark ? "bg-slate-800 border-slate-600" : "bg-white border-slate-200"}`, children: [
1009
- /* @__PURE__ */ jsxs(
1010
- "button",
1011
- {
1012
- onClick: addRow,
1013
- className: `flex items-center gap-1 ${toolbarBtnClass()}`,
1014
- title: "Add Row",
1015
- children: [
1016
- /* @__PURE__ */ jsx(PlusIcon, { size: 14 }),
1017
- " Row"
1018
- ]
1019
- }
1020
- ),
1021
- /* @__PURE__ */ jsxs(
1022
- "button",
1023
- {
1024
- onClick: addColumn,
1025
- className: `flex items-center gap-1 ${toolbarBtnClass()}`,
1026
- title: "Add Column",
1027
- children: [
1028
- /* @__PURE__ */ jsx(PlusIcon, { size: 14 }),
1029
- " Col"
1030
- ]
1031
- }
1032
- ),
1033
- /* @__PURE__ */ jsx("div", { className: `w-px h-6 mx-1 ${isDark ? "bg-slate-600" : "bg-slate-200"}` }),
1034
- /* @__PURE__ */ jsx(
1035
- "button",
1036
- {
1037
- onClick: toggleHeader,
1038
- className: toolbarBtnClass(block.hasHeader),
1039
- children: "Header"
1040
- }
1041
- ),
1042
- selectedCell && /* @__PURE__ */ jsxs(Fragment, { children: [
1043
- /* @__PURE__ */ jsx("div", { className: `w-px h-6 mx-1 ${isDark ? "bg-slate-600" : "bg-slate-200"}` }),
1044
- /* @__PURE__ */ jsx(
1045
- "button",
1046
- {
1047
- onClick: () => setCellAlignment("left"),
1048
- className: toolbarBtnClass(),
1049
- children: "Left"
1050
- }
1051
- ),
1052
- /* @__PURE__ */ jsx(
1053
- "button",
1054
- {
1055
- onClick: () => setCellAlignment("center"),
1056
- className: toolbarBtnClass(),
1057
- children: "Center"
1058
- }
1059
- ),
1060
- /* @__PURE__ */ jsx(
1061
- "button",
1062
- {
1063
- onClick: () => setCellAlignment("right"),
1064
- className: toolbarBtnClass(),
1065
- children: "Right"
1066
- }
1067
- )
1068
- ] })
1069
- ] }),
1070
- /* @__PURE__ */ jsx("div", { className: "overflow-x-auto rounded-xl", children: /* @__PURE__ */ jsx("table", { className: `w-full border-collapse border ${isDark ? "border-slate-600" : "border-slate-300"}`, children: /* @__PURE__ */ jsx("tbody", { children: block.rows.map((row, rowIndex) => /* @__PURE__ */ jsxs("tr", { className: "group/row", children: [
1071
- row.map((cell, colIndex) => {
1072
- const isHeader = block.hasHeader && rowIndex === 0;
1073
- const CellTag = isHeader ? "th" : "td";
1074
- const alignClass = cell.alignment === "center" ? "text-center" : cell.alignment === "right" ? "text-right" : "text-left";
1075
- return /* @__PURE__ */ jsxs(
1076
- CellTag,
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: `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}`,
1079
- children: [
1080
- readOnly ? /* @__PURE__ */ jsx("div", { className: `px-3 py-2 min-h-[40px] ${isDark ? "text-slate-200" : "text-slate-700"}`, children: cell.content }) : /* @__PURE__ */ jsx(
1081
- "input",
1082
- {
1083
- type: "text",
1084
- value: cell.content,
1085
- onChange: (e) => updateCell(rowIndex, colIndex, e.target.value),
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
- onClick: () => deleteColumn(colIndex),
1096
- className: "absolute -top-6 left-1/2 -translate-x-1/2 p-1 rounded-lg bg-red-500 text-white opacity-0 group-hover:opacity-100 transition-opacity",
1097
- title: "Delete Column",
1098
- children: /* @__PURE__ */ jsx(TrashIcon, { size: 12 })
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
- colIndex
1104
- );
1105
- }),
1106
- !readOnly && showToolbar && /* @__PURE__ */ jsx("td", { className: "w-8 border-none bg-transparent p-0", children: /* @__PURE__ */ jsx(
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 = ({ block, onUpdate, readOnly, theme = "light" }) => {
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("p", { className: `text-xs text-center mt-1 opacity-0 group-hover:opacity-100 transition-opacity ${isDark ? "text-slate-500" : "text-slate-400"}`, children: [
1144
- "Click to change style (",
1145
- block.style || "solid",
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 = ({ block, onUpdate, readOnly, theme = "light" }) => {
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("div", { className: `absolute -top-12 left-0 flex items-center gap-1 p-1.5 rounded-xl shadow-lg border z-10 ${isDark ? "bg-slate-800 border-slate-600" : "bg-white border-slate-200"}`, children: [
1188
- /* @__PURE__ */ jsx(
1189
- "button",
1190
- {
1191
- onClick: () => setStyle("default"),
1192
- className: toolbarBtnClass(block.style === "default" || !block.style),
1193
- children: "Simple"
1194
- }
1195
- ),
1196
- /* @__PURE__ */ jsx(
1197
- "button",
1198
- {
1199
- onClick: () => setStyle("bordered"),
1200
- className: toolbarBtnClass(block.style === "bordered"),
1201
- children: "Bordered"
1202
- }
1203
- ),
1204
- /* @__PURE__ */ jsx(
1205
- "button",
1206
- {
1207
- onClick: () => setStyle("modern"),
1208
- className: toolbarBtnClass(block.style === "modern"),
1209
- children: "Modern"
1210
- }
1211
- )
1212
- ] }),
1213
- /* @__PURE__ */ jsx("blockquote", { className: `${styleClasses[block.style || "default"]} ${isDark ? "text-slate-300" : "text-slate-700"}`, children: readOnly ? /* @__PURE__ */ jsxs(Fragment, { children: [
1214
- /* @__PURE__ */ jsx("p", { className: "text-lg leading-relaxed whitespace-pre-wrap", children: block.content }),
1215
- block.author && /* @__PURE__ */ jsxs("cite", { className: `block mt-3 text-sm not-italic ${isDark ? "text-slate-400" : "text-slate-500"}`, children: [
1216
- "— ",
1217
- block.author
1218
- ] })
1219
- ] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
1220
- /* @__PURE__ */ jsx(
1221
- "textarea",
1222
- {
1223
- ref: textareaRef,
1224
- value: block.content,
1225
- onChange: handleContentChange,
1226
- placeholder: "Enter quote...",
1227
- className: `w-full text-lg leading-relaxed bg-transparent outline-none resize-none ${isDark ? "placeholder:text-slate-500" : "placeholder:text-slate-400"}`,
1228
- rows: 1
1229
- }
1230
- ),
1231
- /* @__PURE__ */ jsx(
1232
- "input",
1233
- {
1234
- type: "text",
1235
- value: block.author || "",
1236
- onChange: handleAuthorChange,
1237
- placeholder: "— Author name",
1238
- 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"}`
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 = ({ block, onUpdate, readOnly, theme = "light" }) => {
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("div", { className: `absolute -top-12 left-0 flex items-center gap-1 p-1.5 rounded-xl shadow-lg border z-10 ${isDark ? "bg-slate-800 border-slate-600" : "bg-white border-slate-200"}`, children: [
1316
- /* @__PURE__ */ jsx(
1317
- "button",
1318
- {
1319
- onClick: () => setListType("bullet"),
1320
- className: toolbarBtnClass(block.listType === "bullet"),
1321
- children: "• Bullet"
1322
- }
1323
- ),
1324
- /* @__PURE__ */ jsx(
1325
- "button",
1326
- {
1327
- onClick: () => setListType("numbered"),
1328
- className: toolbarBtnClass(block.listType === "numbered"),
1329
- children: "1. Numbered"
1330
- }
1331
- ),
1332
- /* @__PURE__ */ jsx(
1333
- "button",
1334
- {
1335
- onClick: () => setListType("checklist"),
1336
- className: toolbarBtnClass(block.listType === "checklist"),
1337
- children: "☑ Checklist"
1338
- }
1339
- )
1340
- ] }),
1341
- /* @__PURE__ */ jsx(ListWrapper, { 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"}`, children: block.items.map((item, index) => /* @__PURE__ */ jsxs("li", { className: "group/item flex items-center gap-2", children: [
1342
- block.listType === "checklist" && /* @__PURE__ */ jsx(
1343
- "button",
1344
- {
1345
- onClick: () => toggleChecked(index),
1346
- disabled: readOnly,
1347
- 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"}`,
1348
- children: block.checkedItems?.[index] && /* @__PURE__ */ jsx(CheckIcon, { size: 12 })
1349
- }
1350
- ),
1351
- readOnly ? /* @__PURE__ */ jsx("span", { className: block.checkedItems?.[index] ? isDark ? "line-through text-slate-500" : "line-through text-slate-400" : "", children: item }) : /* @__PURE__ */ jsxs(Fragment, { children: [
1352
- /* @__PURE__ */ jsx(
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
- onClick: () => removeItem(index),
1368
- 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"}`,
1369
- children: /* @__PURE__ */ jsx(TrashIcon, { size: 14 })
1370
- }
1371
- )
1372
- ] })
1373
- ] }, index)) }),
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 = ({ block, onUpdate, readOnly, theme = "light" }) => {
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("div", { className: `absolute -top-12 left-0 flex items-center gap-1 p-1.5 rounded-xl shadow-lg border z-10 ${isDark ? "bg-slate-800 border-slate-600" : "bg-white border-slate-200"}`, children: Object.keys(variantStyles).map((variant) => /* @__PURE__ */ jsxs(
1473
- "button",
2631
+ showToolbar && !readOnly && /* @__PURE__ */ jsx(
2632
+ "div",
1474
2633
  {
1475
- onClick: () => setVariant(variant),
1476
- className: toolbarBtnClass(block.variant === variant),
1477
- children: [
1478
- variantIcons[variant],
1479
- " ",
1480
- variantLabels[variant]
1481
- ]
1482
- },
1483
- variant
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((e) => {
1559
- const target = e.target;
1560
- const interactiveElements = ["INPUT", "TEXTAREA", "BUTTON", "SELECT"];
1561
- if (interactiveElements.includes(target.tagName)) {
1562
- return;
1563
- }
1564
- if (!readOnly) {
1565
- setIsSelected(true);
1566
- }
1567
- }, [readOnly]);
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(TextBlock, { block, onUpdate: (b) => onUpdate(b), ...commonProps });
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(HeadingBlock, { block, onUpdate: (b) => onUpdate(b), ...commonProps });
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(ImageBlock, { block, onUpdate: (b) => onUpdate(b), ...commonProps });
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(CodeBlock, { block, onUpdate: (b) => onUpdate(b), ...commonProps });
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(TableBlock, { block, onUpdate: (b) => onUpdate(b), ...commonProps });
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(DividerBlock, { block, onUpdate: (b) => onUpdate(b), ...commonProps });
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(QuoteBlock, { block, onUpdate: (b) => onUpdate(b), ...commonProps });
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(ListBlock, { block, onUpdate: (b) => onUpdate(b), ...commonProps });
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(CalloutBlock, { block, onUpdate: (b) => onUpdate(b), ...commonProps });
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 showControls = !readOnly && isSelected;
1600
- const handleKeyDown = useCallback((e) => {
1601
- if (readOnly || !isSelected) return;
1602
- switch (e.key) {
1603
- case "Escape":
1604
- setIsSelected(false);
1605
- setShowAddMenu(false);
1606
- break;
1607
- case "Delete":
1608
- case "Backspace":
1609
- if (!e.target.matches("input, textarea, [contenteditable]")) {
1610
- e.preventDefault();
1611
- onDelete();
1612
- }
1613
- break;
1614
- case "ArrowUp":
1615
- if (e.altKey) {
1616
- e.preventDefault();
1617
- onMoveUp();
1618
- }
1619
- break;
1620
- case "ArrowDown":
1621
- if (e.altKey) {
1622
- e.preventDefault();
1623
- onMoveDown();
1624
- }
1625
- break;
1626
- case "d":
1627
- if (e.ctrlKey || e.metaKey) {
1628
- e.preventDefault();
1629
- onDuplicate();
1630
- }
1631
- break;
1632
- }
1633
- }, [readOnly, isSelected, onDelete, onMoveUp, onMoveDown, onDuplicate]);
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("div", { className: "flex items-center gap-1", role: "group", "aria-label": "Reorder controls", children: [
1663
- /* @__PURE__ */ jsx(
1664
- "button",
1665
- {
1666
- type: "button",
1667
- className: `${buttonBaseClass} cursor-grab active:cursor-grabbing`,
1668
- title: "Drag to reorder",
1669
- "aria-label": "Drag to reorder block",
1670
- children: /* @__PURE__ */ jsx(DragIcon, { size: 16 })
1671
- }
1672
- ),
1673
- /* @__PURE__ */ jsx(
1674
- "button",
1675
- {
1676
- type: "button",
1677
- onClick: (e) => {
1678
- e.stopPropagation();
1679
- onMoveUp();
1680
- },
1681
- disabled: index === 0,
1682
- className: `${buttonBaseClass} disabled:opacity-30 disabled:cursor-not-allowed`,
1683
- title: "Move up (Alt+↑)",
1684
- "aria-label": "Move block up",
1685
- "aria-disabled": index === 0,
1686
- children: /* @__PURE__ */ jsx(ChevronUpIcon, { size: 16 })
1687
- }
1688
- ),
1689
- /* @__PURE__ */ jsx(
1690
- "button",
1691
- {
1692
- type: "button",
1693
- onClick: (e) => {
1694
- e.stopPropagation();
1695
- onMoveDown();
1696
- },
1697
- disabled: index === totalBlocks - 1,
1698
- className: `${buttonBaseClass} disabled:opacity-30 disabled:cursor-not-allowed`,
1699
- title: "Move down (Alt+↓)",
1700
- "aria-label": "Move block down",
1701
- "aria-disabled": index === totalBlocks - 1,
1702
- children: /* @__PURE__ */ jsx(ChevronDownIcon, { size: 16 })
1703
- }
1704
- )
1705
- ] }),
1706
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1", role: "group", "aria-label": "Block actions", children: [
1707
- /* @__PURE__ */ jsx(
1708
- "button",
1709
- {
1710
- type: "button",
1711
- onClick: (e) => {
1712
- e.stopPropagation();
1713
- setShowAddMenu(!showAddMenu);
1714
- },
1715
- className: `${buttonBaseClass} hover:!text-indigo-500`,
1716
- title: "Add block below",
1717
- "aria-label": "Add new block below",
1718
- "aria-expanded": showAddMenu,
1719
- "aria-haspopup": "menu",
1720
- children: /* @__PURE__ */ jsx(PlusIcon, { size: 16 })
1721
- }
1722
- ),
1723
- /* @__PURE__ */ jsx(
1724
- "button",
1725
- {
1726
- type: "button",
1727
- onClick: (e) => {
1728
- e.stopPropagation();
1729
- onDuplicate();
1730
- },
1731
- className: `${buttonBaseClass} hover:!text-indigo-500`,
1732
- title: "Duplicate (Ctrl+D)",
1733
- "aria-label": "Duplicate block",
1734
- children: /* @__PURE__ */ jsx(CopyIcon, { size: 16 })
1735
- }
1736
- ),
1737
- /* @__PURE__ */ jsx(
1738
- "button",
1739
- {
1740
- type: "button",
1741
- onClick: (e) => {
1742
- e.stopPropagation();
1743
- onDelete();
1744
- },
1745
- className: `${buttonBaseClass} hover:!text-red-500`,
1746
- title: "Delete",
1747
- "aria-label": "Delete block",
1748
- children: /* @__PURE__ */ jsx(TrashIcon, { size: 16 })
1749
- }
1750
- )
1751
- ] }),
1752
- showAddMenu && /* @__PURE__ */ jsx("div", { className: "absolute left-1/2 -translate-x-1/2 top-full mt-1 z-50", children: /* @__PURE__ */ jsx(
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: (type) => {
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("div", { className: "absolute left-1/2 -translate-x-1/2 top-full mt-2 z-50", children: /* @__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("div", { className: "absolute left-1/2 -translate-x-1/2 bottom-full mb-2 z-50", children: /* @__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({ readOnly = false } = {}) {
3268
+ function useBlockToolbar({
3269
+ readOnly = false
3270
+ } = {}) {
2011
3271
  const [showToolbar, setShowToolbar] = useState(false);
2012
3272
  const handleFocus = useCallback(() => {
2013
3273
  if (!readOnly) {