@blokkli/editor 1.3.4 → 1.4.0-alpha.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/module.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "blokkli",
3
3
  "configKey": "blokkli",
4
- "version": "1.3.4",
4
+ "version": "1.4.0-alpha.0",
5
5
  "compatibility": {
6
6
  "nuxt": "^3.12.0"
7
7
  },
package/dist/module.mjs CHANGED
@@ -7,7 +7,7 @@ import MagicString from 'magic-string';
7
7
  import { walk } from 'estree-walker-ts';
8
8
  import { BK_VISIBLE_LANGUAGES, BK_HIDDEN_GLOBALLY } from '../dist/runtime/helpers/symbols.js';
9
9
 
10
- const version = "1.3.4";
10
+ const version = "1.4.0-alpha.0";
11
11
 
12
12
  function sortObjectKeys(obj) {
13
13
  if (Array.isArray(obj)) {
@@ -190,7 +190,7 @@ class BlockExtractor {
190
190
  icon,
191
191
  proxyComponent,
192
192
  diffComponent,
193
- chunkName: extracted.definition.chunkName || "global",
193
+ chunkName: this.isBuild ? extracted.definition.chunkName || "global" : "global",
194
194
  componentName: "BlokkliComponent_" + extracted.definition.bundle + "_" + componentFileName,
195
195
  source: extracted.source,
196
196
  fileSource,
@@ -203,7 +203,7 @@ class BlockExtractor {
203
203
  this.fragmentDefinitions[filePath2] = {
204
204
  filePath: filePath2,
205
205
  definition: extracted.definition,
206
- chunkName: extracted.definition.chunkName || "global",
206
+ chunkName: this.isBuild ? extracted.definition.chunkName || "global" : "global",
207
207
  componentName: "BlokkliFragmentComponent_" + extracted.definition.name,
208
208
  source: extracted.source,
209
209
  fileSource
@@ -399,7 +399,7 @@ export const getFragmentDefinition = (name: string): FragmentDefinitionInput<Rec
399
399
  generateDefaultGlobalOptions(globalOptions = {}) {
400
400
  const defaults = Object.entries(globalOptions).reduce(
401
401
  (acc, [key, option]) => {
402
- if (option.default) {
402
+ if (option.default !== void 0 && option.default !== null) {
403
403
  acc[key] = {
404
404
  default: option.default,
405
405
  type: option.type
@@ -561,20 +561,28 @@ const fragmentChunkMapping: Record<string, string> = ${JSON.stringify(
561
561
  2
562
562
  )}
563
563
 
564
+ function componentOrFunction(component: any) {
565
+ if (typeof component === 'object') {
566
+ return component
567
+ }
568
+
569
+ return defineAsyncComponent(() => component())
570
+ }
571
+
564
572
  export function getBlokkliItemComponent(bundle: string, fieldListType?: string, parentBundle?: string): any {
565
573
  const forFieldListType = 'block_' + bundle + '__field_list_type_' + fieldListType
566
574
  if (global[forFieldListType]) {
567
- return global[forFieldListType]
575
+ return componentOrFunction(global[forFieldListType])
568
576
  }
569
577
  if (parentBundle) {
570
578
  const forParentBundle = 'block_' + bundle + '__parent_block_' + parentBundle
571
579
  if (global[forParentBundle]) {
572
- return global[forParentBundle]
580
+ return componentOrFunction(global[forParentBundle])
573
581
  }
574
582
  }
575
583
  const key = 'block_' + bundle
576
584
  if (global[key]) {
577
- return global[key]
585
+ return componentOrFunction(global[key])
578
586
  }
579
587
  const chunkName = chunkMapping[key]
580
588
  if (chunkName) {
@@ -587,7 +595,7 @@ export function getBlokkliItemComponent(bundle: string, fieldListType?: string,
587
595
  export function getBlokkliFragmentComponent(name: string): any {
588
596
  const key = 'fragment_' + name
589
597
  if (globalFragments[key]) {
590
- return globalFragments[key]
598
+ return componentOrFunction(globalFragments[key])
591
599
  }
592
600
  const chunkName = fragmentChunkMapping[key]
593
601
  if (chunkName) {
@@ -606,7 +614,11 @@ export function getBlokkliFragmentComponent(name: string): any {
606
614
  return v?.chunkName === chunkName;
607
615
  }).filter(falsy);
608
616
  const imports = definitions.map((v) => {
609
- return `import ${v.componentName} from '${v.filePath}'`;
617
+ if (this.isBuild) {
618
+ return `import ${v.componentName} from '${v.filePath}'`;
619
+ } else {
620
+ return `const ${v.componentName} = () => import('${v.filePath}')`;
621
+ }
610
622
  });
611
623
  const map = definitions.reduce((acc, v) => {
612
624
  if ("bundle" in v.definition) {
@@ -7330,7 +7342,7 @@ export const forceDefaultLanguage: boolean = ${JSON.stringify(
7330
7342
  };
7331
7343
  await generateOptionsSchema();
7332
7344
  getChunkNames().forEach((chunkName) => {
7333
- if (chunkName !== "global") {
7345
+ if (chunkName !== "global" && !nuxt.options.dev) {
7334
7346
  const template = addTemplate({
7335
7347
  write: true,
7336
7348
  filename: `blokkli/chunk-${chunkName}.ts`,
@@ -7348,7 +7360,9 @@ export const forceDefaultLanguage: boolean = ${JSON.stringify(
7348
7360
  write: true,
7349
7361
  filename: "blokkli/imports.ts",
7350
7362
  getContents: () => {
7351
- return blockExtractor.generateImportsTemplate(getChunkNames());
7363
+ return blockExtractor.generateImportsTemplate(
7364
+ nuxt.options.dev ? ["global"] : getChunkNames()
7365
+ );
7352
7366
  },
7353
7367
  options: {
7354
7368
  blokkli: true
@@ -34,7 +34,7 @@ import type {
34
34
  BlockBundleWithNested,
35
35
  ValidFieldListTypes,
36
36
  } from '#blokkli/generated-types'
37
- import { computed, useBlokkli, onMounted, onBeforeUnmount, ref } from '#imports'
37
+ import { computed, useBlokkli, ref } from '#imports'
38
38
  import {
39
39
  getDefinition,
40
40
  getBlokkliItemProxyComponent,
@@ -83,7 +83,7 @@ const proxyBundle = computed(
83
83
  () => libraryItemProps.value?.block?.bundle || props.bundle,
84
84
  )
85
85
 
86
- const { dom, types, runtimeConfig } = useBlokkli()
86
+ const { types, runtimeConfig } = useBlokkli()
87
87
 
88
88
  const root = ref<HTMLElement | null>(null)
89
89
 
@@ -125,18 +125,4 @@ const fieldLayout = computed<FieldConfig[][]>(() => {
125
125
  .forEntityTypeAndBundle(runtimeConfig.itemEntityType, proxyBundle.value)
126
126
  .map((config) => [config])
127
127
  })
128
-
129
- onMounted(() => {
130
- dom.registerBlock(
131
- props.uuid,
132
- root.value,
133
- props.bundle,
134
- props.fieldListType,
135
- props.parentType as BlockBundleWithNested,
136
- )
137
- })
138
-
139
- onBeforeUnmount(() => {
140
- dom.unregisterBlock(props.uuid)
141
- })
142
128
  </script>
@@ -37,7 +37,7 @@
37
37
  <DragInteractions v-if="!isInitializing" />
38
38
  <AnimationCanvas v-if="!isInitializing" />
39
39
  <SystemRequirements />
40
- <slot :mutated-entity="mutatedEntity" />
40
+ <slot v-if="!isInitializing" :mutated-entity="mutatedEntity" />
41
41
  </template>
42
42
 
43
43
  <script lang="ts" setup generic="T">
@@ -176,15 +176,13 @@ onMounted(() => {
176
176
  if (props.isolate) {
177
177
  document.documentElement.classList.add('bk-isolate-provider')
178
178
  }
179
- nextTick(() => {
180
- isInitializing.value = false
181
- })
182
179
 
183
180
  document.documentElement.addEventListener('touchmove', onTouchMove)
184
181
  document.documentElement.addEventListener('touchstart', onTouchStart)
185
182
  setRootClasses()
186
183
  baseLogger.log('EditProvider mounted')
187
184
  dom.init()
185
+ isInitializing.value = false
188
186
  broadcast.emit('editorLoaded', { uuid: props.entityUuid })
189
187
  })
190
188
 
@@ -4,16 +4,9 @@ import {
4
4
  INJECT_FIELD_LIST_BLOCKS,
5
5
  INJECT_FIELD_LIST_TYPE,
6
6
  INJECT_REUSABLE_OPTIONS,
7
- INJECT_PROVIDER_BLOCKS,
8
- INJECT_FIELD_USES_PROXY
7
+ INJECT_PROVIDER_BLOCKS
9
8
  } from "../helpers/symbols.js";
10
- import {
11
- computed,
12
- inject,
13
- getCurrentInstance,
14
- onMounted,
15
- onBeforeUnmount
16
- } from "#imports";
9
+ import { computed, inject } from "#imports";
17
10
  import { globalOptionsDefaults } from "#blokkli/default-global-options";
18
11
  import { getRuntimeOptionValue } from "#blokkli/helpers/runtimeHelpers";
19
12
  export function defineBlokkli(config) {
@@ -82,30 +75,6 @@ export function defineBlokkli(config) {
82
75
  });
83
76
  const parentType = computed(() => item?.value.parentType);
84
77
  const isEditing = !!item?.value.isEditing;
85
- const fieldUsesProxy = inject(INJECT_FIELD_USES_PROXY, false);
86
- onMounted(() => {
87
- if (
88
- // If the field uses proxy mode we don't want to register the block here.
89
- fieldUsesProxy || !item?.value || !isEditing || !editContext || !editContext.dom || // Block is already registered by the from_library block.
90
- fromLibraryOptions || // The defineBlokkliFragment composable registers the block itself.
91
- config.bundle === "blokkli_fragment"
92
- ) {
93
- return;
94
- }
95
- const instance = getCurrentInstance();
96
- editContext.dom.registerBlock(
97
- uuid,
98
- instance,
99
- config.bundle,
100
- fieldListType.value,
101
- item.value.parentType
102
- );
103
- });
104
- onBeforeUnmount(() => {
105
- if (!fieldUsesProxy && isEditing && editContext && editContext.dom && uuid && config.bundle !== "blokkli_fragment") {
106
- editContext.dom.unregisterBlock(uuid);
107
- }
108
- });
109
78
  return {
110
79
  uuid,
111
80
  index,
@@ -1,22 +1,12 @@
1
- import {
2
- INJECT_EDIT_CONTEXT,
3
- INJECT_FRAGMENT_CONTEXT
4
- } from "../helpers/symbols.js";
1
+ import { INJECT_FRAGMENT_CONTEXT } from "../helpers/symbols.js";
5
2
  import { getRuntimeOptionValue } from "../helpers/runtimeHelpers/index.js";
6
- import {
7
- computed,
8
- getCurrentInstance,
9
- inject,
10
- onBeforeUnmount,
11
- onMounted
12
- } from "#imports";
3
+ import { computed, inject } from "#imports";
13
4
  import { globalOptionsDefaults } from "#blokkli/default-global-options";
14
5
  export function defineBlokkliFragment(config) {
15
6
  const ctx = inject(
16
7
  INJECT_FRAGMENT_CONTEXT,
17
8
  null
18
9
  );
19
- const editContext = inject(INJECT_EDIT_CONTEXT, null);
20
10
  const optionKeys = [
21
11
  ...Object.keys(config.options || {}),
22
12
  ...config.globalOptions || []
@@ -36,22 +26,5 @@ export function defineBlokkliFragment(config) {
36
26
  });
37
27
  return result;
38
28
  });
39
- onMounted(() => {
40
- if (editContext && editContext.dom && ctx) {
41
- const instance = getCurrentInstance();
42
- editContext.dom.registerBlock(
43
- ctx.uuid,
44
- instance,
45
- "blokkli_fragment",
46
- ctx.fieldListType.value,
47
- ctx.parentType.value
48
- );
49
- }
50
- });
51
- onBeforeUnmount(() => {
52
- if (editContext && ctx && ctx.uuid && editContext.dom) {
53
- editContext.dom.unregisterBlock(ctx.uuid);
54
- }
55
- });
56
29
  return { ...ctx, options };
57
30
  }
@@ -1,8 +1,6 @@
1
- import type { ComponentInternalInstance } from 'vue';
2
1
  import { type ComputedRef } from '#imports';
3
2
  import type { DraggableExistingBlock, BlokkliFieldElement, DraggableItem, DroppableEntityField, EntityContext, Rectangle } from '#blokkli/types';
4
3
  import type { UiProvider } from './uiProvider.js';
5
- import type { BlockBundleWithNested, ValidFieldListTypes } from '#blokkli/generated-types';
6
4
  import type { DebugProvider } from './debugProvider.js';
7
5
  type RegisteredFieldType = {
8
6
  entityType: string;
@@ -21,8 +19,6 @@ export type DomProvider = {
21
19
  */
22
20
  getDropElementMarkup(item: DraggableItem, checkSize?: boolean): string;
23
21
  findField(entityUuid: string, fieldName: string): BlokkliFieldElement | undefined;
24
- registerBlock: (uuid: string, instance: ComponentInternalInstance | null | HTMLElement, bundle: string, fieldListType: ValidFieldListTypes, parentBlockBundle?: BlockBundleWithNested) => void;
25
- unregisterBlock: (uuid: string) => void;
26
22
  registerField: (entity: EntityContext, fieldName: string, instance: HTMLElement) => void;
27
23
  updateFieldElement: (entity: EntityContext, fieldName: string, element: HTMLElement) => void;
28
24
  unregisterField: (entity: EntityContext, fieldName: string) => void;
@@ -43,16 +43,6 @@ const buildFieldElement = (element) => {
43
43
  };
44
44
  }
45
45
  };
46
- const getVisibleBlockElement = (instance) => {
47
- if (instance instanceof HTMLElement) {
48
- return instance;
49
- }
50
- if (instance.vnode.el instanceof HTMLElement) {
51
- return instance.vnode.el;
52
- } else if (instance?.vnode.el instanceof Text && instance?.vnode.el.nextElementSibling instanceof HTMLElement) {
53
- return instance.vnode.el.nextElementSibling;
54
- }
55
- };
56
46
  function rectWithTime(rect, time) {
57
47
  return {
58
48
  ...rect,
@@ -60,6 +50,7 @@ function rectWithTime(rect, time) {
60
50
  };
61
51
  }
62
52
  export default function(ui, debug) {
53
+ const artboardElement = ui.artboardElement();
63
54
  const logger = debug.createLogger("DomProvider");
64
55
  const mutationsReady = ref(true);
65
56
  const intersectionReady = ref(false);
@@ -136,7 +127,7 @@ export default function(ui, debug) {
136
127
  }
137
128
  }
138
129
  }
139
- const observer = useDelayedIntersectionObserver(intersectionCallback);
130
+ const intersectionObserver = useDelayedIntersectionObserver(intersectionCallback);
140
131
  const registeredBlocks = reactive({});
141
132
  const registeredFields = reactive({});
142
133
  const registeredFieldTypes = computed(() => {
@@ -162,22 +153,22 @@ export default function(ui, debug) {
162
153
  const registerField = (entity, fieldName, element) => {
163
154
  const key = `${entity.uuid}:${fieldName}`;
164
155
  registeredFields[key] = { element, entity, fieldName };
165
- observer.observe(element);
156
+ intersectionObserver.observe(element);
166
157
  };
167
158
  const updateFieldElement = (entity, fieldName, element) => {
168
159
  const key = `${entity.uuid}:${fieldName}`;
169
160
  const existingElement = registeredFields[key]?.element;
170
161
  if (existingElement) {
171
- observer.unobserve(existingElement);
162
+ intersectionObserver.unobserve(existingElement);
172
163
  }
173
164
  registeredFields[key] = { entity, fieldName, element };
174
- observer.observe(element);
165
+ intersectionObserver.observe(element);
175
166
  };
176
167
  const unregisterField = (entity, fieldName) => {
177
168
  const key = `${entity.uuid}:${fieldName}`;
178
169
  const el = registeredFields[key]?.element;
179
170
  if (el) {
180
- observer.unobserve(el);
171
+ intersectionObserver.unobserve(el);
181
172
  }
182
173
  visibleFields.delete(key);
183
174
  registeredFields[key] = void 0;
@@ -196,45 +187,6 @@ export default function(ui, debug) {
196
187
  }
197
188
  return el;
198
189
  }
199
- const registerBlock = (uuid, instance, bundle, fieldListType, parentBlockBundle) => {
200
- if (registeredBlocks[uuid]) {
201
- console.error(
202
- "Trying to register block with already existing UUID: " + uuid
203
- );
204
- }
205
- if (!instance) {
206
- console.error(
207
- `Failed to get component instance of block with UUID "${uuid}"`
208
- );
209
- return;
210
- }
211
- const el = getVisibleBlockElement(instance);
212
- if (!el) {
213
- console.error(
214
- `Failed to locate block component element for UUID "${uuid}". Make sure the block renders at least one root element that is always visible.`
215
- );
216
- return;
217
- }
218
- const observableElement = getElementToObserve(
219
- el,
220
- bundle,
221
- fieldListType,
222
- parentBlockBundle
223
- );
224
- observer.observe(observableElement);
225
- resizeObserver.observe(observableElement);
226
- registeredBlocks[uuid] = el;
227
- };
228
- const unregisterBlock = (uuid) => {
229
- const el = registeredBlocks[uuid];
230
- if (el) {
231
- observer.unobserve(el);
232
- resizeObserver.unobserve(el);
233
- }
234
- registeredBlocks[uuid] = void 0;
235
- delete blockRects[uuid];
236
- visibleBlocks.delete(uuid);
237
- };
238
190
  const findBlock = (uuid) => {
239
191
  const cached = draggableBlockCache[uuid];
240
192
  if (cached) {
@@ -399,26 +351,72 @@ export default function(ui, debug) {
399
351
  logger.log("Refreshed all visible rects");
400
352
  });
401
353
  function init() {
402
- observer.init();
354
+ intersectionObserver.init();
403
355
  intersectionReady.value = true;
404
356
  logger.log("IntersectionObserver initialized");
405
357
  }
406
358
  const dragElementUuidMap = /* @__PURE__ */ new WeakMap();
407
359
  const dragElementCache = /* @__PURE__ */ new Map();
408
- const callback = function(mutationsList) {
360
+ function handleNodeAdded(node) {
361
+ if (!(node instanceof HTMLElement)) {
362
+ return;
363
+ }
364
+ if (node.dataset.uuid) {
365
+ const item = buildDraggableItem(node);
366
+ if (item && item.itemType === "existing") {
367
+ const observableElement = getElementToObserve(
368
+ node,
369
+ item.itemBundle,
370
+ item.hostFieldListType,
371
+ item.hostBundle
372
+ );
373
+ intersectionObserver.observe(observableElement);
374
+ resizeObserver.observe(observableElement);
375
+ registeredBlocks[item.uuid] = node;
376
+ }
377
+ } else if (node.dataset.fieldName && node.dataset.fieldKey && node.dataset.fieldCardinality) {
378
+ const blocks = node.querySelectorAll('[data-element-type="existing"]');
379
+ for (const block of blocks) {
380
+ handleNodeAdded(block);
381
+ }
382
+ }
383
+ }
384
+ function handleNodeRemoved(node) {
385
+ if (node instanceof HTMLElement && node.dataset.uuid) {
386
+ const uuid = node.dataset.uuid;
387
+ const el = registeredBlocks[uuid];
388
+ if (el !== node) {
389
+ return;
390
+ }
391
+ if (el) {
392
+ intersectionObserver.unobserve(el);
393
+ resizeObserver.unobserve(el);
394
+ dragElementUuidMap.delete(el);
395
+ }
396
+ dragElementUuidMap.delete(node);
397
+ dragElementCache.delete(uuid);
398
+ registeredBlocks[uuid] = void 0;
399
+ delete blockRects[uuid];
400
+ visibleBlocks.delete(uuid);
401
+ }
402
+ }
403
+ const mutationObserverCallback = function(mutationsList) {
409
404
  for (const mutation of mutationsList) {
410
405
  if (mutation.type === "childList") {
411
- mutation.removedNodes.forEach((node) => {
412
- const uuid = dragElementUuidMap.get(node);
413
- dragElementUuidMap.delete(node);
414
- if (uuid) {
415
- dragElementCache.delete(uuid);
416
- }
417
- });
406
+ for (const node of mutation.removedNodes) {
407
+ handleNodeRemoved(node);
408
+ }
409
+ for (const node of mutation.addedNodes) {
410
+ handleNodeAdded(node);
411
+ }
418
412
  }
419
413
  }
420
414
  };
421
- const mutationObserver = new MutationObserver(callback);
415
+ const mutationObserver = new MutationObserver(mutationObserverCallback);
416
+ mutationObserver.observe(artboardElement, {
417
+ subtree: true,
418
+ childList: true
419
+ });
422
420
  function getDragElement(block) {
423
421
  const cached = dragElementCache.get(block.uuid);
424
422
  if (cached && document.body.contains(cached)) {
@@ -444,8 +442,6 @@ export default function(ui, debug) {
444
442
  findClosestBlock,
445
443
  getDropElementMarkup,
446
444
  findField,
447
- registerBlock,
448
- unregisterBlock,
449
445
  getAllDroppableFields,
450
446
  findClosestEntityContext,
451
447
  getVisibleBlocks,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@blokkli/editor",
3
- "version": "1.3.4",
3
+ "version": "1.4.0-alpha.0",
4
4
  "description": "Interactive page building experience for Nuxt",
5
5
  "repository": "blokkli/editor",
6
6
  "type": "module",