@blokkli/editor 1.0.1 → 1.0.3

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 (25) hide show
  1. package/dist/module.json +1 -1
  2. package/dist/module.mjs +31 -1
  3. package/dist/runtime/adapter/drupal/graphqlMiddleware.js +9 -1
  4. package/dist/runtime/adapter/index.d.ts +4 -0
  5. package/dist/runtime/components/Blocks/FromLibrary/index.vue +2 -3
  6. package/dist/runtime/components/Edit/Dialog/index.vue +14 -1
  7. package/dist/runtime/components/Edit/DragInteractions/index.vue +6 -7
  8. package/dist/runtime/components/Edit/EditProvider.vue +1 -0
  9. package/dist/runtime/components/Edit/Features/Edit/index.vue +63 -14
  10. package/dist/runtime/components/Edit/Features/Exit/index.vue +2 -1
  11. package/dist/runtime/components/Edit/Features/Library/EditReusable/index.vue +206 -0
  12. package/dist/runtime/components/Edit/Features/Library/index.vue +25 -2
  13. package/dist/runtime/components/Edit/Features/MultiSelect/index.vue +1 -1
  14. package/dist/runtime/components/Edit/Features/Options/Form/Item.vue +2 -4
  15. package/dist/runtime/components/Edit/Features/Publish/index.vue +4 -1
  16. package/dist/runtime/components/Edit/Features/Translations/index.vue +43 -1
  17. package/dist/runtime/css/output.css +1 -1
  18. package/dist/runtime/helpers/broadcastProvider.d.ts +10 -2
  19. package/dist/runtime/helpers/composables/onBroadcastEvent.d.ts +2 -0
  20. package/dist/runtime/helpers/composables/onBroadcastEvent.js +10 -0
  21. package/dist/runtime/helpers/index.js +2 -2
  22. package/dist/runtime/helpers/runtimeHelpers/index.d.ts +5 -0
  23. package/dist/runtime/helpers/runtimeHelpers/index.js +4 -6
  24. package/dist/runtime/types/index.d.ts +12 -2
  25. package/package.json +1 -1
package/dist/module.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "blokkli",
3
3
  "configKey": "blokkli",
4
- "version": "1.0.1",
4
+ "version": "1.0.3",
5
5
  "compatibility": {
6
6
  "nuxt": "^3.12.0"
7
7
  },
package/dist/module.mjs CHANGED
@@ -6,7 +6,7 @@ import { createUnplugin } from 'unplugin';
6
6
  import MagicString from 'magic-string';
7
7
  import { walk } from 'estree-walker-ts';
8
8
 
9
- const version = "1.0.1";
9
+ const version = "1.0.3";
10
10
 
11
11
  function sortObjectKeys(obj) {
12
12
  const sortedKeys = Object.keys(obj).sort();
@@ -1155,6 +1155,14 @@ const libraryError$2 = {
1155
1155
  source: "Failed to add block to library.",
1156
1156
  translation: "Das Element konnte nicht wiederverwendbar gemacht werden."
1157
1157
  };
1158
+ const libraryItemEditOverlayBack$2 = {
1159
+ source: "Back to page",
1160
+ translation: "Zurück zur Seite"
1161
+ };
1162
+ const libraryItemEditOverlayTitle$2 = {
1163
+ source: "Edit reusable block",
1164
+ translation: "Wiederverwendbaren Block bearbeiten"
1165
+ };
1158
1166
  const libraryPlaceBundleSelectLabel$2 = {
1159
1167
  source: "Bundle",
1160
1168
  translation: "Typ"
@@ -1692,6 +1700,8 @@ const de = {
1692
1700
  libraryDialogTitle: libraryDialogTitle$2,
1693
1701
  libraryDialogTitleInputPlaceholder: libraryDialogTitleInputPlaceholder$2,
1694
1702
  libraryError: libraryError$2,
1703
+ libraryItemEditOverlayBack: libraryItemEditOverlayBack$2,
1704
+ libraryItemEditOverlayTitle: libraryItemEditOverlayTitle$2,
1695
1705
  libraryPlaceBundleSelectLabel: libraryPlaceBundleSelectLabel$2,
1696
1706
  libraryPlaceDialogLead: libraryPlaceDialogLead$2,
1697
1707
  libraryPlaceDialogSubmit: libraryPlaceDialogSubmit$2,
@@ -2298,6 +2308,14 @@ const libraryError$1 = {
2298
2308
  source: "Failed to add block to library.",
2299
2309
  translation: "L'élément n’a pas pu être rendu réutilisable."
2300
2310
  };
2311
+ const libraryItemEditOverlayBack$1 = {
2312
+ source: "Back to page",
2313
+ translation: ""
2314
+ };
2315
+ const libraryItemEditOverlayTitle$1 = {
2316
+ source: "Edit reusable block",
2317
+ translation: ""
2318
+ };
2301
2319
  const libraryPlaceBundleSelectLabel$1 = {
2302
2320
  source: "Bundle",
2303
2321
  translation: ""
@@ -2835,6 +2853,8 @@ const fr = {
2835
2853
  libraryDialogTitle: libraryDialogTitle$1,
2836
2854
  libraryDialogTitleInputPlaceholder: libraryDialogTitleInputPlaceholder$1,
2837
2855
  libraryError: libraryError$1,
2856
+ libraryItemEditOverlayBack: libraryItemEditOverlayBack$1,
2857
+ libraryItemEditOverlayTitle: libraryItemEditOverlayTitle$1,
2838
2858
  libraryPlaceBundleSelectLabel: libraryPlaceBundleSelectLabel$1,
2839
2859
  libraryPlaceDialogLead: libraryPlaceDialogLead$1,
2840
2860
  libraryPlaceDialogSubmit: libraryPlaceDialogSubmit$1,
@@ -3441,6 +3461,14 @@ const libraryError = {
3441
3461
  source: "Failed to add block to library.",
3442
3462
  translation: "L'elemento non può essere reso riutilizzabile."
3443
3463
  };
3464
+ const libraryItemEditOverlayBack = {
3465
+ source: "Back to page",
3466
+ translation: ""
3467
+ };
3468
+ const libraryItemEditOverlayTitle = {
3469
+ source: "Edit reusable block",
3470
+ translation: ""
3471
+ };
3444
3472
  const libraryPlaceBundleSelectLabel = {
3445
3473
  source: "Bundle",
3446
3474
  translation: ""
@@ -3978,6 +4006,8 @@ const it = {
3978
4006
  libraryDialogTitle: libraryDialogTitle,
3979
4007
  libraryDialogTitleInputPlaceholder: libraryDialogTitleInputPlaceholder,
3980
4008
  libraryError: libraryError,
4009
+ libraryItemEditOverlayBack: libraryItemEditOverlayBack,
4010
+ libraryItemEditOverlayTitle: libraryItemEditOverlayTitle,
3981
4011
  libraryPlaceBundleSelectLabel: libraryPlaceBundleSelectLabel,
3982
4012
  libraryPlaceDialogLead: libraryPlaceDialogLead,
3983
4013
  libraryPlaceDialogSubmit: libraryPlaceDialogSubmit,
@@ -339,6 +339,13 @@ export default defineBlokkliEditAdapter(
339
339
  const url = typeof parts === "string" ? parts : "/" + parts.join("/");
340
340
  return { url: prefix + url + `?paragraphsBlokkli=true` };
341
341
  };
342
+ const getLibraryItemEditUrl = (uuid) => {
343
+ const url = buildFormUrl(
344
+ ["blokkli", "library-item", uuid],
345
+ ctx.value.language
346
+ ).url;
347
+ return `${url}&blokkliEditing=${uuid}&language=${ctx.value.language}`;
348
+ };
342
349
  const formFrameBuilder = (e) => {
343
350
  const entityType = ctx.value.entityType.toLowerCase();
344
351
  if (e.id === "block:add") {
@@ -637,7 +644,8 @@ export default defineBlokkliEditAdapter(
637
644
  addContentSearchItem,
638
645
  clipboardMapBundle,
639
646
  addBlockFromClipboardItem,
640
- changeLanguage
647
+ changeLanguage,
648
+ getLibraryItemEditUrl
641
649
  };
642
650
  }
643
651
  );
@@ -197,6 +197,10 @@ export interface BlokkliAdapter<T> {
197
197
  * Add a reusable item.
198
198
  */
199
199
  addLibraryItem?: (e: AddReusableItemEvent) => Promise<MutationResponseLike<T>>;
200
+ /**
201
+ * Build the URL to edit a library item.
202
+ */
203
+ getLibraryItemEditUrl?: (uuid: string) => string;
200
204
  /**
201
205
  * Delete multiple items.
202
206
  */
@@ -7,6 +7,7 @@
7
7
  :data-reusable-bundle="item.bundle"
8
8
  :data-reusable-uuid="item.uuid"
9
9
  :data-bk-library-label="libraryItem?.label"
10
+ :data-bk-library-item-uuid="libraryItem?.uuid"
10
11
  data-blokkli-is-reusable="true"
11
12
  :parent-type="parentType"
12
13
  />
@@ -23,6 +24,7 @@ import type { FieldListItem } from '#blokkli/types'
23
24
  interface LibraryItem {
24
25
  block?: FieldListItem
25
26
  label?: string
27
+ uuid?: string
26
28
  }
27
29
 
28
30
  const props = defineProps<{
@@ -31,9 +33,6 @@ const props = defineProps<{
31
33
 
32
34
  const { index, options, parentType } = defineBlokkli({
33
35
  bundle: 'from_library',
34
- editor: {
35
- disableEdit: true,
36
- },
37
36
  })
38
37
 
39
38
  // Reusable items inherit the options from this wrapper paragraph.
@@ -19,7 +19,12 @@
19
19
  </button>
20
20
  </div>
21
21
 
22
- <div class="bk-dialog-content">
22
+ <div
23
+ class="bk-dialog-content"
24
+ :class="{
25
+ 'bk-is-fullscreen': fullScreen,
26
+ }"
27
+ >
23
28
  <div class="bk-dialog-content-inner">
24
29
  <div v-if="lead" class="bk bk-dialog-lead">
25
30
  {{ lead }}
@@ -67,6 +72,7 @@ const props = withDefaults(
67
72
  isLoading?: boolean
68
73
  hideButtons?: boolean
69
74
  icon?: BlokkliIcon
75
+ fullScreen?: boolean
70
76
  }>(),
71
77
  {
72
78
  width: 600,
@@ -82,6 +88,13 @@ const style = computed(() => {
82
88
  return {}
83
89
  }
84
90
 
91
+ if (props.fullScreen) {
92
+ return {
93
+ maxWidth: '100vw',
94
+ height: '100vh',
95
+ }
96
+ }
97
+
85
98
  if (typeof props.width === 'number') {
86
99
  return {
87
100
  maxWidth: props.width + 'px',
@@ -158,15 +158,17 @@ function onPointerDown(e: PointerEvent) {
158
158
  e.stopImmediatePropagation()
159
159
  }
160
160
 
161
+ if (e.pointerType === 'touch') {
162
+ return onTouchStart(e)
163
+ }
164
+
161
165
  // If we are already dragging, return.
162
166
  // This might be the case if a dragging:start event was manually triggered,
163
167
  // e.g. when selecting a draggable item using the keyboard.
164
168
  if (selection.isDragging.value) {
165
169
  return
166
170
  }
167
- if (e.pointerType === 'touch') {
168
- return onTouchStart(e)
169
- }
171
+
170
172
  pointerDownTimestamp = Date.now()
171
173
  const coords = { x: e.clientX, y: e.clientY }
172
174
 
@@ -241,10 +243,7 @@ function onPointerUp(e: PointerEvent) {
241
243
  if (!block) {
242
244
  return
243
245
  }
244
- eventBus.emit('item:edit', {
245
- uuid: lastInteractedElement.uuid,
246
- bundle: block.itemBundle,
247
- })
246
+ eventBus.emit('item:doubleClick', block)
248
247
  }
249
248
  }
250
249
  }
@@ -166,6 +166,7 @@ onMounted(() => {
166
166
  setRootClasses()
167
167
  baseLogger.log('EditProvider mounted')
168
168
  dom.init()
169
+ broadcast.emit('editorLoaded', { uuid: props.entityUuid })
169
170
  })
170
171
 
171
172
  onBeforeUnmount(() => {
@@ -1,8 +1,9 @@
1
1
  <template>
2
2
  <PluginItemAction
3
+ v-if="isEditing"
3
4
  id="edit"
4
5
  :title="$t('edit', 'Edit')"
5
- :disabled="disabled"
6
+ :disabled="!canEdit"
6
7
  meta
7
8
  key-code="E"
8
9
  icon="edit"
@@ -16,6 +17,7 @@ import { computed, useBlokkli, defineBlokkliFeature } from '#imports'
16
17
  import type { DraggableExistingBlock } from '#blokkli/types'
17
18
  import { PluginItemAction } from '#blokkli/plugins'
18
19
  import { getDefinition } from '#blokkli/definitions'
20
+ import onBlokkliEvent from '#blokkli/helpers/composables/onBlokkliEvent'
19
21
 
20
22
  defineBlokkliFeature({
21
23
  id: 'edit',
@@ -25,23 +27,47 @@ defineBlokkliFeature({
25
27
  requiredAdapterMethods: ['formFrameBuilder'],
26
28
  })
27
29
 
28
- const { eventBus, selection, state, $t } = useBlokkli()
30
+ const { eventBus, selection, state, $t, adapter } = useBlokkli()
29
31
 
30
- const disabled = computed(() => {
31
- if (state.editMode.value !== 'editing') {
32
- return true
33
- }
32
+ const block = computed(() => {
34
33
  if (selection.blocks.value.length !== 1) {
35
- return true
34
+ return null
35
+ }
36
+
37
+ return selection.blocks.value[0]
38
+ })
39
+
40
+ const isEditing = computed(() => state.editMode.value === 'editing')
41
+
42
+ const canEdit = computed(() => {
43
+ // Editing is only possible when a single block is selected.
44
+ if (!block.value) {
45
+ return false
36
46
  }
37
47
 
38
- const block = selection.blocks.value[0]
39
48
  const definition = getDefinition(
40
- block.itemBundle,
41
- block.hostFieldListType,
42
- block.parentBlockBundle,
49
+ block.value.itemBundle,
50
+ block.value.hostFieldListType,
51
+ block.value.parentBlockBundle,
43
52
  )
44
- return definition?.editor?.disableEdit === true
53
+
54
+ // Editing is explicitly disabled via the definition.
55
+ if (definition?.editor?.disableEdit) {
56
+ return false
57
+ }
58
+
59
+ // For reusable blocks, editing is only possible if the adapter implements
60
+ // the getLibraryItemEditUrl method.
61
+ if (block.value.libraryItemUuid) {
62
+ return (
63
+ !!adapter.getLibraryItemEditUrl &&
64
+ (state.editMode.value === 'editing' ||
65
+ state.editMode.value === 'translating') &&
66
+ !block.value.isNew
67
+ )
68
+ }
69
+
70
+ return state.editMode.value === 'editing'
45
71
  })
46
72
 
47
73
  function onClick(items: DraggableExistingBlock[]) {
@@ -49,11 +75,34 @@ function onClick(items: DraggableExistingBlock[]) {
49
75
  return
50
76
  }
51
77
 
78
+ if (!canEdit.value) {
79
+ return
80
+ }
81
+
82
+ const item = items[0]
83
+
84
+ // Because editing library items inside the current context is not (yet)
85
+ // supported, editing has to happen in a separate window where the host
86
+ // context is the library item entity.
87
+ if (item.libraryItemUuid && adapter.getLibraryItemEditUrl) {
88
+ const url = adapter.getLibraryItemEditUrl(item.libraryItemUuid)
89
+ eventBus.emit('library:edit-item', {
90
+ url,
91
+ label: item.editTitle,
92
+ uuid: item.libraryItemUuid,
93
+ })
94
+ return
95
+ }
96
+
52
97
  eventBus.emit('item:edit', {
53
- uuid: items[0].uuid,
54
- bundle: items[0].itemBundle,
98
+ uuid: item.uuid,
99
+ bundle: item.itemBundle,
55
100
  })
56
101
  }
102
+
103
+ onBlokkliEvent('item:doubleClick', function (block) {
104
+ onClick([block])
105
+ })
57
106
  </script>
58
107
 
59
108
  <script lang="ts">
@@ -20,12 +20,13 @@ defineBlokkliFeature({
20
20
  description: 'Provides a menu button to exit the editor without saving.',
21
21
  })
22
22
 
23
- const { $t } = useBlokkli()
23
+ const { $t, broadcast, context } = useBlokkli()
24
24
 
25
25
  const route = useRoute()
26
26
 
27
27
  function onClick() {
28
28
  nextTick(() => {
29
+ broadcast.emit('closeEditor', { uuid: context.value.entityUuid })
29
30
  window.location.href = route.path
30
31
  })
31
32
  }
@@ -0,0 +1,206 @@
1
+ <template>
2
+ <Teleport to="body">
3
+ <Loading v-if="isLoading" />
4
+ <Transition name="bk-library-edit-header">
5
+ <header v-show="isLoaded" class="bk bk-library-edit-overlay-header">
6
+ <h2>
7
+ <span>{{
8
+ $t('libraryItemEditOverlayTitle', 'Edit reusable block')
9
+ }}</span>
10
+ <span v-if="label">&nbsp;{{ label }}</span>
11
+ </h2>
12
+ <button @click.prevent="closeOverlay">
13
+ <Icon name="arrow-left" />
14
+ <span>{{ $t('libraryItemEditOverlayBack', 'Back to page') }}</span>
15
+ </button>
16
+ </header>
17
+ </Transition>
18
+ <Transition
19
+ :css="false"
20
+ @enter="onEnter"
21
+ @after-enter="onAfter"
22
+ @enter-cancelled="onAfter"
23
+ @leave="onLeave"
24
+ @after-leave="onAfterLeave"
25
+ @leave-cancelled="onAfterLeave"
26
+ >
27
+ <div v-show="isLoaded" class="bk bk-library-edit-overlay">
28
+ <iframe
29
+ ref="iframe"
30
+ :src="url"
31
+ style="width: 100%; height: 100%"
32
+ @load="onLoad"
33
+ />
34
+ </div>
35
+ </Transition>
36
+ </Teleport>
37
+ </template>
38
+
39
+ <script lang="ts" setup>
40
+ import onBroadcastEvent from '#blokkli/helpers/composables/onBroadcastEvent'
41
+ import { ref, useBlokkli } from '#imports'
42
+ import { Icon } from '#blokkli/components'
43
+ import Loading from './../../../Loading/index.vue'
44
+
45
+ const props = defineProps<{
46
+ url: string
47
+ uuid: string
48
+ label?: string
49
+ }>()
50
+
51
+ const DURATION = 530
52
+ const emit = defineEmits(['submit', 'close'])
53
+
54
+ function getOriginatingElement(): HTMLElement | null {
55
+ const el = document.querySelector(
56
+ `[data-bk-library-item-uuid="${props.uuid}"]`,
57
+ )
58
+ if (el instanceof HTMLElement) {
59
+ return el
60
+ }
61
+
62
+ return null
63
+ }
64
+
65
+ // called one frame after the element is inserted.
66
+ // use this to start the entering animation.
67
+ function onEnter(el: Element, done: () => void) {
68
+ if (el instanceof HTMLElement) {
69
+ const originating = getOriginatingElement()
70
+ if (!originating) {
71
+ done()
72
+ isLoading.value = false
73
+ return
74
+ }
75
+
76
+ const originatingRect = originating.getBoundingClientRect()
77
+ const overlayRect = el.getBoundingClientRect()
78
+
79
+ const offsetX =
80
+ originatingRect.x - overlayRect.x + originatingRect.width / 2
81
+ const offsetY =
82
+ originatingRect.y - overlayRect.y + originatingRect.height / 2
83
+
84
+ el.style.transform = `translate(${offsetX}px, ${offsetY}px) scale(0, 0)`
85
+
86
+ setTimeout(() => {
87
+ el.style.transitionDuration = DURATION + 'ms'
88
+ el.style.transitionTimingFunction = 'cubic-bezier(0.56, 0.04, 0.25, 1)'
89
+ el.style.transitionProperty = 'transform'
90
+ el.style.transformOrigin = '0px 0px'
91
+ el.style.transform = 'translate(0px, 0px)'
92
+ }, 10)
93
+
94
+ setTimeout(() => {
95
+ done()
96
+ isLoading.value = false
97
+ }, DURATION)
98
+ }
99
+ }
100
+
101
+ // called when the enter transition has finished.
102
+ function onAfter(el: Element) {
103
+ if (el instanceof HTMLElement) {
104
+ el.style.transform = ''
105
+ el.style.transitionDuration = ''
106
+ el.style.opacity = ''
107
+ el.style.transitionProperty = ''
108
+ el.style.transitionTimingFunction = ''
109
+ el.style.transformOrigin = ''
110
+ }
111
+ }
112
+
113
+ // called when the leave transition starts.
114
+ // use this to start the leaving animation.
115
+ function onLeave(el: Element, done: () => void) {
116
+ if (el instanceof HTMLElement) {
117
+ const originating = getOriginatingElement()
118
+ if (!originating) {
119
+ done()
120
+ return
121
+ }
122
+
123
+ const originatingRect = originating.getBoundingClientRect()
124
+ const overlayRect = el.getBoundingClientRect()
125
+
126
+ const offsetX =
127
+ originatingRect.x - overlayRect.x + originatingRect.width / 2
128
+ const offsetY =
129
+ originatingRect.y - overlayRect.y + originatingRect.height / 2
130
+
131
+ el.style.transform = 'translate(0px, 0px)'
132
+
133
+ setTimeout(() => {
134
+ el.style.transitionDuration = DURATION + 'ms'
135
+ el.style.transitionTimingFunction = 'cubic-bezier(0.56, 0.04, 0.25, 1)'
136
+ el.style.transitionProperty = 'transform'
137
+ el.style.transformOrigin = '0px 0px'
138
+ el.style.transform = `translate(${offsetX}px, ${offsetY}px) scale(0, 0)`
139
+ }, 10)
140
+
141
+ setTimeout(() => {
142
+ done()
143
+ }, DURATION)
144
+ }
145
+ }
146
+
147
+ function onAfterLeave(el: Element) {
148
+ onAfter(el)
149
+ if (hasPublished.value) {
150
+ emit('submit')
151
+ } else {
152
+ emit('close')
153
+ }
154
+ }
155
+
156
+ const { $t } = useBlokkli()
157
+
158
+ const iframe = ref<HTMLIFrameElement | null>(null)
159
+ const isLoaded = ref(false)
160
+ const isLoading = ref(true)
161
+ const hasPublished = ref(false)
162
+ let timeout: any = null
163
+
164
+ function onLibraryItemPublished({ uuid }: { uuid: string }) {
165
+ if (props.uuid === uuid) {
166
+ hasPublished.value = true
167
+ isLoaded.value = false
168
+ }
169
+ }
170
+
171
+ function onLoad() {
172
+ clearTimeout(timeout)
173
+
174
+ timeout = window.setTimeout(() => {
175
+ isLoaded.value = true
176
+ }, 3000)
177
+ if (!iframe.value) {
178
+ return
179
+ }
180
+
181
+ iframe.value.focus()
182
+
183
+ iframe.value.contentWindow?.focus()
184
+ }
185
+
186
+ function closeOverlay() {
187
+ hasPublished.value = false
188
+ isLoaded.value = false
189
+ }
190
+
191
+ function onLibraryItemClose({ uuid }: { uuid: string }) {
192
+ if (props.uuid === uuid) {
193
+ closeOverlay()
194
+ }
195
+ }
196
+
197
+ function onEditorLoaded({ uuid }: { uuid: string }) {
198
+ if (props.uuid === uuid) {
199
+ isLoaded.value = true
200
+ }
201
+ }
202
+
203
+ onBroadcastEvent('published', onLibraryItemPublished)
204
+ onBroadcastEvent('closeEditor', onLibraryItemClose)
205
+ onBroadcastEvent('editorLoaded', onEditorLoaded)
206
+ </script>
@@ -50,7 +50,7 @@
50
50
  </Teleport>
51
51
 
52
52
  <Teleport to="body">
53
- <transition name="bk-slide-in" :duration="200">
53
+ <transition name="bk-slide-up" :duration="200">
54
54
  <LibraryDialog
55
55
  v-if="placedAction && adapter.getLibraryItems"
56
56
  :field="placedAction.field"
@@ -59,6 +59,12 @@
59
59
  />
60
60
  </transition>
61
61
  </Teleport>
62
+ <EditReusable
63
+ v-if="editingLibraryItem"
64
+ v-bind="editingLibraryItem"
65
+ @submit="onSubmitLibraryItem"
66
+ @close="cancelLibraryItemEdit"
67
+ />
62
68
  </template>
63
69
 
64
70
  <script lang="ts" setup>
@@ -66,8 +72,10 @@ import { ref, computed, useBlokkli, defineBlokkliFeature } from '#imports'
66
72
  import { PluginItemAction, PluginAddAction } from '#blokkli/plugins'
67
73
  import ReusableDialog from './ReusableDialog/index.vue'
68
74
  import LibraryDialog from './LibraryDialog/index.vue'
75
+ import EditReusable from './EditReusable/index.vue'
69
76
  import { getDefinition } from '#blokkli/definitions'
70
- import type { ActionPlacedEvent } from '#blokkli/types'
77
+ import type { ActionPlacedEvent, LibraryEditItemEvent } from '#blokkli/types'
78
+ import onBlokkliEvent from '#blokkli/helpers/composables/onBlokkliEvent'
71
79
 
72
80
  const { adapter } = defineBlokkliFeature({
73
81
  id: 'library',
@@ -175,6 +183,21 @@ const canMakeReusable = computed(
175
183
  itemBundle?.value?.allowReusable &&
176
184
  fromLibraryAllowedInList.value,
177
185
  )
186
+
187
+ const editingLibraryItem = ref<LibraryEditItemEvent | null>(null)
188
+
189
+ onBlokkliEvent('library:edit-item', function (e) {
190
+ editingLibraryItem.value = e
191
+ })
192
+
193
+ function cancelLibraryItemEdit() {
194
+ editingLibraryItem.value = null
195
+ }
196
+
197
+ function onSubmitLibraryItem() {
198
+ eventBus.emit('reloadState')
199
+ cancelLibraryItemEdit()
200
+ }
178
201
  </script>
179
202
 
180
203
  <script lang="ts">
@@ -44,7 +44,7 @@ const onSelect = (uuids: string[]) => {
44
44
  let startTimeout: any = null
45
45
 
46
46
  onBlokkliEvent('mouse:down', (e) => {
47
- if (!enabled.value || e.type !== 'mouse') {
47
+ if (!enabled.value || e.type !== 'mouse' || selection.isDragging.value) {
48
48
  return
49
49
  }
50
50
  if (keyboard.isPressingSpace.value || keyboard.isPressingControl.value) {
@@ -69,6 +69,7 @@ import OptionColor from './Color/index.vue'
69
69
  import OptionRange from './Range/index.vue'
70
70
  import OptionNumber from './Number/index.vue'
71
71
  import type { BlockOptionDefinition } from '#blokkli/types/blokkOptions'
72
+ import { mapCheckboxTrue } from '#blokkli/helpers/runtimeHelpers'
72
73
 
73
74
  const { state } = useBlokkli()
74
75
 
@@ -99,10 +100,7 @@ const validateValue = (
99
100
  return v
100
101
  }
101
102
  } else if (props.option.type === 'checkbox') {
102
- if (typeof v === 'boolean') {
103
- return v ? '1' : '0'
104
- }
105
- return v === '1' ? '1' : '0'
103
+ return mapCheckboxTrue(v)
106
104
  } else if (props.option.type === 'checkboxes') {
107
105
  const options = Object.keys(props.option.options || {})
108
106
  const items = Array.isArray(v)
@@ -24,7 +24,7 @@ const { adapter } = defineBlokkliFeature({
24
24
  'Provides a menu button to publish the changes of the current entity.',
25
25
  })
26
26
 
27
- const { state, $t, eventBus } = useBlokkli()
27
+ const { state, $t, eventBus, broadcast, context } = useBlokkli()
28
28
  const { mutations, canEdit, mutateWithLoadingState } = state
29
29
 
30
30
  const onClick = async () => {
@@ -39,7 +39,10 @@ const onClick = async () => {
39
39
  if (validations.length) {
40
40
  eventBus.emit('publish:failed')
41
41
  }
42
+ return
42
43
  }
44
+
45
+ broadcast.emit('published', { uuid: context.value.entityUuid })
43
46
  }
44
47
  </script>
45
48