@toaster-builder/site-runtime 0.1.1 → 0.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/README.md CHANGED
@@ -70,3 +70,23 @@ const placementId = inject(blockPlacementIdKey, ref(''))
70
70
  ```
71
71
 
72
72
  Для модального Block атрибут ставится на само окно, а не на backdrop.
73
+
74
+ ## Действия блока в Builder
75
+
76
+ По умолчанию Builder показывает полный набор действий. Block может ограничить
77
+ его атрибутом `data-toaster-editor-actions` на том же элементе, который отмечен
78
+ как `data-toaster-editor-root`:
79
+
80
+ ```vue
81
+ <div
82
+ data-toaster-editor-root
83
+ data-toaster-editor-actions="version settings assistant add add-ai"
84
+ :data-toaster-placement-id="placementId"
85
+ >
86
+ <!-- Содержимое блока -->
87
+ </div>
88
+ ```
89
+
90
+ Доступные значения: `version`, `move`, `copy`, `settings`, `assistant`,
91
+ `visibility`, `delete`, `add`, `add-ai`. Если атрибут отсутствует, доступны все
92
+ действия. Пустой атрибут скрывает все элементы управления.
package/dist/module.json CHANGED
@@ -4,7 +4,7 @@
4
4
  "compatibility": {
5
5
  "nuxt": ">=4.0.0"
6
6
  },
7
- "version": "0.1.1",
7
+ "version": "0.1.2",
8
8
  "builder": {
9
9
  "@nuxt/module-builder": "1.0.3",
10
10
  "unbuild": "3.6.1"
@@ -19,6 +19,10 @@ import moveBlockUpIcon from "../assets/editor/move-block-up.svg";
19
19
  import showBlockIcon from "../assets/editor/show-block.svg";
20
20
  import BlockPlacementProvider from "#toaster-site-runtime/components/BlockPlacementProvider.vue";
21
21
  import { useBuilderEventService } from "#toaster-site-runtime/composables/useBuilderEventService";
22
+ import {
23
+ blockEditorActions,
24
+ parseBlockEditorActions
25
+ } from "#toaster-site-runtime/utils/block-editor-actions";
22
26
  const props = defineProps({
23
27
  blockComponent: { type: null, required: true },
24
28
  blockId: { type: String, required: true },
@@ -38,6 +42,9 @@ const overlayHovered = ref(false);
38
42
  const overlayFocused = ref(false);
39
43
  const overlayStyle = ref({});
40
44
  const overlayVisible = ref(false);
45
+ const enabledEditorActions = shallowRef(
46
+ new Set(blockEditorActions)
47
+ );
41
48
  const targetHovered = ref(false);
42
49
  const targetFocused = ref(false);
43
50
  const overlayActive = computed(() => overlayHovered.value || overlayFocused.value || targetHovered.value || targetFocused.value);
@@ -104,6 +111,9 @@ function unbindEditorTarget() {
104
111
  targetFocused.value = false;
105
112
  }
106
113
  function bindEditorTarget(target) {
114
+ enabledEditorActions.value = parseBlockEditorActions(
115
+ target?.dataset.toasterEditorActions
116
+ );
107
117
  if (editorTarget.value === target) {
108
118
  scheduleOverlayBoundsUpdate();
109
119
  return;
@@ -122,6 +132,9 @@ function bindEditorTarget(target) {
122
132
  resizeObserver.observe(target);
123
133
  scheduleOverlayBoundsUpdate();
124
134
  }
135
+ function hasEditorAction(action) {
136
+ return enabledEditorActions.value.has(action);
137
+ }
125
138
  function findPlacementTargets(root) {
126
139
  return Array.from(root.querySelectorAll("[data-toaster-editor-root]")).filter((element) => element.dataset.toasterPlacementId === props.placementId);
127
140
  }
@@ -144,7 +157,16 @@ onMounted(() => {
144
157
  document.addEventListener("scroll", scheduleOverlayBoundsUpdate, true);
145
158
  window.addEventListener("resize", scheduleOverlayBoundsUpdate);
146
159
  mutationObserver = new MutationObserver(resolveEditorTarget);
147
- mutationObserver.observe(document.body, { childList: true, subtree: true });
160
+ mutationObserver.observe(document.body, {
161
+ attributes: true,
162
+ attributeFilter: [
163
+ "data-toaster-editor-actions",
164
+ "data-toaster-editor-root",
165
+ "data-toaster-placement-id"
166
+ ],
167
+ childList: true,
168
+ subtree: true
169
+ });
148
170
  void nextTick(resolveEditorTarget);
149
171
  });
150
172
  onBeforeUnmount(() => {
@@ -192,6 +214,7 @@ onBeforeUnmount(() => {
192
214
  class="block-editor-frame__overlay"
193
215
  :class="{ 'block-editor-frame__overlay--active': overlayActive }"
194
216
  data-toaster-editor-overlay
217
+ :data-toaster-editor-actions="[...enabledEditorActions].join(' ')"
195
218
  :data-toaster-placement-id="placementId"
196
219
  :style="overlayStyle"
197
220
  @pointerenter="overlayHovered = true"
@@ -201,6 +224,7 @@ onBeforeUnmount(() => {
201
224
  >
202
225
  <div class="block-editor-frame__toolbar">
203
226
  <button
227
+ v-if="hasEditorAction('version')"
204
228
  class="block-editor-frame__control block-editor-frame__version"
205
229
  type="button"
206
230
  :aria-label="`\u0421\u043C\u0435\u043D\u0438\u0442\u044C \u0432\u0435\u0440\u0441\u0438\u044E \u0431\u043B\u043E\u043A\u0430 ${blockVersionLabel}`"
@@ -211,6 +235,7 @@ onBeforeUnmount(() => {
211
235
  </button>
212
236
 
213
237
  <button
238
+ v-if="hasEditorAction('move')"
214
239
  class="block-editor-frame__control block-editor-frame__icon-button"
215
240
  type="button"
216
241
  :aria-label="`\u041F\u0435\u0440\u0435\u043D\u0435\u0441\u0442\u0438 \u0432\u0432\u0435\u0440\u0445 \u0431\u043B\u043E\u043A ${blockVersionLabel}`"
@@ -226,6 +251,7 @@ onBeforeUnmount(() => {
226
251
  </button>
227
252
 
228
253
  <button
254
+ v-if="hasEditorAction('move')"
229
255
  class="block-editor-frame__control block-editor-frame__icon-button"
230
256
  type="button"
231
257
  :aria-label="`\u041F\u0435\u0440\u0435\u043D\u0435\u0441\u0442\u0438 \u0432\u043D\u0438\u0437 \u0431\u043B\u043E\u043A ${blockVersionLabel}`"
@@ -241,6 +267,7 @@ onBeforeUnmount(() => {
241
267
  </button>
242
268
 
243
269
  <button
270
+ v-if="hasEditorAction('copy')"
244
271
  class="block-editor-frame__control block-editor-frame__icon-button"
245
272
  type="button"
246
273
  :aria-label="`\u041A\u043E\u043F\u0438\u0440\u043E\u0432\u0430\u0442\u044C \u0431\u043B\u043E\u043A ${blockVersionLabel}`"
@@ -255,6 +282,7 @@ onBeforeUnmount(() => {
255
282
  </button>
256
283
 
257
284
  <button
285
+ v-if="hasEditorAction('settings')"
258
286
  class="block-editor-frame__control block-editor-frame__icon-button"
259
287
  type="button"
260
288
  :aria-label="`\u041D\u0430\u0441\u0442\u0440\u043E\u0439\u043A\u0438 \u0431\u043B\u043E\u043A\u0430 ${blockVersionLabel}`"
@@ -279,6 +307,7 @@ onBeforeUnmount(() => {
279
307
  </button>
280
308
 
281
309
  <button
310
+ v-if="hasEditorAction('assistant')"
282
311
  class="block-editor-frame__control block-editor-frame__icon-button"
283
312
  type="button"
284
313
  :aria-label="`\u041E\u0442\u043A\u0440\u044B\u0442\u044C AI-\u0430\u0441\u0441\u0438\u0441\u0442\u0435\u043D\u0442\u0430 \u0434\u043B\u044F \u0431\u043B\u043E\u043A\u0430 ${blockVersionLabel}`"
@@ -293,6 +322,7 @@ onBeforeUnmount(() => {
293
322
  </button>
294
323
 
295
324
  <button
325
+ v-if="hasEditorAction('visibility')"
296
326
  class="block-editor-frame__control block-editor-frame__icon-button"
297
327
  type="button"
298
328
  :aria-label="enabled ? `\u0412\u0440\u0435\u043C\u0435\u043D\u043D\u043E \u0441\u043A\u0440\u044B\u0442\u044C \u0431\u043B\u043E\u043A ${blockVersionLabel}` : `\u041F\u043E\u043A\u0430\u0437\u0430\u0442\u044C \u0431\u043B\u043E\u043A ${blockVersionLabel}`"
@@ -307,6 +337,7 @@ onBeforeUnmount(() => {
307
337
  </button>
308
338
 
309
339
  <button
340
+ v-if="hasEditorAction('delete')"
310
341
  class="block-editor-frame__control block-editor-frame__icon-button"
311
342
  type="button"
312
343
  :aria-label="`\u0423\u0434\u0430\u043B\u0438\u0442\u044C \u0431\u043B\u043E\u043A ${blockVersionLabel}`"
@@ -322,6 +353,7 @@ onBeforeUnmount(() => {
322
353
  </div>
323
354
 
324
355
  <button
356
+ v-if="hasEditorAction('add')"
325
357
  class="block-editor-frame__control block-editor-frame__add block-editor-frame__add--after"
326
358
  type="button"
327
359
  aria-label="Добавить блок снизу"
@@ -336,6 +368,7 @@ onBeforeUnmount(() => {
336
368
  </button>
337
369
 
338
370
  <button
371
+ v-if="hasEditorAction('add-ai')"
339
372
  class="block-editor-frame__control block-editor-frame__add-ai"
340
373
  type="button"
341
374
  :aria-label="`\u0421\u043E\u0437\u0434\u0430\u0442\u044C \u0431\u043B\u043E\u043A \u0447\u0435\u0440\u0435\u0437 AI \u043F\u043E\u0441\u043B\u0435 \u0431\u043B\u043E\u043A\u0430 ${blockVersionLabel}`"
@@ -0,0 +1,3 @@
1
+ export declare const blockEditorActions: readonly ["version", "move", "copy", "settings", "assistant", "visibility", "delete", "add", "add-ai"];
2
+ export type BlockEditorAction = (typeof blockEditorActions)[number];
3
+ export declare function parseBlockEditorActions(value: string | undefined): ReadonlySet<BlockEditorAction>;
@@ -0,0 +1,18 @@
1
+ export const blockEditorActions = [
2
+ "version",
3
+ "move",
4
+ "copy",
5
+ "settings",
6
+ "assistant",
7
+ "visibility",
8
+ "delete",
9
+ "add",
10
+ "add-ai"
11
+ ];
12
+ const knownActions = new Set(blockEditorActions);
13
+ export function parseBlockEditorActions(value) {
14
+ if (value === void 0) return new Set(blockEditorActions);
15
+ return new Set(
16
+ value.split(/\s+/).filter((action) => knownActions.has(action))
17
+ );
18
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@toaster-builder/site-runtime",
3
- "version": "0.1.1",
3
+ "version": "0.1.2",
4
4
  "description": "Shared Nuxt runtime for Toaster sites and Builder integration",
5
5
  "license": "MIT",
6
6
  "type": "module",