@blokkli/editor 2.0.0-alpha.17 → 2.0.0-alpha.19

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.
Files changed (138) hide show
  1. package/dist/module.json +1 -1
  2. package/dist/module.mjs +380 -59
  3. package/dist/modules/drupal/graphql/base/fragment.paragraphsFieldItem.graphql +3 -1
  4. package/dist/modules/drupal/graphql/base/query.pbConfig.graphql +1 -10
  5. package/dist/modules/drupal/graphql/mutations/set_paragraph_schedule.graphql +15 -0
  6. package/dist/modules/drupal/index.mjs +33 -0
  7. package/dist/modules/drupal/runtime/adapter/index.js +10 -2
  8. package/dist/runtime/adapter/index.d.ts +21 -0
  9. package/dist/runtime/blokkliPlugins/ContextMenu/Menu/index.vue +3 -0
  10. package/dist/runtime/blokkliPlugins/ItemAction/index.vue +23 -13
  11. package/dist/runtime/blokkliPlugins/ItemAction/index.vue.d.ts +20 -44
  12. package/dist/runtime/blokkliPlugins/TourItem/index.vue +10 -5
  13. package/dist/runtime/components/BlokkliEditable.vue +13 -13
  14. package/dist/runtime/components/BlokkliField.vue.d.ts +3 -3
  15. package/dist/runtime/components/BlokkliItem.vue +1 -1
  16. package/dist/runtime/components/BlokkliItem.vue.d.ts +4 -2
  17. package/dist/runtime/components/BlokkliProvider.vue +12 -8
  18. package/dist/runtime/components/Edit/Actions/index.vue +27 -16
  19. package/dist/runtime/components/Edit/AnimationCanvas/index.vue +26 -10
  20. package/dist/runtime/components/Edit/ArtboardTooltip/index.vue +3 -0
  21. package/dist/runtime/components/Edit/Dialog/index.vue +6 -4
  22. package/dist/runtime/components/Edit/DraggableList.vue +15 -7
  23. package/dist/runtime/components/Edit/DraggableList.vue.d.ts +5 -5
  24. package/dist/runtime/components/Edit/EditProvider.vue +29 -16
  25. package/dist/runtime/components/Edit/EditProvider.vue.d.ts +1 -0
  26. package/dist/runtime/components/Edit/Features/AddList/index.vue +9 -11
  27. package/dist/runtime/components/Edit/Features/Analyze/Overlay/index.vue +9 -6
  28. package/dist/runtime/components/Edit/Features/Analyze/Renderer.vue +1 -1
  29. package/dist/runtime/components/Edit/Features/Analyze/Results/ResultsItemNodesTarget.vue +15 -11
  30. package/dist/runtime/components/Edit/Features/Anchors/Renderer.vue +19 -102
  31. package/dist/runtime/components/Edit/Features/Artboard/Renderer.vue +3 -0
  32. package/dist/runtime/components/Edit/Features/BlockAddList/index.vue +28 -52
  33. package/dist/runtime/components/Edit/Features/BlockScheduler/Dialog/ScheduleSection.vue +154 -0
  34. package/dist/runtime/components/Edit/Features/BlockScheduler/Dialog/ScheduleSection.vue.d.ts +27 -0
  35. package/dist/runtime/components/Edit/Features/BlockScheduler/Dialog/index.vue +222 -0
  36. package/dist/runtime/components/Edit/Features/BlockScheduler/Dialog/index.vue.d.ts +11 -0
  37. package/dist/runtime/components/Edit/Features/BlockScheduler/index.vue +96 -0
  38. package/dist/runtime/components/Edit/Features/BlockScheduler/index.vue.d.ts +2 -0
  39. package/dist/runtime/components/Edit/Features/Clipboard/index.vue +15 -16
  40. package/dist/runtime/components/Edit/Features/CommandPalette/Palette/Item/index.vue +51 -0
  41. package/dist/runtime/components/Edit/Features/CommandPalette/Palette/{Group → Item}/index.vue.d.ts +9 -13
  42. package/dist/runtime/components/Edit/Features/CommandPalette/Palette/index.vue +46 -66
  43. package/dist/runtime/components/Edit/Features/Comments/index.vue +1 -1
  44. package/dist/runtime/components/Edit/Features/Conversions/index.vue +4 -7
  45. package/dist/runtime/components/Edit/Features/Debug/Rects/index.vue +2 -2
  46. package/dist/runtime/components/Edit/Features/Debug/index.vue +4 -1
  47. package/dist/runtime/components/Edit/Features/Delete/index.vue +1 -1
  48. package/dist/runtime/components/Edit/Features/DraggingOverlay/DragItems/index.vue +13 -5
  49. package/dist/runtime/components/Edit/Features/DraggingOverlay/DropTargets/index.vue +14 -11
  50. package/dist/runtime/components/Edit/Features/DraggingOverlay/index.vue +30 -18
  51. package/dist/runtime/components/Edit/Features/Duplicate/index.vue +6 -8
  52. package/dist/runtime/components/Edit/Features/Edit/index.vue +15 -21
  53. package/dist/runtime/components/Edit/Features/EditForm/index.vue +7 -6
  54. package/dist/runtime/components/Edit/Features/EditableField/Overlay/Frame/index.vue +8 -3
  55. package/dist/runtime/components/Edit/Features/EditableField/Overlay/Frame/index.vue.d.ts +2 -2
  56. package/dist/runtime/components/Edit/Features/EditableField/Overlay/index.vue +29 -12
  57. package/dist/runtime/components/Edit/Features/EditableField/Overlay/index.vue.d.ts +2 -2
  58. package/dist/runtime/components/Edit/Features/EditableField/index.vue +40 -42
  59. package/dist/runtime/components/Edit/Features/Fragments/Dialog/index.vue +11 -9
  60. package/dist/runtime/components/Edit/Features/Fragments/index.vue +3 -3
  61. package/dist/runtime/components/Edit/Features/Hover/Overlay/index.vue +16 -25
  62. package/dist/runtime/components/Edit/Features/Library/EditReusable/index.vue +5 -7
  63. package/dist/runtime/components/Edit/Features/Library/ReusableDialog/index.vue +5 -5
  64. package/dist/runtime/components/Edit/Features/Library/index.vue +27 -23
  65. package/dist/runtime/components/Edit/Features/MediaLibrary/Library/index.vue +6 -3
  66. package/dist/runtime/components/Edit/Features/MediaLibrary/index.vue +15 -12
  67. package/dist/runtime/components/Edit/Features/MultiSelect/Overlay/index.vue +2 -2
  68. package/dist/runtime/components/Edit/Features/Options/Form/index.vue +7 -6
  69. package/dist/runtime/components/Edit/Features/Options/index.vue +6 -6
  70. package/dist/runtime/components/Edit/Features/Publish/Dialog/index.vue +68 -15
  71. package/dist/runtime/components/Edit/Features/Search/Overlay/Results/Page/index.vue +15 -15
  72. package/dist/runtime/components/Edit/Features/Search/index.vue +4 -1
  73. package/dist/runtime/components/Edit/Features/Selection/AddButtons/Overlay/index.vue.d.ts +3 -3
  74. package/dist/runtime/components/Edit/Features/Selection/AddButtons/Renderer/index.vue +34 -11
  75. package/dist/runtime/components/Edit/Features/Selection/AddButtons/index.vue +21 -20
  76. package/dist/runtime/components/Edit/Features/Selection/AddButtons/index.vue.d.ts +2 -2
  77. package/dist/runtime/components/Edit/Features/Selection/Overlay/index.vue.d.ts +3 -3
  78. package/dist/runtime/components/Edit/Features/Selection/OverlayFallback/index.vue +2 -2
  79. package/dist/runtime/components/Edit/Features/Selection/index.vue +61 -27
  80. package/dist/runtime/components/Edit/Features/Structure/List/Field/index.vue +2 -2
  81. package/dist/runtime/components/Edit/Features/Structure/List/Item/index.vue +13 -6
  82. package/dist/runtime/components/Edit/Features/Tour/Overlay/index.vue +3 -0
  83. package/dist/runtime/components/Edit/Features/Transform/index.vue +2 -27
  84. package/dist/runtime/components/Edit/Features/Translations/index.vue +7 -7
  85. package/dist/runtime/components/Edit/Features/Validations/SidebarItem/index.vue +5 -5
  86. package/dist/runtime/components/Edit/Features/index.vue +17 -7
  87. package/dist/runtime/components/Edit/Form/Toggle/index.vue +4 -3
  88. package/dist/runtime/components/Edit/Form/Toggle/index.vue.d.ts +12 -2
  89. package/dist/runtime/components/Edit/InfoBox/index.vue +6 -2
  90. package/dist/runtime/components/Edit/InfoBox/index.vue.d.ts +12 -2
  91. package/dist/runtime/components/Edit/{Features/Publish/Dialog/ScheduleDate.vue → ScheduleDate/index.vue} +6 -58
  92. package/dist/runtime/components/Edit/{Features/Publish/Dialog/ScheduleDate.vue.d.ts → ScheduleDate/index.vue.d.ts} +11 -1
  93. package/dist/runtime/components/Edit/ShortcutIndicator/index.vue +3 -0
  94. package/dist/runtime/components/Edit/Transition/Height.vue +95 -0
  95. package/dist/runtime/components/Edit/Transition/Height.vue.d.ts +36 -0
  96. package/dist/runtime/components/Edit/index.d.ts +3 -1
  97. package/dist/runtime/components/Edit/index.js +5 -1
  98. package/dist/runtime/css/output.css +1 -1
  99. package/dist/runtime/helpers/animationProvider.d.ts +2 -1
  100. package/dist/runtime/helpers/animationProvider.js +6 -2
  101. package/dist/runtime/helpers/composables/useStateBasedCache.d.ts +4 -0
  102. package/dist/runtime/helpers/composables/useStateBasedCache.js +13 -0
  103. package/dist/runtime/helpers/definitionProvider.d.ts +1 -1
  104. package/dist/runtime/helpers/dom/index.d.ts +1 -1
  105. package/dist/runtime/helpers/domProvider.d.ts +10 -16
  106. package/dist/runtime/helpers/domProvider.js +80 -135
  107. package/dist/runtime/helpers/index.d.ts +1 -8
  108. package/dist/runtime/helpers/index.js +1 -84
  109. package/dist/runtime/helpers/providers/blocks.d.ts +10 -0
  110. package/dist/runtime/helpers/providers/blocks.js +91 -0
  111. package/dist/runtime/helpers/providers/directive.d.ts +24 -0
  112. package/dist/runtime/helpers/{editableProvider.js → providers/directive.js} +90 -29
  113. package/dist/runtime/helpers/providers/element.d.ts +6 -0
  114. package/dist/runtime/helpers/providers/element.js +35 -0
  115. package/dist/runtime/helpers/providers/fields.d.ts +8 -0
  116. package/dist/runtime/helpers/providers/fields.js +47 -0
  117. package/dist/runtime/helpers/selectionProvider.d.ts +11 -11
  118. package/dist/runtime/helpers/selectionProvider.js +38 -45
  119. package/dist/runtime/helpers/stateProvider.d.ts +1 -0
  120. package/dist/runtime/helpers/stateProvider.js +21 -15
  121. package/dist/runtime/helpers/themeProvider.d.ts +2 -1
  122. package/dist/runtime/helpers/themeProvider.js +24 -14
  123. package/dist/runtime/helpers/typesProvider.js +10 -26
  124. package/dist/runtime/helpers/uiProvider.d.ts +3 -2
  125. package/dist/runtime/helpers/uiProvider.js +11 -15
  126. package/dist/runtime/icons/calendar.svg +1 -0
  127. package/dist/runtime/icons/clock.svg +1 -0
  128. package/dist/runtime/icons/comment_add.svg +1 -5
  129. package/dist/runtime/icons/delete.svg +1 -8
  130. package/dist/runtime/icons/duplicate.svg +1 -12
  131. package/dist/runtime/icons/edit.svg +1 -8
  132. package/dist/runtime/icons/reusable.svg +1 -5
  133. package/dist/runtime/plugins/{blokkliEditable.js → blokkliDirectives.js} +14 -20
  134. package/dist/runtime/types/index.d.ts +55 -36
  135. package/package.json +1 -1
  136. package/dist/runtime/components/Edit/Features/CommandPalette/Palette/Group/index.vue +0 -63
  137. package/dist/runtime/helpers/editableProvider.d.ts +0 -14
  138. /package/dist/runtime/plugins/{blokkliEditable.d.ts → blokkliDirectives.d.ts} +0 -0
@@ -3,6 +3,7 @@
3
3
  id="duplicate"
4
4
  :title="$t('duplicate', 'Duplicate')"
5
5
  :disabled="!canDuplicate"
6
+ edit-only
6
7
  meta
7
8
  key-code="D"
8
9
  multiple
@@ -31,22 +32,19 @@ function onClick(items) {
31
32
  );
32
33
  }
33
34
  const canDuplicate = computed(() => {
34
- if (state.editMode.value !== "editing") {
35
- return false;
36
- }
37
35
  const blocksByField = {};
38
36
  const fieldsByKey = {};
39
- const selectedCount = selection.blocks.value.length;
37
+ const selectedCount = selection.items.value.length;
40
38
  for (let i = 0; i < selectedCount; i++) {
41
- const block = selection.blocks.value[i];
42
- const field = state.getMutatedField(block.hostUuid, block.hostFieldName);
39
+ const block = selection.items.value[i];
40
+ const field = state.getMutatedField(block.host.uuid, block.host.fieldName);
43
41
  if (!field) {
44
42
  continue;
45
43
  }
46
44
  const fieldKey = getFieldKey(field.entityUuid, field.name);
47
45
  const fieldConfig = types.getFieldConfig(
48
46
  field.entityType,
49
- block.hostBundle,
47
+ block.host.bundle,
50
48
  field.name
51
49
  );
52
50
  if (!fieldConfig) {
@@ -77,7 +75,7 @@ const canDuplicate = computed(() => {
77
75
  if (field.cardinality !== -1 && count + blocks.length > field.cardinality) {
78
76
  return false;
79
77
  }
80
- const bundles = blocks.map((v) => v.itemBundle);
78
+ const bundles = blocks.map((v) => v.bundle);
81
79
  if (!field.allowedBundles.length || bundles.some((bundle) => !field.allowedBundles.includes(bundle))) {
82
80
  return false;
83
81
  }
@@ -1,7 +1,7 @@
1
1
  <template>
2
2
  <PluginItemAction
3
- v-if="isEditing"
4
3
  id="edit"
4
+ edit-only
5
5
  :title="$t('edit', 'Edit...')"
6
6
  :disabled="!canEdit"
7
7
  meta
@@ -24,27 +24,21 @@ defineBlokkliFeature({
24
24
  requiredAdapterMethods: ["formFrameBuilder"]
25
25
  });
26
26
  const { eventBus, selection, state, $t, adapter, definitions } = useBlokkli();
27
- const block = computed(() => {
28
- if (selection.blocks.value.length !== 1) {
29
- return null;
30
- }
31
- return selection.blocks.value[0];
32
- });
33
- const isEditing = computed(() => state.editMode.value === "editing");
34
27
  const canEdit = computed(() => {
35
- if (!block.value) {
28
+ const item = selection.item.value;
29
+ if (!item) {
36
30
  return false;
37
31
  }
38
32
  const definition = definitions.getBlockDefinition(
39
- block.value.itemBundle,
40
- block.value.hostFieldListType,
41
- block.value.parentBlockBundle
33
+ item.bundle,
34
+ item.fieldListType,
35
+ item.parentBlockBundle
42
36
  );
43
37
  if (definition?.editor?.disableEdit) {
44
38
  return false;
45
39
  }
46
- if (block.value.libraryItemUuid) {
47
- return !!adapter.getLibraryItemEditUrl && (state.editMode.value === "editing" || state.editMode.value === "translating") && !block.value.isNew;
40
+ if (item.library?.libraryItemUuid) {
41
+ return !!adapter.getLibraryItemEditUrl && (state.editMode.value === "editing" || state.editMode.value === "translating") && !item.isNew;
48
42
  }
49
43
  return state.editMode.value === "editing";
50
44
  });
@@ -56,22 +50,22 @@ function onClick(items) {
56
50
  return;
57
51
  }
58
52
  const item = items[0];
59
- if (item.libraryItemUuid && adapter.getLibraryItemEditUrl) {
60
- const url = adapter.getLibraryItemEditUrl(item.libraryItemUuid);
53
+ if (item.library?.libraryItemUuid && adapter.getLibraryItemEditUrl) {
54
+ const url = adapter.getLibraryItemEditUrl(item.library.libraryItemUuid);
61
55
  eventBus.emit("library:edit-item", {
62
56
  url,
63
- label: item.editTitle,
64
- uuid: item.libraryItemUuid
57
+ label: item.library.label,
58
+ uuid: item.library.libraryItemUuid
65
59
  });
66
60
  return;
67
61
  }
68
62
  eventBus.emit("item:edit", {
69
63
  uuid: item.uuid,
70
- bundle: item.itemBundle
64
+ bundle: item.bundle
71
65
  });
72
66
  }
73
- onBlokkliEvent("item:doubleClick", function(block2) {
74
- onClick([block2]);
67
+ onBlokkliEvent("item:doubleClick", function(block) {
68
+ onClick([block]);
75
69
  });
76
70
  </script>
77
71
 
@@ -24,6 +24,7 @@ import { ref, computed, useBlokkli, defineBlokkliFeature } from "#imports";
24
24
  import { FormOverlay, BlokkliTransition } from "#blokkli/components";
25
25
  import FormFrame from "./Frame/index.vue";
26
26
  import onBlokkliEvent from "#blokkli/helpers/composables/onBlokkliEvent";
27
+ import { itemEntityType } from "#blokkli-build/config";
27
28
  const { adapter } = defineBlokkliFeature({
28
29
  id: "edit-form",
29
30
  icon: "form",
@@ -31,7 +32,7 @@ const { adapter } = defineBlokkliFeature({
31
32
  description: "Listens to edit events and renders an iframe containing the edit form.",
32
33
  requiredAdapterMethods: ["formFrameBuilder"]
33
34
  });
34
- const { types, state, context, $t, dom, definitions } = useBlokkli();
35
+ const { types, state, context, $t, dom, definitions, blocks } = useBlokkli();
35
36
  const form = ref(null);
36
37
  const formUrl = computed(() => {
37
38
  if (form.value) {
@@ -99,13 +100,13 @@ onBlokkliEvent("item:edit", (e) => {
99
100
  if (!state.canEdit.value) {
100
101
  return;
101
102
  }
102
- const block = dom.findBlock(e.uuid);
103
+ const block = blocks.getBlock(e.uuid);
103
104
  if (!block) {
104
105
  return;
105
106
  }
106
107
  const definition = definitions.getBlockDefinition(
107
108
  e.bundle,
108
- block.hostFieldListType,
109
+ block.fieldListType,
109
110
  block.parentBlockBundle
110
111
  );
111
112
  if (definition?.editor?.disableEdit) {
@@ -156,12 +157,12 @@ onBlokkliEvent("add:block:new", (e) => {
156
157
  if (!state.canEdit.value) {
157
158
  return;
158
159
  }
159
- const field = dom.findField(e.host.uuid, e.host.fieldName);
160
- if (field) {
160
+ const field = dom.getRegisteredField(e.host.uuid, e.host.fieldName);
161
+ if (field?.entity.type === itemEntityType) {
161
162
  const definition = definitions.getBlockDefinition(
162
163
  e.bundle,
163
164
  field.fieldListType,
164
- field.hostEntityBundle
165
+ field.entity.bundle
165
166
  );
166
167
  if (definition?.editor?.disableEdit) {
167
168
  return;
@@ -18,7 +18,8 @@ import {
18
18
  onBeforeUnmount,
19
19
  useTemplateRef
20
20
  } from "#imports";
21
- const { adapter, ui } = useBlokkli();
21
+ import { itemEntityType } from "#blokkli-build/config";
22
+ const { adapter, ui, element } = useBlokkli();
22
23
  const PROPAGATE_WHEEL = false;
23
24
  const rootElement = ui.rootElement();
24
25
  const props = defineProps({
@@ -40,7 +41,11 @@ function onIframeLoad() {
40
41
  let ckEditor = null;
41
42
  iframe.value.contentDocument.addEventListener("wheel", (e) => {
42
43
  if (!ckEditor) {
43
- const el = iframeDoc.querySelector(".ck-editor__editable");
44
+ const el = element.query(
45
+ iframeDoc.documentElement,
46
+ ".ck-editor__editable",
47
+ "Find CKEditor in editable iframe."
48
+ );
44
49
  if (el) {
45
50
  ckEditor = el;
46
51
  }
@@ -80,7 +85,7 @@ function onIframeLoad() {
80
85
  }
81
86
  const height = ref(props.initialHeight);
82
87
  const url = computed(() => {
83
- if ("itemBundle" in props.host) {
88
+ if (props.host.type === itemEntityType) {
84
89
  return adapter.buildEditableFrameUrl({
85
90
  uuid: props.host.uuid,
86
91
  fieldName: props.fieldName
@@ -1,9 +1,9 @@
1
- import type { DraggableExistingBlock, EditableFieldType, EntityContext } from '#blokkli/types';
1
+ import type { EditableFieldType, EntityContext } from '#blokkli/types';
2
2
  type __VLS_Props = {
3
3
  modelValue: string;
4
4
  type: EditableFieldType;
5
5
  fieldName: string;
6
- host: DraggableExistingBlock | EntityContext;
6
+ host: EntityContext;
7
7
  initialHeight: number;
8
8
  };
9
9
  declare const _default: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
@@ -71,7 +71,16 @@ import InputPlaintext from "./Plaintext/index.vue";
71
71
  import InputContenteditable from "./Contenteditable/index.vue";
72
72
  import InputFrame from "./Frame/index.vue";
73
73
  import onBlokkliEvent from "#blokkli/helpers/composables/onBlokkliEvent";
74
- const { eventBus, selection, state, adapter, $t, types } = useBlokkli();
74
+ import { itemEntityType } from "#blokkli-build/config";
75
+ const {
76
+ eventBus,
77
+ selection,
78
+ state,
79
+ adapter,
80
+ $t,
81
+ types,
82
+ element: elementProvider
83
+ } = useBlokkli();
75
84
  const props = defineProps({
76
85
  fieldName: { type: String, required: true },
77
86
  host: { type: Object, required: true },
@@ -102,12 +111,7 @@ const inputStyle = ref({});
102
111
  const form = ref(null);
103
112
  const input = ref(null);
104
113
  const hasChanged = computed(() => modelValue.value !== originalText.value);
105
- const itemBundle = computed(() => {
106
- if ("itemBundle" in props.host) {
107
- return props.host.itemBundle;
108
- }
109
- return void 0;
110
- });
114
+ const itemBundle = computed(() => props.host.bundle);
111
115
  const maxlength = computed(() => props.config.maxLength);
112
116
  const required = computed(() => !!props.config.required);
113
117
  const title = computed(() => {
@@ -138,7 +142,7 @@ const close = async () => {
138
142
  }
139
143
  const el = getElement();
140
144
  if (shouldSave.value && modelValue.value !== originalText.value) {
141
- if ("itemBundle" in props.host) {
145
+ if (props.host.type === itemEntityType) {
142
146
  await state.mutateWithLoadingState(
143
147
  () => adapter.updateFieldValue({
144
148
  uuid: props.host.uuid,
@@ -187,17 +191,30 @@ const focusInput = (el) => {
187
191
  if (!el) {
188
192
  return;
189
193
  }
190
- const textarea = el.querySelector("textarea");
194
+ const queryEl = el instanceof Document ? el.documentElement : el;
195
+ const textarea = elementProvider.query(
196
+ queryEl,
197
+ "textarea",
198
+ "Focus editable field textarea"
199
+ );
191
200
  if (textarea) {
192
201
  textarea.focus();
193
202
  return;
194
203
  }
195
- const editable = el.querySelector("[contenteditable]");
196
- if (editable instanceof HTMLElement) {
204
+ const editable = elementProvider.query(
205
+ queryEl,
206
+ "[contenteditable]",
207
+ "Focus editable field contenteditable"
208
+ );
209
+ if (editable) {
197
210
  editable.focus();
198
211
  return;
199
212
  }
200
- const iframe = el.querySelector("iframe");
213
+ const iframe = elementProvider.query(
214
+ queryEl,
215
+ "iframe",
216
+ "Find iframe in editable field"
217
+ );
201
218
  if (iframe?.contentDocument) {
202
219
  focusInput(iframe.contentDocument);
203
220
  }
@@ -1,7 +1,7 @@
1
- import type { DraggableExistingBlock, EntityContext, EditableFieldConfig } from '#blokkli/types';
1
+ import type { EntityContext, EditableFieldConfig } from '#blokkli/types';
2
2
  type __VLS_Props = {
3
3
  fieldName: string;
4
- host: DraggableExistingBlock | EntityContext;
4
+ host: EntityContext;
5
5
  element: HTMLElement;
6
6
  config: EditableFieldConfig;
7
7
  isComponent?: boolean;
@@ -1,7 +1,12 @@
1
1
  <template>
2
2
  <Teleport to="body">
3
3
  <BlokkliTransition name="caret-tooltip" :enabled="hasTransition">
4
- <Overlay v-if="editable" v-bind="editable" :key="key" @close="close" />
4
+ <Overlay
5
+ v-if="selectedEditable"
6
+ v-bind="selectedEditable"
7
+ :key="key"
8
+ @close="close"
9
+ />
5
10
  </BlokkliTransition>
6
11
  </Teleport>
7
12
  </template>
@@ -19,6 +24,7 @@ import { BlokkliTransition } from "#blokkli/components";
19
24
  import onBlokkliEvent from "#blokkli/helpers/composables/onBlokkliEvent";
20
25
  import defineCommands from "#blokkli/helpers/composables/defineCommands";
21
26
  import { falsy } from "#blokkli/helpers";
27
+ import { itemEntityType } from "#blokkli-build/config";
22
28
  defineBlokkliFeature({
23
29
  id: "editable-field",
24
30
  icon: "textbox",
@@ -26,41 +32,47 @@ defineBlokkliFeature({
26
32
  requiredAdapterMethods: ["updateFieldValue", "getEditableFieldConfig"],
27
33
  description: "Implements a form overlay to edit a single field of a block."
28
34
  });
29
- const { selection, adapter, types, $t, dom, runtimeConfig, state } = useBlokkli();
30
- const editable = ref(null);
35
+ const { selection, adapter, types, $t, state, directive, blocks, context } = useBlokkli();
36
+ const selectedEditable = ref(null);
31
37
  const hasTransition = ref(false);
32
38
  const key = computed(() => {
33
- if (!editable.value) {
39
+ if (!selectedEditable.value) {
34
40
  return "";
35
41
  }
36
- return editable.value.host.uuid + editable.value.fieldName;
42
+ return selectedEditable.value.host.uuid + selectedEditable.value.fieldName;
37
43
  });
38
44
  const getHost = (uuid) => {
39
45
  if (uuid) {
40
- const block = dom.findBlock(uuid);
46
+ const block = blocks.getBlock(uuid);
41
47
  if (block) {
42
- return block;
48
+ return {
49
+ type: itemEntityType,
50
+ bundle: block.bundle,
51
+ uuid: block.uuid
52
+ };
43
53
  }
44
54
  }
45
- return dom.findClosestEntityContext(dom.getActiveProviderElement());
55
+ return {
56
+ type: context.value.entityType,
57
+ bundle: context.value.entityBundle,
58
+ uuid: context.value.entityUuid
59
+ };
46
60
  };
47
61
  const buildEditable = (fieldName, uuid) => {
48
62
  const host = getHost(uuid);
49
63
  if (!host) {
50
64
  return;
51
65
  }
52
- const hostEntityType = "type" in host ? host.type : runtimeConfig.itemEntityType;
53
- const hostEntityBundle = "bundle" in host ? host.bundle : host.itemBundle;
54
- if (hostEntityBundle === "from_library") {
66
+ if (host.bundle === "from_library") {
55
67
  return;
56
68
  }
57
69
  const config = types.editableFieldConfig.forName(
58
- hostEntityType,
59
- hostEntityBundle,
70
+ host.type,
71
+ host.bundle,
60
72
  fieldName
61
73
  );
62
74
  if (!config) {
63
- let message = `Failed to load editable field config for field "${fieldName}" on entity type "${hostEntityType}" of bundle "${hostEntityBundle}"`;
75
+ let message = `Failed to load editable field config for field "${fieldName}" on entity type "${host.type}" of bundle "${host.bundle}"`;
64
76
  if (uuid) {
65
77
  message += ` with uuid "${uuid}"`;
66
78
  }
@@ -69,10 +81,7 @@ const buildEditable = (fieldName, uuid) => {
69
81
  if (config.type === "frame" && !adapter.buildEditableFrameUrl) {
70
82
  return;
71
83
  }
72
- const hostElement = "itemBundle" in host ? host.element() : dom.getActiveProviderElement();
73
- const element = hostElement.querySelector(
74
- `[data-blokkli-editable-field="${fieldName}"]`
75
- );
84
+ const element = directive.findEditableElement(fieldName, host);
76
85
  if (!(element instanceof HTMLElement)) {
77
86
  return;
78
87
  }
@@ -89,30 +98,19 @@ onBlokkliEvent("editable:focus", (e) => {
89
98
  if (!state.canEdit.value) {
90
99
  return;
91
100
  }
92
- hasTransition.value = !editable.value;
93
- editable.value = buildEditable(e.fieldName, e.uuid) || null;
94
- if (editable.value) {
101
+ hasTransition.value = !selectedEditable.value;
102
+ selectedEditable.value = buildEditable(e.fieldName, e.uuid) || null;
103
+ if (selectedEditable.value) {
95
104
  selection.editableActive.value = true;
96
105
  }
97
106
  });
98
107
  defineCommands(() => {
99
- const editables = selection.blocks.value.flatMap((v) => {
100
- return [...v.element().querySelectorAll("[data-blokkli-editable-field]")].map((el) => {
101
- if (!(el instanceof HTMLElement)) {
102
- return;
103
- }
104
- const block = el.closest("[data-uuid]");
105
- if (!(block instanceof HTMLElement)) {
106
- return;
107
- }
108
- if (block.dataset.uuid !== v.uuid) {
109
- return;
110
- }
111
- const name = el.dataset.blokkliEditableField;
112
- if (!name) {
113
- return;
114
- }
115
- return buildEditable(name, block.dataset.uuid);
108
+ if (selection.items.value.length > 5) {
109
+ return [];
110
+ }
111
+ const editables = selection.items.value.flatMap((item) => {
112
+ return directive.getEditablesForBlock(item.uuid).map((v) => {
113
+ return buildEditable(v.fieldName, item.uuid);
116
114
  }).filter(falsy);
117
115
  });
118
116
  return editables.map((v) => {
@@ -126,7 +124,7 @@ defineCommands(() => {
126
124
  icon: "textbox",
127
125
  disabled: false,
128
126
  callback: () => {
129
- editable.value = v;
127
+ selectedEditable.value = v;
130
128
  }
131
129
  };
132
130
  });
@@ -134,16 +132,16 @@ defineCommands(() => {
134
132
  watch(selection.editableActive, (isActive) => {
135
133
  if (!isActive) {
136
134
  hasTransition.value = true;
137
- editable.value = null;
135
+ selectedEditable.value = null;
138
136
  }
139
137
  });
140
- watch(editable, (v) => {
138
+ watch(selectedEditable, (v) => {
141
139
  if (!v && selection.editableActive.value) {
142
140
  selection.editableActive.value = false;
143
141
  }
144
142
  });
145
143
  const close = () => {
146
- editable.value = null;
144
+ selectedEditable.value = null;
147
145
  selection.editableActive.value = false;
148
146
  };
149
147
  </script>
@@ -37,14 +37,16 @@
37
37
  <ul class="bk-library-dialog-list">
38
38
  <li
39
39
  v-for="(item, index) in fragments"
40
+ v-show="visible === null || visible.includes(item.name)"
41
+ ref="itemElements"
40
42
  :key="item.name"
41
43
  :class="{
42
44
  'bk-is-selected': selectedItem === item.name
43
45
  }"
46
+ :data-bk-fragment-name="item.name"
44
47
  @click="selectedItem = item.name"
45
48
  >
46
49
  <FragmentItem
47
- v-show="visible === null || visible.includes(item.name)"
48
50
  :name="item.name"
49
51
  :label="item.label"
50
52
  :description="item.description"
@@ -65,7 +67,7 @@
65
67
  <script setup>
66
68
  import { FormOverlay } from "#blokkli/components";
67
69
  import { falsy } from "#blokkli/helpers";
68
- import { ref, useBlokkli, computed, watch } from "#imports";
70
+ import { ref, useBlokkli, computed, watch, useTemplateRef } from "#imports";
69
71
  import FragmentItem from "./Item/index.vue";
70
72
  const props = defineProps({
71
73
  field: { type: Object, required: true }
@@ -73,7 +75,7 @@ const props = defineProps({
73
75
  const { $t, definitions } = useBlokkli();
74
76
  const emit = defineEmits(["close", "submit"]);
75
77
  const searchText = ref("");
76
- const listEl = ref(null);
78
+ const itemElements = useTemplateRef("itemElements");
77
79
  const selectedItem = ref("");
78
80
  const allowedInField = computed(() => props.field.allowedFragments || []);
79
81
  const fragments = computed(
@@ -91,15 +93,15 @@ const onClose = () => {
91
93
  };
92
94
  const elements = ref([]);
93
95
  const buildElements = () => {
94
- if (!listEl.value) {
96
+ if (!itemElements.value) {
95
97
  return;
96
98
  }
97
- elements.value = [...listEl.value.querySelectorAll(".bk-library-list-item")].map((el) => {
99
+ elements.value = itemElements.value.map((el) => {
98
100
  if (el instanceof HTMLElement) {
99
- const uuid = el.dataset.libraryItemUuid;
100
- if (uuid) {
101
+ const name = el.dataset.bkFragmentName;
102
+ if (name) {
101
103
  return {
102
- uuid,
104
+ name,
103
105
  text: el.textContent?.toLowerCase() || ""
104
106
  };
105
107
  }
@@ -115,6 +117,6 @@ const visible = computed(() => {
115
117
  if (!searchText.value || !elements.value.length) {
116
118
  return null;
117
119
  }
118
- return elements.value.filter((v) => v.text.includes(searchText.value.toLowerCase())).map((v) => v.uuid);
120
+ return elements.value.filter((v) => v.text.includes(searchText.value.toLowerCase())).map((v) => v.name);
119
121
  });
120
122
  </script>
@@ -45,9 +45,9 @@ const { adapter } = defineBlokkliFeature({
45
45
  });
46
46
  const { state, $t, types, selection, dom } = useBlokkli();
47
47
  const isEnabled = computed(() => {
48
- if (selection.blocks.value.length === 1) {
49
- const block = selection.blocks.value[0];
50
- const field = dom.findField(block.hostUuid, block.hostFieldName);
48
+ const item = selection.item.value;
49
+ if (item) {
50
+ const field = dom.getRegisteredField(item.host.uuid, item.host.fieldName);
51
51
  return !!field?.allowedFragments.length;
52
52
  }
53
53
  return true;
@@ -14,9 +14,8 @@ import { toShaderColor, isInsideRect } from "#blokkli/helpers";
14
14
  const props = defineProps({
15
15
  gl: { type: null, required: true }
16
16
  });
17
- const { animation, theme, dom, selection, state, ui, editable } = useBlokkli();
17
+ const { animation, theme, dom, selection, state, ui, directive, blocks } = useBlokkli();
18
18
  const programInfo = animation.registerProgram("hover", props.gl, [vs, fs]);
19
- const DEBUG = false;
20
19
  const MAX_RECTS = 11;
21
20
  function getDeepestUuid(uuids) {
22
21
  if (uuids.length === 0) {
@@ -90,18 +89,14 @@ function updateHoverState(mouseX, mouseY, offset, scale, artboardSize) {
90
89
  };
91
90
  const isOutsideArtboard = mouseX < artboardRect.x || mouseX > artboardRect.x + artboardRect.width || mouseY < artboardRect.y || mouseY > artboardRect.y + artboardRect.height;
92
91
  if (isOutsideArtboard) {
93
- if (DEBUG || previousHoveredUuids.length > 0 || previousEditableFieldRect !== null) {
94
- hoverState.visible.fill(0);
95
- isHoveringEditableField.value = false;
96
- isHoveringSelectedBlock.value = false;
97
- if (!DEBUG) {
98
- previousHoveredUuids = [];
99
- previousDeepestUuid = null;
100
- previousEditableFieldRect = null;
101
- }
102
- return true;
103
- }
104
- return false;
92
+ const needsUpdate = previousHoveredUuids.length > 0 || previousEditableFieldRect !== null || isHoveringEditableField.value || isHoveringSelectedBlock.value;
93
+ hoverState.visible.fill(0);
94
+ isHoveringEditableField.value = false;
95
+ isHoveringSelectedBlock.value = false;
96
+ previousHoveredUuids = [];
97
+ previousDeepestUuid = null;
98
+ previousEditableFieldRect = null;
99
+ return needsUpdate;
105
100
  }
106
101
  const artboardMouseX = mouseX / scale - offset.x / scale;
107
102
  const artboardMouseY = mouseY / scale - offset.y / scale;
@@ -132,7 +127,7 @@ function updateHoverState(mouseX, mouseY, offset, scale, artboardSize) {
132
127
  (uuid, i) => uuid !== previousHoveredUuids[i]
133
128
  ) || deepestUuid !== previousDeepestUuid;
134
129
  let hoveredEditableFieldRect = null;
135
- const editableRects = editable.getVisible();
130
+ const editableRects = directive.getVisible("editable");
136
131
  for (let i = 0; i < editableRects.length; i++) {
137
132
  const editableRect = editableRects[i];
138
133
  if (isInsideRect(artboardMouseX, artboardMouseY, editableRect)) {
@@ -140,7 +135,7 @@ function updateHoverState(mouseX, mouseY, offset, scale, artboardSize) {
140
135
  break;
141
136
  }
142
137
  }
143
- if (!hoveredChanged && !DEBUG) {
138
+ if (!hoveredChanged) {
144
139
  const editableFieldChanged = hoveredEditableFieldRect === null !== (previousEditableFieldRect === null) || hoveredEditableFieldRect && previousEditableFieldRect && (hoveredEditableFieldRect.x !== previousEditableFieldRect.x || hoveredEditableFieldRect.y !== previousEditableFieldRect.y || hoveredEditableFieldRect.width !== previousEditableFieldRect.width || hoveredEditableFieldRect.height !== previousEditableFieldRect.height);
145
140
  if (!editableFieldChanged) {
146
141
  return false;
@@ -158,7 +153,7 @@ function updateHoverState(mouseX, mouseY, offset, scale, artboardSize) {
158
153
  }
159
154
  for (const [level, uuid] of nestingMap) {
160
155
  const rect = dom.getBlockRect(uuid);
161
- const block = dom.findBlock(uuid);
156
+ const block = blocks.getBlock(uuid);
162
157
  if (!rect || !block) continue;
163
158
  const el = dom.getDragElement(block);
164
159
  if (!el) continue;
@@ -197,15 +192,11 @@ function updateHoverState(mouseX, mouseY, offset, scale, artboardSize) {
197
192
  hoverState.types[10] = 2;
198
193
  hoverState.visible[10] = 1;
199
194
  }
200
- if (!DEBUG) {
201
- previousHoveredUuids = unselectedHoveredUuids;
202
- previousDeepestUuid = deepestUuid;
203
- previousEditableFieldRect = hoveredEditableFieldRect;
204
- }
195
+ previousHoveredUuids = unselectedHoveredUuids;
196
+ previousDeepestUuid = deepestUuid;
197
+ previousEditableFieldRect = hoveredEditableFieldRect;
205
198
  isHoveringEditableField.value = hoveredEditableFieldRect !== null;
206
- isHoveringSelectedBlock.value = hoveredUuids.some(
207
- (uuid) => selectedUuids.includes(uuid)
208
- );
199
+ isHoveringSelectedBlock.value = deepestUuid !== null && selectedUuids.includes(deepestUuid);
209
200
  return true;
210
201
  }
211
202
  const uniforms = computed(() => {
@@ -46,16 +46,15 @@ const props = defineProps({
46
46
  uuid: { type: String, required: true },
47
47
  label: { type: String, required: false }
48
48
  });
49
+ const { $t, element } = useBlokkli();
49
50
  const DURATION = 530;
50
51
  const emit = defineEmits(["submit", "close"]);
51
52
  function getOriginatingElement() {
52
- const el = document.querySelector(
53
- `[data-bk-library-item-uuid="${props.uuid}"]`
53
+ return element.query(
54
+ document.documentElement,
55
+ `[data-bk-library-item-uuid="${props.uuid}"]`,
56
+ "Get originating library item element"
54
57
  );
55
- if (el instanceof HTMLElement) {
56
- return el;
57
- }
58
- return null;
59
58
  }
60
59
  function onEnter(el, done) {
61
60
  if (el instanceof HTMLElement) {
@@ -125,7 +124,6 @@ function onAfterLeave(el) {
125
124
  emit("close");
126
125
  }
127
126
  }
128
- const { $t } = useBlokkli();
129
127
  const iframe = ref(null);
130
128
  const isLoaded = ref(false);
131
129
  const isLoading = ref(true);