@blokkli/editor 2.0.0-alpha.43 → 2.0.0-alpha.45

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 (67) hide show
  1. package/dist/module.json +1 -1
  2. package/dist/module.mjs +3 -4
  3. package/dist/modules/agent/runtime/app/composables/agentProvider.js +28 -19
  4. package/dist/modules/agent/runtime/app/tools/check_readability/index.js +1 -0
  5. package/dist/modules/agent/runtime/app/tools/delegate_text_rewrite/Component.d.vue.ts +2 -0
  6. package/dist/modules/agent/runtime/app/tools/delegate_text_rewrite/Component.vue +7 -3
  7. package/dist/modules/agent/runtime/app/tools/delegate_text_rewrite/Component.vue.d.ts +2 -0
  8. package/dist/modules/agent/runtime/app/tools/helpers.js +5 -3
  9. package/dist/modules/agent/runtime/server/Session.d.ts +2 -0
  10. package/dist/modules/agent/runtime/server/Session.js +17 -0
  11. package/dist/modules/agent/runtime/server/agent.js +2 -1
  12. package/dist/modules/agent/runtime/shared/types.d.ts +1 -0
  13. package/dist/modules/agent/runtime/shared/types.js +2 -1
  14. package/dist/modules/drupal/graphql/mutations/add_file.graphql +2 -0
  15. package/dist/modules/drupal/graphql/mutations/add_image.graphql +2 -0
  16. package/dist/modules/drupal/graphql/mutations/add_video_remote.graphql +2 -0
  17. package/dist/modules/drupal/runtime/adapter/index.js +6 -3
  18. package/dist/runtime/components/BlokkliProvider.vue +14 -13
  19. package/dist/runtime/editor/components/Toolbar/index.vue +1 -2
  20. package/dist/runtime/editor/composables/useStickyToolbar.d.ts +1 -1
  21. package/dist/runtime/editor/composables/useStickyToolbar.js +25 -7
  22. package/dist/runtime/editor/css/output.css +1 -1
  23. package/dist/runtime/editor/features/analyze/Main.d.vue.ts +6 -0
  24. package/dist/runtime/editor/features/analyze/Main.vue +26 -1
  25. package/dist/runtime/editor/features/analyze/Main.vue.d.ts +6 -0
  26. package/dist/runtime/editor/features/analyze/Renderer/index.d.vue.ts +2 -0
  27. package/dist/runtime/editor/features/analyze/Renderer/index.vue +86 -15
  28. package/dist/runtime/editor/features/analyze/Renderer/index.vue.d.ts +2 -0
  29. package/dist/runtime/editor/features/analyze/analyzers/altText.d.ts +2 -0
  30. package/dist/runtime/editor/features/analyze/analyzers/altText.js +60 -0
  31. package/dist/runtime/editor/features/analyze/analyzers/headingStructure.d.ts +2 -0
  32. package/dist/runtime/editor/features/analyze/analyzers/headingStructure.js +141 -0
  33. package/dist/runtime/editor/features/analyze/analyzers/index.d.ts +5 -1
  34. package/dist/runtime/editor/features/analyze/analyzers/index.js +11 -1
  35. package/dist/runtime/editor/features/analyze/analyzers/readability.js +50 -16
  36. package/dist/runtime/editor/features/analyze/analyzers/types.d.ts +3 -2
  37. package/dist/runtime/editor/features/analyze/index.vue +12 -0
  38. package/dist/runtime/editor/features/analyze/readability/builtinAnalyzer.js +38 -22
  39. package/dist/runtime/editor/features/analyze/readability/types.d.ts +18 -3
  40. package/dist/runtime/editor/features/clipboard/index.vue +4 -27
  41. package/dist/runtime/editor/features/clipboard/types.d.ts +6 -0
  42. package/dist/runtime/editor/features/dragging-overlay/DragItems/index.d.vue.ts +1 -0
  43. package/dist/runtime/editor/features/dragging-overlay/DragItems/index.vue +102 -2
  44. package/dist/runtime/editor/features/dragging-overlay/DragItems/index.vue.d.ts +1 -0
  45. package/dist/runtime/editor/features/dragging-overlay/Renderer/index.d.vue.ts +1 -0
  46. package/dist/runtime/editor/features/dragging-overlay/Renderer/index.vue +16 -1
  47. package/dist/runtime/editor/features/dragging-overlay/Renderer/index.vue.d.ts +1 -0
  48. package/dist/runtime/editor/features/dragging-overlay/index.vue +2 -1
  49. package/dist/runtime/editor/features/editable-field/Overlay/ReadabilityIndicator/ChunkOverlay.d.vue.ts +8 -0
  50. package/dist/runtime/editor/features/editable-field/Overlay/ReadabilityIndicator/ChunkOverlay.vue +135 -0
  51. package/dist/runtime/editor/features/editable-field/Overlay/ReadabilityIndicator/ChunkOverlay.vue.d.ts +8 -0
  52. package/dist/runtime/editor/features/editable-field/Overlay/ReadabilityIndicator/index.d.vue.ts +7 -0
  53. package/dist/runtime/editor/features/editable-field/Overlay/ReadabilityIndicator/index.vue +187 -0
  54. package/dist/runtime/editor/features/editable-field/Overlay/ReadabilityIndicator/index.vue.d.ts +7 -0
  55. package/dist/runtime/editor/features/editable-field/Overlay/index.vue +23 -0
  56. package/dist/runtime/editor/features/options/index.vue +4 -3
  57. package/dist/runtime/editor/features/search/Overlay/Results/Content/index.vue +7 -11
  58. package/dist/runtime/editor/features/search/Overlay/Results/Page/index.vue +11 -13
  59. package/dist/runtime/editor/features/selection/Renderer/index.vue +2 -0
  60. package/dist/runtime/editor/features/translations/index.vue +1 -1
  61. package/dist/runtime/editor/providers/analyze.js +1 -1
  62. package/dist/runtime/editor/providers/readability.js +16 -20
  63. package/dist/runtime/editor/translations/de.json +113 -1
  64. package/dist/runtime/editor/translations/fr.json +113 -1
  65. package/dist/runtime/editor/translations/gsw_CH.json +113 -1
  66. package/dist/runtime/editor/translations/it.json +113 -1
  67. 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.43",
4
+ "version": "2.0.0-alpha.45",
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.43";
21
+ const version = "2.0.0-alpha.45";
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
  }
@@ -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") }),
@@ -8,6 +8,7 @@ mutation pbAddFile(
8
8
  $hostUuid: String!
9
9
  $hostFieldName: String!
10
10
  $afterUuid: String
11
+ $paragraphBundle: String!
11
12
  ) {
12
13
  state: paragraphsEditMutationState(
13
14
  entityType: $entityType
@@ -20,6 +21,7 @@ mutation pbAddFile(
20
21
  hostType: $hostType
21
22
  hostUuid: $hostUuid
22
23
  hostFieldName: $hostFieldName
24
+ paragraphBundle: $paragraphBundle
23
25
  ) {
24
26
  ...paragraphsBlokkliMutationResult
25
27
  }
@@ -8,6 +8,7 @@ mutation pbAddImage(
8
8
  $hostUuid: String!
9
9
  $hostFieldName: String!
10
10
  $afterUuid: String
11
+ $paragraphBundle: String!
11
12
  ) {
12
13
  state: paragraphsEditMutationState(
13
14
  entityType: $entityType
@@ -20,6 +21,7 @@ mutation pbAddImage(
20
21
  hostType: $hostType
21
22
  hostUuid: $hostUuid
22
23
  hostFieldName: $hostFieldName
24
+ paragraphBundle: $paragraphBundle
23
25
  ) {
24
26
  ...paragraphsBlokkliMutationResult
25
27
  }
@@ -7,6 +7,7 @@ mutation pbAddVideoRemote(
7
7
  $hostUuid: String!
8
8
  $hostFieldName: String!
9
9
  $afterUuid: String
10
+ $paragraphBundle: String!
10
11
  ) {
11
12
  state: paragraphsEditMutationState(
12
13
  entityType: $entityType
@@ -18,6 +19,7 @@ mutation pbAddVideoRemote(
18
19
  hostType: $hostType
19
20
  hostUuid: $hostUuid
20
21
  hostFieldName: $hostFieldName
22
+ paragraphBundle: $paragraphBundle
21
23
  ) {
22
24
  ...paragraphsBlokkliMutationResult
23
25
  }
@@ -887,7 +887,8 @@ export default defineBlokkliEditAdapter(
887
887
  hostType: e.host.type,
888
888
  hostUuid: e.host.uuid,
889
889
  hostFieldName: e.host.fieldName,
890
- afterUuid: e.afterUuid
890
+ afterUuid: e.afterUuid,
891
+ paragraphBundle: e.blockBundle
891
892
  }).then(mapMutation);
892
893
  } else if (e.item.type === "file" && hasMutation("pbAddFile")) {
893
894
  return useGraphqlMutation("pbAddFile", {
@@ -897,7 +898,8 @@ export default defineBlokkliEditAdapter(
897
898
  hostType: e.host.type,
898
899
  hostUuid: e.host.uuid,
899
900
  hostFieldName: e.host.fieldName,
900
- afterUuid: e.afterUuid
901
+ afterUuid: e.afterUuid,
902
+ paragraphBundle: e.blockBundle
901
903
  }).then(mapMutation);
902
904
  } else if (e.item.type === "video" && hasMutation("pbAddVideoRemote")) {
903
905
  return useGraphqlMutation("pbAddVideoRemote", {
@@ -906,7 +908,8 @@ export default defineBlokkliEditAdapter(
906
908
  hostType: e.host.type,
907
909
  hostUuid: e.host.uuid,
908
910
  hostFieldName: e.host.fieldName,
909
- afterUuid: e.afterUuid
911
+ afterUuid: e.afterUuid,
912
+ paragraphBundle: e.blockBundle
910
913
  }).then(mapMutation);
911
914
  }
912
915
  };
@@ -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);
@@ -91,9 +91,8 @@ import {
91
91
  } from "#imports";
92
92
  import AppMenu from "./../AppMenu/index.vue";
93
93
  import { onBlokkliEvent } from "#blokkli/editor/composables";
94
- const { ui, selection, storage, eventBus } = useBlokkli();
94
+ const { ui, selection, storage } = useBlokkli();
95
95
  function openMenu() {
96
- eventBus.emit("window:clickAway");
97
96
  ui.openDialog({ id: "menu", alignment: "left" });
98
97
  }
99
98
  const sidebarVisible = computed(() => {
@@ -1,7 +1,7 @@
1
1
  import type { ComputedRef, ShallowRef } from 'vue';
2
2
  import type { Coord } from '../types/geometry.js';
3
3
  export type PlacementVertical = 'top' | 'bottom' | 'center' | 'auto';
4
- export type PlacementHorizontal = 'left' | 'center' | 'right';
4
+ export type PlacementHorizontal = 'left' | 'center' | 'right' | 'auto-side';
5
5
  type UseStickyToolbarOptions = {
6
6
  getPlacementY?: () => PlacementVertical;
7
7
  getPlacementX?: () => PlacementHorizontal;
@@ -100,7 +100,6 @@ export function useStickyToolbar(el, options) {
100
100
  }
101
101
  }
102
102
  const padding = ui.visibleViewportPadded.value;
103
- const xSubtract = hasRects ? 5 * Math.min(scale, 1) : 0;
104
103
  const margin = getMargin() * Math.min(scale, 1);
105
104
  const centerX = (minX + maxX) / 2;
106
105
  const centerY = (minY + maxY) / 2;
@@ -117,19 +116,38 @@ export function useStickyToolbar(el, options) {
117
116
  actualPlacementY2 = spaceAbove > spaceBelow ? "top" : "bottom";
118
117
  }
119
118
  }
119
+ const isSidePlacement = placementX === "auto-side";
120
+ let resolvedPlacementX = isSidePlacement ? "right" : placementX;
121
+ if (isSidePlacement) {
122
+ const spaceRight = padding.x + padding.width - maxX;
123
+ const spaceLeft = minX - padding.x;
124
+ if (spaceRight >= width + margin) {
125
+ resolvedPlacementX = "right";
126
+ } else if (spaceLeft >= width + margin) {
127
+ resolvedPlacementX = "left";
128
+ } else {
129
+ resolvedPlacementX = spaceRight >= spaceLeft ? "right" : "left";
130
+ }
131
+ }
120
132
  let y;
121
- if (placementY === "center") {
133
+ if (isSidePlacement) {
134
+ y = minY;
135
+ } else if (placementY === "center") {
122
136
  y = centerY - height / 2;
123
137
  } else {
124
138
  y = actualPlacementY2 === "top" ? minY - height - margin : maxY + margin;
125
139
  }
126
140
  let x;
127
- if (placementX === "center") {
128
- x = centerX - width / 2;
129
- } else if (placementX === "right") {
141
+ if (isSidePlacement && resolvedPlacementX === "right") {
130
142
  x = maxX + margin;
143
+ } else if (isSidePlacement && resolvedPlacementX === "left") {
144
+ x = minX - width - margin;
145
+ } else if (resolvedPlacementX === "center") {
146
+ x = centerX - width / 2;
147
+ } else if (resolvedPlacementX === "right") {
148
+ x = maxX - width;
131
149
  } else {
132
- x = minX - xSubtract;
150
+ x = minX;
133
151
  }
134
152
  const shouldAllowOverflow = options?.allowHorizontalOverflow && width > padding.width;
135
153
  let idealPosition;
@@ -170,7 +188,7 @@ export function useStickyToolbar(el, options) {
170
188
  return {
171
189
  ...idealPosition,
172
190
  actualPlacementY: actualPlacementY2,
173
- actualPlacementX: placementX,
191
+ actualPlacementX: resolvedPlacementX,
174
192
  caretX
175
193
  };
176
194
  }