@blokkli/editor 2.0.0-alpha.42 → 2.0.0-alpha.44

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 (78) hide show
  1. package/dist/module.json +1 -1
  2. package/dist/module.mjs +4 -4
  3. package/dist/modules/agent/index.mjs +6 -2
  4. package/dist/modules/agent/runtime/app/composables/agentProvider.js +28 -19
  5. package/dist/modules/agent/runtime/app/tools/check_readability/index.js +1 -0
  6. package/dist/modules/agent/runtime/app/tools/delegate_text_rewrite/Component.d.vue.ts +2 -0
  7. package/dist/modules/agent/runtime/app/tools/delegate_text_rewrite/Component.vue +7 -3
  8. package/dist/modules/agent/runtime/app/tools/delegate_text_rewrite/Component.vue.d.ts +2 -0
  9. package/dist/modules/agent/runtime/app/tools/helpers.js +5 -3
  10. package/dist/modules/agent/runtime/server/Session.d.ts +2 -0
  11. package/dist/modules/agent/runtime/server/Session.js +17 -0
  12. package/dist/modules/agent/runtime/server/agent.js +2 -1
  13. package/dist/modules/agent/runtime/shared/types.d.ts +1 -0
  14. package/dist/modules/agent/runtime/shared/types.js +2 -1
  15. package/dist/runtime/components/BlokkliProvider.vue +14 -13
  16. package/dist/runtime/editor/components/Actions/Interactions/index.d.vue.ts +3 -0
  17. package/dist/runtime/editor/components/Actions/Interactions/index.vue +110 -0
  18. package/dist/runtime/editor/components/Actions/Interactions/index.vue.d.ts +3 -0
  19. package/dist/runtime/editor/components/Actions/index.vue +34 -3
  20. package/dist/runtime/editor/components/AnimationCanvas/index.vue +2 -10
  21. package/dist/runtime/editor/components/BundleSelector/index.vue +39 -11
  22. package/dist/runtime/editor/components/PreviewProvider.vue +1 -1
  23. package/dist/runtime/editor/components/Toolbar/index.vue +1 -2
  24. package/dist/runtime/editor/composables/useStickyToolbar.d.ts +1 -1
  25. package/dist/runtime/editor/composables/useStickyToolbar.js +25 -7
  26. package/dist/runtime/editor/css/output.css +1 -1
  27. package/dist/runtime/editor/features/analyze/Main.d.vue.ts +6 -0
  28. package/dist/runtime/editor/features/analyze/Main.vue +26 -1
  29. package/dist/runtime/editor/features/analyze/Main.vue.d.ts +6 -0
  30. package/dist/runtime/editor/features/analyze/Renderer/index.d.vue.ts +2 -0
  31. package/dist/runtime/editor/features/analyze/Renderer/index.vue +86 -15
  32. package/dist/runtime/editor/features/analyze/Renderer/index.vue.d.ts +2 -0
  33. package/dist/runtime/editor/features/analyze/analyzers/altText.d.ts +2 -0
  34. package/dist/runtime/editor/features/analyze/analyzers/altText.js +60 -0
  35. package/dist/runtime/editor/features/analyze/analyzers/headingStructure.d.ts +2 -0
  36. package/dist/runtime/editor/features/analyze/analyzers/headingStructure.js +141 -0
  37. package/dist/runtime/editor/features/analyze/analyzers/index.d.ts +5 -1
  38. package/dist/runtime/editor/features/analyze/analyzers/index.js +11 -1
  39. package/dist/runtime/editor/features/analyze/analyzers/readability.js +50 -16
  40. package/dist/runtime/editor/features/analyze/analyzers/types.d.ts +3 -2
  41. package/dist/runtime/editor/features/analyze/index.vue +12 -0
  42. package/dist/runtime/editor/features/analyze/readability/builtinAnalyzer.js +38 -22
  43. package/dist/runtime/editor/features/analyze/readability/types.d.ts +18 -3
  44. package/dist/runtime/editor/features/dragging-overlay/DragItems/index.d.vue.ts +1 -0
  45. package/dist/runtime/editor/features/dragging-overlay/DragItems/index.vue +110 -5
  46. package/dist/runtime/editor/features/dragging-overlay/DragItems/index.vue.d.ts +1 -0
  47. package/dist/runtime/editor/features/dragging-overlay/Renderer/index.d.vue.ts +1 -0
  48. package/dist/runtime/editor/features/dragging-overlay/Renderer/index.vue +16 -1
  49. package/dist/runtime/editor/features/dragging-overlay/Renderer/index.vue.d.ts +1 -0
  50. package/dist/runtime/editor/features/dragging-overlay/index.vue +2 -1
  51. package/dist/runtime/editor/features/editable-field/Overlay/ReadabilityIndicator/ChunkOverlay.d.vue.ts +8 -0
  52. package/dist/runtime/editor/features/editable-field/Overlay/ReadabilityIndicator/ChunkOverlay.vue +135 -0
  53. package/dist/runtime/editor/features/editable-field/Overlay/ReadabilityIndicator/ChunkOverlay.vue.d.ts +8 -0
  54. package/dist/runtime/editor/features/editable-field/Overlay/ReadabilityIndicator/index.d.vue.ts +7 -0
  55. package/dist/runtime/editor/features/editable-field/Overlay/ReadabilityIndicator/index.vue +187 -0
  56. package/dist/runtime/editor/features/editable-field/Overlay/ReadabilityIndicator/index.vue.d.ts +7 -0
  57. package/dist/runtime/editor/features/editable-field/Overlay/index.vue +23 -0
  58. package/dist/runtime/editor/features/hover/Renderer/index.vue +1 -1
  59. package/dist/runtime/editor/features/options/Form/index.vue +7 -17
  60. package/dist/runtime/editor/features/options/index.vue +4 -3
  61. package/dist/runtime/editor/features/search/Overlay/Results/Content/index.vue +7 -11
  62. package/dist/runtime/editor/features/search/Overlay/Results/Page/index.vue +11 -13
  63. package/dist/runtime/editor/features/selection/Renderer/index.vue +2 -0
  64. package/dist/runtime/editor/features/translations/index.vue +1 -1
  65. package/dist/runtime/editor/helpers/draggable/index.d.ts +3 -0
  66. package/dist/runtime/editor/helpers/draggable/index.js +9 -0
  67. package/dist/runtime/editor/providers/analyze.js +1 -1
  68. package/dist/runtime/editor/providers/animation.js +1 -1
  69. package/dist/runtime/editor/providers/readability.js +16 -20
  70. package/dist/runtime/editor/providers/selection.d.ts +0 -4
  71. package/dist/runtime/editor/providers/selection.js +0 -2
  72. package/dist/runtime/editor/providers/ui.d.ts +16 -0
  73. package/dist/runtime/editor/providers/ui.js +5 -1
  74. package/dist/runtime/editor/translations/de.json +129 -1
  75. package/dist/runtime/editor/translations/fr.json +128 -0
  76. package/dist/runtime/editor/translations/gsw_CH.json +128 -0
  77. package/dist/runtime/editor/translations/it.json +128 -0
  78. package/package.json +1 -1
package/dist/module.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@blokkli/editor",
3
3
  "configKey": "blokkli",
4
- "version": "2.0.0-alpha.42",
4
+ "version": "2.0.0-alpha.44",
5
5
  "compatibility": {
6
6
  "nuxt": ">=3.15.0"
7
7
  },
package/dist/module.mjs CHANGED
@@ -18,7 +18,7 @@ import 'typescript';
18
18
  import 'oxc-walker';
19
19
 
20
20
  const name = "@blokkli/editor";
21
- const version = "2.0.0-alpha.42";
21
+ const version = "2.0.0-alpha.44";
22
22
 
23
23
  function validateOption(optionKey, option, icons) {
24
24
  const errors = [];
@@ -809,7 +809,7 @@ const BlokkliEditingPlugin = (nuxt) => {
809
809
  }
810
810
  },
811
811
  vite: {
812
- handleHotUpdate({ file, server, modules }) {
812
+ handleHotUpdate({ file, server }) {
813
813
  if (file.endsWith(".vue") && !file.includes(EDITING_MARKER)) {
814
814
  const editingVariantPath = file.replace(
815
815
  /\.vue$/,
@@ -817,8 +817,7 @@ const BlokkliEditingPlugin = (nuxt) => {
817
817
  );
818
818
  const editingModule = server.moduleGraph.getModuleById(editingVariantPath);
819
819
  if (editingModule) {
820
- server.moduleGraph.invalidateModule(editingModule);
821
- return [...modules, editingModule];
820
+ server.reloadModule(editingModule);
822
821
  }
823
822
  }
824
823
  }
@@ -1417,6 +1416,7 @@ const USED_MATERIAL_ICONS = [
1417
1416
  "bk_mdi_arrow_right",
1418
1417
  "bk_mdi_arrow_right_alt",
1419
1418
  "bk_mdi_arrow_selector_tool",
1419
+ "bk_mdi_arrow_top_left",
1420
1420
  "bk_mdi_arrow_upward",
1421
1421
  "bk_mdi_attach_file",
1422
1422
  "bk_mdi_bakery_dining",
@@ -156,8 +156,12 @@ function createClientTemplate(toolCollector, promptCollector, skillsCollector, o
156
156
  );
157
157
  exports$1.push(`export const routeAgent = ${JSON.stringify(routes.agent)}`);
158
158
  exports$1.push(`export const routeFetch = ${JSON.stringify(routes.fetch)}`);
159
- exports$1.push(`export const routeStream = ${JSON.stringify(routes.stream)}`);
160
- exports$1.push(`export const routeRoute = ${JSON.stringify(routes.routing)}`);
159
+ exports$1.push(
160
+ `export const routeStream = ${JSON.stringify(routes.stream)}`
161
+ );
162
+ exports$1.push(
163
+ `export const routeRoute = ${JSON.stringify(routes.routing)}`
164
+ );
161
165
  exports$1.push(
162
166
  `export const toolNames = ${JSON.stringify(toolCollector.getNames())}`
163
167
  );
@@ -421,8 +421,8 @@ export default function(app, adapter, agentName) {
421
421
  const analyzersList = app.analyze.analyzers.value.filter((a) => !a.requireRawPage).map((a) => ({
422
422
  id: a.id,
423
423
  type: a.type,
424
- label: typeof a.label === "function" ? a.label(context.value.language) : a.label,
425
- description: typeof a.description === "function" ? a.description(context.value.language) : a.description
424
+ label: typeof a.label === "function" ? a.label(context.value.language, $t) : a.label,
425
+ description: typeof a.description === "function" ? a.description(context.value.language, $t) : a.description
426
426
  }));
427
427
  const pageContext = {
428
428
  title: state.entity.value.label || "",
@@ -644,13 +644,22 @@ export default function(app, adapter, agentName) {
644
644
  }
645
645
  }
646
646
  let resultForServer = result;
647
+ let skipLlmResponse;
647
648
  if (typeof result === "object" && result !== null) {
648
649
  const rec = result;
649
650
  if ("_usage" in rec && rec._usage) {
650
651
  usageTurns.value = [...usageTurns.value, rec._usage];
651
652
  }
652
- if ("_details" in rec || "_usage" in rec) {
653
- const { _details: _, _usage: __, ...rest } = rec;
653
+ if (rec._skipLlmResponse === true) {
654
+ skipLlmResponse = true;
655
+ }
656
+ if ("_details" in rec || "_usage" in rec || "_skipLlmResponse" in rec) {
657
+ const {
658
+ _details: _,
659
+ _usage: __,
660
+ _skipLlmResponse: ___,
661
+ ...rest
662
+ } = rec;
654
663
  resultForServer = rest;
655
664
  }
656
665
  }
@@ -669,7 +678,8 @@ export default function(app, adapter, agentName) {
669
678
  send({
670
679
  type: "tool_result",
671
680
  callId,
672
- result: resultForServer
681
+ result: resultForServer,
682
+ skipLlmResponse
673
683
  });
674
684
  }
675
685
  } catch (error) {
@@ -701,6 +711,10 @@ export default function(app, adapter, agentName) {
701
711
  }
702
712
  async function runToolForPrompt(toolName, params) {
703
713
  const ctx = createToolContext();
714
+ if (!Object.keys(toolMap).length) {
715
+ const resolved = await resolveTools(mcpTools, ctx);
716
+ toolMap = createToolMap(resolved);
717
+ }
704
718
  const toolDef = getToolDefinition(toolMap, toolName);
705
719
  const rawResult = await executeTool(toolMap, toolName, ctx, params);
706
720
  const label = isQueryResult(rawResult) ? rawResult.label : toolDef.label($t);
@@ -830,9 +844,15 @@ export default function(app, adapter, agentName) {
830
844
  if (!activeConversationId.value) {
831
845
  activeConversationId.value = generateUUID();
832
846
  }
833
- const isFirstMessage = !conversation.value.some(
834
- (item2) => item2.type === "user"
835
- );
847
+ conversation.value.push({
848
+ type: "user",
849
+ id: generateId(),
850
+ content: displayPrompt ?? prompt,
851
+ timestamp: Date.now(),
852
+ attachments: attachments?.length ? attachments : void 0
853
+ });
854
+ isThinking.value = true;
855
+ const isFirstMessage = conversation.value.filter((v) => v.type === "user").length === 1;
836
856
  const hasClientDirectives = !!(autoLoadTools?.length || autoLoadSkills?.length);
837
857
  let resolvedAutoLoadTools = autoLoadTools;
838
858
  let resolvedAutoLoadSkills = autoLoadSkills;
@@ -867,17 +887,6 @@ export default function(app, adapter, agentName) {
867
887
  } catch {
868
888
  }
869
889
  }
870
- const item = {
871
- type: "user",
872
- id: generateId(),
873
- content: displayPrompt ?? prompt,
874
- timestamp: Date.now()
875
- };
876
- if (attachments?.length) {
877
- ;
878
- item.attachments = attachments;
879
- }
880
- conversation.value.push(item);
881
890
  const serverPreSeeded = preSeededResults?.length ? preSeededResults.map(({ toolName, params, result }) => ({
882
891
  toolName,
883
892
  params,
@@ -42,6 +42,7 @@ export default defineBlokkliAgentTool({
42
42
  let worstLevel = "good";
43
43
  let worstScore = 0;
44
44
  for (const chunk of chunks) {
45
+ if (chunk.band === null || chunk.score === null) continue;
45
46
  const level = bandToLevel(chunk.band);
46
47
  if (level === "hard" || level === "ok" && worstLevel === "good") {
47
48
  worstLevel = level;
@@ -27,6 +27,7 @@ declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {
27
27
  } & {
28
28
  _details?: StreamTextFieldsDetailItem[];
29
29
  _usage?: UsageTurn;
30
+ _skipLlmResponse?: boolean;
30
31
  }) => any;
31
32
  }, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{
32
33
  onDone?: ((result: {
@@ -40,6 +41,7 @@ declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {
40
41
  } & {
41
42
  _details?: StreamTextFieldsDetailItem[];
42
43
  _usage?: UsageTurn;
44
+ _skipLlmResponse?: boolean;
43
45
  }) => any) | undefined;
44
46
  }>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
45
47
  declare const _default: typeof __VLS_export;
@@ -214,10 +214,13 @@ async function analyzeReadability() {
214
214
  const analysisKey = fs.uuid + "/" + fs.fieldName;
215
215
  const fieldResult = rawAnalysis[analysisKey];
216
216
  const chunks = fieldResult?.chunks ?? [];
217
- const issues = chunks.filter((c) => c.band === "hard").map((c) => ({ text: c.text, impact: c.impact, score: c.score }));
217
+ const issues = chunks.filter(
218
+ (c) => c.score !== null && (c.band === "hard" || c.band === "ok")
219
+ ).map((c) => ({ text: c.text, impact: c.impact, score: c.score }));
218
220
  let worstBandValue = -1;
219
221
  let worstScore;
220
222
  for (const chunk of chunks) {
223
+ if (chunk.band === null || chunk.score === null) continue;
221
224
  const value = bandOrder[chunk.band] ?? 0;
222
225
  if (value > worstBandValue) {
223
226
  worstBandValue = value;
@@ -447,7 +450,7 @@ async function readabilityRetryLoop(authToken) {
447
450
  score,
448
451
  issues
449
452
  };
450
- if (level === "hard") {
453
+ if (level === "hard" || level === "ok") {
451
454
  failing.push(check);
452
455
  } else {
453
456
  passing.push(check);
@@ -703,7 +706,8 @@ The user rejected ${fieldList} without a reason. Use the ask_question tool to pr
703
706
  agentMessage,
704
707
  historyIndex: state.currentMutationIndex.value,
705
708
  _details,
706
- _usage: streamUsage.value
709
+ _usage: streamUsage.value,
710
+ _skipLlmResponse: rejectedItems.length === 0
707
711
  });
708
712
  }
709
713
  async function _rejectAll() {
@@ -27,6 +27,7 @@ declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {
27
27
  } & {
28
28
  _details?: StreamTextFieldsDetailItem[];
29
29
  _usage?: UsageTurn;
30
+ _skipLlmResponse?: boolean;
30
31
  }) => any;
31
32
  }, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{
32
33
  onDone?: ((result: {
@@ -40,6 +41,7 @@ declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {
40
41
  } & {
41
42
  _details?: StreamTextFieldsDetailItem[];
42
43
  _usage?: UsageTurn;
44
+ _skipLlmResponse?: boolean;
43
45
  }) => any) | undefined;
44
46
  }>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
45
47
  declare const _default: typeof __VLS_export;
@@ -7,14 +7,16 @@ function mapAnalysisToResult(analysis) {
7
7
  if (slashIndex === -1) continue;
8
8
  const uuid = key.slice(0, slashIndex);
9
9
  const fieldName = key.slice(slashIndex + 1);
10
- const hardChunks = fieldResult.chunks.filter((c) => c.band === "hard");
11
- if (hardChunks.length === 0) continue;
10
+ const issueChunks = fieldResult.chunks.filter(
11
+ (c) => c.score !== null && (c.band === "hard" || c.band === "ok")
12
+ );
13
+ if (issueChunks.length === 0) continue;
12
14
  if (!result[uuid]) {
13
15
  result[uuid] = {};
14
16
  }
15
17
  result[uuid][fieldName] = {
16
18
  fieldValue: fieldResult.rawValue || void 0,
17
- issues: hardChunks.map((c) => ({
19
+ issues: issueChunks.map((c) => ({
18
20
  text: c.text,
19
21
  impact: c.impact,
20
22
  score: c.score
@@ -7,6 +7,7 @@ export declare class Session {
7
7
  resolve: (result: {
8
8
  result: unknown;
9
9
  error?: string;
10
+ skipLlmResponse?: boolean;
10
11
  }) => void;
11
12
  reject: (error: Error) => void;
12
13
  }>;
@@ -67,6 +68,7 @@ export declare class Session {
67
68
  resolveToolResult(callId: string, result: {
68
69
  result: unknown;
69
70
  error?: string;
71
+ skipLlmResponse?: boolean;
70
72
  }): void;
71
73
  cancel(peer: Peer): void;
72
74
  acceptChanges(peer: Peer, authSecret: string): void;
@@ -403,7 +403,10 @@ ${skill.content}`
403
403
  });
404
404
  }
405
405
  }
406
+ let allAutoToolsSkipLlm = false;
406
407
  if (autoExecuteTools?.length) {
408
+ let hasErrors = false;
409
+ let allSkip = true;
407
410
  for (let i = 0; i < autoExecuteTools.length; i++) {
408
411
  const autoTool = autoExecuteTools[i];
409
412
  const callId = `auto_${i}`;
@@ -428,6 +431,8 @@ ${skill.content}`
428
431
  ]
429
432
  });
430
433
  if (clientResult.error) {
434
+ hasErrors = true;
435
+ allSkip = false;
431
436
  this.messages.push({
432
437
  role: "user",
433
438
  content: [
@@ -440,6 +445,9 @@ ${skill.content}`
440
445
  ]
441
446
  });
442
447
  } else {
448
+ if (!clientResult.skipLlmResponse) {
449
+ allSkip = false;
450
+ }
443
451
  let resultForLLM = clientResult.result;
444
452
  if (typeof resultForLLM === "object" && resultForLLM !== null && "agentMessage" in resultForLLM) {
445
453
  const { agentMessage, ...rest } = resultForLLM;
@@ -457,6 +465,8 @@ ${skill.content}`
457
465
  });
458
466
  }
459
467
  } catch {
468
+ hasErrors = true;
469
+ allSkip = false;
460
470
  this.messages.push({
461
471
  role: "assistant",
462
472
  content: [
@@ -483,6 +493,13 @@ ${skill.content}`
483
493
  });
484
494
  }
485
495
  }
496
+ allAutoToolsSkipLlm = allSkip && !hasErrors;
497
+ }
498
+ if (allAutoToolsSkipLlm) {
499
+ send(peer, { type: "done" });
500
+ this.sendConversationState(peer, authSecret);
501
+ this.isProcessing = false;
502
+ return;
486
503
  }
487
504
  this.abortController = new AbortController();
488
505
  this.isProcessing = true;
@@ -96,7 +96,8 @@ export default defineWebSocketHandler({
96
96
  case "tool_result":
97
97
  session.resolveToolResult(data.callId, {
98
98
  result: data.result,
99
- error: data.error
99
+ error: data.error,
100
+ skipLlmResponse: data.skipLlmResponse
100
101
  });
101
102
  break;
102
103
  case "cancel":
@@ -423,6 +423,7 @@ export declare const clientMessageSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
423
423
  callId: z.ZodString;
424
424
  result: z.ZodUnknown;
425
425
  error: z.ZodOptional<z.ZodString>;
426
+ skipLlmResponse: z.ZodOptional<z.ZodBoolean>;
426
427
  }, z.core.$strip>, z.ZodObject<{
427
428
  type: z.ZodLiteral<"cancel">;
428
429
  }, z.core.$strip>, z.ZodObject<{
@@ -163,7 +163,8 @@ export const clientMessageSchema = z.discriminatedUnion("type", [
163
163
  type: z.literal("tool_result"),
164
164
  callId: z.string(),
165
165
  result: z.unknown(),
166
- error: z.string().optional()
166
+ error: z.string().optional(),
167
+ skipLlmResponse: z.boolean().optional()
167
168
  }),
168
169
  z.object({ type: z.literal("cancel") }),
169
170
  z.object({ type: z.literal("accept") }),
@@ -6,8 +6,8 @@
6
6
  :data-provider-entity-bundle="entityBundle"
7
7
  :data-blokkli-provider-active="isInEditor ? 'true' : 'false'"
8
8
  >
9
- <BlokkliRootErrorBoundary v-if="isInEditor">
10
- <ClientOnly>
9
+ <ClientOnly v-if="isInEditor">
10
+ <BlokkliRootErrorBoundary>
11
11
  <PreviewProvider
12
12
  v-if="isPreviewing"
13
13
  v-slot="{ mutatedEntity }"
@@ -45,8 +45,8 @@
45
45
  :entity="mutatedEntity"
46
46
  />
47
47
  </EditProvider>
48
- </ClientOnly>
49
- </BlokkliRootErrorBoundary>
48
+ </BlokkliRootErrorBoundary>
49
+ </ClientOnly>
50
50
 
51
51
  <slot
52
52
  v-else
@@ -100,24 +100,25 @@ const props = defineProps({
100
100
  entity: { type: null, required: false, default: void 0 }
101
101
  });
102
102
  defineSlots();
103
+ const isClient = import.meta.client;
103
104
  const providerEl = useTemplateRef("providerEl");
104
- const PreviewProvider = defineAsyncComponent(
105
+ const PreviewProvider = import.meta.client ? defineAsyncComponent(
105
106
  () => import("./../editor/components/PreviewProvider.vue")
106
- );
107
- const EditProvider = defineAsyncComponent(
107
+ ) : null;
108
+ const EditProvider = import.meta.client ? defineAsyncComponent(
108
109
  () => import("./../editor/components/EditProvider.vue")
109
- );
110
- const BlokkliRootErrorBoundary = defineAsyncComponent(
110
+ ) : null;
111
+ const BlokkliRootErrorBoundary = import.meta.client ? defineAsyncComponent(
111
112
  () => import("./../editor/components/BlokkliRootErrorBoundary.vue")
112
- );
113
- const EditIndicator = defineAsyncComponent(
113
+ ) : "div";
114
+ const EditIndicator = import.meta.client ? defineAsyncComponent(
114
115
  () => import("./../editor/components/EditIndicator.vue")
115
- );
116
+ ) : "div";
116
117
  const route = useRoute();
117
118
  const router = useRouter();
118
119
  const shouldRender = ref(false);
119
120
  const isInEditor = computed(
120
- () => !!props.entityUuid && !!props.entityType && !!props.entityBundle && (isPreviewing.value || isEditing.value)
121
+ () => isClient && !!props.entityUuid && !!props.entityType && !!props.entityBundle && (isPreviewing.value || isEditing.value)
121
122
  );
122
123
  const canEdit = computed(() => props.permissions.includes("edit"));
123
124
  const canUseBlokkli = computed(() => !!props.permissions.length);
@@ -0,0 +1,3 @@
1
+ declare const _default: typeof __VLS_export;
2
+ export default _default;
3
+ declare const __VLS_export: import("vue").DefineComponent<{}, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<{}> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
@@ -0,0 +1,110 @@
1
+ <template>
2
+ <div class="bk-blokkli-item-actions-interactions">
3
+ <button
4
+ type="button"
5
+ :disabled="!canSelectParent"
6
+ @click.prevent="onClickSelectParent"
7
+ >
8
+ <Icon name="bk_mdi_arrow_top_left" />
9
+ <div class="bk-tooltip">
10
+ {{
11
+ parentLabel ? $t("actionsSelectParent", "Select parent (@label)").replace(
12
+ "@label",
13
+ parentLabel
14
+ ) : $t("actionsSelectPage", "Select page")
15
+ }}
16
+ </div>
17
+ </button>
18
+ <button
19
+ type="button"
20
+ :disabled="!canMove"
21
+ @pointerdown.stop.prevent="onMovePointerDown"
22
+ >
23
+ <Icon name="bk_mdi_drag_pan" />
24
+ <div class="bk-tooltip">
25
+ {{
26
+ selection.uuids.value.length === 1 ? $t("actionsMoveBlock", "Move block") : $t("actionsMoveBlocks", "Move @count blocks").replace(
27
+ "@count",
28
+ String(selection.uuids.value.length)
29
+ )
30
+ }}
31
+ </div>
32
+ </button>
33
+ </div>
34
+ </template>
35
+
36
+ <script setup>
37
+ import { computed, useBlokkli } from "#imports";
38
+ import { Icon } from "#blokkli/editor/components";
39
+ import { toDraggableExisting } from "#blokkli/editor/helpers/draggable";
40
+ const { selection, $t, state, eventBus, ui, types } = useBlokkli();
41
+ const canMove = computed(() => {
42
+ return !!selection.items.value.length;
43
+ });
44
+ const canSelectParent = computed(() => {
45
+ if (selection.hasHostSelected.value) {
46
+ return false;
47
+ }
48
+ const items = selection.items.value;
49
+ if (!items.length) {
50
+ return false;
51
+ }
52
+ const firstKey = state.getFieldKeyForUuid(items[0].uuid);
53
+ if (!firstKey) {
54
+ return false;
55
+ }
56
+ return items.every((item) => state.getFieldKeyForUuid(item.uuid) === firstKey);
57
+ });
58
+ const parentLabel = computed(() => {
59
+ const item = selection.items.value[0];
60
+ if (!item) {
61
+ return "";
62
+ }
63
+ const parentUuid = state.getParentEntityUuid(item.uuid);
64
+ if (!parentUuid) {
65
+ return "";
66
+ }
67
+ const parentItem = state.getFieldListItem(parentUuid);
68
+ if (!parentItem) {
69
+ return "";
70
+ }
71
+ return types.getBlockBundleDefinition(parentItem.bundle)?.label ?? "";
72
+ });
73
+ function onClickSelectParent() {
74
+ if (!canSelectParent.value) {
75
+ return;
76
+ }
77
+ const item = selection.items.value[0];
78
+ if (!item) {
79
+ return;
80
+ }
81
+ const parentUuid = state.getParentEntityUuid(item.uuid);
82
+ if (!parentUuid) {
83
+ return;
84
+ }
85
+ ui.actionsToolbarLocked.value = true;
86
+ if (state.getFieldListItem(parentUuid)) {
87
+ eventBus.emit("select", parentUuid);
88
+ eventBus.emit("scrollIntoView", { uuid: parentUuid });
89
+ } else {
90
+ eventBus.emit("select:unselect");
91
+ eventBus.emit("select:host");
92
+ }
93
+ }
94
+ function onMovePointerDown(e) {
95
+ eventBus.emit("dragging:start", {
96
+ items: toDraggableExisting(selection.items.value),
97
+ coords: {
98
+ x: e.clientX,
99
+ y: e.clientY
100
+ },
101
+ mode: "mouse"
102
+ });
103
+ }
104
+ </script>
105
+
106
+ <script>
107
+ export default {
108
+ name: "Interactions"
109
+ };
110
+ </script>
@@ -0,0 +1,3 @@
1
+ declare const _default: typeof __VLS_export;
2
+ export default _default;
3
+ declare const __VLS_export: import("vue").DefineComponent<{}, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<{}> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
@@ -5,7 +5,8 @@
5
5
  visibility: isVisible ? 'visible' : 'hidden'
6
6
  }"
7
7
  class="bk bk-blokkli-item-actions-inner"
8
- @click.stop
8
+ @mouseleave="onMouseLeave"
9
+ @mouseenter="onMouseEnter"
9
10
  >
10
11
  <div
11
12
  id="bk-blokkli-item-actions-controls"
@@ -15,6 +16,7 @@
15
16
  'bk-is-locked': ui.isTransforming.value
16
17
  }"
17
18
  >
19
+ <Interactions />
18
20
  <div id="bk-blokkli-item-actions-title">
19
21
  <button
20
22
  class="bk-blokkli-item-actions-type-button bk-item-icon-hover-parent"
@@ -82,10 +84,18 @@
82
84
  </template>
83
85
 
84
86
  <script setup>
85
- import { watch, ref, computed, useBlokkli, useTemplateRef } from "#imports";
87
+ import {
88
+ watch,
89
+ ref,
90
+ computed,
91
+ useBlokkli,
92
+ useTemplateRef,
93
+ onBeforeUnmount
94
+ } from "#imports";
86
95
  import { falsy } from "#blokkli/helpers";
87
96
  import { Icon, ItemIconBox } from "#blokkli/editor/components";
88
97
  import EditActionsItemDropdown from "./ItemDropdown.vue";
98
+ import Interactions from "./Interactions/index.vue";
89
99
  import { onBlokkliEvent, useStickyToolbar } from "#blokkli/editor/composables";
90
100
  import {
91
101
  fragmentBlockBundle,
@@ -99,11 +109,32 @@ const ACTIONS_HEIGHT = 52;
99
109
  const el = useTemplateRef("el");
100
110
  useStickyToolbar(el, {
101
111
  getPlacementY: () => "top",
102
- shouldUpdate: () => !selection.isChangingOptions.value && isVisible.value,
112
+ shouldUpdate: () => !ui.actionsToolbarLocked.value && isVisible.value,
103
113
  getHeight: () => ACTIONS_HEIGHT,
104
114
  getMargin: () => 20,
105
115
  allowHorizontalOverflow: true
106
116
  });
117
+ let mouseLeaveTimeout = null;
118
+ function onMouseLeave() {
119
+ onMouseEnter();
120
+ if (ui.actionsToolbarLocked.value || ui.isChangingOptions.value) {
121
+ mouseLeaveTimeout = window.setTimeout(() => {
122
+ ui.actionsToolbarLocked.value = false;
123
+ ui.isChangingOptions.value = false;
124
+ }, 500);
125
+ }
126
+ }
127
+ function onMouseEnter() {
128
+ if (mouseLeaveTimeout) {
129
+ window.clearTimeout(mouseLeaveTimeout);
130
+ mouseLeaveTimeout = null;
131
+ }
132
+ }
133
+ onBeforeUnmount(() => {
134
+ if (mouseLeaveTimeout) {
135
+ window.clearTimeout(mouseLeaveTimeout);
136
+ }
137
+ });
107
138
  const showDropdown = ref(false);
108
139
  const hasAnythingSelected = computed(
109
140
  () => selection.hasHostSelected.value || !!selection.items.value.length
@@ -34,6 +34,7 @@ import {
34
34
  } from "#imports";
35
35
  import { itemEntityType } from "#blokkli-build/config";
36
36
  import { onBlokkliEvent } from "#blokkli/editor/composables";
37
+ import { toDraggableExisting } from "#blokkli/editor/helpers/draggable";
37
38
  const {
38
39
  dom,
39
40
  eventBus,
@@ -133,15 +134,6 @@ function getInteractedElement(e) {
133
134
  }
134
135
  return null;
135
136
  }
136
- function toDraggableExisting(v) {
137
- const blocks2 = Array.isArray(v) ? v : [v];
138
- return blocks2.map((block) => {
139
- return {
140
- itemType: "existing",
141
- block
142
- };
143
- });
144
- }
145
137
  function onPointerMove(e) {
146
138
  if (!handlePointerMove) {
147
139
  return;
@@ -475,7 +467,7 @@ function onClick(e) {
475
467
  }
476
468
  return;
477
469
  }
478
- if (canvasEl.value && !selection.activeEditableLabel.value) {
470
+ if (canvasEl.value && !selection.activeEditableLabel.value && !ui.hasTooltipOpen.value) {
479
471
  canvasEl.value.focus();
480
472
  }
481
473
  }