@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
@@ -0,0 +1,417 @@
1
+ <template>
2
+ <Teleport to="#bk-canvas-overlay">
3
+ <div
4
+ class="bk bk-add-button-tooltip"
5
+ :class="{ 'bk-is-field': tooltipData?.isField }"
6
+ :style="{
7
+ position: 'fixed',
8
+ left: (tooltipData?.x ?? 0) + 'px',
9
+ top: (tooltipData?.y ?? 0) + 'px',
10
+ transform: tooltipData?.transform ?? 'translate(0, 0)',
11
+ visibility: tooltipData ? 'visible' : 'hidden'
12
+ }"
13
+ >
14
+ {{ tooltipData?.text ?? "" }}
15
+ </div>
16
+ </Teleport>
17
+ </template>
18
+
19
+ <script setup>
20
+ import onBlokkliEvent from "#blokkli/helpers/composables/onBlokkliEvent";
21
+ import defineRenderer from "#blokkli/helpers/composables/defineRenderer";
22
+ import { useBlokkli, computed, ref } from "#imports";
23
+ import { setBuffersAndAttributes, drawBufferInfo, setUniforms } from "twgl.js";
24
+ import vs from "./vertex.glsl?raw";
25
+ import fs from "./fragment.glsl?raw";
26
+ import { RectangleBufferCollector } from "#blokkli/helpers/webgl";
27
+ import { toShaderColor, getFieldKey } from "#blokkli/helpers";
28
+ import {
29
+ getChildrenOrientation,
30
+ determineCanAddChildren
31
+ } from "#blokkli/helpers/dropTargets";
32
+ import { isInternalBundle } from "#blokkli/helpers/bundles";
33
+ const { animation, theme, dom, selection, state, types, ui, $t } = useBlokkli();
34
+ const emptyFieldTooltips = ref([]);
35
+ const currentUuid = ref("");
36
+ const currentBundleLabel = ref("");
37
+ const currentSingleAllowedBundleLabel = ref(null);
38
+ const tooltipData = computed(() => {
39
+ if (hoveredCircle.value < 0) {
40
+ return null;
41
+ }
42
+ const index = hoveredCircle.value;
43
+ const artboardX = circlePositions[index * 2];
44
+ const artboardY = circlePositions[index * 2 + 1];
45
+ if (artboardX === void 0 || artboardY === void 0) {
46
+ return null;
47
+ }
48
+ const scale = ui.artboardScale.value;
49
+ const offset = ui.artboardOffset.value;
50
+ const screenX = artboardX * scale + offset.x;
51
+ const screenY = artboardY * scale + offset.y;
52
+ let transform;
53
+ let position;
54
+ let text;
55
+ let isField = false;
56
+ if (index === 0 || index === 1) {
57
+ const orientation = currentOrientation.value;
58
+ if (currentSingleAllowedBundleLabel.value) {
59
+ if (index === 0) {
60
+ text = $t("addButtonBundleBefore", 'Add "@bundle" before').replace(
61
+ "@bundle",
62
+ currentSingleAllowedBundleLabel.value
63
+ );
64
+ } else {
65
+ text = $t("addButtonBundleAfter", 'Add "@bundle" after').replace(
66
+ "@bundle",
67
+ currentSingleAllowedBundleLabel.value
68
+ );
69
+ }
70
+ } else {
71
+ if (index === 0) {
72
+ text = $t("addButtonBeforeBundle", "Add before...");
73
+ } else {
74
+ text = $t("addButtonAfterBundle", "Add after...");
75
+ }
76
+ }
77
+ if (orientation === "horizontal") {
78
+ if (index === 0) {
79
+ transform = `translate(${TOOLTIP_MARGIN}px, -50%)`;
80
+ position = "right";
81
+ } else {
82
+ transform = `translate(calc(-100% - ${TOOLTIP_MARGIN}px), -50%)`;
83
+ position = "left";
84
+ }
85
+ } else {
86
+ if (index === 0) {
87
+ transform = `translate(-50%, ${TOOLTIP_MARGIN}px)`;
88
+ position = "bottom";
89
+ } else {
90
+ transform = `translate(-50%, calc(-100% - ${TOOLTIP_MARGIN}px))`;
91
+ position = "top";
92
+ }
93
+ }
94
+ } else {
95
+ transform = `translate(-50%, calc(-100% - ${TOOLTIP_MARGIN}px))`;
96
+ position = "top";
97
+ isField = true;
98
+ const fieldIndex = index - 2;
99
+ text = emptyFieldTooltips.value[fieldIndex] || "Add to field";
100
+ }
101
+ return { x: screenX, y: screenY, transform, position, text, isField };
102
+ });
103
+ const emit = defineEmits(["toggle", "toggleField"]);
104
+ const gl = animation.gl();
105
+ const programInfo = gl ? animation.registerProgram("add-buttons", gl, [vs, fs]) : null;
106
+ const MAX_CIRCLES = 10;
107
+ const BUTTON_RADIUS = 12;
108
+ const TOOLTIP_MARGIN = 20;
109
+ let bufferInfo = null;
110
+ if (gl) {
111
+ class CircleBufferCollector extends RectangleBufferCollector {
112
+ }
113
+ const collector = new CircleBufferCollector(gl);
114
+ for (let i = 0; i < MAX_CIRCLES; i++) {
115
+ collector.addRectangle(
116
+ {
117
+ id: `circle-${i}`,
118
+ x: 0,
119
+ y: 0,
120
+ width: 40,
121
+ height: 40
122
+ },
123
+ i
124
+ );
125
+ }
126
+ bufferInfo = collector.createBufferInfo();
127
+ }
128
+ const circlePositions = new Float32Array(MAX_CIRCLES * 2);
129
+ const circleVisible = new Float32Array(MAX_CIRCLES);
130
+ const hoveredCircle = ref(-1);
131
+ const color = computed(() => {
132
+ return toShaderColor(theme.accent.value[600]);
133
+ });
134
+ const colorHover = computed(() => {
135
+ return toShaderColor(theme.accent.value[500]);
136
+ });
137
+ const colorField = computed(() => {
138
+ return toShaderColor(theme.accent.value[400]);
139
+ });
140
+ const colorFieldHover = computed(() => {
141
+ return toShaderColor(theme.accent.value[300]);
142
+ });
143
+ const orientationCache = /* @__PURE__ */ new Map();
144
+ const currentOrientation = ref("horizontal");
145
+ const blockStateCache = /* @__PURE__ */ new Map();
146
+ function getOrientationForUuid(uuid) {
147
+ let cached = orientationCache.get(uuid);
148
+ if (!cached) {
149
+ const block = dom.findBlock(uuid);
150
+ if (block) {
151
+ const field = dom.findField(block.hostUuid, block.hostFieldName);
152
+ if (field) {
153
+ cached = getChildrenOrientation(field.element);
154
+ orientationCache.set(uuid, cached);
155
+ }
156
+ }
157
+ }
158
+ return cached || "horizontal";
159
+ }
160
+ function getBlockState(uuid) {
161
+ let cached = blockStateCache.get(uuid);
162
+ if (!cached) {
163
+ let canShowBeforeAfter = false;
164
+ let singleAllowedBundleLabel = null;
165
+ const block = dom.findBlock(uuid);
166
+ if (!block) {
167
+ return {
168
+ canShowBeforeAfter: false,
169
+ emptyFieldKeys: [],
170
+ emptyFieldTooltips: [],
171
+ bundleLabel: "",
172
+ singleAllowedBundleLabel: null
173
+ };
174
+ }
175
+ if (block) {
176
+ const field = dom.findField(block.hostUuid, block.hostFieldName);
177
+ if (!field) {
178
+ return {
179
+ canShowBeforeAfter: false,
180
+ emptyFieldKeys: [],
181
+ emptyFieldTooltips: [],
182
+ bundleLabel: "",
183
+ singleAllowedBundleLabel: null
184
+ };
185
+ }
186
+ if (field) {
187
+ const fieldChildren = [...field.element.children];
188
+ const currentCount = state.getFieldBlockCount(field.key);
189
+ canShowBeforeAfter = determineCanAddChildren(
190
+ field,
191
+ fieldChildren,
192
+ [],
193
+ // Not moving any blocks, adding a new one
194
+ currentCount,
195
+ 1,
196
+ // Adding 1 new block
197
+ []
198
+ // Don't know which bundle will be added
199
+ );
200
+ const allowedBundles = field.allowedBundles.filter(
201
+ (bundle) => !isInternalBundle(bundle)
202
+ );
203
+ if (allowedBundles.length === 1) {
204
+ const bundle = allowedBundles[0];
205
+ if (bundle) {
206
+ singleAllowedBundleLabel = types.getBlockBundleDefinition(bundle)?.label || bundle;
207
+ }
208
+ }
209
+ }
210
+ }
211
+ const bundleLabel = block ? types.getBlockBundleDefinition(block.itemBundle)?.label || block.itemBundle : "";
212
+ const emptyFieldKeys = [];
213
+ const emptyFieldTooltips2 = [];
214
+ if (block) {
215
+ const fieldConfigs = types.fieldConfig.forEntityTypeAndBundle(
216
+ block.entityType,
217
+ block.itemBundle
218
+ );
219
+ for (const fieldConfig of fieldConfigs) {
220
+ const key = getFieldKey(uuid, fieldConfig.name);
221
+ const count = state.getFieldBlockCount(key);
222
+ if (count === 0) {
223
+ emptyFieldKeys.push(key);
224
+ const fieldLabel = fieldConfig.label || fieldConfig.name;
225
+ const fieldElement = dom.findField(uuid, fieldConfig.name);
226
+ if (fieldElement) {
227
+ const allowedBundles = fieldElement.allowedBundles.filter(
228
+ (bundle) => !isInternalBundle(bundle)
229
+ );
230
+ if (allowedBundles.length === 1) {
231
+ const bundle = allowedBundles[0];
232
+ if (bundle) {
233
+ const singleBundleLabel = types.getBlockBundleDefinition(bundle)?.label || bundle;
234
+ const tooltip = $t(
235
+ "addButtonBundleInsideField",
236
+ 'Add "@bundle" inside @parentBundle \xBB @fieldLabel'
237
+ ).replace("@bundle", singleBundleLabel).replace("@parentBundle", bundleLabel).replace("@fieldLabel", fieldLabel);
238
+ emptyFieldTooltips2.push(tooltip);
239
+ } else {
240
+ emptyFieldTooltips2.push(
241
+ $t(
242
+ "addButtonInsideField",
243
+ "Add inside @parentBundle \xBB @fieldLabel..."
244
+ ).replace("@parentBundle", bundleLabel).replace("@fieldLabel", fieldLabel)
245
+ );
246
+ }
247
+ } else {
248
+ emptyFieldTooltips2.push(
249
+ $t(
250
+ "addButtonInsideField",
251
+ "Add inside @parentBundle \xBB @fieldLabel..."
252
+ ).replace("@parentBundle", bundleLabel).replace("@fieldLabel", fieldLabel)
253
+ );
254
+ }
255
+ } else {
256
+ emptyFieldTooltips2.push(
257
+ $t(
258
+ "addButtonInsideField",
259
+ "Add inside @parentBundle \xBB @fieldLabel..."
260
+ ).replace("@parentBundle", bundleLabel).replace("@fieldLabel", fieldLabel)
261
+ );
262
+ }
263
+ }
264
+ }
265
+ }
266
+ cached = {
267
+ canShowBeforeAfter,
268
+ emptyFieldKeys,
269
+ emptyFieldTooltips: emptyFieldTooltips2,
270
+ bundleLabel,
271
+ singleAllowedBundleLabel
272
+ };
273
+ blockStateCache.set(uuid, cached);
274
+ }
275
+ return cached;
276
+ }
277
+ onBlokkliEvent("state:reloaded", () => {
278
+ orientationCache.clear();
279
+ blockStateCache.clear();
280
+ });
281
+ function getCircleAtPoint(x, y) {
282
+ if (ui.artboardScale.value <= 0.4) {
283
+ return -1;
284
+ }
285
+ const effectiveScale = Math.max(ui.artboardScale.value, 0.5);
286
+ const radius = BUTTON_RADIUS / effectiveScale;
287
+ for (let i = 0; i < MAX_CIRCLES; i++) {
288
+ if (circleVisible[i] > 0) {
289
+ const cx = circlePositions[i * 2];
290
+ const cy = circlePositions[i * 2 + 1];
291
+ const dx = x - cx;
292
+ const dy = y - cy;
293
+ const distance = Math.sqrt(dx * dx + dy * dy);
294
+ if (distance <= radius) {
295
+ return i;
296
+ }
297
+ }
298
+ }
299
+ return -1;
300
+ }
301
+ if (gl && programInfo && bufferInfo) {
302
+ defineRenderer("add-buttons", {
303
+ zIndex: 1e3,
304
+ enabled: () => selection.uuids.value.length === 1,
305
+ cursor: () => hoveredCircle.value >= 0 ? "pointer" : null,
306
+ onClick: ({ mouseArtboard }) => {
307
+ if (selection.uuids.value.length !== 1) {
308
+ return false;
309
+ }
310
+ const clickedCircle = getCircleAtPoint(mouseArtboard.x, mouseArtboard.y);
311
+ if (clickedCircle >= 0) {
312
+ const cx = circlePositions[clickedCircle * 2];
313
+ const cy = circlePositions[clickedCircle * 2 + 1];
314
+ if (clickedCircle === 0 || clickedCircle === 1) {
315
+ const position = clickedCircle === 0 ? "before" : "after";
316
+ emit("toggle", {
317
+ position,
318
+ coordinates: { x: cx, y: cy }
319
+ });
320
+ } else {
321
+ const fieldIndex = clickedCircle - 2;
322
+ emit("toggleField", {
323
+ index: fieldIndex,
324
+ coordinates: { x: cx, y: cy }
325
+ });
326
+ }
327
+ return true;
328
+ }
329
+ return false;
330
+ },
331
+ render: (ctx) => {
332
+ if (selection.isChangingOptions.value) {
333
+ return;
334
+ }
335
+ circleVisible.fill(0);
336
+ if (ctx.selectedUuids.length !== 1) {
337
+ return;
338
+ }
339
+ const uuid = ctx.selectedUuids[0];
340
+ if (!uuid) {
341
+ return;
342
+ }
343
+ const blockState = getBlockState(uuid);
344
+ if (blockState.canShowBeforeAfter) {
345
+ const blockRect = dom.getBlockRect(uuid);
346
+ if (!blockRect || blockRect.width === 0) {
347
+ return;
348
+ }
349
+ const orientation = getOrientationForUuid(uuid);
350
+ currentOrientation.value = orientation;
351
+ const BUTTON_SHIFT = 2 / ctx.artboardScale;
352
+ if (orientation === "horizontal") {
353
+ circlePositions[0] = blockRect.x - BUTTON_SHIFT;
354
+ circlePositions[1] = blockRect.y + blockRect.height / 2;
355
+ circleVisible[0] = 1;
356
+ circlePositions[2] = blockRect.x + blockRect.width + BUTTON_SHIFT;
357
+ circlePositions[3] = blockRect.y + blockRect.height / 2;
358
+ circleVisible[1] = 1;
359
+ } else {
360
+ circlePositions[0] = blockRect.x + blockRect.width / 2;
361
+ circlePositions[1] = blockRect.y - BUTTON_SHIFT;
362
+ circleVisible[0] = 1;
363
+ circlePositions[2] = blockRect.x + blockRect.width / 2;
364
+ circlePositions[3] = blockRect.y + blockRect.height + BUTTON_SHIFT;
365
+ circleVisible[1] = 1;
366
+ }
367
+ }
368
+ currentUuid.value = uuid;
369
+ currentBundleLabel.value = blockState.bundleLabel;
370
+ currentSingleAllowedBundleLabel.value = blockState.singleAllowedBundleLabel;
371
+ if (blockState.emptyFieldKeys.length > 0) {
372
+ emptyFieldTooltips.value = blockState.emptyFieldTooltips;
373
+ for (let i = 0; i < blockState.emptyFieldKeys.length && i < 8; i++) {
374
+ const fieldKey = blockState.emptyFieldKeys[i];
375
+ if (!fieldKey) {
376
+ continue;
377
+ }
378
+ const fieldRect = dom.getFieldRect(fieldKey);
379
+ if (!fieldRect) {
380
+ continue;
381
+ }
382
+ const circleIndex = i + 2;
383
+ circlePositions[circleIndex * 2] = fieldRect.x + fieldRect.width / 2;
384
+ circlePositions[circleIndex * 2 + 1] = fieldRect.y + fieldRect.height / 2;
385
+ circleVisible[circleIndex] = 1;
386
+ }
387
+ } else {
388
+ emptyFieldTooltips.value = [];
389
+ }
390
+ hoveredCircle.value = getCircleAtPoint(
391
+ ctx.mouseArtboard.x,
392
+ ctx.mouseArtboard.y
393
+ );
394
+ gl.useProgram(programInfo.program);
395
+ setUniforms(programInfo, {
396
+ u_circle_positions: circlePositions,
397
+ u_circle_visible: circleVisible,
398
+ u_color: color.value,
399
+ u_color_hover: colorHover.value,
400
+ u_color_field: colorField.value,
401
+ u_color_field_hover: colorFieldHover.value,
402
+ u_hovered_circle: hoveredCircle.value,
403
+ u_radius: BUTTON_RADIUS
404
+ });
405
+ animation.setSharedUniforms(gl, programInfo);
406
+ setBuffersAndAttributes(gl, programInfo, bufferInfo);
407
+ drawBufferInfo(gl, bufferInfo, gl.TRIANGLES);
408
+ }
409
+ });
410
+ }
411
+ </script>
412
+
413
+ <script>
414
+ export default {
415
+ name: "AddButtonsRenderer"
416
+ };
417
+ </script>
@@ -0,0 +1,32 @@
1
+ declare const _default: import("vue").DefineComponent<{}, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {} & {
2
+ toggle: (data: {
3
+ position: "before" | "after";
4
+ coordinates: {
5
+ x: number;
6
+ y: number;
7
+ };
8
+ }) => any;
9
+ toggleField: (data: {
10
+ index: number;
11
+ coordinates: {
12
+ x: number;
13
+ y: number;
14
+ };
15
+ }) => any;
16
+ }, string, import("vue").PublicProps, Readonly<{}> & Readonly<{
17
+ onToggle?: ((data: {
18
+ position: "before" | "after";
19
+ coordinates: {
20
+ x: number;
21
+ y: number;
22
+ };
23
+ }) => any) | undefined;
24
+ onToggleField?: ((data: {
25
+ index: number;
26
+ coordinates: {
27
+ x: number;
28
+ y: number;
29
+ };
30
+ }) => any) | undefined;
31
+ }>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
32
+ export default _default;
@@ -0,0 +1,102 @@
1
+ precision highp float;
2
+
3
+ // [x, y] position.
4
+ attribute vec2 a_position;
5
+ // The [x,y,width, height] of the quad the vertex belongs to.
6
+ attribute vec4 a_quad;
7
+ attribute float a_rect_id;
8
+
9
+ // The global scaling applied to all quads.
10
+ uniform float u_scale;
11
+ uniform float u_dpi;
12
+ // The amount of pixels to offset on the x axis.
13
+ uniform float u_offset_x;
14
+ // The amount of pixels to offset on the y axis.
15
+ uniform float u_offset_y;
16
+ uniform vec2 u_resolution;
17
+
18
+ // Circle positions (10 vec2s = 20 floats)
19
+ uniform vec2 u_circle_positions[10];
20
+ // Circle visibility (10 floats)
21
+ uniform float u_circle_visible[10];
22
+ // Hovered circle index (-1 for none)
23
+ uniform float u_hovered_circle;
24
+ // Button radius in pixels
25
+ uniform float u_radius;
26
+
27
+ // The transformed quad for the fragment shader.
28
+ varying vec4 v_quad;
29
+ varying vec2 v_circle_center;
30
+ varying float v_visible;
31
+ varying float v_is_hovered;
32
+ varying float v_scale_fade;
33
+ varying float v_rect_id;
34
+
35
+ void main() {
36
+ int rectId = int(a_rect_id);
37
+
38
+ // Get circle position and visibility for this rect
39
+ vec2 circlePos = u_circle_positions[rectId];
40
+ v_visible = u_circle_visible[rectId];
41
+ v_is_hovered = float(rectId) == u_hovered_circle ? 1.0 : 0.0;
42
+ v_rect_id = a_rect_id;
43
+
44
+ // Calculate fade factor based on scale (fade from 1.0 at 0.5 to 0.0 at 0.4)
45
+ v_scale_fade = 1.0;
46
+ if (u_scale < 0.5) {
47
+ // Interpolate from 1.0 (at scale 0.5) to 0.0 (at scale 0.4)
48
+ v_scale_fade = (u_scale - 0.4) / (0.5 - 0.4);
49
+ v_scale_fade = clamp(v_scale_fade, 0.0, 1.0);
50
+ }
51
+
52
+ // Border width in pixels (must match fragment shader)
53
+ float borderWidth = 4.0;
54
+
55
+ // Circle radius in artboard space - apply inverse scaling to keep constant size
56
+ // Then multiply by fade factor
57
+ // Add border width to the radius so the border renders outside
58
+ float radius = (u_radius + borderWidth) / u_scale * v_scale_fade;
59
+
60
+ // Calculate quad bounds centered on circle position
61
+ float left = circlePos.x - radius;
62
+ float top = circlePos.y - radius;
63
+ float width = radius * 2.0;
64
+ float height = radius * 2.0;
65
+
66
+ // Determine which corner of the quad this vertex represents
67
+ // Normalize position within the dummy quad (0.0 to 1.0)
68
+ vec2 quadCorner = vec2(
69
+ (a_position.x - a_quad.x) / a_quad.z,
70
+ (a_position.y - a_quad.y) / a_quad.w
71
+ );
72
+
73
+ // Calculate actual vertex position in artboard space
74
+ vec2 vertexPos = vec2(
75
+ left + quadCorner.x * width,
76
+ top + quadCorner.y * height
77
+ );
78
+
79
+ // Apply global scale and offsets
80
+ vec2 offsetPosition = vertexPos * u_scale;
81
+ offsetPosition.x += u_offset_x;
82
+ offsetPosition.y += u_offset_y;
83
+
84
+ // Normalize position for rendering
85
+ vec2 normalizedPosition = offsetPosition / u_resolution;
86
+
87
+ // Transform to screen space (-1 to 1)
88
+ vec2 screenSpacePosition = normalizedPosition * 2.0 - vec2(1.0, 1.0);
89
+ screenSpacePosition.y = -screenSpacePosition.y;
90
+
91
+ // Output final position in clip space
92
+ gl_Position = vec4(screenSpacePosition, 0.0, 1.0) * u_dpi;
93
+
94
+ // Calculate transformed quad for fragment shader
95
+ v_quad = vec4(
96
+ (left * u_scale + u_offset_x) * u_dpi,
97
+ (u_resolution.y - top * u_scale - height * u_scale - u_offset_y) * u_dpi,
98
+ width * u_scale * u_dpi,
99
+ height * u_scale * u_dpi
100
+ );
101
+ v_circle_center = vec2(v_quad.x + v_quad.z / 2.0, v_quad.y + v_quad.w / 2.0);
102
+ }