@blokkli/editor 2.0.0-alpha.29 → 2.0.0-alpha.30

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/editor",
3
3
  "configKey": "blokkli",
4
- "version": "2.0.0-alpha.29",
4
+ "version": "2.0.0-alpha.30",
5
5
  "compatibility": {
6
6
  "nuxt": ">=3.15.0"
7
7
  },
package/dist/module.mjs CHANGED
@@ -15,7 +15,7 @@ import { BK_VISIBLE_LANGUAGES, BK_HIDDEN_GLOBALLY } from './global/constants';
15
15
  import { defu, createDefu } from 'defu';
16
16
 
17
17
  const name = "@blokkli/editor";
18
- const version = "2.0.0-alpha.29";
18
+ const version = "2.0.0-alpha.30";
19
19
 
20
20
  function sortObjectKeys(obj) {
21
21
  if (Array.isArray(obj)) {
@@ -1,6 +1,9 @@
1
1
  declare const _default: typeof __VLS_export;
2
2
  export default _default;
3
- declare const __VLS_export: import("vue").DefineComponent<{}, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {} & {
3
+ declare const __VLS_export: import("vue").DefineComponent<{
4
+ hostEmptyFieldKeys: string[];
5
+ hostEmptyFieldTooltips: string[];
6
+ }, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {} & {
4
7
  toggle: (data: {
5
8
  position: "before" | "after";
6
9
  coordinates: {
@@ -15,7 +18,10 @@ declare const __VLS_export: import("vue").DefineComponent<{}, {}, {}, {}, {}, im
15
18
  y: number;
16
19
  };
17
20
  }) => any;
18
- }, string, import("vue").PublicProps, Readonly<{}> & Readonly<{
21
+ }, string, import("vue").PublicProps, Readonly<{
22
+ hostEmptyFieldKeys: string[];
23
+ hostEmptyFieldTooltips: string[];
24
+ }> & Readonly<{
19
25
  onToggle?: ((data: {
20
26
  position: "before" | "after";
21
27
  coordinates: {
@@ -30,4 +36,4 @@ declare const __VLS_export: import("vue").DefineComponent<{}, {}, {}, {}, {}, im
30
36
  y: number;
31
37
  };
32
38
  }) => any) | undefined;
33
- }>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
39
+ }>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
@@ -116,6 +116,10 @@ const tooltipData = computed(() => {
116
116
  }
117
117
  return { x: screenX, y: screenY, transform, position, text, isField };
118
118
  });
119
+ const props = defineProps({
120
+ hostEmptyFieldKeys: { type: Array, required: true },
121
+ hostEmptyFieldTooltips: { type: Array, required: true }
122
+ });
119
123
  const emit = defineEmits(["toggle", "toggleField"]);
120
124
  const MAX_CIRCLES = 10;
121
125
  const BUTTON_RADIUS = 12;
@@ -340,7 +344,7 @@ const { collector } = defineRenderer("add-buttons", {
340
344
  },
341
345
  program: () => ({ shaders: [vs, fs] }),
342
346
  enabled: () => {
343
- if (selection.uuids.value.length !== 1) {
347
+ if (selection.uuids.value.length !== 1 && !selection.hasHostSelected.value) {
344
348
  return false;
345
349
  }
346
350
  if (ui.openTooltip.value && ui.openTooltip.value !== "add-buttons") {
@@ -353,7 +357,7 @@ const { collector } = defineRenderer("add-buttons", {
353
357
  },
354
358
  cursor: () => hoveredCircle.value >= 0 ? "pointer" : null,
355
359
  onClick: ({ mouseArtboard }) => {
356
- if (selection.uuids.value.length !== 1) {
360
+ if (selection.uuids.value.length !== 1 && !selection.hasHostSelected.value) {
357
361
  return false;
358
362
  }
359
363
  const clickedCircle = getCircleAtPoint(mouseArtboard.x, mouseArtboard.y);
@@ -361,11 +365,13 @@ const { collector } = defineRenderer("add-buttons", {
361
365
  const cx = circlePositions[clickedCircle * 2];
362
366
  const cy = circlePositions[clickedCircle * 2 + 1];
363
367
  if (clickedCircle === 0 || clickedCircle === 1) {
364
- const position = clickedCircle === 0 ? "before" : "after";
365
- emit("toggle", {
366
- position,
367
- coordinates: { x: cx, y: cy }
368
- });
368
+ if (!selection.hasHostSelected.value) {
369
+ const position = clickedCircle === 0 ? "before" : "after";
370
+ emit("toggle", {
371
+ position,
372
+ coordinates: { x: cx, y: cy }
373
+ });
374
+ }
369
375
  } else {
370
376
  const fieldIndex = clickedCircle - 2;
371
377
  emit("toggleField", {
@@ -385,45 +391,53 @@ const { collector } = defineRenderer("add-buttons", {
385
391
  return;
386
392
  }
387
393
  circleVisible.fill(0);
388
- if (ctx.selectedUuids.length !== 1) {
394
+ const isHostSelected = selection.hasHostSelected.value;
395
+ if (ctx.selectedUuids.length !== 1 && !isHostSelected) {
389
396
  return;
390
397
  }
391
- const uuid = ctx.selectedUuids[0];
392
- if (!uuid) {
393
- return;
394
- }
395
- const blockState = getBlockState(uuid);
396
- const blockRect = dom.getBlockRect(uuid);
397
- if (!blockRect || blockRect.width === 0) {
398
- return;
399
- }
400
- const orientation = getOrientationForUuid(uuid);
401
- currentOrientation.value = orientation;
402
- if (blockState.canShowBeforeAfter) {
403
- const BUTTON_SHIFT = 2 / ctx.artboardScale;
404
- if (orientation === "horizontal") {
405
- circlePositions[0] = blockRect.x - BUTTON_SHIFT;
406
- circlePositions[1] = blockRect.y + blockRect.height / 2;
407
- circleVisible[0] = 1;
408
- circlePositions[2] = blockRect.x + blockRect.width + BUTTON_SHIFT;
409
- circlePositions[3] = blockRect.y + blockRect.height / 2;
410
- circleVisible[1] = 1;
411
- } else {
412
- circlePositions[0] = blockRect.x + blockRect.width / 2;
413
- circlePositions[1] = blockRect.y - BUTTON_SHIFT;
414
- circleVisible[0] = 1;
415
- circlePositions[2] = blockRect.x + blockRect.width / 2;
416
- circlePositions[3] = blockRect.y + blockRect.height + BUTTON_SHIFT;
417
- circleVisible[1] = 1;
398
+ let blockState = null;
399
+ let blockRect;
400
+ if (isHostSelected) {
401
+ } else {
402
+ const uuid = ctx.selectedUuids[0];
403
+ if (!uuid) {
404
+ return;
405
+ }
406
+ blockState = getBlockState(uuid);
407
+ blockRect = dom.getBlockRect(uuid);
408
+ if (!blockRect || blockRect.width === 0) {
409
+ return;
410
+ }
411
+ const orientation = getOrientationForUuid(uuid);
412
+ currentOrientation.value = orientation;
413
+ if (blockState.canShowBeforeAfter) {
414
+ const BUTTON_SHIFT = 2 / ctx.artboardScale;
415
+ if (orientation === "horizontal") {
416
+ circlePositions[0] = blockRect.x - BUTTON_SHIFT;
417
+ circlePositions[1] = blockRect.y + blockRect.height / 2;
418
+ circleVisible[0] = 1;
419
+ circlePositions[2] = blockRect.x + blockRect.width + BUTTON_SHIFT;
420
+ circlePositions[3] = blockRect.y + blockRect.height / 2;
421
+ circleVisible[1] = 1;
422
+ } else {
423
+ circlePositions[0] = blockRect.x + blockRect.width / 2;
424
+ circlePositions[1] = blockRect.y - BUTTON_SHIFT;
425
+ circleVisible[0] = 1;
426
+ circlePositions[2] = blockRect.x + blockRect.width / 2;
427
+ circlePositions[3] = blockRect.y + blockRect.height + BUTTON_SHIFT;
428
+ circleVisible[1] = 1;
429
+ }
418
430
  }
431
+ currentUuid.value = uuid;
432
+ currentBundleLabel.value = blockState.bundleLabel;
433
+ currentSingleAllowedBundleLabel.value = blockState.singleAllowedBundleLabel;
419
434
  }
420
- currentUuid.value = uuid;
421
- currentBundleLabel.value = blockState.bundleLabel;
422
- currentSingleAllowedBundleLabel.value = blockState.singleAllowedBundleLabel;
423
- if (blockState.emptyFieldKeys.length > 0) {
424
- emptyFieldTooltips.value = blockState.emptyFieldTooltips;
425
- for (let i = 0; i < blockState.emptyFieldKeys.length && i < 8; i++) {
426
- const fieldKey = blockState.emptyFieldKeys[i];
435
+ const emptyFieldKeys = isHostSelected ? props.hostEmptyFieldKeys : blockState?.emptyFieldKeys || [];
436
+ const emptyFieldTooltipsData = isHostSelected ? props.hostEmptyFieldTooltips : blockState?.emptyFieldTooltips || [];
437
+ if (emptyFieldKeys.length > 0) {
438
+ emptyFieldTooltips.value = emptyFieldTooltipsData;
439
+ for (let i = 0; i < emptyFieldKeys.length && i < 8; i++) {
440
+ const fieldKey = emptyFieldKeys[i];
427
441
  if (!fieldKey) {
428
442
  continue;
429
443
  }
@@ -433,15 +447,21 @@ const { collector } = defineRenderer("add-buttons", {
433
447
  }
434
448
  const initialX = fieldRect.x + fieldRect.width / 2;
435
449
  const initialY = fieldRect.y + fieldRect.height / 2;
436
- const adjusted = adjustEmptyFieldButtonPosition(
437
- initialX,
438
- initialY,
439
- blockRect,
440
- ctx.artboardScale
441
- );
450
+ let finalX = initialX;
451
+ let finalY = initialY;
452
+ if (blockRect) {
453
+ const adjusted = adjustEmptyFieldButtonPosition(
454
+ initialX,
455
+ initialY,
456
+ blockRect,
457
+ ctx.artboardScale
458
+ );
459
+ finalX = adjusted.x;
460
+ finalY = adjusted.y;
461
+ }
442
462
  const circleIndex = i + 2;
443
- circlePositions[circleIndex * 2] = adjusted.x;
444
- circlePositions[circleIndex * 2 + 1] = adjusted.y;
463
+ circlePositions[circleIndex * 2] = finalX;
464
+ circlePositions[circleIndex * 2 + 1] = finalY;
445
465
  circleVisible[circleIndex] = 1;
446
466
  }
447
467
  } else {
@@ -469,45 +489,53 @@ const { collector } = defineRenderer("add-buttons", {
469
489
  },
470
490
  renderFallback: (ctx, ctx2d) => {
471
491
  circleVisible.fill(0);
472
- if (ctx.selectedUuids.length !== 1) {
473
- return;
474
- }
475
- const uuid = ctx.selectedUuids[0];
476
- if (!uuid) {
492
+ const isHostSelected = selection.hasHostSelected.value;
493
+ if (ctx.selectedUuids.length !== 1 && !isHostSelected) {
477
494
  return;
478
495
  }
479
- const blockState = getBlockState(uuid);
480
- const blockRect = dom.getBlockRect(uuid);
481
- if (!blockRect || blockRect.width === 0) {
482
- return;
483
- }
484
- const orientation = getOrientationForUuid(uuid);
485
- currentOrientation.value = orientation;
486
- if (blockState.canShowBeforeAfter) {
487
- const BUTTON_SHIFT = 2 / ctx.artboardScale;
488
- if (orientation === "horizontal") {
489
- circlePositions[0] = blockRect.x - BUTTON_SHIFT;
490
- circlePositions[1] = blockRect.y + blockRect.height / 2;
491
- circleVisible[0] = 1;
492
- circlePositions[2] = blockRect.x + blockRect.width + BUTTON_SHIFT;
493
- circlePositions[3] = blockRect.y + blockRect.height / 2;
494
- circleVisible[1] = 1;
495
- } else {
496
- circlePositions[0] = blockRect.x + blockRect.width / 2;
497
- circlePositions[1] = blockRect.y - BUTTON_SHIFT;
498
- circleVisible[0] = 1;
499
- circlePositions[2] = blockRect.x + blockRect.width / 2;
500
- circlePositions[3] = blockRect.y + blockRect.height + BUTTON_SHIFT;
501
- circleVisible[1] = 1;
496
+ let blockState = null;
497
+ let blockRect;
498
+ if (isHostSelected) {
499
+ } else {
500
+ const uuid = ctx.selectedUuids[0];
501
+ if (!uuid) {
502
+ return;
503
+ }
504
+ blockState = getBlockState(uuid);
505
+ blockRect = dom.getBlockRect(uuid);
506
+ if (!blockRect || blockRect.width === 0) {
507
+ return;
508
+ }
509
+ const orientation = getOrientationForUuid(uuid);
510
+ currentOrientation.value = orientation;
511
+ if (blockState.canShowBeforeAfter) {
512
+ const BUTTON_SHIFT = 2 / ctx.artboardScale;
513
+ if (orientation === "horizontal") {
514
+ circlePositions[0] = blockRect.x - BUTTON_SHIFT;
515
+ circlePositions[1] = blockRect.y + blockRect.height / 2;
516
+ circleVisible[0] = 1;
517
+ circlePositions[2] = blockRect.x + blockRect.width + BUTTON_SHIFT;
518
+ circlePositions[3] = blockRect.y + blockRect.height / 2;
519
+ circleVisible[1] = 1;
520
+ } else {
521
+ circlePositions[0] = blockRect.x + blockRect.width / 2;
522
+ circlePositions[1] = blockRect.y - BUTTON_SHIFT;
523
+ circleVisible[0] = 1;
524
+ circlePositions[2] = blockRect.x + blockRect.width / 2;
525
+ circlePositions[3] = blockRect.y + blockRect.height + BUTTON_SHIFT;
526
+ circleVisible[1] = 1;
527
+ }
502
528
  }
529
+ currentUuid.value = uuid;
530
+ currentBundleLabel.value = blockState.bundleLabel;
531
+ currentSingleAllowedBundleLabel.value = blockState.singleAllowedBundleLabel;
503
532
  }
504
- currentUuid.value = uuid;
505
- currentBundleLabel.value = blockState.bundleLabel;
506
- currentSingleAllowedBundleLabel.value = blockState.singleAllowedBundleLabel;
507
- if (blockState.emptyFieldKeys.length > 0) {
508
- emptyFieldTooltips.value = blockState.emptyFieldTooltips;
509
- for (let i = 0; i < blockState.emptyFieldKeys.length && i < 8; i++) {
510
- const fieldKey = blockState.emptyFieldKeys[i];
533
+ const emptyFieldKeys = isHostSelected ? props.hostEmptyFieldKeys : blockState?.emptyFieldKeys || [];
534
+ const emptyFieldTooltipsData = isHostSelected ? props.hostEmptyFieldTooltips : blockState?.emptyFieldTooltips || [];
535
+ if (emptyFieldKeys.length > 0) {
536
+ emptyFieldTooltips.value = emptyFieldTooltipsData;
537
+ for (let i = 0; i < emptyFieldKeys.length && i < 8; i++) {
538
+ const fieldKey = emptyFieldKeys[i];
511
539
  if (!fieldKey) {
512
540
  continue;
513
541
  }
@@ -517,15 +545,21 @@ const { collector } = defineRenderer("add-buttons", {
517
545
  }
518
546
  const initialX = fieldRect.x + fieldRect.width / 2;
519
547
  const initialY = fieldRect.y + fieldRect.height / 2;
520
- const adjusted = adjustEmptyFieldButtonPosition(
521
- initialX,
522
- initialY,
523
- blockRect,
524
- ctx.artboardScale
525
- );
548
+ let finalX = initialX;
549
+ let finalY = initialY;
550
+ if (blockRect) {
551
+ const adjusted = adjustEmptyFieldButtonPosition(
552
+ initialX,
553
+ initialY,
554
+ blockRect,
555
+ ctx.artboardScale
556
+ );
557
+ finalX = adjusted.x;
558
+ finalY = adjusted.y;
559
+ }
526
560
  const circleIndex = i + 2;
527
- circlePositions[circleIndex * 2] = adjusted.x;
528
- circlePositions[circleIndex * 2 + 1] = adjusted.y;
561
+ circlePositions[circleIndex * 2] = finalX;
562
+ circlePositions[circleIndex * 2 + 1] = finalY;
529
563
  circleVisible[circleIndex] = 1;
530
564
  }
531
565
  } else {
@@ -1,6 +1,9 @@
1
1
  declare const _default: typeof __VLS_export;
2
2
  export default _default;
3
- declare const __VLS_export: import("vue").DefineComponent<{}, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {} & {
3
+ declare const __VLS_export: import("vue").DefineComponent<{
4
+ hostEmptyFieldKeys: string[];
5
+ hostEmptyFieldTooltips: string[];
6
+ }, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {} & {
4
7
  toggle: (data: {
5
8
  position: "before" | "after";
6
9
  coordinates: {
@@ -15,7 +18,10 @@ declare const __VLS_export: import("vue").DefineComponent<{}, {}, {}, {}, {}, im
15
18
  y: number;
16
19
  };
17
20
  }) => any;
18
- }, string, import("vue").PublicProps, Readonly<{}> & Readonly<{
21
+ }, string, import("vue").PublicProps, Readonly<{
22
+ hostEmptyFieldKeys: string[];
23
+ hostEmptyFieldTooltips: string[];
24
+ }> & Readonly<{
19
25
  onToggle?: ((data: {
20
26
  position: "before" | "after";
21
27
  coordinates: {
@@ -30,4 +36,4 @@ declare const __VLS_export: import("vue").DefineComponent<{}, {}, {}, {}, {}, im
30
36
  y: number;
31
37
  };
32
38
  }) => any) | undefined;
33
- }>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
39
+ }>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
@@ -19,6 +19,8 @@
19
19
  <Renderer
20
20
  v-if="!isLocked"
21
21
  :key="animation.renderKey.value"
22
+ :host-empty-field-keys="hostEmptyFieldKeys"
23
+ :host-empty-field-tooltips="hostFieldTooltips"
22
24
  @toggle="onRendererToggle"
23
25
  @toggle-field="onRendererToggleField"
24
26
  />
@@ -47,7 +49,7 @@ import { onBlokkliEvent } from "#blokkli/editor/composables";
47
49
  const props = defineProps({
48
50
  items: { type: Array, required: true }
49
51
  });
50
- const { dom, state, eventBus, types, $t, blocks, fields, animation } = useBlokkli();
52
+ const { dom, state, eventBus, types, $t, blocks, fields, animation, context, selection } = useBlokkli();
51
53
  const isLocked = ref(false);
52
54
  const shouldRender = computed(() => {
53
55
  return props.items.length === 1;
@@ -78,6 +80,20 @@ const emptyBlockFields = computed(() => {
78
80
  return v.count === 0;
79
81
  });
80
82
  });
83
+ const emptyHostFields = computed(() => {
84
+ return types.fieldConfig.forEntityTypeAndBundle(context.value.entityType, context.value.entityBundle).map((field) => {
85
+ const key = getFieldKey(context.value.entityUuid, field.name);
86
+ const count = state.getFieldBlockCount(key);
87
+ return {
88
+ key,
89
+ count,
90
+ name: field.name
91
+ };
92
+ }).filter((v) => v.count === 0);
93
+ });
94
+ const hostEmptyFieldKeys = computed(() => {
95
+ return emptyHostFields.value.map((v) => v.key);
96
+ });
81
97
  const containerStyle = ref({ visibility: "hidden" });
82
98
  const orientationClass = ref("");
83
99
  const containerRect = ref(null);
@@ -158,6 +174,26 @@ const fieldTooltips = computed(() => {
158
174
  ).replace("@parentBundle", bundleLabel.value).replace("@fieldLabel", fieldLabel);
159
175
  });
160
176
  });
177
+ const hostFieldTooltips = computed(() => {
178
+ return emptyHostFields.value.map((field) => {
179
+ const fieldConfig = types.fieldConfig.forEntityTypeAndBundle(context.value.entityType, context.value.entityBundle).find((f) => f.name === field.name);
180
+ const fieldLabel = fieldConfig?.label || field.name;
181
+ const fieldElement = fields.find(context.value.entityUuid, field.name);
182
+ if (fieldElement) {
183
+ const allowedBundles = fieldElement.allowedBundles.filter(
184
+ (bundle) => !isInternalBundle(bundle)
185
+ );
186
+ if (allowedBundles.length === 1) {
187
+ const bundle = allowedBundles[0];
188
+ if (bundle) {
189
+ const singleBundleLabel = types.getBlockBundleDefinition(bundle)?.label || bundle;
190
+ return $t("addButtonBundleToField", 'Add "@bundle" to @fieldLabel').replace("@bundle", singleBundleLabel).replace("@fieldLabel", fieldLabel);
191
+ }
192
+ }
193
+ }
194
+ return $t("addButtonToField", "Add to @fieldLabel...").replace("@fieldLabel", fieldLabel);
195
+ });
196
+ });
161
197
  watch(emptyBlockFields, (fields2) => {
162
198
  const neededCount = fields2.length;
163
199
  while (fieldButtonSlots.value.length < neededCount) {
@@ -377,18 +413,21 @@ function onRendererToggleField(data) {
377
413
  if (addData.value?.key === key) {
378
414
  return closeOverlay();
379
415
  }
380
- if (!uuid.value) {
416
+ const entityUuid = selection.hasHostSelected.value ? context.value.entityUuid : uuid.value;
417
+ if (!entityUuid) {
381
418
  return;
382
419
  }
383
- const emptyField = emptyBlockFields.value[data.index];
420
+ const emptyFields = selection.hasHostSelected.value ? emptyHostFields.value : emptyBlockFields.value;
421
+ const tooltips = selection.hasHostSelected.value ? hostFieldTooltips.value : fieldTooltips.value;
422
+ const emptyField = emptyFields[data.index];
384
423
  if (!emptyField) {
385
424
  return;
386
425
  }
387
- const field = fields.find(uuid.value, emptyField.name);
426
+ const field = fields.find(entityUuid, emptyField.name);
388
427
  if (!field) {
389
428
  return;
390
429
  }
391
- const label = (fieldTooltips.value[data.index] || "").replace("...", "");
430
+ const label = (tooltips[data.index] || "").replace("...", "");
392
431
  setAddData(key, field, label, null, void 0, data.coordinates);
393
432
  }
394
433
  onBlokkliEvent("dragging:start", closeOverlay);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@blokkli/editor",
3
- "version": "2.0.0-alpha.29",
3
+ "version": "2.0.0-alpha.30",
4
4
  "description": "Interactive page building experience for Nuxt",
5
5
  "keywords": [
6
6
  "cms",