@blokkli/editor 1.1.1 → 1.1.2
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 +1 -1
- package/dist/module.mjs +1 -1
- package/dist/runtime/components/Blocks/FromLibrary/index.vue +2 -8
- package/dist/runtime/components/BlokkliItem.vue +1 -0
- package/dist/runtime/components/Edit/Actions/index.vue +5 -0
- package/dist/runtime/components/Edit/AnimationCanvas/index.vue +2 -2
- package/dist/runtime/components/Edit/BlockProxy/index.vue +40 -9
- package/dist/runtime/components/Edit/DragInteractions/index.vue +16 -7
- package/dist/runtime/components/Edit/Features/Artboard/Overview/index.vue +7 -5
- package/dist/runtime/components/Edit/Features/Artboard/index.vue +7 -1
- package/dist/runtime/components/Edit/Features/Clipboard/index.vue +27 -9
- package/dist/runtime/components/Edit/Features/CommandPalette/Palette/index.vue +7 -1
- package/dist/runtime/components/Edit/Features/CommandPalette/index.vue +1 -1
- package/dist/runtime/components/Edit/Features/Delete/index.vue +46 -2
- package/dist/runtime/components/Edit/Features/DraggingOverlay/DropTargets/index.vue +2 -2
- package/dist/runtime/components/Edit/Features/DraggingOverlay/index.vue +14 -6
- package/dist/runtime/components/Edit/Features/Duplicate/index.vue +33 -15
- package/dist/runtime/components/Edit/Features/History/List/index.vue +149 -0
- package/dist/runtime/components/Edit/Features/History/index.vue +7 -134
- package/dist/runtime/components/Edit/Features/Library/index.vue +1 -1
- package/dist/runtime/components/Edit/Features/Structure/index.vue +1 -0
- package/dist/runtime/components/Edit/ScrollBoundary/index.vue +17 -2
- package/dist/runtime/composables/defineBlokkli.js +10 -3
- package/dist/runtime/composables/defineBlokkliFragment.js +6 -3
- package/dist/runtime/css/output.css +1 -1
- package/dist/runtime/helpers/domProvider.d.ts +0 -2
- package/dist/runtime/helpers/domProvider.js +0 -22
- package/dist/runtime/helpers/index.d.ts +2 -1
- package/dist/runtime/helpers/index.js +9 -0
- package/dist/runtime/helpers/keyboardProvider.d.ts +1 -0
- package/dist/runtime/helpers/keyboardProvider.js +13 -2
- package/dist/runtime/helpers/selectionProvider.d.ts +1 -1
- package/dist/runtime/helpers/selectionProvider.js +6 -0
- package/dist/runtime/helpers/stateProvider.d.ts +1 -0
- package/dist/runtime/helpers/stateProvider.js +9 -1
- package/dist/runtime/types/index.d.ts +6 -0
- package/package.json +1 -1
package/dist/module.json
CHANGED
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.1.
|
|
10
|
+
const version = "1.1.2";
|
|
11
11
|
|
|
12
12
|
function sortObjectKeys(obj) {
|
|
13
13
|
if (Array.isArray(obj)) {
|
|
@@ -19,16 +19,10 @@ import {
|
|
|
19
19
|
INJECT_IS_IN_REUSABLE,
|
|
20
20
|
INJECT_REUSABLE_OPTIONS,
|
|
21
21
|
} from '#blokkli/helpers/symbols'
|
|
22
|
-
import type {
|
|
23
|
-
|
|
24
|
-
interface LibraryItem {
|
|
25
|
-
block?: FieldListItem
|
|
26
|
-
label?: string
|
|
27
|
-
uuid?: string
|
|
28
|
-
}
|
|
22
|
+
import type { LibraryItemProps } from '#blokkli/types'
|
|
29
23
|
|
|
30
24
|
const props = defineProps<{
|
|
31
|
-
libraryItem?:
|
|
25
|
+
libraryItem?: LibraryItemProps
|
|
32
26
|
}>()
|
|
33
27
|
|
|
34
28
|
const { index, options, parentType } = defineBlokkli({
|
|
@@ -198,6 +198,11 @@ onBlokkliEvent('canvas:draw', () => {
|
|
|
198
198
|
const rects = selection.uuids.value
|
|
199
199
|
.map((uuid) => dom.getBlockRect(uuid))
|
|
200
200
|
.filter(falsy)
|
|
201
|
+
|
|
202
|
+
if (!rects.length) {
|
|
203
|
+
return
|
|
204
|
+
}
|
|
205
|
+
|
|
201
206
|
const offset = ui.artboardOffset.value
|
|
202
207
|
const scale = ui.artboardScale.value
|
|
203
208
|
|
|
@@ -60,8 +60,8 @@ const scissor = computed(() => {
|
|
|
60
60
|
canvasAttributes.value.height -
|
|
61
61
|
ui.visibleViewport.value.y * dpi -
|
|
62
62
|
ui.visibleViewport.value.height * dpi,
|
|
63
|
-
width: ui.visibleViewport.value.width * dpi,
|
|
64
|
-
height: ui.visibleViewport.value.height * dpi,
|
|
63
|
+
width: Math.max(ui.visibleViewport.value.width * dpi, 1),
|
|
64
|
+
height: Math.max(ui.visibleViewport.value.height * dpi, 1),
|
|
65
65
|
}
|
|
66
66
|
})
|
|
67
67
|
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<div ref="root" class="bk-block-proxy">
|
|
2
|
+
<div ref="root" class="bk-block-proxy" v-bind="rootProps">
|
|
3
3
|
<div class="bk-block-proxy-header">
|
|
4
4
|
<ItemIcon :bundle="bundle" />
|
|
5
5
|
{{ type?.label }}
|
|
6
6
|
</div>
|
|
7
7
|
<div v-if="proxyComponent" class="bk-block-proxy-component">
|
|
8
|
-
<Component :is="proxyComponent" v-bind="
|
|
8
|
+
<Component :is="proxyComponent" v-bind="proxyComponentProps" />
|
|
9
9
|
</div>
|
|
10
10
|
<div v-if="fieldLayout.length" class="bk-block-proxy-fields">
|
|
11
11
|
<div
|
|
@@ -41,8 +41,8 @@ import {
|
|
|
41
41
|
} from '#blokkli/definitions'
|
|
42
42
|
|
|
43
43
|
import { ItemIcon } from '#blokkli/components'
|
|
44
|
-
import type { FieldConfig } from '#blokkli/types'
|
|
45
|
-
import { falsy } from '#blokkli/helpers'
|
|
44
|
+
import type { FieldConfig, LibraryItemProps } from '#blokkli/types'
|
|
45
|
+
import { buildAttributesForLibraryItem, falsy } from '#blokkli/helpers'
|
|
46
46
|
|
|
47
47
|
const props = defineProps<{
|
|
48
48
|
uuid: string
|
|
@@ -52,16 +52,47 @@ const props = defineProps<{
|
|
|
52
52
|
itemProps?: any
|
|
53
53
|
}>()
|
|
54
54
|
|
|
55
|
+
// Props of the library item, if this is a 'from_library' block.
|
|
56
|
+
const libraryItemProps = computed<LibraryItemProps | null>(() => {
|
|
57
|
+
if (props.bundle === 'from_library') {
|
|
58
|
+
const v = props.itemProps?.libraryItem
|
|
59
|
+
return v as LibraryItemProps
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
return null
|
|
63
|
+
})
|
|
64
|
+
|
|
65
|
+
const proxyComponentProps = computed(() => {
|
|
66
|
+
if (props.bundle === 'from_library') {
|
|
67
|
+
// Pass the props of the reusable block to the proxy component.
|
|
68
|
+
return libraryItemProps.value?.block?.props
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
return props.itemProps
|
|
72
|
+
})
|
|
73
|
+
|
|
74
|
+
const rootProps = computed(() => {
|
|
75
|
+
if (libraryItemProps.value) {
|
|
76
|
+
return buildAttributesForLibraryItem(libraryItemProps.value)
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
return {}
|
|
80
|
+
})
|
|
81
|
+
|
|
82
|
+
const proxyBundle = computed(
|
|
83
|
+
() => libraryItemProps.value?.block?.bundle || props.bundle,
|
|
84
|
+
)
|
|
85
|
+
|
|
55
86
|
const { dom, types, runtimeConfig } = useBlokkli()
|
|
56
87
|
|
|
57
88
|
const root = ref<HTMLElement | null>(null)
|
|
58
89
|
|
|
59
|
-
const type = computed(() => types.getBlockBundleDefinition(
|
|
90
|
+
const type = computed(() => types.getBlockBundleDefinition(proxyBundle.value))
|
|
60
91
|
|
|
61
|
-
const proxyComponent = getBlokkliItemProxyComponent(
|
|
92
|
+
const proxyComponent = getBlokkliItemProxyComponent(proxyBundle.value)
|
|
62
93
|
|
|
63
94
|
const definition = getDefinition(
|
|
64
|
-
|
|
95
|
+
proxyBundle.value,
|
|
65
96
|
props.fieldListType,
|
|
66
97
|
props.parentType,
|
|
67
98
|
)
|
|
@@ -73,7 +104,7 @@ const fieldLayout = computed<FieldConfig[][]>(() => {
|
|
|
73
104
|
.map((fieldName) => {
|
|
74
105
|
return types.fieldConfig.forName(
|
|
75
106
|
runtimeConfig.itemEntityType,
|
|
76
|
-
|
|
107
|
+
proxyBundle.value,
|
|
77
108
|
fieldName,
|
|
78
109
|
)
|
|
79
110
|
})
|
|
@@ -82,7 +113,7 @@ const fieldLayout = computed<FieldConfig[][]>(() => {
|
|
|
82
113
|
}
|
|
83
114
|
|
|
84
115
|
return types.fieldConfig
|
|
85
|
-
.forEntityTypeAndBundle(runtimeConfig.itemEntityType,
|
|
116
|
+
.forEntityTypeAndBundle(runtimeConfig.itemEntityType, proxyBundle.value)
|
|
86
117
|
.map((config) => [config])
|
|
87
118
|
})
|
|
88
119
|
|
|
@@ -183,6 +183,8 @@ function onPointerDown(e: PointerEvent) {
|
|
|
183
183
|
e.stopPropagation()
|
|
184
184
|
e.stopImmediatePropagation()
|
|
185
185
|
}
|
|
186
|
+
// Set the state of the pressed shortcuts.
|
|
187
|
+
keyboard.setShortcutStateFromEvent(e)
|
|
186
188
|
|
|
187
189
|
rootEl.removeEventListener('pointermove', onPointerMove)
|
|
188
190
|
rootEl.addEventListener('pointermove', onPointerMove)
|
|
@@ -198,16 +200,23 @@ function onPointerDown(e: PointerEvent) {
|
|
|
198
200
|
return
|
|
199
201
|
}
|
|
200
202
|
|
|
201
|
-
pointerDownTimestamp = Date.now()
|
|
202
203
|
const coords = { x: e.clientX, y: e.clientY }
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
204
|
+
// Only handle click interactions when:
|
|
205
|
+
// - not pressing the shift key
|
|
206
|
+
// - using the left mouse button
|
|
207
|
+
if (!e.shiftKey && e.buttons !== 2) {
|
|
208
|
+
pointerDownTimestamp = Date.now()
|
|
209
|
+
mouseStartCoordinates = coords
|
|
210
|
+
|
|
211
|
+
const interacted = getInteractedElement(e)
|
|
212
|
+
pointerDownElement = interacted
|
|
213
|
+
if (interacted) {
|
|
214
|
+
return
|
|
215
|
+
}
|
|
209
216
|
}
|
|
210
217
|
|
|
218
|
+
// Either pressing shift or right mouse button.
|
|
219
|
+
// Features may handle this via event (e.g. start multi select).
|
|
211
220
|
eventBus.emit('mouse:down', { ...coords, type: 'mouse', distance: 0 })
|
|
212
221
|
}
|
|
213
222
|
|
|
@@ -60,8 +60,10 @@ function updateCanvas() {
|
|
|
60
60
|
|
|
61
61
|
const scale = rect.width / ui.artboardSize.value.width
|
|
62
62
|
|
|
63
|
+
const LINE_WIDTH = 2.5
|
|
64
|
+
|
|
63
65
|
ctx.fillStyle = overviewFillColor.value
|
|
64
|
-
ctx.lineWidth =
|
|
66
|
+
ctx.lineWidth = LINE_WIDTH
|
|
65
67
|
ctx.strokeStyle = selectedColor.value
|
|
66
68
|
|
|
67
69
|
for (let i = 0; i < rects.length; i++) {
|
|
@@ -74,10 +76,10 @@ function updateCanvas() {
|
|
|
74
76
|
)
|
|
75
77
|
if (selection.isBlockSelected(uuid)) {
|
|
76
78
|
ctx.strokeRect(
|
|
77
|
-
Math.round(blockRect.x * scale) +
|
|
78
|
-
Math.round(blockRect.y * scale) +
|
|
79
|
-
Math.round(blockRect.width * scale),
|
|
80
|
-
Math.round(blockRect.height * scale),
|
|
79
|
+
Math.round(blockRect.x * scale) + LINE_WIDTH / 2,
|
|
80
|
+
Math.round(blockRect.y * scale) + LINE_WIDTH / 2,
|
|
81
|
+
Math.round(blockRect.width * scale) - LINE_WIDTH,
|
|
82
|
+
Math.round(blockRect.height * scale) - LINE_WIDTH,
|
|
81
83
|
)
|
|
82
84
|
}
|
|
83
85
|
}
|
|
@@ -106,7 +106,7 @@ const { settings } = defineBlokkliFeature({
|
|
|
106
106
|
screenshot: 'feature-artboard.jpg',
|
|
107
107
|
})
|
|
108
108
|
|
|
109
|
-
const { context, storage, ui, animation, $t, dom } = useBlokkli()
|
|
109
|
+
const { context, storage, ui, animation, $t, dom, selection } = useBlokkli()
|
|
110
110
|
|
|
111
111
|
const zoomLevel = computed(() => Math.round(ui.artboardScale.value * 100) + '%')
|
|
112
112
|
|
|
@@ -169,6 +169,12 @@ watch(wheelOptions, function (newOptions) {
|
|
|
169
169
|
}
|
|
170
170
|
})
|
|
171
171
|
|
|
172
|
+
watch(selection.uuids, function () {
|
|
173
|
+
if (artboard.getMomentum()) {
|
|
174
|
+
artboard.cancelAnimation()
|
|
175
|
+
}
|
|
176
|
+
})
|
|
177
|
+
|
|
172
178
|
function getArtboard(): Artboard {
|
|
173
179
|
pluginWheel = wheel(wheelOptions.value)
|
|
174
180
|
return createArtboard(
|
|
@@ -76,7 +76,7 @@ import {
|
|
|
76
76
|
import { PluginSidebar } from '#blokkli/plugins'
|
|
77
77
|
import ClipboardList from './List/index.vue'
|
|
78
78
|
import type { ClipboardItem } from '#blokkli/types'
|
|
79
|
-
import { falsy, generateUUID } from '#blokkli/helpers'
|
|
79
|
+
import { falsy, generateUUID, getFieldKey } from '#blokkli/helpers'
|
|
80
80
|
import { Icon } from '#blokkli/components'
|
|
81
81
|
import onBlokkliEvent from '#blokkli/helpers/composables/onBlokkliEvent'
|
|
82
82
|
import defineShortcut from '#blokkli/helpers/composables/defineShortcut'
|
|
@@ -100,7 +100,7 @@ const { settings, logger } = defineBlokkliFeature({
|
|
|
100
100
|
screenshot: 'feature-clipboard.jpg',
|
|
101
101
|
})
|
|
102
102
|
|
|
103
|
-
const { selection, $t, adapter, dom, state, ui } = useBlokkli()
|
|
103
|
+
const { selection, $t, adapter, dom, state, ui, types } = useBlokkli()
|
|
104
104
|
|
|
105
105
|
const plugin = ref<InstanceType<typeof PluginSidebar> | null>(null)
|
|
106
106
|
|
|
@@ -271,21 +271,39 @@ const handleSelectionPaste = (pastedUuids: string[]) => {
|
|
|
271
271
|
}
|
|
272
272
|
|
|
273
273
|
// @TODO: Paste into nested field if possible.
|
|
274
|
-
const
|
|
274
|
+
const block = selection.blocks.value[0]
|
|
275
|
+
if (!block) {
|
|
276
|
+
return
|
|
277
|
+
}
|
|
278
|
+
const field = state.getMutatedField(block.hostUuid, block.hostFieldName)
|
|
279
|
+
if (!field) {
|
|
280
|
+
return
|
|
281
|
+
}
|
|
282
|
+
const fieldConfig = types.getFieldConfig(
|
|
283
|
+
field.entityType,
|
|
284
|
+
block.hostBundle,
|
|
285
|
+
field.name,
|
|
286
|
+
)
|
|
287
|
+
|
|
288
|
+
if (!fieldConfig) {
|
|
289
|
+
return
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
const fieldKey = getFieldKey(field.entityUuid, field.name)
|
|
275
293
|
|
|
276
294
|
const pastedBlocks = pastedUuids
|
|
277
295
|
.map((uuid) => dom.findBlock(uuid))
|
|
278
296
|
.filter(falsy)
|
|
279
|
-
.filter((block) =>
|
|
297
|
+
.filter((block) => fieldConfig.allowedBundles.includes(block.itemBundle))
|
|
280
298
|
|
|
281
299
|
if (!pastedBlocks.length) {
|
|
282
300
|
return
|
|
283
301
|
}
|
|
284
302
|
|
|
285
|
-
const count = state.getFieldBlockCount(
|
|
303
|
+
const count = state.getFieldBlockCount(fieldKey)
|
|
286
304
|
if (
|
|
287
|
-
|
|
288
|
-
count + pastedBlocks.length >
|
|
305
|
+
fieldConfig.cardinality !== -1 &&
|
|
306
|
+
count + pastedBlocks.length > fieldConfig.cardinality
|
|
289
307
|
) {
|
|
290
308
|
return
|
|
291
309
|
}
|
|
@@ -294,8 +312,8 @@ const handleSelectionPaste = (pastedUuids: string[]) => {
|
|
|
294
312
|
adapter.pasteExistingBlocks!({
|
|
295
313
|
uuids: pastedBlocks.map((v) => v.uuid),
|
|
296
314
|
host: {
|
|
297
|
-
type: field.
|
|
298
|
-
uuid: field.
|
|
315
|
+
type: field.entityType,
|
|
316
|
+
uuid: field.entityUuid,
|
|
299
317
|
fieldName: field.name,
|
|
300
318
|
},
|
|
301
319
|
preceedingUuid: selection.uuids.value[0],
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<ScrollBoundary
|
|
3
3
|
class="bk-command-palette bk-control"
|
|
4
|
-
@keydown
|
|
4
|
+
@keydown="onKeyDown"
|
|
5
5
|
@keyup.stop
|
|
6
6
|
@click.stop
|
|
7
7
|
>
|
|
@@ -238,6 +238,12 @@ const onSelect = (id: string) => {
|
|
|
238
238
|
}
|
|
239
239
|
|
|
240
240
|
const onKeyDown = (e: KeyboardEvent) => {
|
|
241
|
+
e.stopPropagation()
|
|
242
|
+
if (e.code === 'KeyK' && (e.ctrlKey || e.metaKey)) {
|
|
243
|
+
e.preventDefault()
|
|
244
|
+
emit('close')
|
|
245
|
+
return
|
|
246
|
+
}
|
|
241
247
|
if (e.code === 'Tab') {
|
|
242
248
|
e.preventDefault()
|
|
243
249
|
if (e.shiftKey) {
|
|
@@ -17,7 +17,7 @@ import { useBlokkli, defineBlokkliFeature } from '#imports'
|
|
|
17
17
|
import type { DraggableExistingBlock } from '#blokkli/types'
|
|
18
18
|
import { PluginItemAction } from '#blokkli/plugins'
|
|
19
19
|
|
|
20
|
-
const { state, $t, eventBus } = useBlokkli()
|
|
20
|
+
const { state, $t, eventBus, dom, runtimeConfig } = useBlokkli()
|
|
21
21
|
|
|
22
22
|
const { adapter } = defineBlokkliFeature({
|
|
23
23
|
id: 'delete',
|
|
@@ -27,12 +27,56 @@ const { adapter } = defineBlokkliFeature({
|
|
|
27
27
|
description: 'Provides an action to delete one or more blocks.',
|
|
28
28
|
})
|
|
29
29
|
|
|
30
|
+
/**
|
|
31
|
+
* Try to find a block to select after deleting a single block.
|
|
32
|
+
*/
|
|
33
|
+
function getSelectionAfterDelete(
|
|
34
|
+
items: DraggableExistingBlock[],
|
|
35
|
+
): string | undefined {
|
|
36
|
+
if (items.length !== 1) {
|
|
37
|
+
return
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
const uuid = items[0].uuid
|
|
41
|
+
const field = state.getFieldListForBlock(uuid)
|
|
42
|
+
if (!field) {
|
|
43
|
+
return
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
const index = field.list.findIndex((v) => v.uuid === uuid)
|
|
47
|
+
if (index === -1) {
|
|
48
|
+
return
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// Find a matching block to select in the same field list.
|
|
52
|
+
const inList = field.list[index + 1]?.uuid || field.list[index - 1]?.uuid
|
|
53
|
+
if (inList) {
|
|
54
|
+
return inList
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// Field does not belong to a block.
|
|
58
|
+
if (field.entityType !== runtimeConfig.itemEntityType) {
|
|
59
|
+
return
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// Select the block which contains the field.
|
|
63
|
+
return field.entityUuid
|
|
64
|
+
}
|
|
65
|
+
|
|
30
66
|
async function onClick(items: DraggableExistingBlock[]) {
|
|
31
|
-
|
|
67
|
+
const selectedUuidsAfter = getSelectionAfterDelete(items)
|
|
68
|
+
|
|
32
69
|
await state.mutateWithLoadingState(
|
|
33
70
|
() => adapter.deleteBlocks(items.map((v) => v.uuid)),
|
|
34
71
|
$t('deleteError', 'The block could not be deleted.'),
|
|
35
72
|
)
|
|
73
|
+
|
|
74
|
+
if (selectedUuidsAfter) {
|
|
75
|
+
eventBus.emit('select', selectedUuidsAfter)
|
|
76
|
+
dom.refreshBlockRect(selectedUuidsAfter)
|
|
77
|
+
} else {
|
|
78
|
+
eventBus.emit('select:unselect')
|
|
79
|
+
}
|
|
36
80
|
}
|
|
37
81
|
</script>
|
|
38
82
|
|
|
@@ -178,9 +178,9 @@ onBlokkliEvent('mouse:up', (e) => {
|
|
|
178
178
|
|
|
179
179
|
const emitDrop = async () => {
|
|
180
180
|
const timeDelta = Date.now() - dragStart
|
|
181
|
-
// Prevent accidental drops. At least
|
|
181
|
+
// Prevent accidental drops. At least 200ms should have passed between the
|
|
182
182
|
// time the drag was initiated and when the drop was made.
|
|
183
|
-
if (active.value && timeDelta >
|
|
183
|
+
if (active.value && timeDelta > 200) {
|
|
184
184
|
if (active.value.type === 'field') {
|
|
185
185
|
const [hostUuid, fieldName, preceedingUuid] = active.value.id.split(':')
|
|
186
186
|
|
|
@@ -169,6 +169,11 @@ const onDropExisting = async (
|
|
|
169
169
|
host,
|
|
170
170
|
}),
|
|
171
171
|
)
|
|
172
|
+
if (uuids.length >= 1 && uuids.length <= 10) {
|
|
173
|
+
for (let i = 0; i < uuids.length; i++) {
|
|
174
|
+
dom.refreshBlockRect(uuids[i])
|
|
175
|
+
}
|
|
176
|
+
}
|
|
172
177
|
|
|
173
178
|
if (ui.isMobile.value) {
|
|
174
179
|
eventBus.emit('scrollIntoView', {
|
|
@@ -365,8 +370,15 @@ onBlokkliEvent('dragging:start', (e) => {
|
|
|
365
370
|
if (!item) {
|
|
366
371
|
return
|
|
367
372
|
}
|
|
373
|
+
|
|
374
|
+
mouseX.value = e.coords.x
|
|
375
|
+
mouseY.value = e.coords.y
|
|
376
|
+
|
|
377
|
+
// Before showing the drop targets we update all currently visible rects to
|
|
378
|
+
// ensure the user sees the correct drop targets right away.
|
|
379
|
+
dom.updateVisibleRects()
|
|
380
|
+
dragItems.value = e.items
|
|
368
381
|
if ('element' in item) {
|
|
369
|
-
eventBus.on('animationFrame', loop)
|
|
370
382
|
if (!isTouching.value) {
|
|
371
383
|
document.removeEventListener('pointerup', onMouseUp)
|
|
372
384
|
document.addEventListener('pointerup', onMouseUp)
|
|
@@ -375,12 +387,8 @@ onBlokkliEvent('dragging:start', (e) => {
|
|
|
375
387
|
})
|
|
376
388
|
document.addEventListener('pointermove', onMouseMove, { capture: true })
|
|
377
389
|
}
|
|
390
|
+
eventBus.on('animationFrame', loop)
|
|
378
391
|
}
|
|
379
|
-
|
|
380
|
-
// Before showing the drop targets we update all currently visible rects to
|
|
381
|
-
// ensure the user sees the correct drop targets right away.
|
|
382
|
-
dom.updateVisibleRects()
|
|
383
|
-
dragItems.value = e.items
|
|
384
392
|
})
|
|
385
393
|
|
|
386
394
|
onBlokkliEvent('dragging:end', () => {
|
|
@@ -14,14 +14,11 @@
|
|
|
14
14
|
|
|
15
15
|
<script lang="ts" setup>
|
|
16
16
|
import { computed, useBlokkli, defineBlokkliFeature } from '#imports'
|
|
17
|
-
|
|
18
|
-
import type {
|
|
19
|
-
BlokkliFieldElement,
|
|
20
|
-
DraggableExistingBlock,
|
|
21
|
-
} from '#blokkli/types'
|
|
17
|
+
import type { DraggableExistingBlock } from '#blokkli/types'
|
|
22
18
|
import { PluginItemAction } from '#blokkli/plugins'
|
|
19
|
+
import { getFieldKey } from '#blokkli/helpers'
|
|
23
20
|
|
|
24
|
-
const { state, $t, selection,
|
|
21
|
+
const { state, $t, selection, types } = useBlokkli()
|
|
25
22
|
|
|
26
23
|
const { adapter } = defineBlokkliFeature({
|
|
27
24
|
id: 'duplicate',
|
|
@@ -44,31 +41,52 @@ const canDuplicate = computed<boolean>(() => {
|
|
|
44
41
|
}
|
|
45
42
|
|
|
46
43
|
const blocksByField: Record<string, DraggableExistingBlock[]> = {}
|
|
47
|
-
const fieldsByKey: Record<
|
|
44
|
+
const fieldsByKey: Record<
|
|
45
|
+
string,
|
|
46
|
+
{ cardinality: number; allowedBundles: string[]; count: number }
|
|
47
|
+
> = {}
|
|
48
48
|
|
|
49
49
|
const selectedCount = selection.blocks.value.length
|
|
50
50
|
for (let i = 0; i < selectedCount; i++) {
|
|
51
51
|
const block = selection.blocks.value[i]
|
|
52
|
-
const field =
|
|
53
|
-
|
|
52
|
+
const field = state.getMutatedField(block.hostUuid, block.hostFieldName)
|
|
53
|
+
if (!field) {
|
|
54
|
+
continue
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
const fieldKey = getFieldKey(field.entityUuid, field.name)
|
|
58
|
+
|
|
59
|
+
const fieldConfig = types.getFieldConfig(
|
|
60
|
+
field.entityType,
|
|
61
|
+
block.hostBundle,
|
|
62
|
+
field.name,
|
|
63
|
+
)
|
|
64
|
+
if (!fieldConfig) {
|
|
65
|
+
continue
|
|
66
|
+
}
|
|
67
|
+
const count = field.list.length
|
|
54
68
|
|
|
55
69
|
// Early return if the field is already full.
|
|
56
|
-
if (
|
|
70
|
+
if (fieldConfig.cardinality !== -1 && count >= fieldConfig.cardinality) {
|
|
57
71
|
return false
|
|
58
72
|
}
|
|
59
73
|
|
|
60
|
-
if (!blocksByField[
|
|
61
|
-
blocksByField[
|
|
74
|
+
if (!blocksByField[fieldKey]) {
|
|
75
|
+
blocksByField[fieldKey] = []
|
|
76
|
+
}
|
|
77
|
+
blocksByField[fieldKey].push(block)
|
|
78
|
+
fieldsByKey[fieldKey] = {
|
|
79
|
+
cardinality: fieldConfig.cardinality,
|
|
80
|
+
allowedBundles: fieldConfig.allowedBundles,
|
|
81
|
+
count,
|
|
62
82
|
}
|
|
63
|
-
blocksByField[field.key].push(block)
|
|
64
|
-
fieldsByKey[field.key] = field
|
|
65
83
|
}
|
|
66
84
|
|
|
67
85
|
const entries = Object.entries(blocksByField)
|
|
68
86
|
for (let i = 0; i < entries.length; i++) {
|
|
69
87
|
const [fieldKey, blocks] = entries[i]
|
|
70
88
|
const field = fieldsByKey[fieldKey]
|
|
71
|
-
const count = state.getFieldBlockCount(
|
|
89
|
+
const count = state.getFieldBlockCount(fieldKey)
|
|
72
90
|
// Check cardinality of the field.
|
|
73
91
|
if (field.cardinality !== -1 && count + blocks.length > field.cardinality) {
|
|
74
92
|
return false
|