@g1cloud/page-builder-editor 1.0.0-alpha.34 → 1.0.0-alpha.36

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.
@@ -7,6 +7,7 @@
7
7
  display: flex;
8
8
  flex-direction: column;
9
9
  margin: 0 auto;
10
+ padding-bottom: 100px;
10
11
  width: 100%;
11
12
  background-position: 50% 50%;
12
13
  background-repeat: no-repeat;
@@ -1,6 +1,6 @@
1
1
  import { defineComponent, openBlock, createElementBlock, createElementVNode, toDisplayString, createVNode, unref } from "vue";
2
2
  import { BSTextInput } from "@g1cloud/bluesea";
3
- import { P as PbColorPicker } from "./index-BaB2TtF-.js";
3
+ import { P as PbColorPicker } from "./index-BPKptjBm.js";
4
4
  const _hoisted_1 = { class: "property-editor property-editor-color" };
5
5
  const _hoisted_2 = { class: "title" };
6
6
  const _hoisted_3 = ["textContent"];
@@ -1,6 +1,6 @@
1
1
  import { defineComponent, openBlock, createElementBlock, createElementVNode, toDisplayString, defineAsyncComponent } from "vue";
2
2
  import { useModal } from "@g1cloud/bluesea";
3
- import { u as usePageBuilderEditor } from "./index-BaB2TtF-.js";
3
+ import { u as usePageBuilderEditor } from "./index-BPKptjBm.js";
4
4
  const _hoisted_1 = { class: "property-editor property-editor-image flex-align-center" };
5
5
  const _hoisted_2 = { class: "title" };
6
6
  const _hoisted_3 = ["textContent"];
@@ -1,5 +1,5 @@
1
1
  import { defineComponent, openBlock, createElementBlock, createElementVNode, toDisplayString } from "vue";
2
- import { u as usePageBuilderEditor } from "./index-BaB2TtF-.js";
2
+ import { u as usePageBuilderEditor } from "./index-BPKptjBm.js";
3
3
  import { useModal } from "@g1cloud/bluesea";
4
4
  const _hoisted_1 = { class: "property-editor property-editor-image flex-align-center" };
5
5
  const _hoisted_2 = { class: "title" };
@@ -1,6 +1,6 @@
1
1
  import { defineComponent, computed, openBlock, createElementBlock, createElementVNode, toDisplayString, createBlock, unref } from "vue";
2
2
  import { BSMultiLangTextArea, BSTextArea } from "@g1cloud/bluesea";
3
- import { u as usePageBuilderEditor } from "./index-BaB2TtF-.js";
3
+ import { u as usePageBuilderEditor } from "./index-BPKptjBm.js";
4
4
  const _hoisted_1 = { class: "property-editor property-editor-multiline-text" };
5
5
  const _hoisted_2 = { class: "title" };
6
6
  const _hoisted_3 = ["textContent"];
@@ -1,6 +1,6 @@
1
1
  import { defineComponent, computed, openBlock, createElementBlock, createElementVNode, toDisplayString, createBlock, unref } from "vue";
2
2
  import { BSMultiLangTextInput, BSTextInput } from "@g1cloud/bluesea";
3
- import { u as usePageBuilderEditor } from "./index-BaB2TtF-.js";
3
+ import { u as usePageBuilderEditor } from "./index-BPKptjBm.js";
4
4
  const _hoisted_1 = { class: "property-editor property-editor-text flex-align-center" };
5
5
  const _hoisted_2 = { class: "title" };
6
6
  const _hoisted_3 = ["textContent"];
@@ -1,6 +1,6 @@
1
1
  import { defineComponent, openBlock, createElementBlock, createElementVNode, toDisplayString } from "vue";
2
2
  import { useModal } from "@g1cloud/bluesea";
3
- import { s as selectYoutubeVideo } from "./index-BaB2TtF-.js";
3
+ import { s as selectYoutubeVideo } from "./index-BPKptjBm.js";
4
4
  const _hoisted_1 = { class: "property-editor property-editor-image flex-align-center" };
5
5
  const _hoisted_2 = { class: "title" };
6
6
  const _hoisted_3 = ["textContent"];
@@ -1,6 +1,6 @@
1
1
  import { defineComponent, computed, openBlock, createBlock, unref, withCtx, createElementVNode, createElementBlock, Fragment, renderList, toDisplayString } from "vue";
2
2
  import { useModalHandle, BSModalFrame } from "@g1cloud/bluesea";
3
- import { w as widgetPartDefinitions } from "./index-BaB2TtF-.js";
3
+ import { w as widgetPartDefinitions } from "./index-BPKptjBm.js";
4
4
  const _hoisted_1 = { class: "bs-layout-vertical pb-part-add-modal" };
5
5
  const _hoisted_2 = { class: "bs-layout-horizontal-wrap ml-16 mb-8 gap-8" };
6
6
  const _hoisted_3 = ["onClick", "textContent"];
@@ -3,9 +3,11 @@ import { IPart } from '@g1cloud/page-builder-viewer';
3
3
  declare const _default: import('vue').DefineComponent<import('vue').ExtractPropTypes<__VLS_TypePropsToRuntimeProps<{
4
4
  part: IPart;
5
5
  isMobilePage: boolean;
6
+ placeholder?: boolean | undefined;
6
7
  }>>, {}, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {}, string, import('vue').PublicProps, Readonly<import('vue').ExtractPropTypes<__VLS_TypePropsToRuntimeProps<{
7
8
  part: IPart;
8
9
  isMobilePage: boolean;
10
+ placeholder?: boolean | undefined;
9
11
  }>>> & Readonly<{}>, {}, {}, {}, {}, string, import('vue').ComponentProvideOptions, true, {}, any>;
10
12
  export default _default;
11
13
  type __VLS_NonUndefinedable<T> = T extends undefined ? never : T;
@@ -3,9 +3,11 @@ import { IPart } from '@g1cloud/page-builder-viewer';
3
3
  declare const _default: import('vue').DefineComponent<import('vue').ExtractPropTypes<__VLS_TypePropsToRuntimeProps<{
4
4
  part: IPart;
5
5
  isMobilePage: boolean;
6
+ placeholder?: boolean | undefined;
6
7
  }>>, {}, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {}, string, import('vue').PublicProps, Readonly<import('vue').ExtractPropTypes<__VLS_TypePropsToRuntimeProps<{
7
8
  part: IPart;
8
9
  isMobilePage: boolean;
10
+ placeholder?: boolean | undefined;
9
11
  }>>> & Readonly<{}>, {}, {}, {}, {}, string, import('vue').ComponentProvideOptions, true, {}, any>;
10
12
  export default _default;
11
13
  type __VLS_NonUndefinedable<T> = T extends undefined ? never : T;
@@ -6670,6 +6670,24 @@ class Part {
6670
6670
  isNestedWidget() {
6671
6671
  return false;
6672
6672
  }
6673
+ isParentOf(part) {
6674
+ if (!part) return false;
6675
+ let parent = part.parent;
6676
+ while (parent) {
6677
+ if (parent === this || parent.partId === this.partId) return true;
6678
+ parent = parent.parent;
6679
+ }
6680
+ return false;
6681
+ }
6682
+ isChildOf(part) {
6683
+ if (!part) return false;
6684
+ let parent = this.parent;
6685
+ while (parent) {
6686
+ if (parent === part || parent.partId === part.partId) return true;
6687
+ parent = parent.parent;
6688
+ }
6689
+ return false;
6690
+ }
6673
6691
  getName() {
6674
6692
  var _a;
6675
6693
  return (_a = this.properties) == null ? void 0 : _a.name;
@@ -7541,8 +7559,7 @@ const _sfc_main$q = /* @__PURE__ */ defineComponent({
7541
7559
  const pageBuilder = usePageBuilder();
7542
7560
  const comp = computed(() => pageBuilder.getCustomWidgetComponent(props.part));
7543
7561
  const bind = computed(() => ({
7544
- ...props.part.properties || {},
7545
- placeholder: props.placeholder
7562
+ ...props.part.properties || {}
7546
7563
  }));
7547
7564
  return (_ctx, _cache) => {
7548
7565
  return comp.value ? (openBlock(), createBlock$1(resolveDynamicComponent(comp.value), normalizeProps(mergeProps({ key: 0 }, bind.value)), null, 16)) : createCommentVNode("", true);
@@ -8128,15 +8145,15 @@ class PartManager {
8128
8145
  const defaultPartPropertyEditors = () => {
8129
8146
  return {
8130
8147
  "readonly-text": () => defineAsyncComponent(() => import("./PbPropertyEditorReadonlyText-Dgp_AVOD.js")),
8131
- "text": () => defineAsyncComponent(() => import("./PbPropertyEditorText-BcsUyRxP.js")),
8148
+ "text": () => defineAsyncComponent(() => import("./PbPropertyEditorText-OLBLie3k.js")),
8132
8149
  "number": () => defineAsyncComponent(() => import("./PbPropertyEditorNumber-TTgo0zbQ.js")),
8133
8150
  "boolean": () => defineAsyncComponent(() => import("./PbPropertyEditorBoolean-C7-iSAtn.js")),
8134
- "multiline-text": () => defineAsyncComponent(() => import("./PbPropertyEditorMultilineText-yHnhkc9I.js")),
8151
+ "multiline-text": () => defineAsyncComponent(() => import("./PbPropertyEditorMultilineText-BaMj-tr_.js")),
8135
8152
  "select": () => defineAsyncComponent(() => import("./PbPropertyEditorSelect-CWedbXJI.js")),
8136
- "color": () => defineAsyncComponent(() => import("./PbPropertyEditorColor-D7_bQLN4.js")),
8137
- "image": () => defineAsyncComponent(() => import("./PbPropertyEditorImage-CeAWWLQE.js")),
8138
- "html": () => defineAsyncComponent(() => import("./PbPropertyEditorHtml-BSfmWiwq.js")),
8139
- "youtube": () => defineAsyncComponent(() => import("./PbPropertyEditorYoutube-Bn0DdIOD.js"))
8153
+ "color": () => defineAsyncComponent(() => import("./PbPropertyEditorColor-BPku9nyl.js")),
8154
+ "image": () => defineAsyncComponent(() => import("./PbPropertyEditorImage-DnUH6vkj.js")),
8155
+ "html": () => defineAsyncComponent(() => import("./PbPropertyEditorHtml-eYbeszpS.js")),
8156
+ "youtube": () => defineAsyncComponent(() => import("./PbPropertyEditorYoutube-DRCsiJt3.js"))
8140
8157
  };
8141
8158
  };
8142
8159
  const getPropertyValueOfParts = (parts, propertyName) => {
@@ -8187,6 +8204,7 @@ const setSelectHandler = (el, binding) => {
8187
8204
  el.onmousedown = async (event) => {
8188
8205
  if (event.button === 0) {
8189
8206
  setTimeout(() => {
8207
+ if (pageBuilder.context.isSelected(part)) return;
8190
8208
  if (event.shiftKey) {
8191
8209
  pageBuilder.context.addSelection([part]);
8192
8210
  } else {
@@ -8205,9 +8223,8 @@ const setContextMenuHandler = (el, binding) => {
8205
8223
  const eventAny = event;
8206
8224
  if (eventAny._partContextMenuHandled) return;
8207
8225
  else eventAny._partContextMenuHandled = true;
8208
- if (!pageBuilder.context.isSelected(part)) {
8209
- pageBuilder.context.setSelection([part]);
8210
- }
8226
+ if (pageBuilder.context.isSelected(part)) return;
8227
+ pageBuilder.context.setSelection([part]);
8211
8228
  };
8212
8229
  };
8213
8230
  const createPositionMark = () => {
@@ -8874,7 +8891,8 @@ const _sfc_main$n = /* @__PURE__ */ defineComponent({
8874
8891
  __name: "PbBlock",
8875
8892
  props: {
8876
8893
  part: {},
8877
- isMobilePage: { type: Boolean }
8894
+ isMobilePage: { type: Boolean },
8895
+ placeholder: { type: Boolean }
8878
8896
  },
8879
8897
  setup(__props) {
8880
8898
  const props = __props;
@@ -9098,7 +9116,8 @@ const _sfc_main$l = /* @__PURE__ */ defineComponent({
9098
9116
  __name: "PbSection",
9099
9117
  props: {
9100
9118
  part: {},
9101
- isMobilePage: { type: Boolean }
9119
+ isMobilePage: { type: Boolean },
9120
+ placeholder: { type: Boolean }
9102
9121
  },
9103
9122
  setup(__props) {
9104
9123
  const props = __props;
@@ -12468,7 +12487,7 @@ __publicField(_OpenAddWidgetModalCommand, "COMMAND_ID", "OpenAddWidgetModal");
12468
12487
  let OpenAddWidgetModalCommand = _OpenAddWidgetModalCommand;
12469
12488
  const openWidgetAddModal = (modal, args, callback) => {
12470
12489
  modal.openModal({
12471
- component: defineAsyncComponent(() => import("./PbWidgetAddModal-BzG-lkZp.js")),
12490
+ component: defineAsyncComponent(() => import("./PbWidgetAddModal-CvBeNnPx.js")),
12472
12491
  style: {
12473
12492
  width: "80%",
12474
12493
  height: "80%",
@@ -12502,12 +12521,38 @@ const openWidgetAddModal = (modal, args, callback) => {
12502
12521
  });
12503
12522
  };
12504
12523
  const findInsertTargetAndIndex = (pageBuilder, partType) => {
12505
- var _a;
12524
+ var _a, _b, _c;
12506
12525
  const selected = pageBuilder.context.getSelectedParts()[0];
12507
- pageBuilder.context.getSelectedPage();
12508
- const target = pageBuilder.partManager.findNearestAvailableParentPart(selected, partType);
12509
- const index = selected === target || !(target == null ? void 0 : target.children) ? ((_a = target == null ? void 0 : target.children) == null ? void 0 : _a.length) || 0 : target.children.indexOf(selected) + 1;
12510
- return { target, index };
12526
+ const page = pageBuilder.context.getSelectedPage();
12527
+ if (!page) return {};
12528
+ if (partType === SECTION_TYPE) {
12529
+ const section = pageBuilder.partManager.findNearestSection(selected);
12530
+ return {
12531
+ target: page,
12532
+ index: section ? page.children.indexOf(section) + 1 : (_a = page.children) == null ? void 0 : _a.length
12533
+ };
12534
+ } else if (partType === BLOCK_TYPE) {
12535
+ let section = pageBuilder.partManager.findNearestSection(selected);
12536
+ let block = pageBuilder.partManager.findNearestBlock(selected);
12537
+ if (!section) {
12538
+ section = page.children[page.children.length - 1];
12539
+ }
12540
+ return {
12541
+ target: section,
12542
+ index: block ? section.children.indexOf(block) + 1 : (_b = section.children) == null ? void 0 : _b.length
12543
+ };
12544
+ } else {
12545
+ let block = pageBuilder.partManager.findNearestBlock(selected);
12546
+ let widget = selected.parent.isWidget() ? selected.parent : selected;
12547
+ if (!block) {
12548
+ const section = page.children[page.children.length - 1];
12549
+ block = section.children[section.children.length - 1];
12550
+ }
12551
+ return {
12552
+ target: block,
12553
+ index: widget ? block.children.indexOf(widget) + 1 : (_c = block.children) == null ? void 0 : _c.length
12554
+ };
12555
+ }
12511
12556
  };
12512
12557
  const createPartWithDefinition = (def, properties) => {
12513
12558
  const part = createPart(def.partType, def.partName, def.initialProperties);
@@ -12574,9 +12619,14 @@ const _AddSectionCommand = class _AddSectionCommand {
12574
12619
  if (args && args.page) {
12575
12620
  addSectionToPage(pageBuilder, args.page);
12576
12621
  } else {
12577
- const def = pageBuilder.partManager.getSectionDefinition();
12578
- if (!def) return;
12579
- addPart(pageBuilder, def);
12622
+ const selected = pageBuilder.context.getSelectedParts()[0];
12623
+ if (selected && selected.isPage()) {
12624
+ addSectionToPage(pageBuilder, selected);
12625
+ } else {
12626
+ const def = pageBuilder.partManager.getSectionDefinition();
12627
+ if (!def) return;
12628
+ addPart(pageBuilder, def);
12629
+ }
12580
12630
  }
12581
12631
  }
12582
12632
  };
@@ -12968,11 +13018,20 @@ const _DeletePartCommand = class _DeletePartCommand {
12968
13018
  __publicField(this, "caption", _DeletePartCommand.CAPTION);
12969
13019
  }
12970
13020
  execute(pageBuilder) {
12971
- const partIds = pageBuilder.context.getSelectedParts().map((part) => part.partId);
12972
- const param = {
12973
- delete: partIds
12974
- };
12975
- pageBuilder.model.updateModel(param);
13021
+ const selected = pageBuilder.context.getSelectedParts();
13022
+ if (selected.length === 0) return;
13023
+ let partIds;
13024
+ if (selected[0].isPage()) {
13025
+ const page = selected[0];
13026
+ const partsToDelete = page.children || [];
13027
+ if (partsToDelete.length === 0) return;
13028
+ partIds = partsToDelete.map((part) => part.partId);
13029
+ } else {
13030
+ partIds = selected.filter((part) => {
13031
+ return !selected.some((v) => part.isChildOf(v));
13032
+ }).map((part) => part.partId);
13033
+ }
13034
+ pageBuilder.model.updateModel({ delete: partIds });
12976
13035
  }
12977
13036
  };
12978
13037
  __publicField(_DeletePartCommand, "COMMAND_ID", "DeletePart");
@@ -12994,7 +13053,11 @@ const _CopyPartCommand = class _CopyPartCommand {
12994
13053
  __publicField(this, "commandId", _CopyPartCommand.COMMAND_ID);
12995
13054
  }
12996
13055
  async execute(pageBuilder) {
12997
- const partIds = pageBuilder.context.getSelectedParts().map((part) => part.partId);
13056
+ const selected = pageBuilder.context.getSelectedParts();
13057
+ if (selected.length === 0) return;
13058
+ const partIds = selected.filter((part) => {
13059
+ return !selected.some((v) => part.isChildOf(v));
13060
+ }).map((part) => part.partId);
12998
13061
  if (partIds.length > 0) {
12999
13062
  const json = pageBuilder.model.serializeParts(partIds);
13000
13063
  await navigator.clipboard.writeText(json);
@@ -13019,13 +13082,14 @@ const _PastePartCommand = class _PastePartCommand {
13019
13082
  __publicField(this, "commandId", _PastePartCommand.COMMAND_ID);
13020
13083
  }
13021
13084
  async execute(pageBuilder) {
13085
+ var _a;
13022
13086
  const json = await navigator.clipboard.readText();
13023
13087
  const object = JSON.parse(json);
13024
13088
  if (object.partType === ROOT_TYPE) {
13025
13089
  const rootPart = partFromJsonObject(object, true);
13026
13090
  if (!rootPart) throw new Error("Invalid data format");
13027
13091
  let partIdsToDelete = void 0;
13028
- if (pageBuilder.model.rootPart.children && pageBuilder.model.rootPart.children.length) {
13092
+ if ((_a = pageBuilder.model.rootPart.children) == null ? void 0 : _a.length) {
13029
13093
  partIdsToDelete = pageBuilder.model.rootPart.children.map((v) => v.partId);
13030
13094
  }
13031
13095
  const param = {
@@ -13039,13 +13103,88 @@ const _PastePartCommand = class _PastePartCommand {
13039
13103
  ]
13040
13104
  };
13041
13105
  pageBuilder.model.updateModel(param);
13106
+ } else if (Array.isArray(object) && object[0] && object[0].partType === PAGE_TYPE) {
13107
+ const newPages = pageBuilder.model.parseParts(json);
13108
+ if (!newPages) throw new Error("Invalid data format");
13109
+ const newPage = newPages[0];
13110
+ const selectedPage = pageBuilder.context.getSelectedPage();
13111
+ if (!selectedPage) return;
13112
+ const pages = pageBuilder.model.rootPart.children;
13113
+ if (!pages) return;
13114
+ let index = 0;
13115
+ if (pages.length == 1) {
13116
+ newPage.properties = {
13117
+ ...newPage.properties || {},
13118
+ name: "Page"
13119
+ };
13120
+ } else if (selectedPage === pages[0]) {
13121
+ newPage.properties = {
13122
+ ...newPage.properties || {},
13123
+ name: "Page (Mobile)"
13124
+ };
13125
+ } else if (selectedPage === pages[1]) {
13126
+ newPage.properties = {
13127
+ ...newPage.properties || {},
13128
+ name: "Page (PC)"
13129
+ };
13130
+ index = 1;
13131
+ }
13132
+ const param = {
13133
+ delete: [selectedPage.partId],
13134
+ insert: [
13135
+ {
13136
+ partId: pageBuilder.model.getRootPartId(),
13137
+ index,
13138
+ parts: [newPage]
13139
+ }
13140
+ ]
13141
+ };
13142
+ pageBuilder.model.updateModel(param);
13042
13143
  } else {
13043
- const { target, index = 0 } = findInsertTargetAndIndex(pageBuilder);
13044
- if (target) {
13045
- const parts = pageBuilder.model.parseParts(json);
13046
- if (parts) {
13047
- insertParts(pageBuilder, target.partId, index, parts, false);
13144
+ const parts = pageBuilder.model.parseParts(json);
13145
+ if (!parts) return;
13146
+ let pasteType = "";
13147
+ parts.forEach((part) => {
13148
+ if (part.partType === SECTION_TYPE) pasteType = SECTION_TYPE;
13149
+ else if (part.partType === BLOCK_TYPE && (!pasteType || pasteType === WIDGET_TYPE)) pasteType = BLOCK_TYPE;
13150
+ else if (part.partType === WIDGET_TYPE && !pasteType) pasteType = WIDGET_TYPE;
13151
+ });
13152
+ if (!pasteType) return;
13153
+ const partsToInsert = parts.map((part) => {
13154
+ if (pasteType === SECTION_TYPE) {
13155
+ if (part.partType === SECTION_TYPE) {
13156
+ return part;
13157
+ } else if (part.partType === BLOCK_TYPE) {
13158
+ const section = createSection(pageBuilder);
13159
+ if (!section) return;
13160
+ section.children = [part];
13161
+ return section;
13162
+ } else {
13163
+ const block = createBlock(pageBuilder);
13164
+ if (!block) return;
13165
+ block.children = [part];
13166
+ const section = createSection(pageBuilder);
13167
+ if (!section) return;
13168
+ section.children = [block];
13169
+ return section;
13170
+ }
13171
+ } else if (pasteType === BLOCK_TYPE) {
13172
+ if (part.partType === BLOCK_TYPE) {
13173
+ return part;
13174
+ } else {
13175
+ const block = createBlock(pageBuilder);
13176
+ if (!block) return;
13177
+ block.children = [part];
13178
+ return block;
13179
+ }
13180
+ } else {
13181
+ return part;
13048
13182
  }
13183
+ }).filter(notNull);
13184
+ const targetType = pasteType === SECTION_TYPE ? SECTION_TYPE : pasteType === BLOCK_TYPE ? BLOCK_TYPE : WIDGET_TYPE;
13185
+ const { target, index } = findInsertTargetAndIndex(pageBuilder, targetType);
13186
+ if (target && index !== void 0 && partsToInsert) {
13187
+ insertParts(pageBuilder, target.partId, index, partsToInsert, false);
13049
13188
  }
13050
13189
  }
13051
13190
  }
@@ -13421,6 +13560,7 @@ class PageBuilderContextImpl {
13421
13560
  }
13422
13561
  }
13423
13562
  addSelection(parts) {
13563
+ if (parts && !parts.length) return;
13424
13564
  parts.forEach((part) => this.selection.push(part));
13425
13565
  }
13426
13566
  removeSelection(parts) {
@@ -14297,7 +14437,6 @@ const _sfc_main$3 = /* @__PURE__ */ defineComponent({
14297
14437
  const style = computed(() => {
14298
14438
  var _a, _b;
14299
14439
  return {
14300
- // width: `${props.width || 420}px`,
14301
14440
  minHeight: ((_b = (_a = props.part) == null ? void 0 : _a.children) == null ? void 0 : _b.length) ? void 0 : "200px"
14302
14441
  };
14303
14442
  });
@@ -14318,7 +14457,7 @@ const _sfc_main$3 = /* @__PURE__ */ defineComponent({
14318
14457
  const contextMenu = useContextMenu();
14319
14458
  const handleClick = (event) => {
14320
14459
  if (event.button === 0) {
14321
- pageBuilder.context.clearSelection();
14460
+ pageBuilder.context.setSelection([props.part]);
14322
14461
  }
14323
14462
  };
14324
14463
  const showContextMenu = (event) => {
@@ -14365,14 +14504,13 @@ const _sfc_main$3 = /* @__PURE__ */ defineComponent({
14365
14504
  }, _cache[0] || (_cache[0] = [
14366
14505
  createElementVNode("i", { class: "material-icons-outlined" }, "add_circle_outline", -1)
14367
14506
  ]))
14368
- ], 46, _hoisted_1$3),
14369
- _cache[1] || (_cache[1] = createElementVNode("div", { style: { "height": "100px" } }, null, -1))
14507
+ ], 46, _hoisted_1$3)
14370
14508
  ], 64);
14371
14509
  };
14372
14510
  }
14373
14511
  });
14374
- const canvasStyle = '.pb-page-wrapper {\n margin: 0 auto;\n padding: 0;\n}\n\n.pb-page {\n display: flex;\n flex-direction: column;\n margin: 0 auto;\n width: 100%;\n background-position: 50% 50%;\n background-repeat: no-repeat;\n background-size: cover;\n}\n\n.pb-page .pb-page-content.selected::before {\n content: "";\n position: absolute;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n border: 2px solid #4998f8;\n z-index: 999;\n pointer-events: none;\n}\n\n.pb-page * {\n box-sizing: border-box;\n}\n\n.pb-add-widget-button {\n width: 100%;\n height: 100%;\n min-height: 200px;\n position: relative;\n}\n\n.pb-add-widget-button button {\n position: absolute;\n top: 50%;\n left: 50%;\n transform: translate(-50%, -50%);\n padding: 8px;\n background: none;\n border: none;\n cursor: pointer;\n}\n\n.pb-add-widget-button button:hover {\n background-color: #eeeeee;\n}\n\n.pb-add-widget-button .icon {\n font-size: 1rem;\n vertical-align: middle;\n}\n\n.pb-add-widget-button .text {\n font-size: 1rem;\n vertical-align: middle;\n margin-left: 0.4rem;\n}\n\n.pb-section {\n display: flex;\n position: relative;\n width: 100%;\n background-position: 50% 50%;\n background-repeat: no-repeat;\n background-size: cover;\n outline: 1px dashed #ccc;\n background-color: #fff;\n}\n\n.pb-section:hover:not(:has(.pb-block:hover)) {\n background-color: #f0f0f0;\n}\n\n.pb-section.selected::before {\n content: "";\n position: absolute;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n border: 2px solid #4998f8;\n z-index: 999;\n pointer-events: none;\n}\n\n.pb-section.pb-section-static {\n width: 100%;\n display: flex;\n justify-content: center;\n align-items: center;\n pointer-events: none;\n}\n\n.pb-section.pb-section-static:after {\n content: "";\n position: absolute;\n left: 0;\n right: 0;\n top: 0;\n bottom: 0;\n background-color: rgba(0, 0, 0, 0.2);\n}\n\n.pb-section-static .pb-widget {\n outline: none;\n}\n\n.pb-block {\n display: flex;\n min-width: 1px;\n position: relative;\n background-position: 50% 50%;\n background-repeat: no-repeat;\n background-size: cover;\n width: 100%;\n outline: 1px dashed #ccc;\n}\n\n.pb-block:hover:not(:has(.pb-widget:hover)) {\n background-color: #f0f0f0;\n}\n\n.pb-block.selected::before {\n content: "";\n position: absolute;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n border: 2px solid #4998f8;\n z-index: 999;\n pointer-events: none;\n}\n\n.pb-widget {\n position: relative;\n outline: 1px dashed #ccc;\n background-position: 50% 50%;\n background-repeat: no-repeat;\n background-size: cover;\n pointer-events: auto !important;\n}\n\n.pb-widget * {\n pointer-events: none;\n}\n\n.pb-widget.selected::before {\n content: "";\n position: absolute;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n border: 2px solid #4998f8;\n z-index: 999;\n pointer-events: none;\n}\n\n.pb-widget .children {\n position: absolute;\n width: 100%;\n height: 100%;\n}\n\n.pb-widget .pan-handle {\n position: absolute;\n left: -6px;\n top: -6px;\n width: 12px;\n height: 12px;\n background-color: #27ae60;\n cursor: move;\n pointer-events: auto !important;\n}\n\n.pb-widget .resize-handle {\n position: absolute;\n right: -6px;\n bottom: -6px;\n width: 12px;\n height: 12px;\n background-color: #27ae60;\n cursor: nwse-resize;\n pointer-events: auto !important;\n}\n\n.pb-widget {\n position: relative;\n background-position: 50% 50%;\n background-repeat: no-repeat;\n background-size: cover;\n width: 100%;\n}\n\n.pb-widget .children {\n position: absolute;\n width: 100%;\n height: 100%;\n}\n\n.pb-text-widget {\n width: 100%;\n height: fit-content;\n}\n\n.pb-text-widget .text {\n color: #333;\n}\n\n.pb-text-widget .placeholder {\n padding: 4px 0;\n font-size: 18px;\n text-align: center;\n color: #999;\n}\n\n.pb-image-widget {\n width: 100%;\n}\n\n.pb-image-widget .image {\n width: 100%;\n}\n\n.pb-image-widget .placeholder {\n height: 100px;\n background-color: #eee;\n text-align: center;\n}\n\n.pb-image-widget .placeholder span {\n font-size: 40px;\n color: #999;\n line-height: 100px;\n vertical-align: middle;\n}\n\n.pb-html-widget {\n width: 100%;\n height: fit-content;\n}\n\n.pb-html-widget .placeholder {\n padding: 4px 0;\n font-size: 18px;\n text-align: center;\n color: #999;\n}\n\n.pb-iframe-widget {\n width: 100%;\n height: fit-content;\n}\n\n.pb-iframe-widget .placeholder {\n padding: 4px 0;\n font-size: 18px;\n text-align: center;\n color: #999;\n}\n\n.pb-youtube-widget {\n width: 100%;\n}\n\n.pb-youtube-widget .youtube {\n width: 100%;\n height: 100%;\n}\n\n.pb-youtube-widget .placeholder {\n height: 100px;\n background-color: #eee;\n text-align: center;\n}\n\n.pb-youtube-widget .placeholder span {\n font-size: 40px;\n color: #999;\n line-height: 100px;\n vertical-align: middle;\n}\n\n.pb-container-widget {\n width: 100%;\n}\n\n.pb-container-widget .placeholder {\n height: 100px;\n background-color: #eee;\n text-align: center;\n}\n\n.pb-container-widget .placeholder span {\n font-size: 40px;\n color: #999;\n line-height: 100px;\n vertical-align: middle;\n}\n\n.pb-product-list-widget {\n width: 100%;\n display: flex;\n flex-direction: row;\n flex-wrap: wrap;\n justify-content: flex-start;\n align-items: center;\n}\n\n.pb-product-list-widget .product-wrapper {\n width: 25%;\n}\n\n.pb-product-list-widget .product-wrapper .product {\n width: 95%;\n margin: 0 auto;\n padding-top: 8px;\n padding-bottom: 8px;\n}\n\n.pb-product-list-widget .product-wrapper img {\n width: 100%;\n}\n\n.pb-product-list-widget .product-wrapper .name {\n margin-top: 8px;\n font-size: 14px;\n}\n\n.pb-product-list-widget .product-wrapper .price {\n margin-top: 8px;\n font-size: 14px;\n font-weight: bold;\n}\n\n.pb-product-list-widget .product-wrapper .empty {\n height: 200px;\n background-color: #eee;\n text-align: center;\n}\n\n.pb-product-list-widget .product-wrapper .empty span {\n font-size: 40px;\n color: #999;\n line-height: 200px;\n vertical-align: middle;\n}\n\n@media (max-width: 768px) {\n .pb-product-list-widget .product-wrapper {\n width: 50%;\n }\n}\n\n.mobile .pb-product-list-widget .product-wrapper {\n width: 50%;\n}\n\n.pb-login-widget {\n height: 200px;\n text-align: center;\n}\n\n.pb-login-widget h3 {\n padding: 0;\n margin: 0;\n font-size: 32px;\n font-weight: bold;\n color: #ccc;\n line-height: 200px;\n vertical-align: middle;\n}\n\n.font-icon {\n font-family: Material Symbols Outlined, monospace;\n font-size: 1rem;\n max-width: 1em;\n}\n\nhtml, body {\n font-family: Noto Sans, Noto Sans KR, Noto Sans JP, Arial, sans-serif;\n font-size: 12px;\n}\n\nbody {\n margin: 0;\n padding: 0;\n background-color: #aaa;\n overflow: hidden;\n}\n\n.pb-position-mark {\n background-color: #ff3333;\n opacity: 0.5;\n border-radius: 2px;\n}\n\n.pb-add-section-handle {\n position: relative;\n text-align: center;\n cursor: pointer;\n z-index: 5;\n height: 0;\n}\n\n.pb-add-section-handle.top::before, .pb-add-section-handle.bottom::before, .pb-add-section-handle.middle::before {\n content: "";\n position: absolute;\n left: 0;\n right: 0;\n top: 0;\n opacity: 0;\n pointer-events: none;\n}\n\n.pb-add-section-handle.bottom {\n left: 50%;\n bottom: -32px;\n}\n\n.pb-add-section-handle:hover.top::before, .pb-add-section-handle:hover.bottom::before, .pb-add-section-handle:hover.middle::before,\n.pb-add-section-handle:hover > i {\n opacity: 1;\n}\n\n.pb-add-section-handle > i {\n vertical-align: middle;\n position: absolute;\n top: 50%;\n left: 0;\n font-size: 2rem;\n transform: translate(-50%, -50%);\n opacity: 0.2;\n}';
14375
- const _hoisted_1$2 = ["height", "width"];
14512
+ const canvasStyle = '.pb-page-wrapper {\n margin: 0 auto;\n padding: 0;\n}\n\n.pb-page {\n display: flex;\n flex-direction: column;\n margin: 0 auto;\n padding-bottom: 100px;\n width: 100%;\n background-position: 50% 50%;\n background-repeat: no-repeat;\n background-size: cover;\n}\n\n.pb-page .pb-page-content.selected::before {\n content: "";\n position: absolute;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n border: 2px solid #4998f8;\n z-index: 999;\n pointer-events: none;\n}\n\n.pb-page * {\n box-sizing: border-box;\n}\n\n.pb-add-widget-button {\n width: 100%;\n height: 100%;\n min-height: 200px;\n position: relative;\n}\n\n.pb-add-widget-button button {\n position: absolute;\n top: 50%;\n left: 50%;\n transform: translate(-50%, -50%);\n padding: 8px;\n background: none;\n border: none;\n cursor: pointer;\n}\n\n.pb-add-widget-button button:hover {\n background-color: #eeeeee;\n}\n\n.pb-add-widget-button .icon {\n font-size: 1rem;\n vertical-align: middle;\n}\n\n.pb-add-widget-button .text {\n font-size: 1rem;\n vertical-align: middle;\n margin-left: 0.4rem;\n}\n\n.pb-section {\n display: flex;\n position: relative;\n width: 100%;\n background-position: 50% 50%;\n background-repeat: no-repeat;\n background-size: cover;\n outline: 1px dashed #ccc;\n background-color: #fff;\n}\n\n.pb-section:hover:not(:has(.pb-block:hover)) {\n background-color: #f0f0f0;\n}\n\n.pb-section.selected::before {\n content: "";\n position: absolute;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n border: 2px solid #4998f8;\n z-index: 999;\n pointer-events: none;\n}\n\n.pb-section.pb-section-static {\n width: 100%;\n display: flex;\n justify-content: center;\n align-items: center;\n pointer-events: none;\n}\n\n.pb-section.pb-section-static:after {\n content: "";\n position: absolute;\n left: 0;\n right: 0;\n top: 0;\n bottom: 0;\n background-color: rgba(0, 0, 0, 0.2);\n}\n\n.pb-section-static .pb-widget {\n outline: none;\n}\n\n.pb-block {\n display: flex;\n min-width: 1px;\n position: relative;\n background-position: 50% 50%;\n background-repeat: no-repeat;\n background-size: cover;\n width: 100%;\n outline: 1px dashed #ccc;\n}\n\n.pb-block:hover:not(:has(.pb-widget:hover)) {\n background-color: #f0f0f0;\n}\n\n.pb-block.selected::before {\n content: "";\n position: absolute;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n border: 2px solid #4998f8;\n z-index: 999;\n pointer-events: none;\n}\n\n.pb-widget {\n position: relative;\n outline: 1px dashed #ccc;\n background-position: 50% 50%;\n background-repeat: no-repeat;\n background-size: cover;\n pointer-events: auto !important;\n}\n\n.pb-widget * {\n pointer-events: none;\n}\n\n.pb-widget.selected::before {\n content: "";\n position: absolute;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n border: 2px solid #4998f8;\n z-index: 999;\n pointer-events: none;\n}\n\n.pb-widget .children {\n position: absolute;\n width: 100%;\n height: 100%;\n}\n\n.pb-widget .pan-handle {\n position: absolute;\n left: -6px;\n top: -6px;\n width: 12px;\n height: 12px;\n background-color: #27ae60;\n cursor: move;\n pointer-events: auto !important;\n}\n\n.pb-widget .resize-handle {\n position: absolute;\n right: -6px;\n bottom: -6px;\n width: 12px;\n height: 12px;\n background-color: #27ae60;\n cursor: nwse-resize;\n pointer-events: auto !important;\n}\n\n.pb-widget {\n position: relative;\n background-position: 50% 50%;\n background-repeat: no-repeat;\n background-size: cover;\n width: 100%;\n}\n\n.pb-widget .children {\n position: absolute;\n width: 100%;\n height: 100%;\n}\n\n.pb-text-widget {\n width: 100%;\n height: fit-content;\n}\n\n.pb-text-widget .text {\n color: #333;\n}\n\n.pb-text-widget .placeholder {\n padding: 4px 0;\n font-size: 18px;\n text-align: center;\n color: #999;\n}\n\n.pb-image-widget {\n width: 100%;\n}\n\n.pb-image-widget .image {\n width: 100%;\n}\n\n.pb-image-widget .placeholder {\n height: 100px;\n background-color: #eee;\n text-align: center;\n}\n\n.pb-image-widget .placeholder span {\n font-size: 40px;\n color: #999;\n line-height: 100px;\n vertical-align: middle;\n}\n\n.pb-html-widget {\n width: 100%;\n height: fit-content;\n}\n\n.pb-html-widget .placeholder {\n padding: 4px 0;\n font-size: 18px;\n text-align: center;\n color: #999;\n}\n\n.pb-iframe-widget {\n width: 100%;\n height: fit-content;\n}\n\n.pb-iframe-widget .placeholder {\n padding: 4px 0;\n font-size: 18px;\n text-align: center;\n color: #999;\n}\n\n.pb-youtube-widget {\n width: 100%;\n}\n\n.pb-youtube-widget .youtube {\n width: 100%;\n height: 100%;\n}\n\n.pb-youtube-widget .placeholder {\n height: 100px;\n background-color: #eee;\n text-align: center;\n}\n\n.pb-youtube-widget .placeholder span {\n font-size: 40px;\n color: #999;\n line-height: 100px;\n vertical-align: middle;\n}\n\n.pb-container-widget {\n width: 100%;\n}\n\n.pb-container-widget .placeholder {\n height: 100px;\n background-color: #eee;\n text-align: center;\n}\n\n.pb-container-widget .placeholder span {\n font-size: 40px;\n color: #999;\n line-height: 100px;\n vertical-align: middle;\n}\n\n.pb-product-list-widget {\n width: 100%;\n display: flex;\n flex-direction: row;\n flex-wrap: wrap;\n justify-content: flex-start;\n align-items: center;\n}\n\n.pb-product-list-widget .product-wrapper {\n width: 25%;\n}\n\n.pb-product-list-widget .product-wrapper .product {\n width: 95%;\n margin: 0 auto;\n padding-top: 8px;\n padding-bottom: 8px;\n}\n\n.pb-product-list-widget .product-wrapper img {\n width: 100%;\n}\n\n.pb-product-list-widget .product-wrapper .name {\n margin-top: 8px;\n font-size: 14px;\n}\n\n.pb-product-list-widget .product-wrapper .price {\n margin-top: 8px;\n font-size: 14px;\n font-weight: bold;\n}\n\n.pb-product-list-widget .product-wrapper .empty {\n height: 200px;\n background-color: #eee;\n text-align: center;\n}\n\n.pb-product-list-widget .product-wrapper .empty span {\n font-size: 40px;\n color: #999;\n line-height: 200px;\n vertical-align: middle;\n}\n\n@media (max-width: 768px) {\n .pb-product-list-widget .product-wrapper {\n width: 50%;\n }\n}\n\n.mobile .pb-product-list-widget .product-wrapper {\n width: 50%;\n}\n\n.pb-login-widget {\n height: 200px;\n text-align: center;\n}\n\n.pb-login-widget h3 {\n padding: 0;\n margin: 0;\n font-size: 32px;\n font-weight: bold;\n color: #ccc;\n line-height: 200px;\n vertical-align: middle;\n}\n\n.font-icon {\n font-family: Material Symbols Outlined, monospace;\n font-size: 1rem;\n max-width: 1em;\n}\n\nhtml, body {\n font-family: Noto Sans, Noto Sans KR, Noto Sans JP, Arial, sans-serif;\n font-size: 12px;\n}\n\nbody {\n margin: 0;\n padding: 0;\n background-color: #aaa;\n overflow: hidden;\n}\n\n.pb-position-mark {\n background-color: #ff3333;\n opacity: 0.5;\n border-radius: 2px;\n}\n\n.pb-add-section-handle {\n position: relative;\n text-align: center;\n cursor: pointer;\n z-index: 5;\n height: 0;\n}\n\n.pb-add-section-handle.top::before, .pb-add-section-handle.bottom::before, .pb-add-section-handle.middle::before {\n content: "";\n position: absolute;\n left: 0;\n right: 0;\n top: 0;\n opacity: 0;\n pointer-events: none;\n}\n\n.pb-add-section-handle.bottom {\n left: 50%;\n bottom: -32px;\n}\n\n.pb-add-section-handle:hover.top::before, .pb-add-section-handle:hover.bottom::before, .pb-add-section-handle:hover.middle::before,\n.pb-add-section-handle:hover > i {\n opacity: 1;\n}\n\n.pb-add-section-handle > i {\n vertical-align: middle;\n position: absolute;\n top: 50%;\n left: 0;\n font-size: 2rem;\n transform: translate(-50%, -50%);\n opacity: 0.2;\n}';
14513
+ const _hoisted_1$2 = ["width"];
14376
14514
  const _sfc_main$2 = /* @__PURE__ */ defineComponent({
14377
14515
  __name: "PbPageFrame",
14378
14516
  props: {
@@ -14433,35 +14571,43 @@ const _sfc_main$2 = /* @__PURE__ */ defineComponent({
14433
14571
  }
14434
14572
  );
14435
14573
  const width = ref(props.width);
14436
- const height = ref(200);
14574
+ ref(200);
14437
14575
  const isMobilePage = computed(() => width.value <= 768);
14438
14576
  const style = computed(() => ({
14439
14577
  // width: `${width.value}px`,
14440
14578
  // height: `${height.value}px`,
14441
14579
  }));
14442
14580
  let resizeObserver;
14581
+ let mutationObserver;
14443
14582
  const updateIframeHeight = () => {
14444
- setTimeout(() => {
14583
+ requestAnimationFrame(() => {
14445
14584
  if (!iframeRef.value || !iframeRef.value.contentDocument) return;
14446
14585
  const iframeBody = iframeRef.value.contentDocument.body;
14447
14586
  if (iframeBody) {
14448
- height.value = iframeBody.scrollHeight;
14587
+ void iframeBody.offsetHeight;
14588
+ const newHeight = iframeBody.scrollHeight;
14589
+ if (iframeRef.value.style.height !== `${newHeight}px`) {
14590
+ iframeRef.value.style.height = `${newHeight}px`;
14591
+ }
14449
14592
  }
14450
- }, 100);
14593
+ });
14451
14594
  };
14452
14595
  onMounted(() => {
14453
14596
  if (!iframeRef.value || !iframeRef.value.contentDocument) return;
14454
14597
  const iframeBody = iframeRef.value.contentDocument.body;
14455
- resizeObserver = new ResizeObserver(() => {
14456
- updateIframeHeight();
14457
- });
14598
+ resizeObserver = new ResizeObserver(updateIframeHeight);
14458
14599
  resizeObserver.observe(iframeBody, {});
14600
+ mutationObserver = new MutationObserver(updateIframeHeight);
14601
+ mutationObserver.observe(iframeBody, { childList: true, subtree: true });
14459
14602
  iframeRef.value.onload = updateIframeHeight;
14460
14603
  });
14461
14604
  onBeforeUnmount(() => {
14462
14605
  if (resizeObserver) {
14463
14606
  resizeObserver.disconnect();
14464
14607
  }
14608
+ if (mutationObserver) {
14609
+ mutationObserver.disconnect();
14610
+ }
14465
14611
  });
14466
14612
  return (_ctx, _cache) => {
14467
14613
  var _a, _b, _c, _d;
@@ -14483,7 +14629,6 @@ const _sfc_main$2 = /* @__PURE__ */ defineComponent({
14483
14629
  createElementVNode("iframe", {
14484
14630
  ref_key: "iframeRef",
14485
14631
  ref: iframeRef,
14486
- height: `${height.value}px`,
14487
14632
  style: normalizeStyle(style.value),
14488
14633
  width: `${width.value}px`,
14489
14634
  class: "page-frame mt-12"
@@ -44,6 +44,8 @@ export declare class PageBuilderContextImpl implements PageBuilderContext {
44
44
  isBlock: () => boolean;
45
45
  isWidget: () => boolean;
46
46
  isNestedWidget: () => boolean;
47
+ isParentOf: (part: IPart | undefined) => boolean;
48
+ isChildOf: (part: IPart | undefined) => boolean;
47
49
  getName: () => string | undefined;
48
50
  getProperty: (propertyName: string) => import('@g1cloud/page-builder-viewer').MultiLangText | undefined;
49
51
  getClassNames: () => string;
@@ -64,6 +66,8 @@ export declare class PageBuilderContextImpl implements PageBuilderContext {
64
66
  isBlock: () => boolean;
65
67
  isWidget: () => boolean;
66
68
  isNestedWidget: () => boolean;
69
+ isParentOf: (part: IPart | undefined) => boolean;
70
+ isChildOf: (part: IPart | undefined) => boolean;
67
71
  getName: () => string | undefined;
68
72
  getProperty: (propertyName: string) => import('@g1cloud/page-builder-viewer').MultiLangText | undefined;
69
73
  getClassNames: () => string;
@@ -84,6 +88,8 @@ export declare class PageBuilderContextImpl implements PageBuilderContext {
84
88
  isBlock: () => boolean;
85
89
  isWidget: () => boolean;
86
90
  isNestedWidget: () => boolean;
91
+ isParentOf: (part: IPart | undefined) => boolean;
92
+ isChildOf: (part: IPart | undefined) => boolean;
87
93
  getName: () => string | undefined;
88
94
  getProperty: (propertyName: string) => import('@g1cloud/page-builder-viewer').MultiLangText | undefined;
89
95
  getClassNames: () => string;
@@ -1,4 +1,4 @@
1
- import { B, b, M, c, d, e, _, a, f, g, h, i, j, k, l, m, n, R, o, S, p, W, q, r, t, v, x, y, z, A, C } from "./index-BaB2TtF-.js";
1
+ import { B, b, M, c, d, e, _, a, f, g, h, i, j, k, l, m, n, R, o, S, p, W, q, r, t, v, x, y, z, A, C } from "./index-BPKptjBm.js";
2
2
  export {
3
3
  B as BLOCK_TYPE,
4
4
  b as Block,
@@ -6671,6 +6671,24 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
6671
6671
  isNestedWidget() {
6672
6672
  return false;
6673
6673
  }
6674
+ isParentOf(part) {
6675
+ if (!part) return false;
6676
+ let parent = part.parent;
6677
+ while (parent) {
6678
+ if (parent === this || parent.partId === this.partId) return true;
6679
+ parent = parent.parent;
6680
+ }
6681
+ return false;
6682
+ }
6683
+ isChildOf(part) {
6684
+ if (!part) return false;
6685
+ let parent = this.parent;
6686
+ while (parent) {
6687
+ if (parent === part || parent.partId === part.partId) return true;
6688
+ parent = parent.parent;
6689
+ }
6690
+ return false;
6691
+ }
6674
6692
  getName() {
6675
6693
  var _a;
6676
6694
  return (_a = this.properties) == null ? void 0 : _a.name;
@@ -7542,8 +7560,7 @@ ${_html.style}
7542
7560
  const pageBuilder = usePageBuilder();
7543
7561
  const comp = vue.computed(() => pageBuilder.getCustomWidgetComponent(props.part));
7544
7562
  const bind = vue.computed(() => ({
7545
- ...props.part.properties || {},
7546
- placeholder: props.placeholder
7563
+ ...props.part.properties || {}
7547
7564
  }));
7548
7565
  return (_ctx, _cache) => {
7549
7566
  return comp.value ? (vue.openBlock(), vue.createBlock(vue.resolveDynamicComponent(comp.value), vue.normalizeProps(vue.mergeProps({ key: 0 }, bind.value)), null, 16)) : vue.createCommentVNode("", true);
@@ -8188,6 +8205,7 @@ ${_html.style}
8188
8205
  el.onmousedown = async (event) => {
8189
8206
  if (event.button === 0) {
8190
8207
  setTimeout(() => {
8208
+ if (pageBuilder.context.isSelected(part)) return;
8191
8209
  if (event.shiftKey) {
8192
8210
  pageBuilder.context.addSelection([part]);
8193
8211
  } else {
@@ -8206,9 +8224,8 @@ ${_html.style}
8206
8224
  const eventAny = event;
8207
8225
  if (eventAny._partContextMenuHandled) return;
8208
8226
  else eventAny._partContextMenuHandled = true;
8209
- if (!pageBuilder.context.isSelected(part)) {
8210
- pageBuilder.context.setSelection([part]);
8211
- }
8227
+ if (pageBuilder.context.isSelected(part)) return;
8228
+ pageBuilder.context.setSelection([part]);
8212
8229
  };
8213
8230
  };
8214
8231
  const createPositionMark = () => {
@@ -8875,7 +8892,8 @@ ${_html.style}
8875
8892
  __name: "PbBlock",
8876
8893
  props: {
8877
8894
  part: {},
8878
- isMobilePage: { type: Boolean }
8895
+ isMobilePage: { type: Boolean },
8896
+ placeholder: { type: Boolean }
8879
8897
  },
8880
8898
  setup(__props) {
8881
8899
  const props = __props;
@@ -9099,7 +9117,8 @@ ${_html.style}
9099
9117
  __name: "PbSection",
9100
9118
  props: {
9101
9119
  part: {},
9102
- isMobilePage: { type: Boolean }
9120
+ isMobilePage: { type: Boolean },
9121
+ placeholder: { type: Boolean }
9103
9122
  },
9104
9123
  setup(__props) {
9105
9124
  const props = __props;
@@ -12503,12 +12522,38 @@ ${_html.style}
12503
12522
  });
12504
12523
  };
12505
12524
  const findInsertTargetAndIndex = (pageBuilder, partType) => {
12506
- var _a;
12525
+ var _a, _b, _c;
12507
12526
  const selected = pageBuilder.context.getSelectedParts()[0];
12508
- pageBuilder.context.getSelectedPage();
12509
- const target = pageBuilder.partManager.findNearestAvailableParentPart(selected, partType);
12510
- const index = selected === target || !(target == null ? void 0 : target.children) ? ((_a = target == null ? void 0 : target.children) == null ? void 0 : _a.length) || 0 : target.children.indexOf(selected) + 1;
12511
- return { target, index };
12527
+ const page = pageBuilder.context.getSelectedPage();
12528
+ if (!page) return {};
12529
+ if (partType === SECTION_TYPE) {
12530
+ const section = pageBuilder.partManager.findNearestSection(selected);
12531
+ return {
12532
+ target: page,
12533
+ index: section ? page.children.indexOf(section) + 1 : (_a = page.children) == null ? void 0 : _a.length
12534
+ };
12535
+ } else if (partType === BLOCK_TYPE) {
12536
+ let section = pageBuilder.partManager.findNearestSection(selected);
12537
+ let block = pageBuilder.partManager.findNearestBlock(selected);
12538
+ if (!section) {
12539
+ section = page.children[page.children.length - 1];
12540
+ }
12541
+ return {
12542
+ target: section,
12543
+ index: block ? section.children.indexOf(block) + 1 : (_b = section.children) == null ? void 0 : _b.length
12544
+ };
12545
+ } else {
12546
+ let block = pageBuilder.partManager.findNearestBlock(selected);
12547
+ let widget = selected.parent.isWidget() ? selected.parent : selected;
12548
+ if (!block) {
12549
+ const section = page.children[page.children.length - 1];
12550
+ block = section.children[section.children.length - 1];
12551
+ }
12552
+ return {
12553
+ target: block,
12554
+ index: widget ? block.children.indexOf(widget) + 1 : (_c = block.children) == null ? void 0 : _c.length
12555
+ };
12556
+ }
12512
12557
  };
12513
12558
  const createPartWithDefinition = (def, properties) => {
12514
12559
  const part = createPart(def.partType, def.partName, def.initialProperties);
@@ -12575,9 +12620,14 @@ ${_html.style}
12575
12620
  if (args && args.page) {
12576
12621
  addSectionToPage(pageBuilder, args.page);
12577
12622
  } else {
12578
- const def = pageBuilder.partManager.getSectionDefinition();
12579
- if (!def) return;
12580
- addPart(pageBuilder, def);
12623
+ const selected = pageBuilder.context.getSelectedParts()[0];
12624
+ if (selected && selected.isPage()) {
12625
+ addSectionToPage(pageBuilder, selected);
12626
+ } else {
12627
+ const def = pageBuilder.partManager.getSectionDefinition();
12628
+ if (!def) return;
12629
+ addPart(pageBuilder, def);
12630
+ }
12581
12631
  }
12582
12632
  }
12583
12633
  };
@@ -12969,11 +13019,20 @@ ${_html.style}
12969
13019
  __publicField(this, "caption", _DeletePartCommand.CAPTION);
12970
13020
  }
12971
13021
  execute(pageBuilder) {
12972
- const partIds = pageBuilder.context.getSelectedParts().map((part) => part.partId);
12973
- const param = {
12974
- delete: partIds
12975
- };
12976
- pageBuilder.model.updateModel(param);
13022
+ const selected = pageBuilder.context.getSelectedParts();
13023
+ if (selected.length === 0) return;
13024
+ let partIds;
13025
+ if (selected[0].isPage()) {
13026
+ const page = selected[0];
13027
+ const partsToDelete = page.children || [];
13028
+ if (partsToDelete.length === 0) return;
13029
+ partIds = partsToDelete.map((part) => part.partId);
13030
+ } else {
13031
+ partIds = selected.filter((part) => {
13032
+ return !selected.some((v) => part.isChildOf(v));
13033
+ }).map((part) => part.partId);
13034
+ }
13035
+ pageBuilder.model.updateModel({ delete: partIds });
12977
13036
  }
12978
13037
  };
12979
13038
  __publicField(_DeletePartCommand, "COMMAND_ID", "DeletePart");
@@ -12995,7 +13054,11 @@ ${_html.style}
12995
13054
  __publicField(this, "commandId", _CopyPartCommand.COMMAND_ID);
12996
13055
  }
12997
13056
  async execute(pageBuilder) {
12998
- const partIds = pageBuilder.context.getSelectedParts().map((part) => part.partId);
13057
+ const selected = pageBuilder.context.getSelectedParts();
13058
+ if (selected.length === 0) return;
13059
+ const partIds = selected.filter((part) => {
13060
+ return !selected.some((v) => part.isChildOf(v));
13061
+ }).map((part) => part.partId);
12999
13062
  if (partIds.length > 0) {
13000
13063
  const json = pageBuilder.model.serializeParts(partIds);
13001
13064
  await navigator.clipboard.writeText(json);
@@ -13020,13 +13083,14 @@ ${_html.style}
13020
13083
  __publicField(this, "commandId", _PastePartCommand.COMMAND_ID);
13021
13084
  }
13022
13085
  async execute(pageBuilder) {
13086
+ var _a;
13023
13087
  const json = await navigator.clipboard.readText();
13024
13088
  const object = JSON.parse(json);
13025
13089
  if (object.partType === ROOT_TYPE) {
13026
13090
  const rootPart = partFromJsonObject(object, true);
13027
13091
  if (!rootPart) throw new Error("Invalid data format");
13028
13092
  let partIdsToDelete = void 0;
13029
- if (pageBuilder.model.rootPart.children && pageBuilder.model.rootPart.children.length) {
13093
+ if ((_a = pageBuilder.model.rootPart.children) == null ? void 0 : _a.length) {
13030
13094
  partIdsToDelete = pageBuilder.model.rootPart.children.map((v) => v.partId);
13031
13095
  }
13032
13096
  const param = {
@@ -13040,13 +13104,88 @@ ${_html.style}
13040
13104
  ]
13041
13105
  };
13042
13106
  pageBuilder.model.updateModel(param);
13107
+ } else if (Array.isArray(object) && object[0] && object[0].partType === PAGE_TYPE) {
13108
+ const newPages = pageBuilder.model.parseParts(json);
13109
+ if (!newPages) throw new Error("Invalid data format");
13110
+ const newPage = newPages[0];
13111
+ const selectedPage = pageBuilder.context.getSelectedPage();
13112
+ if (!selectedPage) return;
13113
+ const pages = pageBuilder.model.rootPart.children;
13114
+ if (!pages) return;
13115
+ let index = 0;
13116
+ if (pages.length == 1) {
13117
+ newPage.properties = {
13118
+ ...newPage.properties || {},
13119
+ name: "Page"
13120
+ };
13121
+ } else if (selectedPage === pages[0]) {
13122
+ newPage.properties = {
13123
+ ...newPage.properties || {},
13124
+ name: "Page (Mobile)"
13125
+ };
13126
+ } else if (selectedPage === pages[1]) {
13127
+ newPage.properties = {
13128
+ ...newPage.properties || {},
13129
+ name: "Page (PC)"
13130
+ };
13131
+ index = 1;
13132
+ }
13133
+ const param = {
13134
+ delete: [selectedPage.partId],
13135
+ insert: [
13136
+ {
13137
+ partId: pageBuilder.model.getRootPartId(),
13138
+ index,
13139
+ parts: [newPage]
13140
+ }
13141
+ ]
13142
+ };
13143
+ pageBuilder.model.updateModel(param);
13043
13144
  } else {
13044
- const { target, index = 0 } = findInsertTargetAndIndex(pageBuilder);
13045
- if (target) {
13046
- const parts = pageBuilder.model.parseParts(json);
13047
- if (parts) {
13048
- insertParts(pageBuilder, target.partId, index, parts, false);
13145
+ const parts = pageBuilder.model.parseParts(json);
13146
+ if (!parts) return;
13147
+ let pasteType = "";
13148
+ parts.forEach((part) => {
13149
+ if (part.partType === SECTION_TYPE) pasteType = SECTION_TYPE;
13150
+ else if (part.partType === BLOCK_TYPE && (!pasteType || pasteType === WIDGET_TYPE)) pasteType = BLOCK_TYPE;
13151
+ else if (part.partType === WIDGET_TYPE && !pasteType) pasteType = WIDGET_TYPE;
13152
+ });
13153
+ if (!pasteType) return;
13154
+ const partsToInsert = parts.map((part) => {
13155
+ if (pasteType === SECTION_TYPE) {
13156
+ if (part.partType === SECTION_TYPE) {
13157
+ return part;
13158
+ } else if (part.partType === BLOCK_TYPE) {
13159
+ const section = createSection(pageBuilder);
13160
+ if (!section) return;
13161
+ section.children = [part];
13162
+ return section;
13163
+ } else {
13164
+ const block = createBlock(pageBuilder);
13165
+ if (!block) return;
13166
+ block.children = [part];
13167
+ const section = createSection(pageBuilder);
13168
+ if (!section) return;
13169
+ section.children = [block];
13170
+ return section;
13171
+ }
13172
+ } else if (pasteType === BLOCK_TYPE) {
13173
+ if (part.partType === BLOCK_TYPE) {
13174
+ return part;
13175
+ } else {
13176
+ const block = createBlock(pageBuilder);
13177
+ if (!block) return;
13178
+ block.children = [part];
13179
+ return block;
13180
+ }
13181
+ } else {
13182
+ return part;
13049
13183
  }
13184
+ }).filter(bluesea.notNull);
13185
+ const targetType = pasteType === SECTION_TYPE ? SECTION_TYPE : pasteType === BLOCK_TYPE ? BLOCK_TYPE : WIDGET_TYPE;
13186
+ const { target, index } = findInsertTargetAndIndex(pageBuilder, targetType);
13187
+ if (target && index !== void 0 && partsToInsert) {
13188
+ insertParts(pageBuilder, target.partId, index, partsToInsert, false);
13050
13189
  }
13051
13190
  }
13052
13191
  }
@@ -13422,6 +13561,7 @@ ${_html.style}
13422
13561
  }
13423
13562
  }
13424
13563
  addSelection(parts) {
13564
+ if (parts && !parts.length) return;
13425
13565
  parts.forEach((part) => this.selection.push(part));
13426
13566
  }
13427
13567
  removeSelection(parts) {
@@ -14298,7 +14438,6 @@ ${_html.style}
14298
14438
  const style = vue.computed(() => {
14299
14439
  var _a, _b;
14300
14440
  return {
14301
- // width: `${props.width || 420}px`,
14302
14441
  minHeight: ((_b = (_a = props.part) == null ? void 0 : _a.children) == null ? void 0 : _b.length) ? void 0 : "200px"
14303
14442
  };
14304
14443
  });
@@ -14319,7 +14458,7 @@ ${_html.style}
14319
14458
  const contextMenu = bluesea.useContextMenu();
14320
14459
  const handleClick = (event) => {
14321
14460
  if (event.button === 0) {
14322
- pageBuilder.context.clearSelection();
14461
+ pageBuilder.context.setSelection([props.part]);
14323
14462
  }
14324
14463
  };
14325
14464
  const showContextMenu = (event) => {
@@ -14366,14 +14505,13 @@ ${_html.style}
14366
14505
  }, _cache[0] || (_cache[0] = [
14367
14506
  vue.createElementVNode("i", { class: "material-icons-outlined" }, "add_circle_outline", -1)
14368
14507
  ]))
14369
- ], 46, _hoisted_1$h),
14370
- _cache[1] || (_cache[1] = vue.createElementVNode("div", { style: { "height": "100px" } }, null, -1))
14508
+ ], 46, _hoisted_1$h)
14371
14509
  ], 64);
14372
14510
  };
14373
14511
  }
14374
14512
  });
14375
- const canvasStyle = '.pb-page-wrapper {\n margin: 0 auto;\n padding: 0;\n}\n\n.pb-page {\n display: flex;\n flex-direction: column;\n margin: 0 auto;\n width: 100%;\n background-position: 50% 50%;\n background-repeat: no-repeat;\n background-size: cover;\n}\n\n.pb-page .pb-page-content.selected::before {\n content: "";\n position: absolute;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n border: 2px solid #4998f8;\n z-index: 999;\n pointer-events: none;\n}\n\n.pb-page * {\n box-sizing: border-box;\n}\n\n.pb-add-widget-button {\n width: 100%;\n height: 100%;\n min-height: 200px;\n position: relative;\n}\n\n.pb-add-widget-button button {\n position: absolute;\n top: 50%;\n left: 50%;\n transform: translate(-50%, -50%);\n padding: 8px;\n background: none;\n border: none;\n cursor: pointer;\n}\n\n.pb-add-widget-button button:hover {\n background-color: #eeeeee;\n}\n\n.pb-add-widget-button .icon {\n font-size: 1rem;\n vertical-align: middle;\n}\n\n.pb-add-widget-button .text {\n font-size: 1rem;\n vertical-align: middle;\n margin-left: 0.4rem;\n}\n\n.pb-section {\n display: flex;\n position: relative;\n width: 100%;\n background-position: 50% 50%;\n background-repeat: no-repeat;\n background-size: cover;\n outline: 1px dashed #ccc;\n background-color: #fff;\n}\n\n.pb-section:hover:not(:has(.pb-block:hover)) {\n background-color: #f0f0f0;\n}\n\n.pb-section.selected::before {\n content: "";\n position: absolute;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n border: 2px solid #4998f8;\n z-index: 999;\n pointer-events: none;\n}\n\n.pb-section.pb-section-static {\n width: 100%;\n display: flex;\n justify-content: center;\n align-items: center;\n pointer-events: none;\n}\n\n.pb-section.pb-section-static:after {\n content: "";\n position: absolute;\n left: 0;\n right: 0;\n top: 0;\n bottom: 0;\n background-color: rgba(0, 0, 0, 0.2);\n}\n\n.pb-section-static .pb-widget {\n outline: none;\n}\n\n.pb-block {\n display: flex;\n min-width: 1px;\n position: relative;\n background-position: 50% 50%;\n background-repeat: no-repeat;\n background-size: cover;\n width: 100%;\n outline: 1px dashed #ccc;\n}\n\n.pb-block:hover:not(:has(.pb-widget:hover)) {\n background-color: #f0f0f0;\n}\n\n.pb-block.selected::before {\n content: "";\n position: absolute;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n border: 2px solid #4998f8;\n z-index: 999;\n pointer-events: none;\n}\n\n.pb-widget {\n position: relative;\n outline: 1px dashed #ccc;\n background-position: 50% 50%;\n background-repeat: no-repeat;\n background-size: cover;\n pointer-events: auto !important;\n}\n\n.pb-widget * {\n pointer-events: none;\n}\n\n.pb-widget.selected::before {\n content: "";\n position: absolute;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n border: 2px solid #4998f8;\n z-index: 999;\n pointer-events: none;\n}\n\n.pb-widget .children {\n position: absolute;\n width: 100%;\n height: 100%;\n}\n\n.pb-widget .pan-handle {\n position: absolute;\n left: -6px;\n top: -6px;\n width: 12px;\n height: 12px;\n background-color: #27ae60;\n cursor: move;\n pointer-events: auto !important;\n}\n\n.pb-widget .resize-handle {\n position: absolute;\n right: -6px;\n bottom: -6px;\n width: 12px;\n height: 12px;\n background-color: #27ae60;\n cursor: nwse-resize;\n pointer-events: auto !important;\n}\n\n.pb-widget {\n position: relative;\n background-position: 50% 50%;\n background-repeat: no-repeat;\n background-size: cover;\n width: 100%;\n}\n\n.pb-widget .children {\n position: absolute;\n width: 100%;\n height: 100%;\n}\n\n.pb-text-widget {\n width: 100%;\n height: fit-content;\n}\n\n.pb-text-widget .text {\n color: #333;\n}\n\n.pb-text-widget .placeholder {\n padding: 4px 0;\n font-size: 18px;\n text-align: center;\n color: #999;\n}\n\n.pb-image-widget {\n width: 100%;\n}\n\n.pb-image-widget .image {\n width: 100%;\n}\n\n.pb-image-widget .placeholder {\n height: 100px;\n background-color: #eee;\n text-align: center;\n}\n\n.pb-image-widget .placeholder span {\n font-size: 40px;\n color: #999;\n line-height: 100px;\n vertical-align: middle;\n}\n\n.pb-html-widget {\n width: 100%;\n height: fit-content;\n}\n\n.pb-html-widget .placeholder {\n padding: 4px 0;\n font-size: 18px;\n text-align: center;\n color: #999;\n}\n\n.pb-iframe-widget {\n width: 100%;\n height: fit-content;\n}\n\n.pb-iframe-widget .placeholder {\n padding: 4px 0;\n font-size: 18px;\n text-align: center;\n color: #999;\n}\n\n.pb-youtube-widget {\n width: 100%;\n}\n\n.pb-youtube-widget .youtube {\n width: 100%;\n height: 100%;\n}\n\n.pb-youtube-widget .placeholder {\n height: 100px;\n background-color: #eee;\n text-align: center;\n}\n\n.pb-youtube-widget .placeholder span {\n font-size: 40px;\n color: #999;\n line-height: 100px;\n vertical-align: middle;\n}\n\n.pb-container-widget {\n width: 100%;\n}\n\n.pb-container-widget .placeholder {\n height: 100px;\n background-color: #eee;\n text-align: center;\n}\n\n.pb-container-widget .placeholder span {\n font-size: 40px;\n color: #999;\n line-height: 100px;\n vertical-align: middle;\n}\n\n.pb-product-list-widget {\n width: 100%;\n display: flex;\n flex-direction: row;\n flex-wrap: wrap;\n justify-content: flex-start;\n align-items: center;\n}\n\n.pb-product-list-widget .product-wrapper {\n width: 25%;\n}\n\n.pb-product-list-widget .product-wrapper .product {\n width: 95%;\n margin: 0 auto;\n padding-top: 8px;\n padding-bottom: 8px;\n}\n\n.pb-product-list-widget .product-wrapper img {\n width: 100%;\n}\n\n.pb-product-list-widget .product-wrapper .name {\n margin-top: 8px;\n font-size: 14px;\n}\n\n.pb-product-list-widget .product-wrapper .price {\n margin-top: 8px;\n font-size: 14px;\n font-weight: bold;\n}\n\n.pb-product-list-widget .product-wrapper .empty {\n height: 200px;\n background-color: #eee;\n text-align: center;\n}\n\n.pb-product-list-widget .product-wrapper .empty span {\n font-size: 40px;\n color: #999;\n line-height: 200px;\n vertical-align: middle;\n}\n\n@media (max-width: 768px) {\n .pb-product-list-widget .product-wrapper {\n width: 50%;\n }\n}\n\n.mobile .pb-product-list-widget .product-wrapper {\n width: 50%;\n}\n\n.pb-login-widget {\n height: 200px;\n text-align: center;\n}\n\n.pb-login-widget h3 {\n padding: 0;\n margin: 0;\n font-size: 32px;\n font-weight: bold;\n color: #ccc;\n line-height: 200px;\n vertical-align: middle;\n}\n\n.font-icon {\n font-family: Material Symbols Outlined, monospace;\n font-size: 1rem;\n max-width: 1em;\n}\n\nhtml, body {\n font-family: Noto Sans, Noto Sans KR, Noto Sans JP, Arial, sans-serif;\n font-size: 12px;\n}\n\nbody {\n margin: 0;\n padding: 0;\n background-color: #aaa;\n overflow: hidden;\n}\n\n.pb-position-mark {\n background-color: #ff3333;\n opacity: 0.5;\n border-radius: 2px;\n}\n\n.pb-add-section-handle {\n position: relative;\n text-align: center;\n cursor: pointer;\n z-index: 5;\n height: 0;\n}\n\n.pb-add-section-handle.top::before, .pb-add-section-handle.bottom::before, .pb-add-section-handle.middle::before {\n content: "";\n position: absolute;\n left: 0;\n right: 0;\n top: 0;\n opacity: 0;\n pointer-events: none;\n}\n\n.pb-add-section-handle.bottom {\n left: 50%;\n bottom: -32px;\n}\n\n.pb-add-section-handle:hover.top::before, .pb-add-section-handle:hover.bottom::before, .pb-add-section-handle:hover.middle::before,\n.pb-add-section-handle:hover > i {\n opacity: 1;\n}\n\n.pb-add-section-handle > i {\n vertical-align: middle;\n position: absolute;\n top: 50%;\n left: 0;\n font-size: 2rem;\n transform: translate(-50%, -50%);\n opacity: 0.2;\n}';
14376
- const _hoisted_1$g = ["height", "width"];
14513
+ const canvasStyle = '.pb-page-wrapper {\n margin: 0 auto;\n padding: 0;\n}\n\n.pb-page {\n display: flex;\n flex-direction: column;\n margin: 0 auto;\n padding-bottom: 100px;\n width: 100%;\n background-position: 50% 50%;\n background-repeat: no-repeat;\n background-size: cover;\n}\n\n.pb-page .pb-page-content.selected::before {\n content: "";\n position: absolute;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n border: 2px solid #4998f8;\n z-index: 999;\n pointer-events: none;\n}\n\n.pb-page * {\n box-sizing: border-box;\n}\n\n.pb-add-widget-button {\n width: 100%;\n height: 100%;\n min-height: 200px;\n position: relative;\n}\n\n.pb-add-widget-button button {\n position: absolute;\n top: 50%;\n left: 50%;\n transform: translate(-50%, -50%);\n padding: 8px;\n background: none;\n border: none;\n cursor: pointer;\n}\n\n.pb-add-widget-button button:hover {\n background-color: #eeeeee;\n}\n\n.pb-add-widget-button .icon {\n font-size: 1rem;\n vertical-align: middle;\n}\n\n.pb-add-widget-button .text {\n font-size: 1rem;\n vertical-align: middle;\n margin-left: 0.4rem;\n}\n\n.pb-section {\n display: flex;\n position: relative;\n width: 100%;\n background-position: 50% 50%;\n background-repeat: no-repeat;\n background-size: cover;\n outline: 1px dashed #ccc;\n background-color: #fff;\n}\n\n.pb-section:hover:not(:has(.pb-block:hover)) {\n background-color: #f0f0f0;\n}\n\n.pb-section.selected::before {\n content: "";\n position: absolute;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n border: 2px solid #4998f8;\n z-index: 999;\n pointer-events: none;\n}\n\n.pb-section.pb-section-static {\n width: 100%;\n display: flex;\n justify-content: center;\n align-items: center;\n pointer-events: none;\n}\n\n.pb-section.pb-section-static:after {\n content: "";\n position: absolute;\n left: 0;\n right: 0;\n top: 0;\n bottom: 0;\n background-color: rgba(0, 0, 0, 0.2);\n}\n\n.pb-section-static .pb-widget {\n outline: none;\n}\n\n.pb-block {\n display: flex;\n min-width: 1px;\n position: relative;\n background-position: 50% 50%;\n background-repeat: no-repeat;\n background-size: cover;\n width: 100%;\n outline: 1px dashed #ccc;\n}\n\n.pb-block:hover:not(:has(.pb-widget:hover)) {\n background-color: #f0f0f0;\n}\n\n.pb-block.selected::before {\n content: "";\n position: absolute;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n border: 2px solid #4998f8;\n z-index: 999;\n pointer-events: none;\n}\n\n.pb-widget {\n position: relative;\n outline: 1px dashed #ccc;\n background-position: 50% 50%;\n background-repeat: no-repeat;\n background-size: cover;\n pointer-events: auto !important;\n}\n\n.pb-widget * {\n pointer-events: none;\n}\n\n.pb-widget.selected::before {\n content: "";\n position: absolute;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n border: 2px solid #4998f8;\n z-index: 999;\n pointer-events: none;\n}\n\n.pb-widget .children {\n position: absolute;\n width: 100%;\n height: 100%;\n}\n\n.pb-widget .pan-handle {\n position: absolute;\n left: -6px;\n top: -6px;\n width: 12px;\n height: 12px;\n background-color: #27ae60;\n cursor: move;\n pointer-events: auto !important;\n}\n\n.pb-widget .resize-handle {\n position: absolute;\n right: -6px;\n bottom: -6px;\n width: 12px;\n height: 12px;\n background-color: #27ae60;\n cursor: nwse-resize;\n pointer-events: auto !important;\n}\n\n.pb-widget {\n position: relative;\n background-position: 50% 50%;\n background-repeat: no-repeat;\n background-size: cover;\n width: 100%;\n}\n\n.pb-widget .children {\n position: absolute;\n width: 100%;\n height: 100%;\n}\n\n.pb-text-widget {\n width: 100%;\n height: fit-content;\n}\n\n.pb-text-widget .text {\n color: #333;\n}\n\n.pb-text-widget .placeholder {\n padding: 4px 0;\n font-size: 18px;\n text-align: center;\n color: #999;\n}\n\n.pb-image-widget {\n width: 100%;\n}\n\n.pb-image-widget .image {\n width: 100%;\n}\n\n.pb-image-widget .placeholder {\n height: 100px;\n background-color: #eee;\n text-align: center;\n}\n\n.pb-image-widget .placeholder span {\n font-size: 40px;\n color: #999;\n line-height: 100px;\n vertical-align: middle;\n}\n\n.pb-html-widget {\n width: 100%;\n height: fit-content;\n}\n\n.pb-html-widget .placeholder {\n padding: 4px 0;\n font-size: 18px;\n text-align: center;\n color: #999;\n}\n\n.pb-iframe-widget {\n width: 100%;\n height: fit-content;\n}\n\n.pb-iframe-widget .placeholder {\n padding: 4px 0;\n font-size: 18px;\n text-align: center;\n color: #999;\n}\n\n.pb-youtube-widget {\n width: 100%;\n}\n\n.pb-youtube-widget .youtube {\n width: 100%;\n height: 100%;\n}\n\n.pb-youtube-widget .placeholder {\n height: 100px;\n background-color: #eee;\n text-align: center;\n}\n\n.pb-youtube-widget .placeholder span {\n font-size: 40px;\n color: #999;\n line-height: 100px;\n vertical-align: middle;\n}\n\n.pb-container-widget {\n width: 100%;\n}\n\n.pb-container-widget .placeholder {\n height: 100px;\n background-color: #eee;\n text-align: center;\n}\n\n.pb-container-widget .placeholder span {\n font-size: 40px;\n color: #999;\n line-height: 100px;\n vertical-align: middle;\n}\n\n.pb-product-list-widget {\n width: 100%;\n display: flex;\n flex-direction: row;\n flex-wrap: wrap;\n justify-content: flex-start;\n align-items: center;\n}\n\n.pb-product-list-widget .product-wrapper {\n width: 25%;\n}\n\n.pb-product-list-widget .product-wrapper .product {\n width: 95%;\n margin: 0 auto;\n padding-top: 8px;\n padding-bottom: 8px;\n}\n\n.pb-product-list-widget .product-wrapper img {\n width: 100%;\n}\n\n.pb-product-list-widget .product-wrapper .name {\n margin-top: 8px;\n font-size: 14px;\n}\n\n.pb-product-list-widget .product-wrapper .price {\n margin-top: 8px;\n font-size: 14px;\n font-weight: bold;\n}\n\n.pb-product-list-widget .product-wrapper .empty {\n height: 200px;\n background-color: #eee;\n text-align: center;\n}\n\n.pb-product-list-widget .product-wrapper .empty span {\n font-size: 40px;\n color: #999;\n line-height: 200px;\n vertical-align: middle;\n}\n\n@media (max-width: 768px) {\n .pb-product-list-widget .product-wrapper {\n width: 50%;\n }\n}\n\n.mobile .pb-product-list-widget .product-wrapper {\n width: 50%;\n}\n\n.pb-login-widget {\n height: 200px;\n text-align: center;\n}\n\n.pb-login-widget h3 {\n padding: 0;\n margin: 0;\n font-size: 32px;\n font-weight: bold;\n color: #ccc;\n line-height: 200px;\n vertical-align: middle;\n}\n\n.font-icon {\n font-family: Material Symbols Outlined, monospace;\n font-size: 1rem;\n max-width: 1em;\n}\n\nhtml, body {\n font-family: Noto Sans, Noto Sans KR, Noto Sans JP, Arial, sans-serif;\n font-size: 12px;\n}\n\nbody {\n margin: 0;\n padding: 0;\n background-color: #aaa;\n overflow: hidden;\n}\n\n.pb-position-mark {\n background-color: #ff3333;\n opacity: 0.5;\n border-radius: 2px;\n}\n\n.pb-add-section-handle {\n position: relative;\n text-align: center;\n cursor: pointer;\n z-index: 5;\n height: 0;\n}\n\n.pb-add-section-handle.top::before, .pb-add-section-handle.bottom::before, .pb-add-section-handle.middle::before {\n content: "";\n position: absolute;\n left: 0;\n right: 0;\n top: 0;\n opacity: 0;\n pointer-events: none;\n}\n\n.pb-add-section-handle.bottom {\n left: 50%;\n bottom: -32px;\n}\n\n.pb-add-section-handle:hover.top::before, .pb-add-section-handle:hover.bottom::before, .pb-add-section-handle:hover.middle::before,\n.pb-add-section-handle:hover > i {\n opacity: 1;\n}\n\n.pb-add-section-handle > i {\n vertical-align: middle;\n position: absolute;\n top: 50%;\n left: 0;\n font-size: 2rem;\n transform: translate(-50%, -50%);\n opacity: 0.2;\n}';
14514
+ const _hoisted_1$g = ["width"];
14377
14515
  const _sfc_main$g = /* @__PURE__ */ vue.defineComponent({
14378
14516
  __name: "PbPageFrame",
14379
14517
  props: {
@@ -14434,35 +14572,43 @@ ${_html.style}
14434
14572
  }
14435
14573
  );
14436
14574
  const width = vue.ref(props.width);
14437
- const height = vue.ref(200);
14575
+ vue.ref(200);
14438
14576
  const isMobilePage = vue.computed(() => width.value <= 768);
14439
14577
  const style = vue.computed(() => ({
14440
14578
  // width: `${width.value}px`,
14441
14579
  // height: `${height.value}px`,
14442
14580
  }));
14443
14581
  let resizeObserver;
14582
+ let mutationObserver;
14444
14583
  const updateIframeHeight = () => {
14445
- setTimeout(() => {
14584
+ requestAnimationFrame(() => {
14446
14585
  if (!iframeRef.value || !iframeRef.value.contentDocument) return;
14447
14586
  const iframeBody = iframeRef.value.contentDocument.body;
14448
14587
  if (iframeBody) {
14449
- height.value = iframeBody.scrollHeight;
14588
+ void iframeBody.offsetHeight;
14589
+ const newHeight = iframeBody.scrollHeight;
14590
+ if (iframeRef.value.style.height !== `${newHeight}px`) {
14591
+ iframeRef.value.style.height = `${newHeight}px`;
14592
+ }
14450
14593
  }
14451
- }, 100);
14594
+ });
14452
14595
  };
14453
14596
  vue.onMounted(() => {
14454
14597
  if (!iframeRef.value || !iframeRef.value.contentDocument) return;
14455
14598
  const iframeBody = iframeRef.value.contentDocument.body;
14456
- resizeObserver = new ResizeObserver(() => {
14457
- updateIframeHeight();
14458
- });
14599
+ resizeObserver = new ResizeObserver(updateIframeHeight);
14459
14600
  resizeObserver.observe(iframeBody, {});
14601
+ mutationObserver = new MutationObserver(updateIframeHeight);
14602
+ mutationObserver.observe(iframeBody, { childList: true, subtree: true });
14460
14603
  iframeRef.value.onload = updateIframeHeight;
14461
14604
  });
14462
14605
  vue.onBeforeUnmount(() => {
14463
14606
  if (resizeObserver) {
14464
14607
  resizeObserver.disconnect();
14465
14608
  }
14609
+ if (mutationObserver) {
14610
+ mutationObserver.disconnect();
14611
+ }
14466
14612
  });
14467
14613
  return (_ctx, _cache) => {
14468
14614
  var _a, _b, _c, _d;
@@ -14484,7 +14630,6 @@ ${_html.style}
14484
14630
  vue.createElementVNode("iframe", {
14485
14631
  ref_key: "iframeRef",
14486
14632
  ref: iframeRef,
14487
- height: `${height.value}px`,
14488
14633
  style: vue.normalizeStyle(style.value),
14489
14634
  width: `${width.value}px`,
14490
14635
  class: "page-frame mt-12"
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@g1cloud/page-builder-editor",
3
3
  "private": false,
4
- "version": "1.0.0-alpha.34",
4
+ "version": "1.0.0-alpha.36",
5
5
  "engins": {
6
6
  "node": ">= 20.0.0"
7
7
  },
@@ -16,7 +16,7 @@
16
16
  "author": "zag@g1project.net",
17
17
  "license": "LicenseRef-LICENSE",
18
18
  "peerDependencies": {
19
- "@g1cloud/bluesea": "5.0.0-alpha.76",
19
+ "@g1cloud/bluesea": "5.0.0-alpha.78",
20
20
  "vue3-youtube": "^0.1.9"
21
21
  },
22
22
  "dependencies": {
@@ -30,7 +30,7 @@
30
30
  "vue-router": "^4.4.3",
31
31
  "vue3-click-away": "^1.2.4",
32
32
  "yjs": "^13.6.14",
33
- "@g1cloud/page-builder-viewer": "1.0.0-alpha.34"
33
+ "@g1cloud/page-builder-viewer": "1.0.0-alpha.36"
34
34
  },
35
35
  "devDependencies": {
36
36
  "@types/node": "^20.12.7",