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

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 (106) hide show
  1. package/dist/module.json +1 -1
  2. package/dist/module.mjs +265 -83
  3. package/dist/modules/drupal/graphql/base/fragment.blokkliProps.graphql +1 -1
  4. package/dist/modules/drupal/graphql/features/comments.graphql +11 -8
  5. package/dist/modules/drupal/runtime/adapter/index.js +2 -2
  6. package/dist/runtime/blokkliPlugins/ItemAction/index.vue +1 -3
  7. package/dist/runtime/components/Blocks/FromLibrary/index.vue +4 -2
  8. package/dist/runtime/components/BlokkliEditable.vue +22 -4
  9. package/dist/runtime/components/BlokkliProvider.vue +29 -20
  10. package/dist/runtime/components/BlokkliProvider.vue.d.ts +2 -1
  11. package/dist/runtime/components/Edit/Actions/index.vue +9 -4
  12. package/dist/runtime/components/Edit/AnimationCanvas/index.vue +420 -25
  13. package/dist/runtime/components/Edit/ArtboardTooltip/index.vue +80 -0
  14. package/dist/runtime/components/Edit/ArtboardTooltip/index.vue.d.ts +32 -0
  15. package/dist/runtime/components/Edit/Banner/index.vue +51 -0
  16. package/dist/runtime/components/Edit/Banner/index.vue.d.ts +18 -0
  17. package/dist/runtime/components/Edit/EditIndicator.vue +118 -44
  18. package/dist/runtime/components/Edit/EditIndicator.vue.d.ts +3 -0
  19. package/dist/runtime/components/Edit/EditProvider.vue +79 -22
  20. package/dist/runtime/components/Edit/EditProvider.vue.d.ts +2 -0
  21. package/dist/runtime/components/Edit/Features/Analyze/Overlay/index.vue +19 -20
  22. package/dist/runtime/components/Edit/Features/BlockAddList/index.vue +1 -1
  23. package/dist/runtime/components/Edit/Features/CommandPalette/index.vue +2 -0
  24. package/dist/runtime/components/Edit/Features/Comments/AddForm/index.vue +35 -20
  25. package/dist/runtime/components/Edit/Features/Comments/AddForm/index.vue.d.ts +5 -3
  26. package/dist/runtime/components/Edit/Features/Comments/CommentInput/index.vue +29 -0
  27. package/dist/runtime/components/Edit/Features/Comments/CommentInput/index.vue.d.ts +13 -0
  28. package/dist/runtime/components/Edit/Features/Comments/Overlay/Item/index.vue +22 -16
  29. package/dist/runtime/components/Edit/Features/Comments/Overlay/Item/index.vue.d.ts +1 -0
  30. package/dist/runtime/components/Edit/Features/Comments/Overlay/index.vue +15 -6
  31. package/dist/runtime/components/Edit/Features/Comments/index.vue +20 -8
  32. package/dist/runtime/components/Edit/Features/Debug/Rects/index.vue +26 -35
  33. package/dist/runtime/components/Edit/Features/Debug/Renderer.vue +240 -0
  34. package/dist/runtime/components/Edit/Features/Debug/Renderer.vue.d.ts +6 -0
  35. package/dist/runtime/components/Edit/Features/Debug/index.vue +4 -165
  36. package/dist/runtime/components/Edit/Features/DraggingOverlay/DragItems/index.vue +1 -1
  37. package/dist/runtime/components/Edit/Features/DraggingOverlay/DropTargets/index.vue +41 -37
  38. package/dist/runtime/components/Edit/Features/Edit/index.vue +1 -1
  39. package/dist/runtime/components/Edit/Features/EditableField/Overlay/Frame/index.vue +63 -3
  40. package/dist/runtime/components/Edit/Features/EditableField/Overlay/Plaintext/index.vue +13 -9
  41. package/dist/runtime/components/Edit/Features/EditableField/Overlay/index.vue +17 -76
  42. package/dist/runtime/components/Edit/Features/EditableField/index.vue +1 -1
  43. package/dist/runtime/components/Edit/Features/History/index.vue +5 -2
  44. package/dist/runtime/components/Edit/Features/Hover/Overlay/fragment.glsl +139 -0
  45. package/dist/runtime/components/Edit/Features/Hover/Overlay/index.vue +270 -0
  46. package/dist/runtime/components/Edit/Features/Hover/Overlay/index.vue.d.ts +6 -0
  47. package/dist/runtime/components/Edit/Features/Hover/Overlay/vertex.glsl +117 -0
  48. package/dist/runtime/components/Edit/Features/Hover/index.vue +25 -0
  49. package/dist/runtime/components/Edit/Features/Library/LibraryDialog/index.vue +19 -27
  50. package/dist/runtime/components/Edit/Features/Library/ReusableDialog/index.vue +27 -23
  51. package/dist/runtime/components/Edit/Features/Library/index.vue +2 -1
  52. package/dist/runtime/components/Edit/Features/MultiSelect/Overlay/index.vue +34 -27
  53. package/dist/runtime/components/Edit/Features/MultiSelect/index.vue +2 -4
  54. package/dist/runtime/components/Edit/Features/Options/Form/Item.vue +6 -1
  55. package/dist/runtime/components/Edit/Features/Options/Form/index.vue +1 -0
  56. package/dist/runtime/components/Edit/Features/Ownership/Renderer.vue +35 -0
  57. package/dist/runtime/components/Edit/Features/Ownership/Renderer.vue.d.ts +6 -0
  58. package/dist/runtime/components/Edit/Features/Ownership/index.vue +7 -25
  59. package/dist/runtime/components/Edit/Features/ProxyView/index.vue +5 -1
  60. package/dist/runtime/components/Edit/Features/Selection/AddButtons/Overlay/index.vue +39 -74
  61. package/dist/runtime/components/Edit/Features/Selection/AddButtons/Overlay/index.vue.d.ts +4 -2
  62. package/dist/runtime/components/Edit/Features/Selection/AddButtons/Renderer/fragment.glsl +106 -0
  63. package/dist/runtime/components/Edit/Features/Selection/AddButtons/Renderer/index.vue +417 -0
  64. package/dist/runtime/components/Edit/Features/Selection/AddButtons/Renderer/index.vue.d.ts +32 -0
  65. package/dist/runtime/components/Edit/Features/Selection/AddButtons/Renderer/vertex.glsl +102 -0
  66. package/dist/runtime/components/Edit/Features/Selection/AddButtons/index.vue +33 -106
  67. package/dist/runtime/components/Edit/Features/Selection/Overlay/index.vue +88 -29
  68. package/dist/runtime/components/Edit/Features/Selection/Overlay/index.vue.d.ts +2 -0
  69. package/dist/runtime/components/Edit/Features/Selection/Overlay/vertex.glsl +11 -2
  70. package/dist/runtime/components/Edit/Features/Selection/index.vue +5 -12
  71. package/dist/runtime/components/Edit/Features/Translations/Banner/index.vue +17 -11
  72. package/dist/runtime/components/Edit/Features/Translations/index.vue +13 -16
  73. package/dist/runtime/components/Edit/Form/Text/index.vue +2 -1
  74. package/dist/runtime/components/Edit/Form/Text/index.vue.d.ts +1 -0
  75. package/dist/runtime/components/Edit/Indicators/index.vue +1 -1
  76. package/dist/runtime/components/Edit/Konami/Game/index.vue +5 -5
  77. package/dist/runtime/components/Edit/index.d.ts +5 -3
  78. package/dist/runtime/components/Edit/index.js +8 -4
  79. package/dist/runtime/composables/defineBlokkli.js +4 -2
  80. package/dist/runtime/css/output.css +1 -1
  81. package/dist/runtime/helpers/animationProvider.d.ts +34 -1
  82. package/dist/runtime/helpers/animationProvider.js +175 -48
  83. package/dist/runtime/helpers/composables/defineRenderer.d.ts +8 -0
  84. package/dist/runtime/helpers/composables/defineRenderer.js +8 -0
  85. package/dist/runtime/helpers/composables/useStickyToolbar.d.ts +4 -1
  86. package/dist/runtime/helpers/composables/useStickyToolbar.js +53 -35
  87. package/dist/runtime/helpers/dom/index.d.ts +1 -0
  88. package/dist/runtime/helpers/domProvider.d.ts +46 -0
  89. package/dist/runtime/helpers/domProvider.js +95 -6
  90. package/dist/runtime/helpers/editableProvider.d.ts +14 -0
  91. package/dist/runtime/helpers/editableProvider.js +144 -0
  92. package/dist/runtime/helpers/stateProvider.d.ts +6 -2
  93. package/dist/runtime/helpers/stateProvider.js +66 -3
  94. package/dist/runtime/helpers/storageProvider.d.ts +3 -2
  95. package/dist/runtime/helpers/storageProvider.js +6 -2
  96. package/dist/runtime/helpers/symbols.d.ts +1 -0
  97. package/dist/runtime/helpers/symbols.js +1 -0
  98. package/dist/runtime/helpers/uiProvider.d.ts +8 -1
  99. package/dist/runtime/helpers/uiProvider.js +34 -2
  100. package/dist/runtime/plugins/blokkliEditable.js +74 -3
  101. package/dist/runtime/types/index.d.ts +13 -1
  102. package/package.json +1 -1
  103. package/dist/runtime/components/Edit/DragInteractions/index.vue +0 -401
  104. package/dist/runtime/components/Edit/Features/Selection/AddButtons/AddButtonsField.vue +0 -54
  105. package/dist/runtime/components/Edit/Features/Selection/AddButtons/AddButtonsField.vue.d.ts +0 -14
  106. /package/dist/runtime/components/Edit/{DragInteractions → Features/Hover}/index.vue.d.ts +0 -0
@@ -1,185 +1,24 @@
1
1
  <template>
2
- <PluginSidebar
3
- v-if="debug.isEnabled.value"
4
- id="debug"
5
- title="Debug"
6
- icon="bug"
7
- weight="200"
8
- >
9
- <div class="bk bk-debug">
10
- <section>
11
- <h2>Keyboard</h2>
12
- <div class="bk-debug-list">
13
- <div>
14
- <div>Space</div>
15
- <div>{{ keyboard.isPressingSpace.value }}</div>
16
- </div>
17
- <div>
18
- <div>Control</div>
19
- <div>{{ keyboard.isPressingControl.value }}</div>
20
- </div>
21
- </div>
22
- </section>
23
-
24
- <section>
25
- <h2>Selection</h2>
26
- <div class="bk-debug-list">
27
- <div>
28
- <div>Count</div>
29
- <div>{{ selection.uuids.value.length }}</div>
30
- </div>
31
- <div>
32
- <div>isDragging</div>
33
- <div>{{ selection.isDragging.value }}</div>
34
- </div>
35
- <div>
36
- <div>isDraggingExisting</div>
37
- <div>{{ selection.isDraggingExisting.value }}</div>
38
- </div>
39
- <div>
40
- <div>Is multiselecting</div>
41
- <div>{{ selection.isMultiSelecting.value }}</div>
42
- </div>
43
- </div>
44
- </section>
45
-
46
- <section>
47
- <h2>Rendering</h2>
48
- <div class="bk-debug-list">
49
- <div v-for="overlay in debug.overlays.value" :key="overlay.id">
50
- <FormToggle
51
- :label="overlay.label"
52
- :model-value="overlay.active"
53
- @update:model-value="debug.toggleOverlay(overlay.id)"
54
- />
55
- </div>
56
- <div>
57
- <FormToggle
58
- label="Set transforming"
59
- :model-value="ui.isTransforming.value"
60
- @update:model-value="toggleTransforming"
61
- />
62
- </div>
63
-
64
- <div>
65
- <FormToggle
66
- label="Enable WebGL"
67
- :model-value="animation.webglEnabled.value"
68
- @update:model-value="toggleWebgl"
69
- />
70
- </div>
71
- </div>
72
- </section>
73
-
74
- <section>
75
- <h2>Icons</h2>
76
- <div class="bk-debug-icons">
77
- <div v-for="icon in iconItems" :key="icon">
78
- <Icon :name="icon" />
79
- <p>{{ icon }}</p>
80
- </div>
81
- </div>
82
- </section>
83
-
84
- <section>
85
- <h2>Features</h2>
86
- <div class="bk-debug-features">
87
- <div v-for="feature in featuresList" :key="feature.id">
88
- <div>
89
- <span
90
- class="bk-status-indicator"
91
- :class="feature.mounted ? 'bk-is-success' : 'bk-is-danger'"
92
- />
93
- </div>
94
- <div>
95
- <h3>{{ feature.label }}</h3>
96
- <div>{{ feature.id }}</div>
97
- <p>{{ feature.description }}</p>
98
- </div>
99
- </div>
100
- </div>
101
- </section>
102
- </div>
103
- </PluginSidebar>
104
-
105
- <PluginDebugOverlay id="viewport" title="Show viewport overlay">
106
- <DebugViewport />
107
- </PluginDebugOverlay>
108
-
109
- <PluginDebugOverlay id="rects" title="Show field and block rects">
110
- <DebugRects />
111
- </PluginDebugOverlay>
2
+ <Renderer v-if="debug.isEnabled.value" :logger />
112
3
  </template>
113
4
 
114
5
  <script setup>
115
- import {
116
- useBlokkli,
117
- onMounted,
118
- onBeforeUnmount,
119
- defineBlokkliFeature,
120
- computed
121
- } from "#imports";
122
- import { PluginSidebar, PluginDebugOverlay } from "#blokkli/plugins";
123
- import { Icon, FormToggle } from "#blokkli/components";
124
- import { icons } from "#blokkli-build/icons";
125
6
  import onBlokkliEvent from "#blokkli/helpers/composables/onBlokkliEvent";
126
- import DebugViewport from "./Viewport/index.vue";
127
- import DebugRects from "./Rects/index.vue";
7
+ import { defineBlokkliFeature, useBlokkli } from "#imports";
8
+ import Renderer from "./Renderer.vue";
128
9
  const { logger } = defineBlokkliFeature({
129
10
  id: "debug",
130
11
  label: "Debug",
131
12
  icon: "bug",
132
13
  description: "Provides debugging functionality."
133
14
  });
134
- const { keyboard, selection, eventBus, features, debug, ui, animation } = useBlokkli();
135
- const iconItems = computed(() => Object.keys(icons));
136
- const featuresList = computed(() => {
137
- return features.features.value.map((v) => {
138
- const feature = features.mountedFeatures.value.find((f) => f.id === v.id);
139
- return {
140
- id: v.id,
141
- label: v.label,
142
- description: v.description,
143
- dependencies: v.dependencies?.join(", "),
144
- mounted: !!feature
145
- };
146
- });
147
- });
15
+ const { debug } = useBlokkli();
148
16
  onBlokkliEvent("keyPressed", (e) => {
149
17
  if (e.code === "=" && e.meta) {
150
18
  e.originalEvent.preventDefault();
151
19
  debug.toggle();
152
20
  }
153
21
  });
154
- const onEvent = (name, data) => {
155
- if (!debug.isEnabled.value) {
156
- return;
157
- }
158
- if (name === "animationFrame" || name === "animationFrame:before" || name === "canvas:draw") {
159
- return;
160
- }
161
- logger.log("Event: " + String(name), data);
162
- };
163
- function toggleTransforming() {
164
- if (ui.isTransforming.value) {
165
- ui.setTransform();
166
- } else {
167
- ui.setTransform("Transform plugin label");
168
- }
169
- }
170
- function toggleWebgl() {
171
- if (animation.webglEnabled.value) {
172
- animation.webglEnabled.value = false;
173
- } else {
174
- animation.webglEnabled.value = true;
175
- }
176
- }
177
- onMounted(() => {
178
- eventBus.on("*", onEvent);
179
- });
180
- onBeforeUnmount(() => {
181
- eventBus.off("*", onEvent);
182
- });
183
22
  </script>
184
23
 
185
24
  <script>
@@ -7,7 +7,7 @@
7
7
  <BlokkliTransition name="drag-item">
8
8
  <div
9
9
  v-show="activeLabel"
10
- class="bk-dragging-overlay-label"
10
+ class="bk bk-dragging-overlay-label"
11
11
  :style="{ backgroundColor: currentActiveColor }"
12
12
  >
13
13
  <Icon name="cursor-move" />
@@ -14,6 +14,7 @@ import {
14
14
  toShaderColor
15
15
  } from "#blokkli/helpers";
16
16
  import onBlokkliEvent from "#blokkli/helpers/composables/onBlokkliEvent";
17
+ import defineRenderer from "#blokkli/helpers/composables/defineRenderer";
17
18
  import { ref, computed, useBlokkli, onBeforeUnmount } from "#imports";
18
19
  import {
19
20
  setBuffersAndAttributes,
@@ -626,6 +627,8 @@ function setHoveredFieldArea(box, mouse) {
626
627
  activeHoverField.value = candidate;
627
628
  }
628
629
  }
630
+ let bufferInfo = null;
631
+ let bufferChanged = false;
629
632
  onBlokkliEvent("canvas:draw", () => {
630
633
  const scale = ui.artboardScale.value;
631
634
  const offset = { ...ui.artboardOffset.value };
@@ -636,11 +639,9 @@ onBlokkliEvent("canvas:draw", () => {
636
639
  height: props.box.height / scale
637
640
  };
638
641
  const mouseAbsolute = toCanvasSpaceCoordinates(props.mouseX, props.mouseY);
639
- if (gl && programInfo) {
640
- gl.useProgram(programInfo.program);
641
- animation.setSharedUniforms(gl, programInfo);
642
- }
643
- const { info, hasChanged } = collector.getBufferInfo();
642
+ const result = collector.getBufferInfo();
643
+ bufferInfo = result.info;
644
+ bufferChanged = result.hasChanged;
644
645
  if (!props.isTouch) {
645
646
  if (cursorIsInsideClipped()) {
646
647
  const closest = collector.getClosestIntersectingRect(
@@ -652,43 +653,46 @@ onBlokkliEvent("canvas:draw", () => {
652
653
  active.value = null;
653
654
  }
654
655
  }
655
- if (programInfo && gl) {
656
- setHoveredFieldArea(dragBox.value, mouseAbsolute);
657
- setUniforms(programInfo, uniforms.value);
658
- if (info) {
659
- if (hasChanged && gl && programInfo) {
660
- setBuffersAndAttributes(gl, programInfo, info);
661
- }
662
- if (gl) {
663
- drawBufferInfo(gl, info, gl.TRIANGLES);
656
+ setHoveredFieldArea(dragBox.value, mouseAbsolute);
657
+ if (!gl && ctx) {
658
+ ctx.clearRect(0, 0, canvas.width, canvas.height);
659
+ const rects = Object.values(collector.rects);
660
+ for (let i = 0; i < rects.length; i++) {
661
+ const rect = rects[i];
662
+ if (active.value?.id === rect.id) {
663
+ ctx.fillStyle = rect.color;
664
+ } else {
665
+ ctx.fillStyle = rect.colorAlpha;
664
666
  }
667
+ ctx.fillRect(
668
+ (rect.x * scale + offset.x) * animation.dpi.value,
669
+ (rect.y * scale + offset.y) * animation.dpi.value,
670
+ rect.width * animation.dpi.value * scale,
671
+ rect.height * animation.dpi.value * scale
672
+ );
665
673
  }
666
- return;
667
- }
668
- if (!ctx) {
669
- return;
670
- }
671
- ctx.clearRect(0, 0, canvas.width, canvas.height);
672
- const rects = Object.values(collector.rects);
673
- for (let i = 0; i < rects.length; i++) {
674
- const rect = rects[i];
675
- if (active.value?.id === rect.id) {
676
- ctx.fillStyle = rect.color;
677
- } else {
678
- ctx.fillStyle = rect.colorAlpha;
679
- }
680
- ctx.fillRect(
681
- (rect.x * scale + offset.x) * animation.dpi.value,
682
- (rect.y * scale + offset.y) * animation.dpi.value,
683
- rect.width * animation.dpi.value * scale,
684
- rect.height * animation.dpi.value * scale
685
- );
686
674
  }
687
675
  });
676
+ if (gl && programInfo) {
677
+ defineRenderer("drop-targets", {
678
+ zIndex: 400,
679
+ only: true,
680
+ cursor: () => "grabbing",
681
+ render: () => {
682
+ gl.useProgram(programInfo.program);
683
+ animation.setSharedUniforms(gl, programInfo);
684
+ setUniforms(programInfo, uniforms.value);
685
+ if (!bufferInfo) {
686
+ return;
687
+ }
688
+ if (bufferChanged) {
689
+ setBuffersAndAttributes(gl, programInfo, bufferInfo);
690
+ }
691
+ drawBufferInfo(gl, bufferInfo, gl.TRIANGLES);
692
+ }
693
+ });
694
+ }
688
695
  onBeforeUnmount(() => {
689
- if (gl) {
690
- gl.clear(gl.COLOR_BUFFER_BIT);
691
- }
692
696
  if (ctx) {
693
697
  ctx.clearRect(0, 0, canvas.width, canvas.height);
694
698
  }
@@ -2,7 +2,7 @@
2
2
  <PluginItemAction
3
3
  v-if="isEditing"
4
4
  id="edit"
5
- :title="$t('edit', 'Edit')"
5
+ :title="$t('edit', 'Edit...')"
6
6
  :disabled="!canEdit"
7
7
  meta
8
8
  key-code="E"
@@ -4,13 +4,23 @@
4
4
  ref="iframe"
5
5
  :style="{ height: Math.max(height, 150) + 'px' }"
6
6
  :src="url"
7
+ @load="onIframeLoad"
7
8
  />
8
9
  </div>
9
10
  </template>
10
11
 
11
12
  <script setup>
12
- import { useBlokkli, ref, computed, onMounted, onBeforeUnmount } from "#imports";
13
- const { adapter } = useBlokkli();
13
+ import {
14
+ useBlokkli,
15
+ ref,
16
+ computed,
17
+ onMounted,
18
+ onBeforeUnmount,
19
+ useTemplateRef
20
+ } from "#imports";
21
+ const { adapter, ui } = useBlokkli();
22
+ const PROPAGATE_WHEEL = false;
23
+ const rootElement = ui.rootElement();
14
24
  const props = defineProps({
15
25
  modelValue: { type: String, required: true },
16
26
  type: { type: String, required: true },
@@ -18,6 +28,56 @@ const props = defineProps({
18
28
  host: { type: Object, required: true },
19
29
  initialHeight: { type: Number, required: true }
20
30
  });
31
+ const iframe = useTemplateRef("iframe");
32
+ function onIframeLoad() {
33
+ if (!iframe.value || !PROPAGATE_WHEEL) {
34
+ return;
35
+ }
36
+ const iframeDoc = iframe.value.contentDocument;
37
+ if (!iframeDoc) {
38
+ return;
39
+ }
40
+ let ckEditor = null;
41
+ iframe.value.contentDocument.addEventListener("wheel", (e) => {
42
+ if (!ckEditor) {
43
+ const el = iframeDoc.querySelector(".ck-editor__editable");
44
+ if (el) {
45
+ ckEditor = el;
46
+ }
47
+ }
48
+ if (!ckEditor) {
49
+ return;
50
+ }
51
+ const scrollTop = ckEditor.scrollTop;
52
+ const scrollHeight = ckEditor.scrollHeight;
53
+ const clientHeight = ckEditor.clientHeight;
54
+ const isScrolledToTop = scrollTop === 0;
55
+ const isScrolledToBottom = scrollTop + clientHeight >= scrollHeight - 1;
56
+ const isScrollingDown = e.deltaY > 0;
57
+ const isScrollingUp = e.deltaY < 0;
58
+ const shouldPropagate = isScrollingUp && isScrolledToTop || isScrollingDown && isScrolledToBottom;
59
+ if (!shouldPropagate) {
60
+ return;
61
+ }
62
+ const wheelEvent = new WheelEvent("wheel", {
63
+ deltaX: e.deltaX,
64
+ deltaY: e.deltaY,
65
+ deltaZ: e.deltaZ,
66
+ deltaMode: e.deltaMode,
67
+ clientX: e.clientX,
68
+ clientY: e.clientY,
69
+ screenX: e.screenX,
70
+ screenY: e.screenY,
71
+ bubbles: true,
72
+ cancelable: true,
73
+ ctrlKey: e.ctrlKey,
74
+ shiftKey: e.shiftKey,
75
+ altKey: e.altKey,
76
+ metaKey: e.metaKey
77
+ });
78
+ rootElement?.dispatchEvent(wheelEvent);
79
+ });
80
+ }
21
81
  const height = ref(props.initialHeight);
22
82
  const url = computed(() => {
23
83
  if ("itemBundle" in props.host) {
@@ -43,7 +103,7 @@ const onMessage = (e) => {
43
103
  };
44
104
  onMounted(() => {
45
105
  original.value = props.modelValue;
46
- height.value = props.initialHeight + 48;
106
+ height.value = props.initialHeight;
47
107
  window.addEventListener("message", onMessage);
48
108
  });
49
109
  onBeforeUnmount(() => {
@@ -1,11 +1,16 @@
1
1
  <template>
2
- <div class="bk bk-editable-field-textarea">
2
+ <div
3
+ class="bk bk-editable-field-textarea"
4
+ :style="{
5
+ height: height + 'px'
6
+ }"
7
+ >
3
8
  <textarea
9
+ id="bk-editable-field-textarea"
4
10
  ref="input"
5
11
  :value="modelValue"
6
12
  enterkeyhint="done"
7
13
  rows="2"
8
- :style="inputStyle"
9
14
  v-bind="inputAttributes"
10
15
  @keydown.stop.capture="onKeyDown"
11
16
  @blur="onBlur"
@@ -13,12 +18,12 @@
13
18
  $emit('update:modelValue', $event.target.value)
14
19
  "
15
20
  />
16
- <div :style="inputStyle" class="bk-textarea" v-html="modelValue" />
17
21
  </div>
18
22
  </template>
19
23
 
20
24
  <script setup>
21
- import { useBlokkli, computed } from "#imports";
25
+ import onBlokkliEvent from "#blokkli/helpers/composables/onBlokkliEvent";
26
+ import { useBlokkli, computed, useTemplateRef, ref } from "#imports";
22
27
  const { ui, selection } = useBlokkli();
23
28
  const props = defineProps({
24
29
  element: { type: null, required: true },
@@ -27,6 +32,8 @@ const props = defineProps({
27
32
  modelValue: { type: String, required: true }
28
33
  });
29
34
  const emit = defineEmits(["close", "save", "update:modelValue"]);
35
+ const input = useTemplateRef("input");
36
+ const height = ref(20);
30
37
  const onKeyDown = (e) => {
31
38
  if (e.code === "Escape") {
32
39
  e.preventDefault();
@@ -61,10 +68,7 @@ const onBlur = (e) => {
61
68
  emit("save");
62
69
  }, 100);
63
70
  };
64
- const inputStyle = computed(() => {
65
- const computedStyle = window.getComputedStyle(props.element);
66
- return {
67
- textAlign: computedStyle.textAlign
68
- };
71
+ onBlokkliEvent("animationFrame", () => {
72
+ height.value = Math.max(input.value?.scrollHeight ?? 20, 20);
69
73
  });
70
74
  </script>
@@ -1,26 +1,15 @@
1
1
  <template>
2
- <div
2
+ <ArtboardTooltip
3
3
  v-if="loaded"
4
- ref="root"
5
- :style="style"
6
- class="bk-editable-field bk-control"
4
+ id="editable"
5
+ :title
6
+ :anchor-el="element"
7
+ placement-y="top"
8
+ class="bk-editable-field"
9
+ close-icon="check"
10
+ @close="save"
7
11
  >
8
12
  <form ref="form" class="bk-editable-field-input" @submit.prevent="close">
9
- <div class="bk bk-editable-field-buttons">
10
- <h3>
11
- <ItemIcon :bundle="itemBundle" />
12
- <span>{{ title }}</span>
13
- </h3>
14
- <button @click.prevent="cancel">
15
- <Icon name="close" />
16
- <span>{{ $t("cancel", "Cancel") }}</span>
17
- </button>
18
- <button :disabled="!hasChanged" type="submit" @click.prevent="save">
19
- <Icon name="save" />
20
- <span>{{ $t("save", "Save") }}</span>
21
- </button>
22
- </div>
23
-
24
13
  <div ref="input">
25
14
  <InputContenteditable
26
15
  v-if="config.type === 'markup'"
@@ -50,21 +39,24 @@
50
39
  />
51
40
  </div>
52
41
 
53
- <div v-if="!isMarkup" class="bk bk-editable-field-info">
42
+ <div class="bk bk-editable-field-info">
43
+ <button :disabled="!hasChanged" @click.prevent="cancel">
44
+ {{ $t("editableFieldDiscard", "Discard") }}
45
+ </button>
54
46
  <div v-if="errorText" class="bk-editable-field-info-error">
55
47
  {{ errorText }}
56
48
  </div>
57
- <div class="bk-editable-field-info-count">
49
+ <div v-if="!isMarkup" class="bk-editable-field-info-count">
58
50
  <span>{{ count }}</span>
59
51
  <span v-if="maxlength >= 1">&nbsp;/&nbsp;{{ maxlength }}</span>
60
52
  </div>
61
53
  </div>
62
54
  </form>
63
- </div>
55
+ </ArtboardTooltip>
64
56
  </template>
65
57
 
66
58
  <script setup>
67
- import { Icon, ItemIcon } from "#blokkli/components";
59
+ import { ArtboardTooltip } from "#blokkli/components";
68
60
  import {
69
61
  computed,
70
62
  ref,
@@ -74,12 +66,12 @@ import {
74
66
  useBlokkli,
75
67
  nextTick
76
68
  } from "#imports";
77
- import { falsy, findIdealRectPosition } from "#blokkli/helpers";
69
+ import { falsy } from "#blokkli/helpers";
78
70
  import InputPlaintext from "./Plaintext/index.vue";
79
71
  import InputContenteditable from "./Contenteditable/index.vue";
80
72
  import InputFrame from "./Frame/index.vue";
81
73
  import onBlokkliEvent from "#blokkli/helpers/composables/onBlokkliEvent";
82
- const { eventBus, ui, selection, state, adapter, $t, types } = useBlokkli();
74
+ const { eventBus, selection, state, adapter, $t, types } = useBlokkli();
83
75
  const props = defineProps({
84
76
  fieldName: { type: String, required: true },
85
77
  host: { type: Object, required: true },
@@ -102,41 +94,13 @@ const save = () => {
102
94
  };
103
95
  onBlokkliEvent("window:clickAway", save);
104
96
  const getElement = () => props.element;
105
- const alignment = computed(() => {
106
- if (props.element) {
107
- const style2 = window.getComputedStyle(props.element);
108
- if (style2.textAlign === "left" || style2.textAlign === "center" || style2.textAlign === "right") {
109
- return style2.textAlign;
110
- } else if (style2.textAlign === "start") {
111
- return "left";
112
- } else if (style2.textAlign === "end") {
113
- return "right";
114
- }
115
- }
116
- return "center";
117
- });
118
97
  const scrollHeight = ref(0);
119
98
  const loaded = ref(false);
120
99
  const originalText = ref(props.value || "");
121
100
  const modelValue = ref("");
122
- const width = ref(320);
123
101
  const inputStyle = ref({});
124
102
  const form = ref(null);
125
- const root = ref(null);
126
103
  const input = ref(null);
127
- const x = ref(0);
128
- const y = ref(0);
129
- const style = computed(() => {
130
- if (ui.isMobile.value) {
131
- return {};
132
- } else {
133
- return {
134
- width: width.value + "px",
135
- top: y.value + "px",
136
- left: x.value + "px"
137
- };
138
- }
139
- });
140
104
  const hasChanged = computed(() => modelValue.value !== originalText.value);
141
105
  const itemBundle = computed(() => {
142
106
  if ("itemBundle" in props.host) {
@@ -238,29 +202,6 @@ const focusInput = (el) => {
238
202
  focusInput(iframe.contentDocument);
239
203
  }
240
204
  };
241
- const onAnimationFrame = () => {
242
- if (ui.isMobile.value) {
243
- return;
244
- }
245
- const elementRect = props.element.getBoundingClientRect();
246
- const height = form.value?.scrollHeight || 100;
247
- const newWidth = Math.min(Math.max(elementRect.width, 360), 1e3);
248
- const ideal = findIdealRectPosition(
249
- ui.viewportBlockingRects.value,
250
- {
251
- x: alignment.value === "left" ? elementRect.x : elementRect.x + (Math.max(elementRect.width, 360) - newWidth) / 2,
252
- y: elementRect.y - height - 20,
253
- height,
254
- width: newWidth
255
- },
256
- ui.visibleViewportPadded.value
257
- );
258
- x.value = ideal.x;
259
- y.value = ideal.y + height;
260
- width.value = newWidth;
261
- };
262
- onAnimationFrame();
263
- onBlokkliEvent("animationFrame", onAnimationFrame);
264
205
  onMounted(() => {
265
206
  const el = getElement();
266
207
  if (props.isComponent) {
@@ -1,6 +1,6 @@
1
1
  <template>
2
2
  <Teleport to="body">
3
- <BlokkliTransition name="editable" :enabled="hasTransition">
3
+ <BlokkliTransition name="caret-tooltip" :enabled="hasTransition">
4
4
  <Overlay v-if="editable" v-bind="editable" :key="key" @close="close" />
5
5
  </BlokkliTransition>
6
6
  </Teleport>
@@ -3,6 +3,7 @@
3
3
  id="history"
4
4
  v-slot="{ scrolledToEnd }"
5
5
  :title="$t('history', 'History')"
6
+ edit-only
6
7
  :tour-text="
7
8
  $t(
8
9
  'historyTourText',
@@ -74,9 +75,11 @@ const { state, $t, ui, selection, eventBus } = useBlokkli();
74
75
  const { mutations, currentMutationIndex, mutateWithLoadingState } = state;
75
76
  const mutationsCount = computed(() => mutations.value.length);
76
77
  const useMouseForHistory = computed(() => settings.value.useMouseButtons);
77
- const canUndo = computed(() => currentMutationIndex.value >= 0);
78
+ const canUndo = computed(
79
+ () => currentMutationIndex.value >= 0 && state.canEdit.value
80
+ );
78
81
  const canRedo = computed(
79
- () => currentMutationIndex.value < mutationsCount.value - 1
82
+ () => currentMutationIndex.value < mutationsCount.value - 1 && state.canEdit.value
80
83
  );
81
84
  const selectionAtHistoryIndex = /* @__PURE__ */ new Map();
82
85
  function updateCurrentHistorySelection() {