@tecof/theme-editor 0.0.35 → 0.0.39

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
@@ -2,7 +2,6 @@
2
2
 
3
3
  var React__default = require('react');
4
4
  var jsxRuntime = require('react/jsx-runtime');
5
- var core = require('@puckeditor/core');
6
5
  var zustand = require('zustand');
7
6
  var immer = require('zustand/middleware/immer');
8
7
  var nanoid = require('nanoid');
@@ -337,872 +336,165 @@ function useTecof() {
337
336
  return ctx;
338
337
  }
339
338
 
340
- // node_modules/lucide-react/dist/esm/shared/src/utils/mergeClasses.js
341
- var mergeClasses = (...classes) => classes.filter((className, index2, array) => {
342
- return Boolean(className) && className.trim() !== "" && array.indexOf(className) === index2;
343
- }).join(" ").trim();
344
-
345
- // node_modules/lucide-react/dist/esm/shared/src/utils/toKebabCase.js
346
- var toKebabCase = (string) => string.replace(/([a-z0-9])([A-Z])/g, "$1-$2").toLowerCase();
347
-
348
- // node_modules/lucide-react/dist/esm/shared/src/utils/toCamelCase.js
349
- var toCamelCase = (string) => string.replace(
350
- /^([A-Z])|[\s-_]+(\w)/g,
351
- (match, p1, p2) => p2 ? p2.toUpperCase() : p1.toLowerCase()
352
- );
353
-
354
- // node_modules/lucide-react/dist/esm/shared/src/utils/toPascalCase.js
355
- var toPascalCase = (string) => {
356
- const camelCase = toCamelCase(string);
357
- return camelCase.charAt(0).toUpperCase() + camelCase.slice(1);
339
+ // src/engine/document.ts
340
+ var EMPTY_DOCUMENT = {
341
+ root: { props: {} },
342
+ content: [],
343
+ zones: {}
358
344
  };
359
-
360
- // node_modules/lucide-react/dist/esm/defaultAttributes.js
361
- var defaultAttributes = {
362
- xmlns: "http://www.w3.org/2000/svg",
363
- width: 24,
364
- height: 24,
365
- viewBox: "0 0 24 24",
366
- fill: "none",
367
- stroke: "currentColor",
368
- strokeWidth: 2,
369
- strokeLinecap: "round",
370
- strokeLinejoin: "round"
345
+ var parseDocument = (rawData) => {
346
+ if (!rawData) return { ...EMPTY_DOCUMENT };
347
+ return {
348
+ root: rawData.root || { props: {} },
349
+ content: rawData.content || [],
350
+ zones: rawData.zones || {}
351
+ };
352
+ };
353
+ var serializeDocument = (doc) => {
354
+ return {
355
+ root: doc.root,
356
+ content: doc.content,
357
+ zones: doc.zones
358
+ };
371
359
  };
372
360
 
373
- // node_modules/lucide-react/dist/esm/shared/src/utils/hasA11yProp.js
374
- var hasA11yProp = (props) => {
375
- for (const prop in props) {
376
- if (prop.startsWith("aria-") || prop === "role" || prop === "title") {
377
- return true;
361
+ // src/engine/zones.ts
362
+ var parseZoneKey = (zoneKey) => {
363
+ const parts = zoneKey.split(":");
364
+ return {
365
+ parentId: parts[0],
366
+ slotName: parts[1] || "default"
367
+ };
368
+ };
369
+ var findNodeById = (doc, id) => {
370
+ for (let i2 = 0; i2 < doc.content.length; i2++) {
371
+ if (doc.content[i2].props.id === id) {
372
+ return { node: doc.content[i2], path: { index: i2 } };
378
373
  }
379
374
  }
380
- return false;
375
+ for (const [zoneKey, items] of Object.entries(doc.zones)) {
376
+ for (let i2 = 0; i2 < items.length; i2++) {
377
+ if (items[i2].props.id === id) {
378
+ return { node: items[i2], path: { zoneKey, index: i2 } };
379
+ }
380
+ }
381
+ }
382
+ return null;
381
383
  };
382
- var LucideContext = React__default.createContext({});
383
- var useLucideContext = () => React__default.useContext(LucideContext);
384
-
385
- // node_modules/lucide-react/dist/esm/Icon.js
386
- var Icon = React__default.forwardRef(
387
- ({ color, size, strokeWidth, absoluteStrokeWidth, className = "", children, iconNode, ...rest }, ref) => {
388
- const {
389
- size: contextSize = 24,
390
- strokeWidth: contextStrokeWidth = 2,
391
- absoluteStrokeWidth: contextAbsoluteStrokeWidth = false,
392
- color: contextColor = "currentColor",
393
- className: contextClass = ""
394
- } = useLucideContext() ?? {};
395
- const calculatedStrokeWidth = absoluteStrokeWidth ?? contextAbsoluteStrokeWidth ? Number(strokeWidth ?? contextStrokeWidth) * 24 / Number(size ?? contextSize) : strokeWidth ?? contextStrokeWidth;
396
- return React__default.createElement(
397
- "svg",
398
- {
399
- ref,
400
- ...defaultAttributes,
401
- width: size ?? contextSize ?? defaultAttributes.width,
402
- height: size ?? contextSize ?? defaultAttributes.height,
403
- stroke: color ?? contextColor,
404
- strokeWidth: calculatedStrokeWidth,
405
- className: mergeClasses("lucide", contextClass, className),
406
- ...!children && !hasA11yProp(rest) && { "aria-hidden": "true" },
407
- ...rest
408
- },
409
- [
410
- ...iconNode.map(([tag, attrs]) => React__default.createElement(tag, attrs)),
411
- ...Array.isArray(children) ? children : [children]
412
- ]
413
- );
384
+ var getDescendantZoneKeys = (zones, nodeId, acc = []) => {
385
+ const prefix = `${nodeId}:`;
386
+ for (const zoneKey of Object.keys(zones)) {
387
+ if (zoneKey.startsWith(prefix)) {
388
+ acc.push(zoneKey);
389
+ for (const child of zones[zoneKey]) {
390
+ getDescendantZoneKeys(zones, child.props.id, acc);
391
+ }
392
+ }
414
393
  }
415
- );
416
-
417
- // node_modules/lucide-react/dist/esm/createLucideIcon.js
418
- var createLucideIcon = (iconName, iconNode) => {
419
- const Component2 = React__default.forwardRef(
420
- ({ className, ...props }, ref) => React__default.createElement(Icon, {
421
- ref,
422
- iconNode,
423
- className: mergeClasses(
424
- `lucide-${toKebabCase(toPascalCase(iconName))}`,
425
- `lucide-${iconName}`,
426
- className
427
- ),
428
- ...props
429
- })
430
- );
431
- Component2.displayName = toPascalCase(iconName);
432
- return Component2;
394
+ return acc;
433
395
  };
434
-
435
- // node_modules/lucide-react/dist/esm/icons/arrow-down.js
436
- var __iconNode = [
437
- ["path", { d: "M12 5v14", key: "s699le" }],
438
- ["path", { d: "m19 12-7 7-7-7", key: "1idqje" }]
439
- ];
440
- var ArrowDown = createLucideIcon("arrow-down", __iconNode);
441
-
442
- // node_modules/lucide-react/dist/esm/icons/arrow-up.js
443
- var __iconNode2 = [
444
- ["path", { d: "m5 12 7-7 7 7", key: "hav0vg" }],
445
- ["path", { d: "M12 19V5", key: "x0mq9r" }]
446
- ];
447
- var ArrowUp = createLucideIcon("arrow-up", __iconNode2);
448
-
449
- // node_modules/lucide-react/dist/esm/icons/check.js
450
- var __iconNode3 = [["path", { d: "M20 6 9 17l-5-5", key: "1gmf2c" }]];
451
- var Check = createLucideIcon("check", __iconNode3);
452
-
453
- // node_modules/lucide-react/dist/esm/icons/chevron-down.js
454
- var __iconNode4 = [["path", { d: "m6 9 6 6 6-6", key: "qrunsl" }]];
455
- var ChevronDown = createLucideIcon("chevron-down", __iconNode4);
456
-
457
- // node_modules/lucide-react/dist/esm/icons/chevron-right.js
458
- var __iconNode5 = [["path", { d: "m9 18 6-6-6-6", key: "mthhwq" }]];
459
- var ChevronRight = createLucideIcon("chevron-right", __iconNode5);
460
-
461
- // node_modules/lucide-react/dist/esm/icons/chevron-up.js
462
- var __iconNode6 = [["path", { d: "m18 15-6-6-6 6", key: "153udz" }]];
463
- var ChevronUp = createLucideIcon("chevron-up", __iconNode6);
464
-
465
- // node_modules/lucide-react/dist/esm/icons/code.js
466
- var __iconNode7 = [
467
- ["path", { d: "m16 18 6-6-6-6", key: "eg8j8" }],
468
- ["path", { d: "m8 6-6 6 6 6", key: "ppft3o" }]
469
- ];
470
- var Code = createLucideIcon("code", __iconNode7);
471
-
472
- // node_modules/lucide-react/dist/esm/icons/copy.js
473
- var __iconNode8 = [
474
- ["rect", { width: "14", height: "14", x: "8", y: "8", rx: "2", ry: "2", key: "17jyea" }],
475
- ["path", { d: "M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2", key: "zix9uf" }]
476
- ];
477
- var Copy = createLucideIcon("copy", __iconNode8);
478
-
479
- // node_modules/lucide-react/dist/esm/icons/database.js
480
- var __iconNode9 = [
481
- ["ellipse", { cx: "12", cy: "5", rx: "9", ry: "3", key: "msslwz" }],
482
- ["path", { d: "M3 5V19A9 3 0 0 0 21 19V5", key: "1wlel7" }],
483
- ["path", { d: "M3 12A9 3 0 0 0 21 12", key: "mv7ke4" }]
484
- ];
485
- var Database = createLucideIcon("database", __iconNode9);
486
-
487
- // node_modules/lucide-react/dist/esm/icons/external-link.js
488
- var __iconNode10 = [
489
- ["path", { d: "M15 3h6v6", key: "1q9fwt" }],
490
- ["path", { d: "M10 14 21 3", key: "gplh6r" }],
491
- ["path", { d: "M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6", key: "a6xqqp" }]
492
- ];
493
- var ExternalLink = createLucideIcon("external-link", __iconNode10);
494
-
495
- // node_modules/lucide-react/dist/esm/icons/file-text.js
496
- var __iconNode11 = [
497
- [
498
- "path",
499
- {
500
- d: "M6 22a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h8a2.4 2.4 0 0 1 1.704.706l3.588 3.588A2.4 2.4 0 0 1 20 8v12a2 2 0 0 1-2 2z",
501
- key: "1oefj6"
396
+ var getParentId = (doc, id) => {
397
+ const res2 = findNodeById(doc, id);
398
+ if (!res2 || !res2.path.zoneKey) return null;
399
+ return parseZoneKey(res2.path.zoneKey).parentId;
400
+ };
401
+ var getBreadcrumbs = (doc, id) => {
402
+ const crumbs = [];
403
+ let currentId = id;
404
+ while (currentId) {
405
+ const res2 = findNodeById(doc, currentId);
406
+ if (!res2) break;
407
+ crumbs.unshift({ id: currentId, type: res2.node.type });
408
+ currentId = res2.path.zoneKey ? parseZoneKey(res2.path.zoneKey).parentId : null;
409
+ }
410
+ return crumbs;
411
+ };
412
+ var generateId = () => nanoid.nanoid(8);
413
+ var remapNodeIds = (node, sourceZones, idMap = /* @__PURE__ */ new Map()) => {
414
+ const oldId = node.props.id;
415
+ const newId = generateId();
416
+ idMap.set(oldId, newId);
417
+ const remappedNode = {
418
+ ...node,
419
+ props: {
420
+ ...node.props,
421
+ id: newId
502
422
  }
503
- ],
504
- ["path", { d: "M14 2v5a1 1 0 0 0 1 1h5", key: "wfsgrz" }],
505
- ["path", { d: "M10 9H8", key: "b1mrlr" }],
506
- ["path", { d: "M16 13H8", key: "t4e002" }],
507
- ["path", { d: "M16 17H8", key: "z1uh3a" }]
508
- ];
509
- var FileText = createLucideIcon("file-text", __iconNode11);
423
+ };
424
+ const newZones = {};
425
+ const prefix = `${oldId}:`;
426
+ for (const [zoneKey, zoneItems] of Object.entries(sourceZones)) {
427
+ if (zoneKey.startsWith(prefix)) {
428
+ const slotName = zoneKey.split(":")[1];
429
+ const newZoneKey = `${newId}:${slotName}`;
430
+ const newZoneItems = [];
431
+ for (const item2 of zoneItems) {
432
+ const { remappedNode: childNode, newZones: childZones } = remapNodeIds(item2, sourceZones, idMap);
433
+ newZoneItems.push(childNode);
434
+ Object.assign(newZones, childZones);
435
+ }
436
+ newZones[newZoneKey] = newZoneItems;
437
+ }
438
+ }
439
+ return { remappedNode, newZones };
440
+ };
510
441
 
511
- // node_modules/lucide-react/dist/esm/icons/file.js
512
- var __iconNode12 = [
513
- [
514
- "path",
515
- {
516
- d: "M6 22a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h8a2.4 2.4 0 0 1 1.704.706l3.588 3.588A2.4 2.4 0 0 1 20 8v12a2 2 0 0 1-2 2z",
517
- key: "1oefj6"
518
- }
519
- ],
520
- ["path", { d: "M14 2v5a1 1 0 0 0 1 1h5", key: "wfsgrz" }]
521
- ];
522
- var File2 = createLucideIcon("file", __iconNode12);
523
-
524
- // node_modules/lucide-react/dist/esm/icons/folder-open.js
525
- var __iconNode13 = [
526
- [
527
- "path",
528
- {
529
- d: "m6 14 1.5-2.9A2 2 0 0 1 9.24 10H20a2 2 0 0 1 1.94 2.5l-1.54 6a2 2 0 0 1-1.95 1.5H4a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h3.9a2 2 0 0 1 1.69.9l.81 1.2a2 2 0 0 0 1.67.9H18a2 2 0 0 1 2 2v2",
530
- key: "usdka0"
531
- }
532
- ]
533
- ];
534
- var FolderOpen = createLucideIcon("folder-open", __iconNode13);
535
-
536
- // node_modules/lucide-react/dist/esm/icons/globe.js
537
- var __iconNode14 = [
538
- ["circle", { cx: "12", cy: "12", r: "10", key: "1mglay" }],
539
- ["path", { d: "M12 2a14.5 14.5 0 0 0 0 20 14.5 14.5 0 0 0 0-20", key: "13o1zl" }],
540
- ["path", { d: "M2 12h20", key: "9i4pu4" }]
541
- ];
542
- var Globe = createLucideIcon("globe", __iconNode14);
543
-
544
- // node_modules/lucide-react/dist/esm/icons/grip-vertical.js
545
- var __iconNode15 = [
546
- ["circle", { cx: "9", cy: "12", r: "1", key: "1vctgf" }],
547
- ["circle", { cx: "9", cy: "5", r: "1", key: "hp0tcf" }],
548
- ["circle", { cx: "9", cy: "19", r: "1", key: "fkjjf6" }],
549
- ["circle", { cx: "15", cy: "12", r: "1", key: "1tmaij" }],
550
- ["circle", { cx: "15", cy: "5", r: "1", key: "19l28e" }],
551
- ["circle", { cx: "15", cy: "19", r: "1", key: "f4zoj3" }]
552
- ];
553
- var GripVertical = createLucideIcon("grip-vertical", __iconNode15);
554
-
555
- // node_modules/lucide-react/dist/esm/icons/image-plus.js
556
- var __iconNode16 = [
557
- ["path", { d: "M16 5h6", key: "1vod17" }],
558
- ["path", { d: "M19 2v6", key: "4bpg5p" }],
559
- ["path", { d: "M21 11.5V19a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h7.5", key: "1ue2ih" }],
560
- ["path", { d: "m21 15-3.086-3.086a2 2 0 0 0-2.828 0L6 21", key: "1xmnt7" }],
561
- ["circle", { cx: "9", cy: "9", r: "2", key: "af1f0g" }]
562
- ];
563
- var ImagePlus = createLucideIcon("image-plus", __iconNode16);
564
-
565
- // node_modules/lucide-react/dist/esm/icons/image.js
566
- var __iconNode17 = [
567
- ["rect", { width: "18", height: "18", x: "3", y: "3", rx: "2", ry: "2", key: "1m3agn" }],
568
- ["circle", { cx: "9", cy: "9", r: "2", key: "af1f0g" }],
569
- ["path", { d: "m21 15-3.086-3.086a2 2 0 0 0-2.828 0L6 21", key: "1xmnt7" }]
570
- ];
571
- var Image2 = createLucideIcon("image", __iconNode17);
572
-
573
- // node_modules/lucide-react/dist/esm/icons/languages.js
574
- var __iconNode18 = [
575
- ["path", { d: "m5 8 6 6", key: "1wu5hv" }],
576
- ["path", { d: "m4 14 6-6 2-3", key: "1k1g8d" }],
577
- ["path", { d: "M2 5h12", key: "or177f" }],
578
- ["path", { d: "M7 2h1", key: "1t2jsx" }],
579
- ["path", { d: "m22 22-5-10-5 10", key: "don7ne" }],
580
- ["path", { d: "M14 18h6", key: "1m8k6r" }]
581
- ];
582
- var Languages = createLucideIcon("languages", __iconNode18);
583
-
584
- // node_modules/lucide-react/dist/esm/icons/link-2.js
585
- var __iconNode19 = [
586
- ["path", { d: "M9 17H7A5 5 0 0 1 7 7h2", key: "8i5ue5" }],
587
- ["path", { d: "M15 7h2a5 5 0 1 1 0 10h-2", key: "1b9ql8" }],
588
- ["line", { x1: "8", x2: "16", y1: "12", y2: "12", key: "1jonct" }]
589
- ];
590
- var Link2 = createLucideIcon("link-2", __iconNode19);
591
-
592
- // node_modules/lucide-react/dist/esm/icons/link.js
593
- var __iconNode20 = [
594
- ["path", { d: "M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71", key: "1cjeqo" }],
595
- ["path", { d: "M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71", key: "19qd67" }]
596
- ];
597
- var Link = createLucideIcon("link", __iconNode20);
598
-
599
- // node_modules/lucide-react/dist/esm/icons/loader-circle.js
600
- var __iconNode21 = [["path", { d: "M21 12a9 9 0 1 1-6.219-8.56", key: "13zald" }]];
601
- var LoaderCircle = createLucideIcon("loader-circle", __iconNode21);
602
-
603
- // node_modules/lucide-react/dist/esm/icons/pencil.js
604
- var __iconNode22 = [
605
- [
606
- "path",
607
- {
608
- d: "M21.174 6.812a1 1 0 0 0-3.986-3.987L3.842 16.174a2 2 0 0 0-.5.83l-1.321 4.352a.5.5 0 0 0 .623.622l4.353-1.32a2 2 0 0 0 .83-.497z",
609
- key: "1a8usu"
610
- }
611
- ],
612
- ["path", { d: "m15 5 4 4", key: "1mk7zo" }]
613
- ];
614
- var Pencil = createLucideIcon("pencil", __iconNode22);
615
-
616
- // node_modules/lucide-react/dist/esm/icons/plus.js
617
- var __iconNode23 = [
618
- ["path", { d: "M5 12h14", key: "1ays0h" }],
619
- ["path", { d: "M12 5v14", key: "s699le" }]
620
- ];
621
- var Plus = createLucideIcon("plus", __iconNode23);
622
-
623
- // node_modules/lucide-react/dist/esm/icons/refresh-ccw.js
624
- var __iconNode24 = [
625
- ["path", { d: "M21 12a9 9 0 0 0-9-9 9.75 9.75 0 0 0-6.74 2.74L3 8", key: "14sxne" }],
626
- ["path", { d: "M3 3v5h5", key: "1xhq8a" }],
627
- ["path", { d: "M3 12a9 9 0 0 0 9 9 9.75 9.75 0 0 0 6.74-2.74L21 16", key: "1hlbsb" }],
628
- ["path", { d: "M16 16h5v5", key: "ccwih5" }]
629
- ];
630
- var RefreshCcw = createLucideIcon("refresh-ccw", __iconNode24);
631
-
632
- // node_modules/lucide-react/dist/esm/icons/refresh-cw.js
633
- var __iconNode25 = [
634
- ["path", { d: "M3 12a9 9 0 0 1 9-9 9.75 9.75 0 0 1 6.74 2.74L21 8", key: "v9h5vc" }],
635
- ["path", { d: "M21 3v5h-5", key: "1q7to0" }],
636
- ["path", { d: "M21 12a9 9 0 0 1-9 9 9.75 9.75 0 0 1-6.74-2.74L3 16", key: "3uifl3" }],
637
- ["path", { d: "M8 16H3v5", key: "1cv678" }]
638
- ];
639
- var RefreshCw = createLucideIcon("refresh-cw", __iconNode25);
640
-
641
- // node_modules/lucide-react/dist/esm/icons/rotate-ccw.js
642
- var __iconNode26 = [
643
- ["path", { d: "M3 12a9 9 0 1 0 9-9 9.75 9.75 0 0 0-6.74 2.74L3 8", key: "1357e3" }],
644
- ["path", { d: "M3 3v5h5", key: "1xhq8a" }]
645
- ];
646
- var RotateCcw = createLucideIcon("rotate-ccw", __iconNode26);
647
-
648
- // node_modules/lucide-react/dist/esm/icons/search.js
649
- var __iconNode27 = [
650
- ["path", { d: "m21 21-4.34-4.34", key: "14j7rj" }],
651
- ["circle", { cx: "11", cy: "11", r: "8", key: "4ej97u" }]
652
- ];
653
- var Search = createLucideIcon("search", __iconNode27);
654
-
655
- // node_modules/lucide-react/dist/esm/icons/trash-2.js
656
- var __iconNode28 = [
657
- ["path", { d: "M10 11v6", key: "nco0om" }],
658
- ["path", { d: "M14 11v6", key: "outv1u" }],
659
- ["path", { d: "M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6", key: "miytrc" }],
660
- ["path", { d: "M3 6h18", key: "d0wm0j" }],
661
- ["path", { d: "M8 6V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2", key: "e791ji" }]
662
- ];
663
- var Trash2 = createLucideIcon("trash-2", __iconNode28);
664
-
665
- // node_modules/lucide-react/dist/esm/icons/upload.js
666
- var __iconNode29 = [
667
- ["path", { d: "M12 3v12", key: "1x0j5s" }],
668
- ["path", { d: "m17 8-5-5-5 5", key: "7q97r8" }],
669
- ["path", { d: "M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4", key: "ih7n3h" }]
670
- ];
671
- var Upload = createLucideIcon("upload", __iconNode29);
672
-
673
- // node_modules/lucide-react/dist/esm/icons/x.js
674
- var __iconNode30 = [
675
- ["path", { d: "M18 6 6 18", key: "1bl5f8" }],
676
- ["path", { d: "m6 6 12 12", key: "d8bk6v" }]
677
- ];
678
- var X = createLucideIcon("x", __iconNode30);
679
- var EMPTY_PAGE = { content: [], root: { props: {} }, zones: {} };
680
- var DrawerSearchContext = React__default.createContext(null);
681
- var ComponentDrawerItem = ({
682
- name: name3,
683
- apiClient,
684
- children
685
- }) => {
686
- const [imgSrc, setImgSrc] = React__default.useState(null);
687
- const [loading, setLoading] = React__default.useState(false);
688
- const [error2, setError] = React__default.useState(false);
689
- const fetchedRef = React__default.useRef(false);
690
- const handleMouseEnter = React__default.useCallback(async () => {
691
- if (fetchedRef.current) return;
692
- fetchedRef.current = true;
693
- setLoading(true);
694
- try {
695
- const domain = typeof window !== "undefined" ? window.location.hostname : "";
696
- const blobUrl = await apiClient.getComponentPreview(domain, name3);
697
- if (blobUrl) {
698
- setImgSrc(blobUrl);
699
- } else {
700
- setError(true);
701
- }
702
- } catch {
703
- setError(true);
704
- } finally {
705
- setLoading(false);
442
+ // src/engine/operations.ts
443
+ var insertNode = (draft, node, targetZoneKey, index2) => {
444
+ if (!node.props.id) {
445
+ node.props.id = generateId();
446
+ }
447
+ let list3 = targetZoneKey ? draft.zones[targetZoneKey] : draft.content;
448
+ if (!list3) {
449
+ list3 = [];
450
+ if (targetZoneKey) {
451
+ draft.zones[targetZoneKey] = list3;
706
452
  }
707
- }, [name3, apiClient]);
708
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "tecof-drawer-item-group group", onMouseEnter: handleMouseEnter, children: [
709
- children,
710
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "tecof-drawer-popover", children: [
711
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "tecof-drawer-popover-header", children: [
712
- name3,
713
- " \xD6nizleme"
714
- ] }),
715
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "tecof-drawer-popover-body", children: [
716
- (loading || !imgSrc && !error2) && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "tecof-drawer-skeleton" }),
717
- imgSrc && /* @__PURE__ */ jsxRuntime.jsx(
718
- "img",
719
- {
720
- src: imgSrc,
721
- alt: `${name3} preview`,
722
- className: "tecof-drawer-img"
723
- }
724
- ),
725
- error2 && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "tecof-drawer-preview-error", children: "\xD6nizleme y\xFCklenemedi" })
726
- ] })
727
- ] })
728
- ] });
453
+ }
454
+ const insertIndex = typeof index2 === "number" ? index2 : list3.length;
455
+ list3.splice(insertIndex, 0, node);
729
456
  };
730
- var CustomDrawer = ({ children }) => {
731
- const context = React__default.useContext(DrawerSearchContext);
732
- if (!context) return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "tecof-drawer-list-layout", children });
733
- const { searchQuery, setSearchQuery } = context;
734
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "tecof-drawer-wrapper-layout", children: [
735
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "tecof-drawer-search-wrapper", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "tecof-drawer-search-box", children: [
736
- /* @__PURE__ */ jsxRuntime.jsx(Search, { size: 14, color: "#71717a" }),
737
- /* @__PURE__ */ jsxRuntime.jsx(
738
- "input",
739
- {
740
- type: "text",
741
- placeholder: "Blok ara...",
742
- value: searchQuery,
743
- onChange: (e3) => setSearchQuery(e3.target.value),
744
- className: "tecof-drawer-search-input"
745
- }
746
- ),
747
- searchQuery && /* @__PURE__ */ jsxRuntime.jsx(
748
- "button",
749
- {
750
- type: "button",
751
- onClick: () => setSearchQuery(""),
752
- className: "tecof-drawer-clear-btn",
753
- title: "Temizle",
754
- children: /* @__PURE__ */ jsxRuntime.jsx(X, { size: 14 })
755
- }
756
- )
757
- ] }) }),
758
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "tecof-drawer-list-layout", children })
759
- ] });
457
+ var removeNode = (draft, id) => {
458
+ const result = findNodeById(draft, id);
459
+ if (!result) return;
460
+ const { path } = result;
461
+ const list3 = path.zoneKey ? draft.zones[path.zoneKey] : draft.content;
462
+ if (list3) {
463
+ list3.splice(path.index, 1);
464
+ }
465
+ const descendantZoneKeys = getDescendantZoneKeys(draft.zones, id);
466
+ for (const zoneKey of descendantZoneKeys) {
467
+ delete draft.zones[zoneKey];
468
+ }
760
469
  };
761
- var CustomDrawerItem = ({ children, name: name3 }) => {
762
- const context = React__default.useContext(DrawerSearchContext);
763
- const { apiClient } = useTecof();
764
- if (!context) {
765
- return /* @__PURE__ */ jsxRuntime.jsx(ComponentDrawerItem, { name: name3, apiClient, children });
470
+ var moveNode = (draft, id, targetZoneKey, targetIndex) => {
471
+ const result = findNodeById(draft, id);
472
+ if (!result) return;
473
+ const { node, path: sourcePath } = result;
474
+ const sourceList = sourcePath.zoneKey ? draft.zones[sourcePath.zoneKey] : draft.content;
475
+ let targetList = targetZoneKey ? draft.zones[targetZoneKey] : draft.content;
476
+ if (!targetList && targetZoneKey) {
477
+ targetList = [];
478
+ draft.zones[targetZoneKey] = targetList;
766
479
  }
767
- const { searchQuery, config: config3 } = context;
768
- const componentConfig = config3.components?.[name3];
769
- const label = componentConfig?.label || name3;
770
- if (searchQuery.trim()) {
771
- const query = searchQuery.toLowerCase();
772
- const matchesName = name3.toLowerCase().includes(query);
773
- const matchesLabel = label.toLowerCase().includes(query);
774
- if (!matchesName && !matchesLabel) {
775
- return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, {});
776
- }
480
+ if (!sourceList || !targetList) return;
481
+ sourceList.splice(sourcePath.index, 1);
482
+ let finalIndex = targetIndex ?? targetList.length;
483
+ if (sourcePath.zoneKey === targetZoneKey && sourcePath.index < finalIndex) {
484
+ finalIndex -= 1;
777
485
  }
778
- return /* @__PURE__ */ jsxRuntime.jsx(ComponentDrawerItem, { name: name3, apiClient, children });
486
+ targetList.splice(finalIndex, 0, node);
779
487
  };
780
- var AutoFieldsOnSelect = () => {
781
- const { selectedItem, dispatch } = core.usePuck();
782
- const prevSelectedRef = React__default.useRef(null);
783
- React__default.useEffect(() => {
784
- const currentId = selectedItem?.props?.id || null;
785
- if (currentId && currentId !== prevSelectedRef.current) {
786
- dispatch({
787
- type: "setUi",
788
- ui: { plugin: { current: "fields" } }
789
- });
790
- }
791
- prevSelectedRef.current = currentId;
792
- }, [selectedItem, dispatch]);
793
- return null;
794
- };
795
- var CustomActionBar = ({ children, label }) => {
796
- const { appState, dispatch, getSelectorForId, selectedItem } = core.usePuck();
797
- const canMoveUp = React__default.useMemo(() => {
798
- if (!selectedItem || !selectedItem.props?.id) return false;
799
- const selector = getSelectorForId(selectedItem.props.id);
800
- if (!selector) return false;
801
- return selector.index > 0;
802
- }, [selectedItem, getSelectorForId]);
803
- const canMoveDown = React__default.useMemo(() => {
804
- if (!selectedItem || !selectedItem.props?.id) return false;
805
- const selector = getSelectorForId(selectedItem.props.id);
806
- if (!selector) return false;
807
- const { index: index2, zone } = selector;
808
- const items = zone ? appState.data.zones?.[zone] || [] : appState.data.content || [];
809
- return index2 < items.length - 1;
810
- }, [selectedItem, getSelectorForId, appState.data]);
811
- const handleMove = React__default.useCallback((direction) => {
812
- if (!selectedItem || !selectedItem.props?.id) return;
813
- const selector = getSelectorForId(selectedItem.props.id);
814
- if (!selector) return;
815
- const { index: index2, zone } = selector;
816
- let items = zone ? [...appState.data.zones?.[zone] || []] : [...appState.data.content || []];
817
- const targetIndex = direction === "up" ? index2 - 1 : index2 + 1;
818
- if (targetIndex < 0 || targetIndex >= items.length) return;
819
- const temp = items[index2];
820
- items[index2] = items[targetIndex];
821
- items[targetIndex] = temp;
822
- if (zone) {
823
- dispatch({
824
- type: "setData",
825
- data: {
826
- ...appState.data,
827
- zones: {
828
- ...appState.data.zones,
829
- [zone]: items
830
- }
831
- }
832
- });
833
- dispatch({
834
- type: "setUi",
835
- ui: {
836
- itemSelector: {
837
- index: targetIndex,
838
- zone
839
- }
840
- }
841
- });
842
- } else {
843
- dispatch({
844
- type: "setData",
845
- data: {
846
- ...appState.data,
847
- content: items
848
- }
849
- });
850
- dispatch({
851
- type: "setUi",
852
- ui: {
853
- itemSelector: {
854
- index: targetIndex
855
- }
856
- }
857
- });
858
- }
859
- }, [selectedItem, getSelectorForId, appState.data, dispatch]);
860
- return /* @__PURE__ */ jsxRuntime.jsx(core.ActionBar, { label, children: /* @__PURE__ */ jsxRuntime.jsxs(core.ActionBar.Group, { children: [
861
- /* @__PURE__ */ jsxRuntime.jsx(core.ActionBar.Action, { onClick: () => handleMove("up"), disabled: !canMoveUp, label: "Yukar\u0131 Ta\u015F\u0131", children: /* @__PURE__ */ jsxRuntime.jsx(ArrowUp, { size: 14 }) }),
862
- /* @__PURE__ */ jsxRuntime.jsx(core.ActionBar.Action, { onClick: () => handleMove("down"), disabled: !canMoveDown, label: "A\u015Fa\u011F\u0131 Ta\u015F\u0131", children: /* @__PURE__ */ jsxRuntime.jsx(ArrowDown, { size: 14 }) }),
863
- /* @__PURE__ */ jsxRuntime.jsx(core.ActionBar.Separator, {}),
864
- children
865
- ] }) });
866
- };
867
- var TecofEditor = ({
868
- pageId,
869
- config: config3,
870
- accessToken,
871
- onSave,
872
- onChange,
873
- overrides,
874
- plugins: extraPlugins,
875
- className
876
- }) => {
877
- const { apiClient, secretKey } = useTecof();
878
- const [initialData, setInitialData] = React__default.useState(null);
879
- const [loading, setLoading] = React__default.useState(true);
880
- const [saving, setSaving] = React__default.useState(false);
881
- const [saveStatus, setSaveStatus] = React__default.useState("idle");
882
- const [searchQuery, setSearchQuery] = React__default.useState("");
883
- const draftDataRef = React__default.useRef(null);
884
- const isEmbedded = typeof window !== "undefined" && window.parent !== window;
885
- React__default.useEffect(() => {
886
- let cancelled = false;
887
- const load = async () => {
888
- setLoading(true);
889
- const res2 = await apiClient.getPage(pageId);
890
- if (cancelled) return;
891
- const data3 = res2.success && res2.data?.draftData ? res2.data.draftData : EMPTY_PAGE;
892
- setInitialData(data3);
893
- draftDataRef.current = data3;
894
- setLoading(false);
895
- };
896
- load();
897
- return () => {
898
- cancelled = true;
899
- };
900
- }, [pageId, apiClient]);
901
- const handleSaveDraft = React__default.useCallback(
902
- async (data3) => {
903
- const currentData = data3 || draftDataRef.current;
904
- if (!currentData) return;
905
- const draftData = currentData;
906
- setSaving(true);
907
- setSaveStatus("idle");
908
- const res2 = await apiClient.savePage(pageId, draftData, void 0, accessToken);
909
- if (res2.success) {
910
- setSaveStatus("success");
911
- setTimeout(() => setSaveStatus("idle"), 3e3);
912
- onSave?.(draftData);
913
- if (isEmbedded) window.parent.postMessage({ type: "puck:saved" }, "*");
914
- } else {
915
- setSaveStatus("error");
916
- if (isEmbedded) window.parent.postMessage({ type: "puck:saveError", message: res2.message }, "*");
917
- }
918
- setSaving(false);
919
- },
920
- [pageId, apiClient, isEmbedded, onSave, accessToken]
921
- );
922
- const handleChange = React__default.useCallback(
923
- (data3) => {
924
- draftDataRef.current = data3;
925
- const draftData = data3;
926
- onChange?.(draftData);
927
- if (isEmbedded) window.parent.postMessage({ type: "puck:changed" }, "*");
928
- },
929
- [onChange, isEmbedded]
930
- );
931
- const handlePuckPublish = React__default.useCallback(
932
- (data3) => {
933
- handleSaveDraft(data3);
934
- },
935
- [handleSaveDraft]
936
- );
937
- React__default.useEffect(() => {
938
- if (!isEmbedded) return;
939
- const onMessage = (e3) => {
940
- switch (e3.data?.type) {
941
- case "puck:save": {
942
- handleSaveDraft();
943
- break;
944
- }
945
- case "puck:undo":
946
- document.dispatchEvent(new KeyboardEvent("keydown", { key: "z", code: "KeyZ", ctrlKey: true, bubbles: true }));
947
- break;
948
- case "puck:redo":
949
- document.dispatchEvent(new KeyboardEvent("keydown", { key: "z", code: "KeyZ", ctrlKey: true, shiftKey: true, bubbles: true }));
950
- break;
951
- case "puck:viewport": {
952
- const frame = document.querySelector('[data-testid="puck-frame"]');
953
- if (frame) {
954
- const w = e3.data.width || "100%";
955
- frame.style.maxWidth = w;
956
- frame.style.margin = w === "100%" ? "0" : "0 auto";
957
- frame.style.transition = "max-width 0.3s ease";
958
- }
959
- break;
960
- }
961
- }
962
- };
963
- window.addEventListener("message", onMessage);
964
- return () => window.removeEventListener("message", onMessage);
965
- }, [isEmbedded, handleSaveDraft]);
966
- React__default.useEffect(() => {
967
- if (!isEmbedded) return;
968
- const handleClick = (e3) => {
969
- const target = e3.target;
970
- const puckComponent = target.closest("[data-puck-component]");
971
- if (puckComponent) {
972
- const componentType = puckComponent.getAttribute("data-puck-component");
973
- const draggableId = puckComponent.closest("[data-rfd-draggable-id]")?.getAttribute("data-rfd-draggable-id");
974
- window.parent.postMessage({
975
- type: "puck:itemSelected",
976
- item: {
977
- type: componentType,
978
- id: draggableId || null
979
- }
980
- }, "*");
981
- }
982
- };
983
- const handleDeselect = (e3) => {
984
- const target = e3.target;
985
- if (!target.closest("[data-puck-component]")) {
986
- window.parent.postMessage({ type: "puck:itemDeselected" }, "*");
987
- }
988
- };
989
- document.addEventListener("click", handleClick, true);
990
- document.addEventListener("click", handleDeselect, false);
991
- return () => {
992
- document.removeEventListener("click", handleClick, true);
993
- document.removeEventListener("click", handleDeselect, false);
994
- };
995
- }, [isEmbedded]);
996
- const searchContextValue = React__default.useMemo(() => ({
997
- searchQuery,
998
- setSearchQuery,
999
- config: config3
1000
- }), [searchQuery, config3]);
1001
- const plugins = React__default.useMemo(() => [
1002
- { ...core.blocksPlugin(), label: "Bloklar" },
1003
- { ...core.outlinePlugin(), label: "Anahat" },
1004
- { ...core.fieldsPlugin({ desktopSideBar: "right" }), label: "Alanlar" },
1005
- ...extraPlugins || []
1006
- ], [extraPlugins]);
1007
- const mergedOverrides = React__default.useMemo(() => {
1008
- return {
1009
- header: () => /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, {}),
1010
- drawer: CustomDrawer,
1011
- drawerItem: CustomDrawerItem,
1012
- actionBar: ({ children, label }) => {
1013
- return /* @__PURE__ */ jsxRuntime.jsx(CustomActionBar, { label, children });
1014
- },
1015
- puck: ({ children }) => {
1016
- return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
1017
- /* @__PURE__ */ jsxRuntime.jsx(AutoFieldsOnSelect, {}),
1018
- children
1019
- ] });
1020
- },
1021
- ...overrides || {}
1022
- };
1023
- }, [overrides]);
1024
- if (loading || !initialData) {
1025
- return /* @__PURE__ */ jsxRuntime.jsx("div", { className: `tecof-editor-loading ${className || ""}`.trim(), children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "tecof-editor-loading-inner", children: [
1026
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "tecof-editor-spinner" }),
1027
- /* @__PURE__ */ jsxRuntime.jsx("p", { className: "tecof-editor-loading-text", children: "Loading editor..." })
1028
- ] }) });
1029
- }
1030
- return /* @__PURE__ */ jsxRuntime.jsx(DrawerSearchContext.Provider, { value: searchContextValue, children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `tecof-editor-wrapper ${className || ""}`.trim(), children: [
1031
- /* @__PURE__ */ jsxRuntime.jsx(
1032
- core.Puck,
1033
- {
1034
- plugins,
1035
- config: config3,
1036
- data: initialData,
1037
- onPublish: handlePuckPublish,
1038
- onChange: handleChange,
1039
- overrides: mergedOverrides,
1040
- metadata: { editMode: true }
1041
- }
1042
- ),
1043
- saving && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "tecof-editor-save-indicator", children: saveStatus === "error" ? "Save failed" : "Saving..." })
1044
- ] }) });
1045
- };
1046
-
1047
- // src/engine/document.ts
1048
- var EMPTY_DOCUMENT = {
1049
- root: { props: {} },
1050
- content: [],
1051
- zones: {}
1052
- };
1053
- var parseDocument = (rawData) => {
1054
- if (!rawData) return { ...EMPTY_DOCUMENT };
1055
- return {
1056
- root: rawData.root || { props: {} },
1057
- content: rawData.content || [],
1058
- zones: rawData.zones || {}
1059
- };
1060
- };
1061
- var serializeDocument = (doc) => {
1062
- return {
1063
- root: doc.root,
1064
- content: doc.content,
1065
- zones: doc.zones
1066
- };
1067
- };
1068
-
1069
- // src/engine/zones.ts
1070
- var parseZoneKey = (zoneKey) => {
1071
- const parts = zoneKey.split(":");
1072
- return {
1073
- parentId: parts[0],
1074
- slotName: parts[1] || "default"
1075
- };
1076
- };
1077
- var findNodeById = (doc, id) => {
1078
- for (let i2 = 0; i2 < doc.content.length; i2++) {
1079
- if (doc.content[i2].props.id === id) {
1080
- return { node: doc.content[i2], path: { index: i2 } };
1081
- }
1082
- }
1083
- for (const [zoneKey, items] of Object.entries(doc.zones)) {
1084
- for (let i2 = 0; i2 < items.length; i2++) {
1085
- if (items[i2].props.id === id) {
1086
- return { node: items[i2], path: { zoneKey, index: i2 } };
1087
- }
1088
- }
1089
- }
1090
- return null;
1091
- };
1092
- var getDescendantZoneKeys = (zones, nodeId, acc = []) => {
1093
- const prefix = `${nodeId}:`;
1094
- for (const zoneKey of Object.keys(zones)) {
1095
- if (zoneKey.startsWith(prefix)) {
1096
- acc.push(zoneKey);
1097
- for (const child of zones[zoneKey]) {
1098
- getDescendantZoneKeys(zones, child.props.id, acc);
1099
- }
1100
- }
1101
- }
1102
- return acc;
1103
- };
1104
- var getParentId = (doc, id) => {
1105
- const res2 = findNodeById(doc, id);
1106
- if (!res2 || !res2.path.zoneKey) return null;
1107
- return parseZoneKey(res2.path.zoneKey).parentId;
1108
- };
1109
- var getBreadcrumbs = (doc, id) => {
1110
- const crumbs = [];
1111
- let currentId = id;
1112
- while (currentId) {
1113
- const res2 = findNodeById(doc, currentId);
1114
- if (!res2) break;
1115
- crumbs.unshift({ id: currentId, type: res2.node.type });
1116
- currentId = res2.path.zoneKey ? parseZoneKey(res2.path.zoneKey).parentId : null;
1117
- }
1118
- return crumbs;
1119
- };
1120
- var generateId = () => nanoid.nanoid(8);
1121
- var remapNodeIds = (node, sourceZones, idMap = /* @__PURE__ */ new Map()) => {
1122
- const oldId = node.props.id;
1123
- const newId = generateId();
1124
- idMap.set(oldId, newId);
1125
- const remappedNode = {
1126
- ...node,
1127
- props: {
1128
- ...node.props,
1129
- id: newId
1130
- }
1131
- };
1132
- const newZones = {};
1133
- const prefix = `${oldId}:`;
1134
- for (const [zoneKey, zoneItems] of Object.entries(sourceZones)) {
1135
- if (zoneKey.startsWith(prefix)) {
1136
- const slotName = zoneKey.split(":")[1];
1137
- const newZoneKey = `${newId}:${slotName}`;
1138
- const newZoneItems = [];
1139
- for (const item2 of zoneItems) {
1140
- const { remappedNode: childNode, newZones: childZones } = remapNodeIds(item2, sourceZones, idMap);
1141
- newZoneItems.push(childNode);
1142
- Object.assign(newZones, childZones);
1143
- }
1144
- newZones[newZoneKey] = newZoneItems;
1145
- }
1146
- }
1147
- return { remappedNode, newZones };
1148
- };
1149
-
1150
- // src/engine/operations.ts
1151
- var insertNode = (draft, node, targetZoneKey, index2) => {
1152
- if (!node.props.id) {
1153
- node.props.id = generateId();
1154
- }
1155
- let list3 = targetZoneKey ? draft.zones[targetZoneKey] : draft.content;
1156
- if (!list3) {
1157
- list3 = [];
1158
- if (targetZoneKey) {
1159
- draft.zones[targetZoneKey] = list3;
1160
- }
1161
- }
1162
- const insertIndex = typeof index2 === "number" ? index2 : list3.length;
1163
- list3.splice(insertIndex, 0, node);
1164
- };
1165
- var removeNode = (draft, id) => {
1166
- const result = findNodeById(draft, id);
1167
- if (!result) return;
1168
- const { path } = result;
1169
- const list3 = path.zoneKey ? draft.zones[path.zoneKey] : draft.content;
1170
- if (list3) {
1171
- list3.splice(path.index, 1);
1172
- }
1173
- const descendantZoneKeys = getDescendantZoneKeys(draft.zones, id);
1174
- for (const zoneKey of descendantZoneKeys) {
1175
- delete draft.zones[zoneKey];
1176
- }
1177
- };
1178
- var moveNode = (draft, id, targetZoneKey, targetIndex) => {
1179
- const result = findNodeById(draft, id);
1180
- if (!result) return;
1181
- const { node, path: sourcePath } = result;
1182
- const sourceList = sourcePath.zoneKey ? draft.zones[sourcePath.zoneKey] : draft.content;
1183
- let targetList = targetZoneKey ? draft.zones[targetZoneKey] : draft.content;
1184
- if (!targetList && targetZoneKey) {
1185
- targetList = [];
1186
- draft.zones[targetZoneKey] = targetList;
1187
- }
1188
- if (!sourceList || !targetList) return;
1189
- sourceList.splice(sourcePath.index, 1);
1190
- let finalIndex = targetIndex ?? targetList.length;
1191
- if (sourcePath.zoneKey === targetZoneKey && sourcePath.index < finalIndex) {
1192
- finalIndex -= 1;
1193
- }
1194
- targetList.splice(finalIndex, 0, node);
1195
- };
1196
- var duplicateNode = (draft, id) => {
1197
- const result = findNodeById(draft, id);
1198
- if (!result) return;
1199
- const { node, path } = result;
1200
- const { remappedNode, newZones } = remapNodeIds(node, draft.zones);
1201
- const targetList = path.zoneKey ? draft.zones[path.zoneKey] : draft.content;
1202
- if (targetList) {
1203
- targetList.splice(path.index + 1, 0, remappedNode);
1204
- }
1205
- Object.assign(draft.zones, newZones);
488
+ var duplicateNode = (draft, id) => {
489
+ const result = findNodeById(draft, id);
490
+ if (!result) return;
491
+ const { node, path } = result;
492
+ const { remappedNode, newZones } = remapNodeIds(node, draft.zones);
493
+ const targetList = path.zoneKey ? draft.zones[path.zoneKey] : draft.content;
494
+ if (targetList) {
495
+ targetList.splice(path.index + 1, 0, remappedNode);
496
+ }
497
+ Object.assign(draft.zones, newZones);
1206
498
  };
1207
499
  var updateProps = (draft, id, patch) => {
1208
500
  const result = findNodeById(draft, id);
@@ -1215,7 +507,7 @@ var setRootProps = (draft, patch) => {
1215
507
 
1216
508
  // src/engine/store.ts
1217
509
  var pushToHistory = (state3) => {
1218
- state3.history.past.push(JSON.parse(JSON.stringify(state3.document)));
510
+ state3.history.past.push(state3.document);
1219
511
  state3.history.future = [];
1220
512
  };
1221
513
  var useEditorStore = zustand.create()(
@@ -1276,13 +568,13 @@ var useEditorStore = zustand.create()(
1276
568
  undo: () => set2((state3) => {
1277
569
  if (state3.history.past.length === 0) return;
1278
570
  const previous = state3.history.past.pop();
1279
- state3.history.future.push(JSON.parse(JSON.stringify(state3.document)));
571
+ state3.history.future.push(state3.document);
1280
572
  state3.document = previous;
1281
573
  }),
1282
574
  redo: () => set2((state3) => {
1283
575
  if (state3.history.future.length === 0) return;
1284
576
  const next = state3.history.future.pop();
1285
- state3.history.past.push(JSON.parse(JSON.stringify(state3.document)));
577
+ state3.history.past.push(state3.document);
1286
578
  state3.document = next;
1287
579
  })
1288
580
  }))
@@ -1358,6 +650,44 @@ var NodeRenderer = ({ node, index: index2, zoneKey }) => {
1358
650
  },
1359
651
  [selectNode, node.props.id, node.type, readOnly]
1360
652
  );
653
+ const handleDoubleClick = React__default.useCallback(
654
+ (e3) => {
655
+ if (readOnly) return;
656
+ const target = e3.target;
657
+ const validTags = ["h1", "h2", "h3", "h4", "h5", "h6", "p", "span", "a", "div"];
658
+ const tag = target.tagName.toLowerCase();
659
+ if (!validTags.includes(tag)) return;
660
+ const text2 = target.textContent?.trim() || "";
661
+ if (!text2) return;
662
+ let matchingPropName = null;
663
+ for (const [key, value] of Object.entries(node.props)) {
664
+ if (typeof value === "string" && value.trim() === text2) {
665
+ matchingPropName = key;
666
+ break;
667
+ }
668
+ }
669
+ if (!matchingPropName) return;
670
+ e3.stopPropagation();
671
+ target.contentEditable = "true";
672
+ target.focus();
673
+ const range = document.createRange();
674
+ range.selectNodeContents(target);
675
+ const sel = window.getSelection();
676
+ sel?.removeAllRanges();
677
+ sel?.addRange(range);
678
+ const propName = matchingPropName;
679
+ const handleBlur = () => {
680
+ target.contentEditable = "false";
681
+ target.removeEventListener("blur", handleBlur);
682
+ const newText = target.textContent?.trim() || "";
683
+ useEditorStore.getState().updateProps(node.props.id, {
684
+ [propName]: newText
685
+ });
686
+ };
687
+ target.addEventListener("blur", handleBlur);
688
+ },
689
+ [node.props, node.props.id, readOnly]
690
+ );
1361
691
  if (!componentConfig) {
1362
692
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { padding: "12px", background: "#fee2e2", color: "#991b1b", fontSize: "12px", borderRadius: "4px" }, children: [
1363
693
  "Bile\u015Fen bulunamad\u0131: ",
@@ -1387,6 +717,7 @@ var NodeRenderer = ({ node, index: index2, zoneKey }) => {
1387
717
  onMouseEnter: handleMouseEnter,
1388
718
  onMouseLeave: handleMouseLeave,
1389
719
  onClick: handleClick,
720
+ onDoubleClick: handleDoubleClick,
1390
721
  style: {
1391
722
  cursor: readOnly ? void 0 : "pointer"
1392
723
  },
@@ -1454,6 +785,10 @@ var Frame = ({ children, title = "Canvas Frame", ...props }) => {
1454
785
  doc.head.appendChild(style);
1455
786
  };
1456
787
  copyStyles();
788
+ const observer = new MutationObserver(() => {
789
+ copyStyles();
790
+ });
791
+ observer.observe(document.head, { childList: true, subtree: true });
1457
792
  if (doc.body) {
1458
793
  doc.body.className = "tecof-canvas-body";
1459
794
  const handleBodyClick = (e3) => {
@@ -1466,71 +801,520 @@ var Frame = ({ children, title = "Canvas Frame", ...props }) => {
1466
801
  }
1467
802
  }
1468
803
  };
804
+ const handleIframeKeyDown = (e3) => {
805
+ const event = new KeyboardEvent("keydown", {
806
+ key: e3.key,
807
+ code: e3.code,
808
+ ctrlKey: e3.ctrlKey,
809
+ metaKey: e3.metaKey,
810
+ shiftKey: e3.shiftKey,
811
+ altKey: e3.altKey,
812
+ bubbles: true
813
+ });
814
+ window.dispatchEvent(event);
815
+ };
1469
816
  doc.body.addEventListener("click", handleBodyClick);
817
+ doc.addEventListener("keydown", handleIframeKeyDown);
1470
818
  return () => {
819
+ observer.disconnect();
1471
820
  doc.body.removeEventListener("click", handleBodyClick);
821
+ doc.removeEventListener("keydown", handleIframeKeyDown);
1472
822
  };
1473
823
  }
1474
- }, [contentRef]);
1475
- return /* @__PURE__ */ jsxRuntime.jsx(
1476
- "iframe",
824
+ }, [contentRef]);
825
+ return /* @__PURE__ */ jsxRuntime.jsx(
826
+ "iframe",
827
+ {
828
+ title,
829
+ ref: setContentRef,
830
+ style: {
831
+ width: "100%",
832
+ height: "100%",
833
+ border: "none",
834
+ background: "#ffffff",
835
+ ...props.style
836
+ },
837
+ ...props,
838
+ children: mountNode && ReactDOM.createPortal(children, mountNode)
839
+ }
840
+ );
841
+ };
842
+ var Canvas = () => {
843
+ const content = useEditorStore((state3) => state3.document.content);
844
+ const viewport = useEditorStore((state3) => state3.viewport);
845
+ const getWidth2 = () => {
846
+ switch (viewport) {
847
+ case "tablet":
848
+ return "768px";
849
+ case "mobile":
850
+ return "375px";
851
+ case "desktop":
852
+ default:
853
+ return "100%";
854
+ }
855
+ };
856
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "tecof-canvas-container", style: {
857
+ flex: 1,
858
+ display: "flex",
859
+ alignItems: "center",
860
+ justifyContent: "center",
861
+ background: "#f4f4f5",
862
+ padding: "24px",
863
+ overflow: "auto",
864
+ height: "100%",
865
+ boxSizing: "border-box"
866
+ }, children: /* @__PURE__ */ jsxRuntime.jsx(
867
+ "div",
868
+ {
869
+ className: "tecof-canvas-viewport-wrapper",
870
+ style: {
871
+ width: getWidth2(),
872
+ height: "100%",
873
+ maxWidth: "100%",
874
+ transition: "width 0.3s cubic-bezier(0.4, 0, 0.2, 1)",
875
+ boxShadow: "0 10px 25px -5px rgba(0, 0, 0, 0.05), 0 8px 10px -6px rgba(0, 0, 0, 0.05)",
876
+ borderRadius: viewport === "desktop" ? "0" : "12px",
877
+ overflow: "hidden",
878
+ backgroundColor: "#ffffff"
879
+ },
880
+ children: /* @__PURE__ */ jsxRuntime.jsx(Frame, { children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "tecof-canvas-root", style: { minHeight: "100%" }, children: content.map((item2, index2) => /* @__PURE__ */ jsxRuntime.jsx(NodeRenderer, { node: item2, index: index2 }, item2.props.id)) }) })
881
+ }
882
+ ) });
883
+ };
884
+
885
+ // node_modules/lucide-react/dist/esm/shared/src/utils/mergeClasses.js
886
+ var mergeClasses = (...classes) => classes.filter((className, index2, array) => {
887
+ return Boolean(className) && className.trim() !== "" && array.indexOf(className) === index2;
888
+ }).join(" ").trim();
889
+
890
+ // node_modules/lucide-react/dist/esm/shared/src/utils/toKebabCase.js
891
+ var toKebabCase = (string) => string.replace(/([a-z0-9])([A-Z])/g, "$1-$2").toLowerCase();
892
+
893
+ // node_modules/lucide-react/dist/esm/shared/src/utils/toCamelCase.js
894
+ var toCamelCase = (string) => string.replace(
895
+ /^([A-Z])|[\s-_]+(\w)/g,
896
+ (match, p1, p2) => p2 ? p2.toUpperCase() : p1.toLowerCase()
897
+ );
898
+
899
+ // node_modules/lucide-react/dist/esm/shared/src/utils/toPascalCase.js
900
+ var toPascalCase = (string) => {
901
+ const camelCase = toCamelCase(string);
902
+ return camelCase.charAt(0).toUpperCase() + camelCase.slice(1);
903
+ };
904
+
905
+ // node_modules/lucide-react/dist/esm/defaultAttributes.js
906
+ var defaultAttributes = {
907
+ xmlns: "http://www.w3.org/2000/svg",
908
+ width: 24,
909
+ height: 24,
910
+ viewBox: "0 0 24 24",
911
+ fill: "none",
912
+ stroke: "currentColor",
913
+ strokeWidth: 2,
914
+ strokeLinecap: "round",
915
+ strokeLinejoin: "round"
916
+ };
917
+
918
+ // node_modules/lucide-react/dist/esm/shared/src/utils/hasA11yProp.js
919
+ var hasA11yProp = (props) => {
920
+ for (const prop in props) {
921
+ if (prop.startsWith("aria-") || prop === "role" || prop === "title") {
922
+ return true;
923
+ }
924
+ }
925
+ return false;
926
+ };
927
+ var LucideContext = React__default.createContext({});
928
+ var useLucideContext = () => React__default.useContext(LucideContext);
929
+
930
+ // node_modules/lucide-react/dist/esm/Icon.js
931
+ var Icon = React__default.forwardRef(
932
+ ({ color, size, strokeWidth, absoluteStrokeWidth, className = "", children, iconNode, ...rest }, ref) => {
933
+ const {
934
+ size: contextSize = 24,
935
+ strokeWidth: contextStrokeWidth = 2,
936
+ absoluteStrokeWidth: contextAbsoluteStrokeWidth = false,
937
+ color: contextColor = "currentColor",
938
+ className: contextClass = ""
939
+ } = useLucideContext() ?? {};
940
+ const calculatedStrokeWidth = absoluteStrokeWidth ?? contextAbsoluteStrokeWidth ? Number(strokeWidth ?? contextStrokeWidth) * 24 / Number(size ?? contextSize) : strokeWidth ?? contextStrokeWidth;
941
+ return React__default.createElement(
942
+ "svg",
943
+ {
944
+ ref,
945
+ ...defaultAttributes,
946
+ width: size ?? contextSize ?? defaultAttributes.width,
947
+ height: size ?? contextSize ?? defaultAttributes.height,
948
+ stroke: color ?? contextColor,
949
+ strokeWidth: calculatedStrokeWidth,
950
+ className: mergeClasses("lucide", contextClass, className),
951
+ ...!children && !hasA11yProp(rest) && { "aria-hidden": "true" },
952
+ ...rest
953
+ },
954
+ [
955
+ ...iconNode.map(([tag, attrs]) => React__default.createElement(tag, attrs)),
956
+ ...Array.isArray(children) ? children : [children]
957
+ ]
958
+ );
959
+ }
960
+ );
961
+
962
+ // node_modules/lucide-react/dist/esm/createLucideIcon.js
963
+ var createLucideIcon = (iconName, iconNode) => {
964
+ const Component2 = React__default.forwardRef(
965
+ ({ className, ...props }, ref) => React__default.createElement(Icon, {
966
+ ref,
967
+ iconNode,
968
+ className: mergeClasses(
969
+ `lucide-${toKebabCase(toPascalCase(iconName))}`,
970
+ `lucide-${iconName}`,
971
+ className
972
+ ),
973
+ ...props
974
+ })
975
+ );
976
+ Component2.displayName = toPascalCase(iconName);
977
+ return Component2;
978
+ };
979
+
980
+ // node_modules/lucide-react/dist/esm/icons/arrow-down.js
981
+ var __iconNode = [
982
+ ["path", { d: "M12 5v14", key: "s699le" }],
983
+ ["path", { d: "m19 12-7 7-7-7", key: "1idqje" }]
984
+ ];
985
+ var ArrowDown = createLucideIcon("arrow-down", __iconNode);
986
+
987
+ // node_modules/lucide-react/dist/esm/icons/arrow-up.js
988
+ var __iconNode2 = [
989
+ ["path", { d: "m5 12 7-7 7 7", key: "hav0vg" }],
990
+ ["path", { d: "M12 19V5", key: "x0mq9r" }]
991
+ ];
992
+ var ArrowUp = createLucideIcon("arrow-up", __iconNode2);
993
+
994
+ // node_modules/lucide-react/dist/esm/icons/check.js
995
+ var __iconNode3 = [["path", { d: "M20 6 9 17l-5-5", key: "1gmf2c" }]];
996
+ var Check = createLucideIcon("check", __iconNode3);
997
+
998
+ // node_modules/lucide-react/dist/esm/icons/chevron-down.js
999
+ var __iconNode4 = [["path", { d: "m6 9 6 6 6-6", key: "qrunsl" }]];
1000
+ var ChevronDown = createLucideIcon("chevron-down", __iconNode4);
1001
+
1002
+ // node_modules/lucide-react/dist/esm/icons/chevron-right.js
1003
+ var __iconNode5 = [["path", { d: "m9 18 6-6-6-6", key: "mthhwq" }]];
1004
+ var ChevronRight = createLucideIcon("chevron-right", __iconNode5);
1005
+
1006
+ // node_modules/lucide-react/dist/esm/icons/chevron-up.js
1007
+ var __iconNode6 = [["path", { d: "m18 15-6-6-6 6", key: "153udz" }]];
1008
+ var ChevronUp = createLucideIcon("chevron-up", __iconNode6);
1009
+
1010
+ // node_modules/lucide-react/dist/esm/icons/code.js
1011
+ var __iconNode7 = [
1012
+ ["path", { d: "m16 18 6-6-6-6", key: "eg8j8" }],
1013
+ ["path", { d: "m8 6-6 6 6 6", key: "ppft3o" }]
1014
+ ];
1015
+ var Code = createLucideIcon("code", __iconNode7);
1016
+
1017
+ // node_modules/lucide-react/dist/esm/icons/copy.js
1018
+ var __iconNode8 = [
1019
+ ["rect", { width: "14", height: "14", x: "8", y: "8", rx: "2", ry: "2", key: "17jyea" }],
1020
+ ["path", { d: "M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2", key: "zix9uf" }]
1021
+ ];
1022
+ var Copy = createLucideIcon("copy", __iconNode8);
1023
+
1024
+ // node_modules/lucide-react/dist/esm/icons/database.js
1025
+ var __iconNode9 = [
1026
+ ["ellipse", { cx: "12", cy: "5", rx: "9", ry: "3", key: "msslwz" }],
1027
+ ["path", { d: "M3 5V19A9 3 0 0 0 21 19V5", key: "1wlel7" }],
1028
+ ["path", { d: "M3 12A9 3 0 0 0 21 12", key: "mv7ke4" }]
1029
+ ];
1030
+ var Database = createLucideIcon("database", __iconNode9);
1031
+
1032
+ // node_modules/lucide-react/dist/esm/icons/external-link.js
1033
+ var __iconNode10 = [
1034
+ ["path", { d: "M15 3h6v6", key: "1q9fwt" }],
1035
+ ["path", { d: "M10 14 21 3", key: "gplh6r" }],
1036
+ ["path", { d: "M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6", key: "a6xqqp" }]
1037
+ ];
1038
+ var ExternalLink = createLucideIcon("external-link", __iconNode10);
1039
+
1040
+ // node_modules/lucide-react/dist/esm/icons/file-text.js
1041
+ var __iconNode11 = [
1042
+ [
1043
+ "path",
1044
+ {
1045
+ d: "M6 22a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h8a2.4 2.4 0 0 1 1.704.706l3.588 3.588A2.4 2.4 0 0 1 20 8v12a2 2 0 0 1-2 2z",
1046
+ key: "1oefj6"
1047
+ }
1048
+ ],
1049
+ ["path", { d: "M14 2v5a1 1 0 0 0 1 1h5", key: "wfsgrz" }],
1050
+ ["path", { d: "M10 9H8", key: "b1mrlr" }],
1051
+ ["path", { d: "M16 13H8", key: "t4e002" }],
1052
+ ["path", { d: "M16 17H8", key: "z1uh3a" }]
1053
+ ];
1054
+ var FileText = createLucideIcon("file-text", __iconNode11);
1055
+
1056
+ // node_modules/lucide-react/dist/esm/icons/file.js
1057
+ var __iconNode12 = [
1058
+ [
1059
+ "path",
1060
+ {
1061
+ d: "M6 22a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h8a2.4 2.4 0 0 1 1.704.706l3.588 3.588A2.4 2.4 0 0 1 20 8v12a2 2 0 0 1-2 2z",
1062
+ key: "1oefj6"
1063
+ }
1064
+ ],
1065
+ ["path", { d: "M14 2v5a1 1 0 0 0 1 1h5", key: "wfsgrz" }]
1066
+ ];
1067
+ var File2 = createLucideIcon("file", __iconNode12);
1068
+
1069
+ // node_modules/lucide-react/dist/esm/icons/folder-open.js
1070
+ var __iconNode13 = [
1071
+ [
1072
+ "path",
1073
+ {
1074
+ d: "m6 14 1.5-2.9A2 2 0 0 1 9.24 10H20a2 2 0 0 1 1.94 2.5l-1.54 6a2 2 0 0 1-1.95 1.5H4a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h3.9a2 2 0 0 1 1.69.9l.81 1.2a2 2 0 0 0 1.67.9H18a2 2 0 0 1 2 2v2",
1075
+ key: "usdka0"
1076
+ }
1077
+ ]
1078
+ ];
1079
+ var FolderOpen = createLucideIcon("folder-open", __iconNode13);
1080
+
1081
+ // node_modules/lucide-react/dist/esm/icons/globe.js
1082
+ var __iconNode14 = [
1083
+ ["circle", { cx: "12", cy: "12", r: "10", key: "1mglay" }],
1084
+ ["path", { d: "M12 2a14.5 14.5 0 0 0 0 20 14.5 14.5 0 0 0 0-20", key: "13o1zl" }],
1085
+ ["path", { d: "M2 12h20", key: "9i4pu4" }]
1086
+ ];
1087
+ var Globe = createLucideIcon("globe", __iconNode14);
1088
+
1089
+ // node_modules/lucide-react/dist/esm/icons/grid-3x3.js
1090
+ var __iconNode15 = [
1091
+ ["rect", { width: "18", height: "18", x: "3", y: "3", rx: "2", key: "afitv7" }],
1092
+ ["path", { d: "M3 9h18", key: "1pudct" }],
1093
+ ["path", { d: "M3 15h18", key: "5xshup" }],
1094
+ ["path", { d: "M9 3v18", key: "fh3hqa" }],
1095
+ ["path", { d: "M15 3v18", key: "14nvp0" }]
1096
+ ];
1097
+ var Grid3x3 = createLucideIcon("grid-3x3", __iconNode15);
1098
+
1099
+ // node_modules/lucide-react/dist/esm/icons/grip-vertical.js
1100
+ var __iconNode16 = [
1101
+ ["circle", { cx: "9", cy: "12", r: "1", key: "1vctgf" }],
1102
+ ["circle", { cx: "9", cy: "5", r: "1", key: "hp0tcf" }],
1103
+ ["circle", { cx: "9", cy: "19", r: "1", key: "fkjjf6" }],
1104
+ ["circle", { cx: "15", cy: "12", r: "1", key: "1tmaij" }],
1105
+ ["circle", { cx: "15", cy: "5", r: "1", key: "19l28e" }],
1106
+ ["circle", { cx: "15", cy: "19", r: "1", key: "f4zoj3" }]
1107
+ ];
1108
+ var GripVertical = createLucideIcon("grip-vertical", __iconNode16);
1109
+
1110
+ // node_modules/lucide-react/dist/esm/icons/image-plus.js
1111
+ var __iconNode17 = [
1112
+ ["path", { d: "M16 5h6", key: "1vod17" }],
1113
+ ["path", { d: "M19 2v6", key: "4bpg5p" }],
1114
+ ["path", { d: "M21 11.5V19a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h7.5", key: "1ue2ih" }],
1115
+ ["path", { d: "m21 15-3.086-3.086a2 2 0 0 0-2.828 0L6 21", key: "1xmnt7" }],
1116
+ ["circle", { cx: "9", cy: "9", r: "2", key: "af1f0g" }]
1117
+ ];
1118
+ var ImagePlus = createLucideIcon("image-plus", __iconNode17);
1119
+
1120
+ // node_modules/lucide-react/dist/esm/icons/image.js
1121
+ var __iconNode18 = [
1122
+ ["rect", { width: "18", height: "18", x: "3", y: "3", rx: "2", ry: "2", key: "1m3agn" }],
1123
+ ["circle", { cx: "9", cy: "9", r: "2", key: "af1f0g" }],
1124
+ ["path", { d: "m21 15-3.086-3.086a2 2 0 0 0-2.828 0L6 21", key: "1xmnt7" }]
1125
+ ];
1126
+ var Image2 = createLucideIcon("image", __iconNode18);
1127
+
1128
+ // node_modules/lucide-react/dist/esm/icons/languages.js
1129
+ var __iconNode19 = [
1130
+ ["path", { d: "m5 8 6 6", key: "1wu5hv" }],
1131
+ ["path", { d: "m4 14 6-6 2-3", key: "1k1g8d" }],
1132
+ ["path", { d: "M2 5h12", key: "or177f" }],
1133
+ ["path", { d: "M7 2h1", key: "1t2jsx" }],
1134
+ ["path", { d: "m22 22-5-10-5 10", key: "don7ne" }],
1135
+ ["path", { d: "M14 18h6", key: "1m8k6r" }]
1136
+ ];
1137
+ var Languages = createLucideIcon("languages", __iconNode19);
1138
+
1139
+ // node_modules/lucide-react/dist/esm/icons/layers.js
1140
+ var __iconNode20 = [
1141
+ [
1142
+ "path",
1143
+ {
1144
+ d: "M12.83 2.18a2 2 0 0 0-1.66 0L2.6 6.08a1 1 0 0 0 0 1.83l8.58 3.91a2 2 0 0 0 1.66 0l8.58-3.9a1 1 0 0 0 0-1.83z",
1145
+ key: "zw3jo"
1146
+ }
1147
+ ],
1148
+ [
1149
+ "path",
1477
1150
  {
1478
- title,
1479
- ref: setContentRef,
1480
- style: {
1481
- width: "100%",
1482
- height: "100%",
1483
- border: "none",
1484
- background: "#ffffff",
1485
- ...props.style
1486
- },
1487
- ...props,
1488
- children: mountNode && ReactDOM.createPortal(children, mountNode)
1151
+ d: "M2 12a1 1 0 0 0 .58.91l8.6 3.91a2 2 0 0 0 1.65 0l8.58-3.9A1 1 0 0 0 22 12",
1152
+ key: "1wduqc"
1489
1153
  }
1490
- );
1491
- };
1492
- var Canvas = () => {
1493
- const content = useEditorStore((state3) => state3.document.content);
1494
- const viewport = useEditorStore((state3) => state3.viewport);
1495
- const getWidth2 = () => {
1496
- switch (viewport) {
1497
- case "tablet":
1498
- return "768px";
1499
- case "mobile":
1500
- return "375px";
1501
- case "desktop":
1502
- default:
1503
- return "100%";
1154
+ ],
1155
+ [
1156
+ "path",
1157
+ {
1158
+ d: "M2 17a1 1 0 0 0 .58.91l8.6 3.91a2 2 0 0 0 1.65 0l8.58-3.9A1 1 0 0 0 22 17",
1159
+ key: "kqbvx6"
1504
1160
  }
1505
- };
1506
- return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "tecof-canvas-container", style: {
1507
- flex: 1,
1508
- display: "flex",
1509
- alignItems: "center",
1510
- justifyContent: "center",
1511
- background: "#f4f4f5",
1512
- padding: "24px",
1513
- overflow: "auto",
1514
- height: "100%",
1515
- boxSizing: "border-box"
1516
- }, children: /* @__PURE__ */ jsxRuntime.jsx(
1517
- "div",
1161
+ ]
1162
+ ];
1163
+ var Layers = createLucideIcon("layers", __iconNode20);
1164
+
1165
+ // node_modules/lucide-react/dist/esm/icons/link-2.js
1166
+ var __iconNode21 = [
1167
+ ["path", { d: "M9 17H7A5 5 0 0 1 7 7h2", key: "8i5ue5" }],
1168
+ ["path", { d: "M15 7h2a5 5 0 1 1 0 10h-2", key: "1b9ql8" }],
1169
+ ["line", { x1: "8", x2: "16", y1: "12", y2: "12", key: "1jonct" }]
1170
+ ];
1171
+ var Link2 = createLucideIcon("link-2", __iconNode21);
1172
+
1173
+ // node_modules/lucide-react/dist/esm/icons/link.js
1174
+ var __iconNode22 = [
1175
+ ["path", { d: "M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71", key: "1cjeqo" }],
1176
+ ["path", { d: "M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71", key: "19qd67" }]
1177
+ ];
1178
+ var Link = createLucideIcon("link", __iconNode22);
1179
+
1180
+ // node_modules/lucide-react/dist/esm/icons/loader-circle.js
1181
+ var __iconNode23 = [["path", { d: "M21 12a9 9 0 1 1-6.219-8.56", key: "13zald" }]];
1182
+ var LoaderCircle = createLucideIcon("loader-circle", __iconNode23);
1183
+
1184
+ // node_modules/lucide-react/dist/esm/icons/monitor.js
1185
+ var __iconNode24 = [
1186
+ ["rect", { width: "20", height: "14", x: "2", y: "3", rx: "2", key: "48i651" }],
1187
+ ["line", { x1: "8", x2: "16", y1: "21", y2: "21", key: "1svkeh" }],
1188
+ ["line", { x1: "12", x2: "12", y1: "17", y2: "21", key: "vw1qmm" }]
1189
+ ];
1190
+ var Monitor = createLucideIcon("monitor", __iconNode24);
1191
+
1192
+ // node_modules/lucide-react/dist/esm/icons/panels-top-left.js
1193
+ var __iconNode25 = [
1194
+ ["rect", { width: "18", height: "18", x: "3", y: "3", rx: "2", key: "afitv7" }],
1195
+ ["path", { d: "M3 9h18", key: "1pudct" }],
1196
+ ["path", { d: "M9 21V9", key: "1oto5p" }]
1197
+ ];
1198
+ var PanelsTopLeft = createLucideIcon("panels-top-left", __iconNode25);
1199
+
1200
+ // node_modules/lucide-react/dist/esm/icons/pencil.js
1201
+ var __iconNode26 = [
1202
+ [
1203
+ "path",
1518
1204
  {
1519
- className: "tecof-canvas-viewport-wrapper",
1520
- style: {
1521
- width: getWidth2(),
1522
- height: "100%",
1523
- maxWidth: "100%",
1524
- transition: "width 0.3s cubic-bezier(0.4, 0, 0.2, 1)",
1525
- boxShadow: "0 10px 25px -5px rgba(0, 0, 0, 0.05), 0 8px 10px -6px rgba(0, 0, 0, 0.05)",
1526
- borderRadius: viewport === "desktop" ? "0" : "12px",
1527
- overflow: "hidden",
1528
- backgroundColor: "#ffffff"
1529
- },
1530
- children: /* @__PURE__ */ jsxRuntime.jsx(Frame, { children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "tecof-canvas-root", style: { minHeight: "100%" }, children: content.map((item2, index2) => /* @__PURE__ */ jsxRuntime.jsx(NodeRenderer, { node: item2, index: index2 }, item2.props.id)) }) })
1205
+ d: "M21.174 6.812a1 1 0 0 0-3.986-3.987L3.842 16.174a2 2 0 0 0-.5.83l-1.321 4.352a.5.5 0 0 0 .623.622l4.353-1.32a2 2 0 0 0 .83-.497z",
1206
+ key: "1a8usu"
1531
1207
  }
1532
- ) });
1533
- };
1208
+ ],
1209
+ ["path", { d: "m15 5 4 4", key: "1mk7zo" }]
1210
+ ];
1211
+ var Pencil = createLucideIcon("pencil", __iconNode26);
1212
+
1213
+ // node_modules/lucide-react/dist/esm/icons/plus.js
1214
+ var __iconNode27 = [
1215
+ ["path", { d: "M5 12h14", key: "1ays0h" }],
1216
+ ["path", { d: "M12 5v14", key: "s699le" }]
1217
+ ];
1218
+ var Plus = createLucideIcon("plus", __iconNode27);
1219
+
1220
+ // node_modules/lucide-react/dist/esm/icons/redo-2.js
1221
+ var __iconNode28 = [
1222
+ ["path", { d: "m15 14 5-5-5-5", key: "12vg1m" }],
1223
+ ["path", { d: "M20 9H9.5A5.5 5.5 0 0 0 4 14.5A5.5 5.5 0 0 0 9.5 20H13", key: "6uklza" }]
1224
+ ];
1225
+ var Redo2 = createLucideIcon("redo-2", __iconNode28);
1226
+
1227
+ // node_modules/lucide-react/dist/esm/icons/refresh-ccw.js
1228
+ var __iconNode29 = [
1229
+ ["path", { d: "M21 12a9 9 0 0 0-9-9 9.75 9.75 0 0 0-6.74 2.74L3 8", key: "14sxne" }],
1230
+ ["path", { d: "M3 3v5h5", key: "1xhq8a" }],
1231
+ ["path", { d: "M3 12a9 9 0 0 0 9 9 9.75 9.75 0 0 0 6.74-2.74L21 16", key: "1hlbsb" }],
1232
+ ["path", { d: "M16 16h5v5", key: "ccwih5" }]
1233
+ ];
1234
+ var RefreshCcw = createLucideIcon("refresh-ccw", __iconNode29);
1235
+
1236
+ // node_modules/lucide-react/dist/esm/icons/refresh-cw.js
1237
+ var __iconNode30 = [
1238
+ ["path", { d: "M3 12a9 9 0 0 1 9-9 9.75 9.75 0 0 1 6.74 2.74L21 8", key: "v9h5vc" }],
1239
+ ["path", { d: "M21 3v5h-5", key: "1q7to0" }],
1240
+ ["path", { d: "M21 12a9 9 0 0 1-9 9 9.75 9.75 0 0 1-6.74-2.74L3 16", key: "3uifl3" }],
1241
+ ["path", { d: "M8 16H3v5", key: "1cv678" }]
1242
+ ];
1243
+ var RefreshCw = createLucideIcon("refresh-cw", __iconNode30);
1244
+
1245
+ // node_modules/lucide-react/dist/esm/icons/rotate-ccw.js
1246
+ var __iconNode31 = [
1247
+ ["path", { d: "M3 12a9 9 0 1 0 9-9 9.75 9.75 0 0 0-6.74 2.74L3 8", key: "1357e3" }],
1248
+ ["path", { d: "M3 3v5h5", key: "1xhq8a" }]
1249
+ ];
1250
+ var RotateCcw = createLucideIcon("rotate-ccw", __iconNode31);
1251
+
1252
+ // node_modules/lucide-react/dist/esm/icons/save.js
1253
+ var __iconNode32 = [
1254
+ [
1255
+ "path",
1256
+ {
1257
+ d: "M15.2 3a2 2 0 0 1 1.4.6l3.8 3.8a2 2 0 0 1 .6 1.4V19a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2z",
1258
+ key: "1c8476"
1259
+ }
1260
+ ],
1261
+ ["path", { d: "M17 21v-7a1 1 0 0 0-1-1H8a1 1 0 0 0-1 1v7", key: "1ydtos" }],
1262
+ ["path", { d: "M7 3v4a1 1 0 0 0 1 1h7", key: "t51u73" }]
1263
+ ];
1264
+ var Save = createLucideIcon("save", __iconNode32);
1265
+
1266
+ // node_modules/lucide-react/dist/esm/icons/search.js
1267
+ var __iconNode33 = [
1268
+ ["path", { d: "m21 21-4.34-4.34", key: "14j7rj" }],
1269
+ ["circle", { cx: "11", cy: "11", r: "8", key: "4ej97u" }]
1270
+ ];
1271
+ var Search = createLucideIcon("search", __iconNode33);
1272
+
1273
+ // node_modules/lucide-react/dist/esm/icons/smartphone.js
1274
+ var __iconNode34 = [
1275
+ ["rect", { width: "14", height: "20", x: "5", y: "2", rx: "2", ry: "2", key: "1yt0o3" }],
1276
+ ["path", { d: "M12 18h.01", key: "mhygvu" }]
1277
+ ];
1278
+ var Smartphone = createLucideIcon("smartphone", __iconNode34);
1279
+
1280
+ // node_modules/lucide-react/dist/esm/icons/tablet.js
1281
+ var __iconNode35 = [
1282
+ ["rect", { width: "16", height: "20", x: "4", y: "2", rx: "2", ry: "2", key: "76otgf" }],
1283
+ ["line", { x1: "12", x2: "12.01", y1: "18", y2: "18", key: "1dp563" }]
1284
+ ];
1285
+ var Tablet = createLucideIcon("tablet", __iconNode35);
1286
+
1287
+ // node_modules/lucide-react/dist/esm/icons/trash-2.js
1288
+ var __iconNode36 = [
1289
+ ["path", { d: "M10 11v6", key: "nco0om" }],
1290
+ ["path", { d: "M14 11v6", key: "outv1u" }],
1291
+ ["path", { d: "M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6", key: "miytrc" }],
1292
+ ["path", { d: "M3 6h18", key: "d0wm0j" }],
1293
+ ["path", { d: "M8 6V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2", key: "e791ji" }]
1294
+ ];
1295
+ var Trash2 = createLucideIcon("trash-2", __iconNode36);
1296
+
1297
+ // node_modules/lucide-react/dist/esm/icons/undo-2.js
1298
+ var __iconNode37 = [
1299
+ ["path", { d: "M9 14 4 9l5-5", key: "102s5s" }],
1300
+ ["path", { d: "M4 9h10.5a5.5 5.5 0 0 1 5.5 5.5a5.5 5.5 0 0 1-5.5 5.5H11", key: "f3b9sd" }]
1301
+ ];
1302
+ var Undo2 = createLucideIcon("undo-2", __iconNode37);
1303
+
1304
+ // node_modules/lucide-react/dist/esm/icons/upload.js
1305
+ var __iconNode38 = [
1306
+ ["path", { d: "M12 3v12", key: "1x0j5s" }],
1307
+ ["path", { d: "m17 8-5-5-5 5", key: "7q97r8" }],
1308
+ ["path", { d: "M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4", key: "ih7n3h" }]
1309
+ ];
1310
+ var Upload = createLucideIcon("upload", __iconNode38);
1311
+
1312
+ // node_modules/lucide-react/dist/esm/icons/x.js
1313
+ var __iconNode39 = [
1314
+ ["path", { d: "M18 6 6 18", key: "1bl5f8" }],
1315
+ ["path", { d: "m6 6 12 12", key: "d8bk6v" }]
1316
+ ];
1317
+ var X = createLucideIcon("x", __iconNode39);
1534
1318
  var useOverlayCoords = (id, iframeEl, containerEl, documentState) => {
1535
1319
  const [coords, setCoords] = React__default.useState(null);
1536
1320
  React__default.useEffect(() => {
@@ -1907,6 +1691,7 @@ var FieldRenderer = ({
1907
1691
  onChange,
1908
1692
  readOnly = false
1909
1693
  }) => {
1694
+ const [expandedIndices, setExpandedIndices] = React__default.useState({});
1910
1695
  const label = definition.label || name3;
1911
1696
  const type = definition.type;
1912
1697
  if (definition.render) {
@@ -2070,6 +1855,215 @@ var FieldRenderer = ({
2070
1855
  },
2071
1856
  opt.value
2072
1857
  )) }) });
1858
+ case "array": {
1859
+ const items = Array.isArray(value) ? value : [];
1860
+ const arrayFields = definition.arrayFields || {};
1861
+ const getItemLabel = (item2, idx) => {
1862
+ if (!item2) return `\xD6\u011Fe ${idx + 1}`;
1863
+ for (const val of Object.values(item2)) {
1864
+ if (typeof val === "string" && val.trim().length > 0) {
1865
+ return val;
1866
+ }
1867
+ if (Array.isArray(val)) {
1868
+ const trVal = val.find((v2) => typeof v2 === "object" && v2 !== null && "value" in v2);
1869
+ if (trVal && typeof trVal.value === "string" && trVal.value.trim().length > 0) {
1870
+ return trVal.value;
1871
+ }
1872
+ }
1873
+ }
1874
+ return `\xD6\u011Fe ${idx + 1}`;
1875
+ };
1876
+ const toggleExpand = (idx) => {
1877
+ setExpandedIndices((prev) => ({ ...prev, [idx]: !prev[idx] }));
1878
+ };
1879
+ const handleAdd = () => {
1880
+ const newItem = {};
1881
+ Object.entries(arrayFields).forEach(([subName, subDef]) => {
1882
+ newItem[subName] = subDef.defaultValue !== void 0 ? subDef.defaultValue : null;
1883
+ });
1884
+ onChange([...items, newItem]);
1885
+ setExpandedIndices((prev) => ({ ...prev, [items.length]: true }));
1886
+ };
1887
+ const handleRemove = (idx) => {
1888
+ const copy = [...items];
1889
+ copy.splice(idx, 1);
1890
+ onChange(copy);
1891
+ const newExpanded = { ...expandedIndices };
1892
+ delete newExpanded[idx];
1893
+ setExpandedIndices(newExpanded);
1894
+ };
1895
+ const handleMove = (idx, direction) => {
1896
+ if (direction === "up" && idx === 0) return;
1897
+ if (direction === "down" && idx === items.length - 1) return;
1898
+ const copy = [...items];
1899
+ const targetIdx = direction === "up" ? idx - 1 : idx + 1;
1900
+ const temp = copy[idx];
1901
+ copy[idx] = copy[targetIdx];
1902
+ copy[targetIdx] = temp;
1903
+ onChange(copy);
1904
+ const newExpanded = { ...expandedIndices };
1905
+ const tempExpanded = newExpanded[idx];
1906
+ newExpanded[idx] = newExpanded[targetIdx];
1907
+ newExpanded[targetIdx] = tempExpanded;
1908
+ setExpandedIndices(newExpanded);
1909
+ };
1910
+ return /* @__PURE__ */ jsxRuntime.jsx(FieldLabel, { label, readOnly, children: /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { display: "flex", flexDirection: "column", gap: "8px", width: "100%" }, children: [
1911
+ items.map((item2, idx) => {
1912
+ const isExpanded = !!expandedIndices[idx];
1913
+ const itemLabel = getItemLabel(item2, idx);
1914
+ return /* @__PURE__ */ jsxRuntime.jsxs(
1915
+ "div",
1916
+ {
1917
+ style: {
1918
+ border: "1px solid #e4e4e7",
1919
+ borderRadius: "8px",
1920
+ overflow: "hidden",
1921
+ background: "#f8fafc",
1922
+ display: "flex",
1923
+ flexDirection: "column"
1924
+ },
1925
+ children: [
1926
+ /* @__PURE__ */ jsxRuntime.jsxs(
1927
+ "div",
1928
+ {
1929
+ onClick: () => toggleExpand(idx),
1930
+ style: {
1931
+ padding: "8px 12px",
1932
+ display: "flex",
1933
+ alignItems: "center",
1934
+ justifyContent: "space-between",
1935
+ cursor: "pointer",
1936
+ background: "#ffffff",
1937
+ userSelect: "none"
1938
+ },
1939
+ children: [
1940
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { display: "flex", alignItems: "center", gap: "6px" }, children: [
1941
+ isExpanded ? /* @__PURE__ */ jsxRuntime.jsx(ChevronDown, { size: 14, color: "#71717a" }) : /* @__PURE__ */ jsxRuntime.jsx(ChevronRight, { size: 14, color: "#71717a" }),
1942
+ /* @__PURE__ */ jsxRuntime.jsx("span", { style: { fontSize: "13px", fontWeight: 500, color: "#3f3f46" }, children: itemLabel })
1943
+ ] }),
1944
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { display: "flex", alignItems: "center", gap: "4px" }, onClick: (e3) => e3.stopPropagation(), children: [
1945
+ /* @__PURE__ */ jsxRuntime.jsx(
1946
+ "button",
1947
+ {
1948
+ onClick: () => handleMove(idx, "up"),
1949
+ disabled: idx === 0,
1950
+ style: {
1951
+ background: "transparent",
1952
+ border: "none",
1953
+ cursor: idx === 0 ? "not-allowed" : "pointer",
1954
+ padding: "2px",
1955
+ color: idx === 0 ? "#e4e4e7" : "#71717a"
1956
+ },
1957
+ children: /* @__PURE__ */ jsxRuntime.jsx(ArrowUp, { size: 12 })
1958
+ }
1959
+ ),
1960
+ /* @__PURE__ */ jsxRuntime.jsx(
1961
+ "button",
1962
+ {
1963
+ onClick: () => handleMove(idx, "down"),
1964
+ disabled: idx === items.length - 1,
1965
+ style: {
1966
+ background: "transparent",
1967
+ border: "none",
1968
+ cursor: idx === items.length - 1 ? "not-allowed" : "pointer",
1969
+ padding: "2px",
1970
+ color: idx === items.length - 1 ? "#e4e4e7" : "#71717a"
1971
+ },
1972
+ children: /* @__PURE__ */ jsxRuntime.jsx(ArrowDown, { size: 12 })
1973
+ }
1974
+ ),
1975
+ !readOnly && /* @__PURE__ */ jsxRuntime.jsx(
1976
+ "button",
1977
+ {
1978
+ onClick: () => handleRemove(idx),
1979
+ style: {
1980
+ background: "transparent",
1981
+ border: "none",
1982
+ cursor: "pointer",
1983
+ padding: "2px",
1984
+ color: "#ef4444",
1985
+ marginLeft: "4px"
1986
+ },
1987
+ children: /* @__PURE__ */ jsxRuntime.jsx(Trash2, { size: 12 })
1988
+ }
1989
+ )
1990
+ ] })
1991
+ ]
1992
+ }
1993
+ ),
1994
+ isExpanded && /* @__PURE__ */ jsxRuntime.jsx(
1995
+ "div",
1996
+ {
1997
+ style: {
1998
+ padding: "12px",
1999
+ borderTop: "1px solid #e4e4e7",
2000
+ display: "flex",
2001
+ flexDirection: "column",
2002
+ gap: "12px",
2003
+ background: "#ffffff"
2004
+ },
2005
+ children: Object.entries(arrayFields).map(([subFieldName, subFieldDef]) => /* @__PURE__ */ jsxRuntime.jsx(
2006
+ FieldRenderer,
2007
+ {
2008
+ name: subFieldName,
2009
+ definition: subFieldDef,
2010
+ value: item2[subFieldName],
2011
+ onChange: (newSubVal) => {
2012
+ const updatedItems = [...items];
2013
+ updatedItems[idx] = {
2014
+ ...updatedItems[idx],
2015
+ [subFieldName]: newSubVal
2016
+ };
2017
+ onChange(updatedItems);
2018
+ },
2019
+ readOnly
2020
+ },
2021
+ subFieldName
2022
+ ))
2023
+ }
2024
+ )
2025
+ ]
2026
+ },
2027
+ idx
2028
+ );
2029
+ }),
2030
+ !readOnly && /* @__PURE__ */ jsxRuntime.jsxs(
2031
+ "button",
2032
+ {
2033
+ type: "button",
2034
+ onClick: handleAdd,
2035
+ style: {
2036
+ display: "flex",
2037
+ alignItems: "center",
2038
+ justifyContent: "center",
2039
+ gap: "6px",
2040
+ width: "100%",
2041
+ padding: "10px",
2042
+ borderRadius: "8px",
2043
+ border: "1px dashed #cbd5e1",
2044
+ background: "#ffffff",
2045
+ color: "#64748b",
2046
+ fontSize: "13px",
2047
+ fontWeight: 500,
2048
+ cursor: "pointer",
2049
+ transition: "all 0.2s"
2050
+ },
2051
+ className: "tecof-add-array-item-btn",
2052
+ children: [
2053
+ /* @__PURE__ */ jsxRuntime.jsx(Plus, { size: 14 }),
2054
+ "\xD6\u011Fe Ekle"
2055
+ ]
2056
+ }
2057
+ ),
2058
+ /* @__PURE__ */ jsxRuntime.jsx("style", { dangerouslySetInnerHTML: { __html: `
2059
+ .tecof-add-array-item-btn:hover {
2060
+ border-color: #3b82f6 !important;
2061
+ color: #2563eb !important;
2062
+ background-color: #eff6ff !important;
2063
+ }
2064
+ ` } })
2065
+ ] }) });
2066
+ }
2073
2067
  default:
2074
2068
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { padding: "8px", fontSize: "11px", color: "#71717a", background: "#fafafa", borderRadius: "4px" }, children: [
2075
2069
  'Desteklenmeyen alan t\xFCr\xFC: "',
@@ -2269,6 +2263,528 @@ var Inspector = () => {
2269
2263
  }
2270
2264
  );
2271
2265
  };
2266
+ var TopBar = ({ onSave, saving, saveStatus }) => {
2267
+ const viewport = useEditorStore((state3) => state3.viewport);
2268
+ const setViewport = useEditorStore((state3) => state3.setViewport);
2269
+ const pastCount = useEditorStore((state3) => state3.history.past.length);
2270
+ const futureCount = useEditorStore((state3) => state3.history.future.length);
2271
+ const undo = useEditorStore((state3) => state3.undo);
2272
+ const redo = useEditorStore((state3) => state3.redo);
2273
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "tecof-studio-topbar", style: {
2274
+ height: "56px",
2275
+ borderBottom: "1px solid #e4e4e7",
2276
+ background: "#ffffff",
2277
+ display: "flex",
2278
+ alignItems: "center",
2279
+ justifyContent: "space-between",
2280
+ padding: "0 20px",
2281
+ boxSizing: "border-box",
2282
+ zIndex: 100
2283
+ }, children: [
2284
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "tecof-studio-topbar-title", style: {
2285
+ fontSize: "14px",
2286
+ fontWeight: 600,
2287
+ color: "#18181b",
2288
+ display: "flex",
2289
+ alignItems: "center",
2290
+ gap: "8px"
2291
+ }, children: [
2292
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: "Sayfa D\xFCzenleyici" }),
2293
+ saveStatus === "success" && /* @__PURE__ */ jsxRuntime.jsxs("span", { style: {
2294
+ fontSize: "11px",
2295
+ color: "#10b981",
2296
+ display: "inline-flex",
2297
+ alignItems: "center",
2298
+ gap: "4px",
2299
+ fontWeight: 500
2300
+ }, children: [
2301
+ /* @__PURE__ */ jsxRuntime.jsx(Check, { size: 12 }),
2302
+ " Kaydedildi"
2303
+ ] })
2304
+ ] }),
2305
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "tecof-studio-topbar-viewports", style: {
2306
+ display: "flex",
2307
+ alignItems: "center",
2308
+ background: "#f4f4f5",
2309
+ padding: "3px",
2310
+ borderRadius: "8px",
2311
+ gap: "2px"
2312
+ }, children: [
2313
+ /* @__PURE__ */ jsxRuntime.jsx(
2314
+ "button",
2315
+ {
2316
+ onClick: () => setViewport("desktop"),
2317
+ style: {
2318
+ background: viewport === "desktop" ? "#ffffff" : "transparent",
2319
+ border: "none",
2320
+ outline: "none",
2321
+ cursor: "pointer",
2322
+ padding: "6px 12px",
2323
+ borderRadius: "6px",
2324
+ color: viewport === "desktop" ? "#18181b" : "#71717a",
2325
+ display: "flex",
2326
+ alignItems: "center",
2327
+ justifyContent: "center",
2328
+ boxShadow: viewport === "desktop" ? "0 1px 3px 0 rgba(0, 0, 0, 0.1)" : "none",
2329
+ transition: "all 0.2s"
2330
+ },
2331
+ title: "Masa\xFCst\xFC",
2332
+ children: /* @__PURE__ */ jsxRuntime.jsx(Monitor, { size: 16 })
2333
+ }
2334
+ ),
2335
+ /* @__PURE__ */ jsxRuntime.jsx(
2336
+ "button",
2337
+ {
2338
+ onClick: () => setViewport("tablet"),
2339
+ style: {
2340
+ background: viewport === "tablet" ? "#ffffff" : "transparent",
2341
+ border: "none",
2342
+ outline: "none",
2343
+ cursor: "pointer",
2344
+ padding: "6px 12px",
2345
+ borderRadius: "6px",
2346
+ color: viewport === "tablet" ? "#18181b" : "#71717a",
2347
+ display: "flex",
2348
+ alignItems: "center",
2349
+ justifyContent: "center",
2350
+ boxShadow: viewport === "tablet" ? "0 1px 3px 0 rgba(0, 0, 0, 0.1)" : "none",
2351
+ transition: "all 0.2s"
2352
+ },
2353
+ title: "Tablet",
2354
+ children: /* @__PURE__ */ jsxRuntime.jsx(Tablet, { size: 16 })
2355
+ }
2356
+ ),
2357
+ /* @__PURE__ */ jsxRuntime.jsx(
2358
+ "button",
2359
+ {
2360
+ onClick: () => setViewport("mobile"),
2361
+ style: {
2362
+ background: viewport === "mobile" ? "#ffffff" : "transparent",
2363
+ border: "none",
2364
+ outline: "none",
2365
+ cursor: "pointer",
2366
+ padding: "6px 12px",
2367
+ borderRadius: "6px",
2368
+ color: viewport === "mobile" ? "#18181b" : "#71717a",
2369
+ display: "flex",
2370
+ alignItems: "center",
2371
+ justifyContent: "center",
2372
+ boxShadow: viewport === "mobile" ? "0 1px 3px 0 rgba(0, 0, 0, 0.1)" : "none",
2373
+ transition: "all 0.2s"
2374
+ },
2375
+ title: "Mobil",
2376
+ children: /* @__PURE__ */ jsxRuntime.jsx(Smartphone, { size: 16 })
2377
+ }
2378
+ )
2379
+ ] }),
2380
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "tecof-studio-topbar-actions", style: {
2381
+ display: "flex",
2382
+ alignItems: "center",
2383
+ gap: "12px"
2384
+ }, children: [
2385
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { display: "flex", gap: "4px" }, children: [
2386
+ /* @__PURE__ */ jsxRuntime.jsx(
2387
+ "button",
2388
+ {
2389
+ onClick: undo,
2390
+ disabled: pastCount === 0,
2391
+ style: {
2392
+ background: "transparent",
2393
+ border: "none",
2394
+ cursor: pastCount === 0 ? "not-allowed" : "pointer",
2395
+ padding: "8px",
2396
+ borderRadius: "6px",
2397
+ color: pastCount === 0 ? "#d4d4d8" : "#71717a",
2398
+ display: "flex",
2399
+ alignItems: "center",
2400
+ justifyContent: "center",
2401
+ transition: "background 0.2s"
2402
+ },
2403
+ title: "Geri Al",
2404
+ children: /* @__PURE__ */ jsxRuntime.jsx(Undo2, { size: 16 })
2405
+ }
2406
+ ),
2407
+ /* @__PURE__ */ jsxRuntime.jsx(
2408
+ "button",
2409
+ {
2410
+ onClick: redo,
2411
+ disabled: futureCount === 0,
2412
+ style: {
2413
+ background: "transparent",
2414
+ border: "none",
2415
+ cursor: futureCount === 0 ? "not-allowed" : "pointer",
2416
+ padding: "8px",
2417
+ borderRadius: "6px",
2418
+ color: futureCount === 0 ? "#d4d4d8" : "#71717a",
2419
+ display: "flex",
2420
+ alignItems: "center",
2421
+ justifyContent: "center",
2422
+ transition: "background 0.2s"
2423
+ },
2424
+ title: "Yinele",
2425
+ children: /* @__PURE__ */ jsxRuntime.jsx(Redo2, { size: 16 })
2426
+ }
2427
+ )
2428
+ ] }),
2429
+ /* @__PURE__ */ jsxRuntime.jsx("div", { style: { width: "1px", height: "20px", background: "#e4e4e7" } }),
2430
+ /* @__PURE__ */ jsxRuntime.jsxs(
2431
+ "button",
2432
+ {
2433
+ onClick: onSave,
2434
+ disabled: saving,
2435
+ style: {
2436
+ background: "#2563eb",
2437
+ color: "#ffffff",
2438
+ border: "none",
2439
+ cursor: saving ? "wait" : "pointer",
2440
+ padding: "8px 16px",
2441
+ borderRadius: "8px",
2442
+ fontSize: "13px",
2443
+ fontWeight: 500,
2444
+ display: "flex",
2445
+ alignItems: "center",
2446
+ gap: "8px",
2447
+ transition: "background 0.2s",
2448
+ opacity: saving ? 0.7 : 1
2449
+ },
2450
+ children: [
2451
+ /* @__PURE__ */ jsxRuntime.jsx(Save, { size: 14 }),
2452
+ saving ? "Kaydediliyor..." : "Taslak Kaydet"
2453
+ ]
2454
+ }
2455
+ )
2456
+ ] })
2457
+ ] });
2458
+ };
2459
+ var TreeNode = ({ node, depth }) => {
2460
+ const { config: config3 } = useStudio();
2461
+ const documentState = useEditorStore((state3) => state3.document);
2462
+ const selectedId = useEditorStore((state3) => state3.selection.selectedId);
2463
+ const selectNode = useEditorStore((state3) => state3.selectNode);
2464
+ const hoverNode = useEditorStore((state3) => state3.hoverNode);
2465
+ const removeNode2 = useEditorStore((state3) => state3.removeNode);
2466
+ const [expanded, setExpanded] = React__default.useState(true);
2467
+ const isSelected = selectedId === node.props.id;
2468
+ const componentConfig = config3.components[node.type];
2469
+ const label = componentConfig?.label || node.type;
2470
+ const childZoneKeys = Object.keys(documentState.zones).filter(
2471
+ (key) => key.startsWith(`${node.props.id}:`)
2472
+ );
2473
+ const hasChildren = childZoneKeys.some(
2474
+ (key) => (documentState.zones[key] || []).length > 0
2475
+ );
2476
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "tecof-layers-tree-node", style: { display: "flex", flexDirection: "column" }, children: [
2477
+ /* @__PURE__ */ jsxRuntime.jsxs(
2478
+ "div",
2479
+ {
2480
+ onMouseEnter: () => hoverNode(node.props.id),
2481
+ onMouseLeave: () => hoverNode(null),
2482
+ onClick: () => selectNode(node.props.id),
2483
+ style: {
2484
+ display: "flex",
2485
+ alignItems: "center",
2486
+ justifyContent: "space-between",
2487
+ padding: "6px 8px",
2488
+ paddingLeft: `${depth * 12 + 8}px`,
2489
+ background: isSelected ? "#eff6ff" : "transparent",
2490
+ color: isSelected ? "#1d4ed8" : "#3f3f46",
2491
+ cursor: "pointer",
2492
+ borderRadius: "6px",
2493
+ fontSize: "13px",
2494
+ fontWeight: isSelected ? 500 : 400,
2495
+ transition: "all 0.15s"
2496
+ },
2497
+ children: [
2498
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { display: "flex", alignItems: "center", gap: "6px" }, children: [
2499
+ hasChildren ? /* @__PURE__ */ jsxRuntime.jsx(
2500
+ "button",
2501
+ {
2502
+ onClick: (e3) => {
2503
+ e3.stopPropagation();
2504
+ setExpanded(!expanded);
2505
+ },
2506
+ style: {
2507
+ background: "transparent",
2508
+ border: "none",
2509
+ cursor: "pointer",
2510
+ padding: 0,
2511
+ display: "flex",
2512
+ alignItems: "center",
2513
+ color: "#a1a1aa"
2514
+ },
2515
+ children: expanded ? /* @__PURE__ */ jsxRuntime.jsx(ChevronDown, { size: 14 }) : /* @__PURE__ */ jsxRuntime.jsx(ChevronRight, { size: 14 })
2516
+ }
2517
+ ) : /* @__PURE__ */ jsxRuntime.jsx("div", { style: { width: "14px" } }),
2518
+ /* @__PURE__ */ jsxRuntime.jsx(PanelsTopLeft, { size: 14, style: { color: isSelected ? "#3b82f6" : "#71717a" } }),
2519
+ /* @__PURE__ */ jsxRuntime.jsx("span", { style: {
2520
+ whiteSpace: "nowrap",
2521
+ overflow: "hidden",
2522
+ textOverflow: "ellipsis",
2523
+ maxWidth: "120px"
2524
+ }, children: label })
2525
+ ] }),
2526
+ /* @__PURE__ */ jsxRuntime.jsx(
2527
+ "button",
2528
+ {
2529
+ onClick: (e3) => {
2530
+ e3.stopPropagation();
2531
+ removeNode2(node.props.id);
2532
+ },
2533
+ className: "tecof-layers-delete-btn",
2534
+ style: {
2535
+ background: "transparent",
2536
+ border: "none",
2537
+ cursor: "pointer",
2538
+ padding: "2px",
2539
+ color: "#a1a1aa",
2540
+ display: "flex",
2541
+ alignItems: "center",
2542
+ opacity: 0,
2543
+ transition: "opacity 0.2s"
2544
+ },
2545
+ children: /* @__PURE__ */ jsxRuntime.jsx(Trash2, { size: 12 })
2546
+ }
2547
+ )
2548
+ ]
2549
+ }
2550
+ ),
2551
+ /* @__PURE__ */ jsxRuntime.jsx("style", { dangerouslySetInnerHTML: { __html: `
2552
+ .tecof-layers-tree-node:hover .tecof-layers-delete-btn {
2553
+ opacity: 1 !important;
2554
+ }
2555
+ .tecof-layers-delete-btn:hover {
2556
+ color: #ef4444 !important;
2557
+ }
2558
+ ` } }),
2559
+ expanded && childZoneKeys.map((zoneKey) => {
2560
+ const zoneItems = documentState.zones[zoneKey] || [];
2561
+ const zoneName = zoneKey.split(":").pop() || "";
2562
+ if (zoneItems.length === 0) return null;
2563
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { display: "flex", flexDirection: "column" }, children: [
2564
+ /* @__PURE__ */ jsxRuntime.jsx("div", { style: {
2565
+ fontSize: "10px",
2566
+ textTransform: "uppercase",
2567
+ letterSpacing: "0.05em",
2568
+ color: "#a1a1aa",
2569
+ padding: "4px 8px",
2570
+ paddingLeft: `${(depth + 1) * 12 + 14}px`,
2571
+ fontWeight: 600
2572
+ }, children: zoneName }),
2573
+ zoneItems.map((childNode) => /* @__PURE__ */ jsxRuntime.jsx(TreeNode, { node: childNode, depth: depth + 1 }, childNode.props.id))
2574
+ ] }, zoneKey);
2575
+ })
2576
+ ] });
2577
+ };
2578
+ var LayersTree = () => {
2579
+ const documentState = useEditorStore((state3) => state3.document);
2580
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "tecof-studio-layers-tree", style: {
2581
+ display: "flex",
2582
+ flexDirection: "column",
2583
+ gap: "2px",
2584
+ overflowY: "auto",
2585
+ height: "100%"
2586
+ }, children: documentState.content.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx("div", { style: {
2587
+ textAlign: "center",
2588
+ color: "#a1a1aa",
2589
+ fontSize: "13px",
2590
+ padding: "24px 12px"
2591
+ }, children: "S\xFCr\xFCklenmi\u015F katman yok" }) : documentState.content.map((node) => /* @__PURE__ */ jsxRuntime.jsx(TreeNode, { node, depth: 0 }, node.props.id)) });
2592
+ };
2593
+ var LeftPanel = () => {
2594
+ const { config: config3 } = useStudio();
2595
+ const insertNode2 = useEditorStore((state3) => state3.insertNode);
2596
+ useEditorStore((state3) => state3.selection.selectedId);
2597
+ useEditorStore((state3) => state3.document);
2598
+ const [activeTab, setActiveTab] = React__default.useState("blocks");
2599
+ const [searchQuery, setSearchQuery] = React__default.useState("");
2600
+ const categories = config3.categories || {};
2601
+ const components = config3.components || {};
2602
+ const groupedComponents = {};
2603
+ if (Object.keys(categories).length > 0) {
2604
+ Object.entries(categories).forEach(([key, value]) => {
2605
+ groupedComponents[value.title || key] = value.components;
2606
+ });
2607
+ } else {
2608
+ Object.entries(components).forEach(([name3, compConfig]) => {
2609
+ const cat = compConfig.category || "Genel";
2610
+ if (!groupedComponents[cat]) {
2611
+ groupedComponents[cat] = [];
2612
+ }
2613
+ groupedComponents[cat].push(name3);
2614
+ });
2615
+ }
2616
+ const handleAddBlock = (type) => {
2617
+ const compConfig = components[type] || {};
2618
+ const defaultProps = compConfig.defaultProps || {};
2619
+ const newNode = {
2620
+ type,
2621
+ props: {
2622
+ id: generateId(),
2623
+ ...JSON.parse(JSON.stringify(defaultProps))
2624
+ }
2625
+ };
2626
+ insertNode2(newNode);
2627
+ };
2628
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "tecof-studio-left-panel", style: {
2629
+ width: "280px",
2630
+ borderRight: "1px solid #e4e4e7",
2631
+ background: "#ffffff",
2632
+ display: "flex",
2633
+ flexDirection: "column",
2634
+ height: "100%",
2635
+ boxSizing: "border-box"
2636
+ }, children: [
2637
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: {
2638
+ display: "flex",
2639
+ borderBottom: "1px solid #e4e4e7",
2640
+ padding: "8px 12px",
2641
+ gap: "4px"
2642
+ }, children: [
2643
+ /* @__PURE__ */ jsxRuntime.jsxs(
2644
+ "button",
2645
+ {
2646
+ onClick: () => setActiveTab("blocks"),
2647
+ style: {
2648
+ flex: 1,
2649
+ display: "flex",
2650
+ alignItems: "center",
2651
+ justifyContent: "center",
2652
+ gap: "6px",
2653
+ border: "none",
2654
+ outline: "none",
2655
+ padding: "8px",
2656
+ borderRadius: "6px",
2657
+ fontSize: "12px",
2658
+ fontWeight: 600,
2659
+ cursor: "pointer",
2660
+ background: activeTab === "blocks" ? "#f4f4f5" : "transparent",
2661
+ color: activeTab === "blocks" ? "#18181b" : "#71717a",
2662
+ transition: "all 0.2s"
2663
+ },
2664
+ children: [
2665
+ /* @__PURE__ */ jsxRuntime.jsx(Grid3x3, { size: 14 }),
2666
+ "Blok Ekle"
2667
+ ]
2668
+ }
2669
+ ),
2670
+ /* @__PURE__ */ jsxRuntime.jsxs(
2671
+ "button",
2672
+ {
2673
+ onClick: () => setActiveTab("layers"),
2674
+ style: {
2675
+ flex: 1,
2676
+ display: "flex",
2677
+ alignItems: "center",
2678
+ justifyContent: "center",
2679
+ gap: "6px",
2680
+ border: "none",
2681
+ outline: "none",
2682
+ padding: "8px",
2683
+ borderRadius: "6px",
2684
+ fontSize: "12px",
2685
+ fontWeight: 600,
2686
+ cursor: "pointer",
2687
+ background: activeTab === "layers" ? "#f4f4f5" : "transparent",
2688
+ color: activeTab === "layers" ? "#18181b" : "#71717a",
2689
+ transition: "all 0.2s"
2690
+ },
2691
+ children: [
2692
+ /* @__PURE__ */ jsxRuntime.jsx(Layers, { size: 14 }),
2693
+ "Katmanlar"
2694
+ ]
2695
+ }
2696
+ )
2697
+ ] }),
2698
+ /* @__PURE__ */ jsxRuntime.jsx("div", { style: { flex: 1, overflowY: "auto", padding: "12px" }, children: activeTab === "blocks" ? /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { display: "flex", flexDirection: "column", gap: "16px" }, children: [
2699
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: {
2700
+ display: "flex",
2701
+ alignItems: "center",
2702
+ background: "#f4f4f5",
2703
+ padding: "6px 10px",
2704
+ borderRadius: "8px",
2705
+ gap: "8px"
2706
+ }, children: [
2707
+ /* @__PURE__ */ jsxRuntime.jsx(Search, { size: 14, color: "#a1a1aa" }),
2708
+ /* @__PURE__ */ jsxRuntime.jsx(
2709
+ "input",
2710
+ {
2711
+ type: "text",
2712
+ placeholder: "Bile\u015Fen ara...",
2713
+ value: searchQuery,
2714
+ onChange: (e3) => setSearchQuery(e3.target.value),
2715
+ style: {
2716
+ border: "none",
2717
+ outline: "none",
2718
+ background: "transparent",
2719
+ fontSize: "12px",
2720
+ color: "#18181b",
2721
+ width: "100%"
2722
+ }
2723
+ }
2724
+ )
2725
+ ] }),
2726
+ Object.entries(groupedComponents).map(([catTitle, blockTypes]) => {
2727
+ const filteredTypes = blockTypes.filter((type) => {
2728
+ const label = components[type]?.label || type;
2729
+ return label.toLowerCase().includes(searchQuery.toLowerCase());
2730
+ });
2731
+ if (filteredTypes.length === 0) return null;
2732
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { display: "flex", flexDirection: "column", gap: "8px" }, children: [
2733
+ /* @__PURE__ */ jsxRuntime.jsx("div", { style: {
2734
+ fontSize: "11px",
2735
+ fontWeight: 700,
2736
+ color: "#71717a",
2737
+ textTransform: "uppercase",
2738
+ letterSpacing: "0.05em"
2739
+ }, children: catTitle }),
2740
+ /* @__PURE__ */ jsxRuntime.jsx("div", { style: {
2741
+ display: "grid",
2742
+ gridTemplateColumns: "1fr",
2743
+ gap: "6px"
2744
+ }, children: filteredTypes.map((type) => {
2745
+ const compConfig = components[type] || {};
2746
+ const label = compConfig.label || type;
2747
+ return /* @__PURE__ */ jsxRuntime.jsxs(
2748
+ "button",
2749
+ {
2750
+ onClick: () => handleAddBlock(type),
2751
+ style: {
2752
+ background: "#ffffff",
2753
+ border: "1px solid #e4e4e7",
2754
+ padding: "10px 12px",
2755
+ borderRadius: "8px",
2756
+ fontSize: "13px",
2757
+ fontWeight: 500,
2758
+ color: "#3f3f46",
2759
+ cursor: "pointer",
2760
+ display: "flex",
2761
+ alignItems: "center",
2762
+ justifyContent: "space-between",
2763
+ textAlign: "left",
2764
+ transition: "all 0.2s",
2765
+ boxShadow: "0 1px 2px 0 rgba(0, 0, 0, 0.02)"
2766
+ },
2767
+ className: "tecof-studio-block-btn",
2768
+ children: [
2769
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: label }),
2770
+ /* @__PURE__ */ jsxRuntime.jsx(Plus, { size: 14, style: { color: "#a1a1aa" } })
2771
+ ]
2772
+ },
2773
+ type
2774
+ );
2775
+ }) })
2776
+ ] }, catTitle);
2777
+ }),
2778
+ /* @__PURE__ */ jsxRuntime.jsx("style", { dangerouslySetInnerHTML: { __html: `
2779
+ .tecof-studio-block-btn:hover {
2780
+ border-color: #3b82f6 !important;
2781
+ color: #2563eb !important;
2782
+ background-color: #eff6ff !important;
2783
+ }
2784
+ ` } })
2785
+ ] }) : /* @__PURE__ */ jsxRuntime.jsx(LayersTree, {}) })
2786
+ ] });
2787
+ };
2272
2788
  var TecofStudio = ({
2273
2789
  pageId,
2274
2790
  config: config3,
@@ -2382,6 +2898,67 @@ var TecofStudio = ({
2382
2898
  window.addEventListener("message", onMessage);
2383
2899
  return () => window.removeEventListener("message", onMessage);
2384
2900
  }, [isEmbedded, handleSaveDraft, undo, redo, setViewport]);
2901
+ React__default.useEffect(() => {
2902
+ const handleKeyDown = (e3) => {
2903
+ const isInput2 = () => {
2904
+ const activeEl = document.activeElement;
2905
+ if (activeEl) {
2906
+ const tag = activeEl.tagName.toLowerCase();
2907
+ if (tag === "input" || tag === "textarea" || activeEl.hasAttribute("contenteditable")) {
2908
+ return true;
2909
+ }
2910
+ }
2911
+ const iframe = document.querySelector(".tecof-canvas-viewport-wrapper iframe");
2912
+ const iframeDoc = iframe?.contentDocument;
2913
+ const iframeActiveEl = iframeDoc?.activeElement;
2914
+ if (iframeActiveEl) {
2915
+ const tag = iframeActiveEl.tagName.toLowerCase();
2916
+ if (tag === "input" || tag === "textarea" || iframeActiveEl.hasAttribute("contenteditable")) {
2917
+ return true;
2918
+ }
2919
+ }
2920
+ return false;
2921
+ };
2922
+ const selectedId = useEditorStore.getState().selection.selectedId;
2923
+ const isCmdOrCtrl = e3.metaKey || e3.ctrlKey;
2924
+ if (e3.key === "Escape") {
2925
+ useEditorStore.getState().selectNode(null);
2926
+ if (isEmbedded) {
2927
+ window.parent.postMessage({ type: "puck:itemDeselected" }, "*");
2928
+ }
2929
+ return;
2930
+ }
2931
+ if (isCmdOrCtrl && e3.key.toLowerCase() === "z") {
2932
+ e3.preventDefault();
2933
+ if (e3.shiftKey) {
2934
+ redo();
2935
+ } else {
2936
+ undo();
2937
+ }
2938
+ return;
2939
+ }
2940
+ if (isCmdOrCtrl && e3.key.toLowerCase() === "y") {
2941
+ e3.preventDefault();
2942
+ redo();
2943
+ return;
2944
+ }
2945
+ if (isInput2()) return;
2946
+ if ((e3.key === "Delete" || e3.key === "Backspace") && selectedId) {
2947
+ e3.preventDefault();
2948
+ useEditorStore.getState().removeNode(selectedId);
2949
+ return;
2950
+ }
2951
+ if (isCmdOrCtrl && e3.key.toLowerCase() === "d" && selectedId) {
2952
+ e3.preventDefault();
2953
+ useEditorStore.getState().duplicateNode(selectedId);
2954
+ return;
2955
+ }
2956
+ };
2957
+ window.addEventListener("keydown", handleKeyDown);
2958
+ return () => {
2959
+ window.removeEventListener("keydown", handleKeyDown);
2960
+ };
2961
+ }, [undo, redo, isEmbedded]);
2385
2962
  const studioContextValue = React__default.useMemo(() => ({
2386
2963
  config: config3,
2387
2964
  readOnly: false,
@@ -2416,13 +2993,15 @@ var TecofStudio = ({
2416
2993
  position: "relative",
2417
2994
  background: "#f4f4f5"
2418
2995
  }, children: [
2996
+ /* @__PURE__ */ jsxRuntime.jsx(TopBar, { onSave: handleSaveDraft, saving, saveStatus }),
2419
2997
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "tecof-studio-workspace-container", style: {
2420
2998
  display: "flex",
2421
2999
  flex: 1,
2422
- height: "100%",
3000
+ height: "calc(100% - 56px)",
2423
3001
  width: "100%",
2424
3002
  overflow: "hidden"
2425
3003
  }, children: [
3004
+ /* @__PURE__ */ jsxRuntime.jsx(LeftPanel, {}),
2426
3005
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "tecof-studio-workspace", style: {
2427
3006
  display: "flex",
2428
3007
  flex: 1,
@@ -2450,16 +3029,46 @@ var TecofStudio = ({
2450
3029
  }, children: saveStatus === "error" ? "Kaydedilemedi" : "Kaydediliyor..." })
2451
3030
  ] }) });
2452
3031
  };
3032
+
3033
+ // src/components/TecofEditor.tsx
3034
+ var TecofEditor = TecofStudio;
3035
+ var RenderContext = React__default.createContext(null);
3036
+ var ParentNodeContext2 = React__default.createContext(null);
3037
+ var RenderDropZone = ({ zone, className, style }) => {
3038
+ const parentId = React__default.useContext(ParentNodeContext2);
3039
+ const zoneKey = parentId ? `${parentId}:${zone}` : zone;
3040
+ const context = React__default.useContext(RenderContext);
3041
+ if (!context) return null;
3042
+ const items = context.zones[zoneKey] || [];
3043
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className, style, children: items.map((item2, index2) => /* @__PURE__ */ jsxRuntime.jsx(RenderNode, { node: item2, index: index2 }, item2.props.id || index2)) });
3044
+ };
3045
+ var RenderNode = ({ node, index: index2 }) => {
3046
+ const context = React__default.useContext(RenderContext);
3047
+ if (!context) return null;
3048
+ const componentConfig = context.config.components[node.type];
3049
+ if (!componentConfig) return null;
3050
+ const componentProps = {
3051
+ ...node.props,
3052
+ puck: {
3053
+ renderDropZone: RenderDropZone,
3054
+ isEditing: false,
3055
+ metadata: {
3056
+ cmsData: context.cmsData || null,
3057
+ ...componentConfig.metadata || {}
3058
+ }
3059
+ },
3060
+ editMode: false
3061
+ };
3062
+ return /* @__PURE__ */ jsxRuntime.jsx(ParentNodeContext2.Provider, { value: node.props.id || null, children: componentConfig.render(componentProps) });
3063
+ };
2453
3064
  var TecofRender = ({ data: data3, config: config3, className, cmsData }) => {
2454
3065
  if (!data3) return null;
2455
- return /* @__PURE__ */ jsxRuntime.jsx("div", { className, children: /* @__PURE__ */ jsxRuntime.jsx(
2456
- core.Render,
2457
- {
2458
- config: config3,
2459
- data: data3,
2460
- metadata: { cmsData: cmsData || null }
2461
- }
2462
- ) });
3066
+ const contextValue = {
3067
+ zones: data3.zones || {},
3068
+ config: config3,
3069
+ cmsData: cmsData || null
3070
+ };
3071
+ return /* @__PURE__ */ jsxRuntime.jsx(RenderContext.Provider, { value: contextValue, children: /* @__PURE__ */ jsxRuntime.jsx("div", { className, children: data3.content.map((item2, index2) => /* @__PURE__ */ jsxRuntime.jsx(RenderNode, { node: item2, index: index2 }, item2.props.id || index2)) }) });
2463
3072
  };
2464
3073
  var IMAGE_EXTENSIONS = ["png", "jpg", "jpeg", "webp", "gif", "svg", "avif", "bmp", "tiff", "heic"];
2465
3074
  var VIDEO_EXTENSIONS = ["mp4", "webm", "ogg", "avi", "mov", "quicktime"];
@@ -26987,20 +27596,29 @@ lucide-react/dist/esm/icons/file-text.js:
26987
27596
  lucide-react/dist/esm/icons/file.js:
26988
27597
  lucide-react/dist/esm/icons/folder-open.js:
26989
27598
  lucide-react/dist/esm/icons/globe.js:
27599
+ lucide-react/dist/esm/icons/grid-3x3.js:
26990
27600
  lucide-react/dist/esm/icons/grip-vertical.js:
26991
27601
  lucide-react/dist/esm/icons/image-plus.js:
26992
27602
  lucide-react/dist/esm/icons/image.js:
26993
27603
  lucide-react/dist/esm/icons/languages.js:
27604
+ lucide-react/dist/esm/icons/layers.js:
26994
27605
  lucide-react/dist/esm/icons/link-2.js:
26995
27606
  lucide-react/dist/esm/icons/link.js:
26996
27607
  lucide-react/dist/esm/icons/loader-circle.js:
27608
+ lucide-react/dist/esm/icons/monitor.js:
27609
+ lucide-react/dist/esm/icons/panels-top-left.js:
26997
27610
  lucide-react/dist/esm/icons/pencil.js:
26998
27611
  lucide-react/dist/esm/icons/plus.js:
27612
+ lucide-react/dist/esm/icons/redo-2.js:
26999
27613
  lucide-react/dist/esm/icons/refresh-ccw.js:
27000
27614
  lucide-react/dist/esm/icons/refresh-cw.js:
27001
27615
  lucide-react/dist/esm/icons/rotate-ccw.js:
27616
+ lucide-react/dist/esm/icons/save.js:
27002
27617
  lucide-react/dist/esm/icons/search.js:
27618
+ lucide-react/dist/esm/icons/smartphone.js:
27619
+ lucide-react/dist/esm/icons/tablet.js:
27003
27620
  lucide-react/dist/esm/icons/trash-2.js:
27621
+ lucide-react/dist/esm/icons/undo-2.js:
27004
27622
  lucide-react/dist/esm/icons/upload.js:
27005
27623
  lucide-react/dist/esm/icons/x.js:
27006
27624
  lucide-react/dist/esm/lucide-react.js: