@blokkli/editor 1.1.3 → 1.3.0

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 +1693 -41
  3. package/dist/runtime/adapter/drupal/graphql/base.graphql +40 -3
  4. package/dist/runtime/adapter/drupal/graphql/comments.graphql +6 -1
  5. package/dist/runtime/adapter/drupal/graphql/transform.graphql +10 -2
  6. package/dist/runtime/adapter/drupal/graphqlMiddleware.js +44 -18
  7. package/dist/runtime/adapter/index.d.ts +15 -2
  8. package/dist/runtime/blokkliPlugins/Sidebar/index.vue +4 -1
  9. package/dist/runtime/components/BlokkliField.vue +8 -2
  10. package/dist/runtime/components/Edit/Actions/index.vue +27 -6
  11. package/dist/runtime/components/Edit/AnimationCanvas/index.vue +1 -0
  12. package/dist/runtime/components/Edit/DragInteractions/index.vue +7 -0
  13. package/dist/runtime/components/Edit/EditProvider.vue +23 -5
  14. package/dist/runtime/components/Edit/Features/Artboard/index.vue +4 -0
  15. package/dist/runtime/components/Edit/Features/BlockAddList/index.vue +1 -0
  16. package/dist/runtime/components/Edit/Features/Clipboard/index.vue +3 -1
  17. package/dist/runtime/components/Edit/Features/CommandPalette/Palette/index.vue +14 -2
  18. package/dist/runtime/components/Edit/Features/Debug/index.vue +26 -4
  19. package/dist/runtime/components/Edit/Features/Diff/DiffView/index.vue +236 -0
  20. package/dist/runtime/components/Edit/Features/Diff/index.vue +37 -0
  21. package/dist/runtime/components/Edit/Features/DraggingOverlay/DragItems/index.vue +14 -4
  22. package/dist/runtime/components/Edit/Features/DraggingOverlay/DropTargets/index.vue +3 -0
  23. package/dist/runtime/components/Edit/Features/DraggingOverlay/index.vue +20 -6
  24. package/dist/runtime/components/Edit/Features/EditForm/Frame/index.vue +8 -1
  25. package/dist/runtime/components/Edit/Features/EditableField/index.vue +11 -5
  26. package/dist/runtime/components/Edit/Features/EntityTitle/index.vue +1 -0
  27. package/dist/runtime/components/Edit/Features/History/index.vue +3 -1
  28. package/dist/runtime/components/Edit/Features/ImportExisting/index.vue +5 -2
  29. package/dist/runtime/components/Edit/Features/Library/ReusableDialog/index.vue +10 -3
  30. package/dist/runtime/components/Edit/Features/MediaLibrary/Library/Item.vue +46 -0
  31. package/dist/runtime/components/Edit/Features/MediaLibrary/Library/index.vue +66 -34
  32. package/dist/runtime/components/Edit/Features/MultiSelect/index.vue +4 -1
  33. package/dist/runtime/components/Edit/Features/Options/Form/index.vue +14 -1
  34. package/dist/runtime/components/Edit/Features/Preview/index.vue +2 -1
  35. package/dist/runtime/components/Edit/Features/PreviewGrant/index.vue +2 -1
  36. package/dist/runtime/components/Edit/Features/Publish/index.vue +2 -0
  37. package/dist/runtime/components/Edit/Features/ResponsivePreview/index.vue +2 -1
  38. package/dist/runtime/components/Edit/Features/Selection/Overlay/fragment.glsl +78 -44
  39. package/dist/runtime/components/Edit/Features/Selection/Overlay/index.vue +8 -8
  40. package/dist/runtime/components/Edit/Features/Selection/Overlay/vertex.glsl +6 -1
  41. package/dist/runtime/components/Edit/Features/Settings/Dialog/FeatureSetting/index.vue +23 -2
  42. package/dist/runtime/components/Edit/Features/Settings/Dialog/index.vue +71 -38
  43. package/dist/runtime/components/Edit/Features/Settings/index.vue +4 -0
  44. package/dist/runtime/components/Edit/Features/Transform/index.vue +5 -1
  45. package/dist/runtime/components/Edit/Features/Translations/index.vue +24 -2
  46. package/dist/runtime/components/Edit/Features/index.vue +4 -0
  47. package/dist/runtime/components/Edit/InfoBox/index.vue +14 -0
  48. package/dist/runtime/components/Edit/Messages/index.vue +10 -12
  49. package/dist/runtime/components/Edit/PreviewProvider.vue +9 -2
  50. package/dist/runtime/components/Edit/Sortli/index.vue +6 -1
  51. package/dist/runtime/components/Edit/index.d.ts +2 -1
  52. package/dist/runtime/components/Edit/index.js +3 -1
  53. package/dist/runtime/constants/index.d.ts +1 -1
  54. package/dist/runtime/constants/index.js +1 -0
  55. package/dist/runtime/css/output.css +1 -1
  56. package/dist/runtime/helpers/animationProvider.js +2 -1
  57. package/dist/runtime/helpers/featuresProvider.d.ts +7 -14
  58. package/dist/runtime/helpers/featuresProvider.js +29 -1
  59. package/dist/runtime/helpers/stateProvider.d.ts +1 -0
  60. package/dist/runtime/helpers/stateProvider.js +23 -4
  61. package/dist/runtime/helpers/uiProvider.d.ts +5 -1
  62. package/dist/runtime/helpers/uiProvider.js +10 -2
  63. package/dist/runtime/icons/diff.svg +1 -0
  64. package/dist/runtime/icons/info.svg +1 -0
  65. package/dist/runtime/types/generatedModuleTypes.d.ts +4 -4
  66. package/dist/runtime/types/index.d.ts +59 -1
  67. package/package.json +2 -1
@@ -22,7 +22,8 @@ export default function(ui) {
22
22
  eventBus.emit("animationFrame", {
23
23
  mouseX,
24
24
  mouseY,
25
- fieldAreas: []
25
+ fieldAreas: [],
26
+ time
26
27
  });
27
28
  });
28
29
  function onWindowMouseMove(e) {
@@ -1,23 +1,16 @@
1
1
  import type { FeatureDefinition, AdapterMethods } from '#blokkli/types';
2
- import type { ValidFeatureKey } from '#blokkli-runtime/features';
2
+ import { type ValidFeatureKey } from '#blokkli-runtime/features';
3
3
  import { type ComputedRef } from '#imports';
4
+ import type { StorageProvider } from './storageProvider.js';
4
5
  export type FeaturesProvider = {
5
6
  features: ComputedRef<FeatureDefinition<AdapterMethods[], ValidFeatureKey>[]>;
6
- mount: (feature: FeatureDefinition<AdapterMethods[], ValidFeatureKey>) => void;
7
- unmount: (id: string) => void;
8
- };
9
- export default function (): {
10
- features: ComputedRef<{
7
+ betaFeatures: ComputedRef<{
11
8
  id: ValidFeatureKey;
12
- label?: string | undefined;
13
- icon: import("../../../.nuxt/blokkli/icons").BlokkliIcon;
14
- description?: string | undefined;
15
- dependencies?: ValidFeatureKey[] | undefined;
16
- viewports?: import("../constants").Viewport[] | undefined;
17
- requiredAdapterMethods?: (keyof import("../adapter").BlokkliAdapter<any>)[] | undefined;
18
- settings?: Record<string, import("#blokkli/types").FeatureDefinitionSetting> | undefined;
19
- screenshot?: string | undefined;
9
+ label: string;
10
+ description?: string;
20
11
  }[]>;
12
+ enabledBetaFeatures: ComputedRef<ValidFeatureKey[]>;
21
13
  mount: (feature: FeatureDefinition<AdapterMethods[], ValidFeatureKey>) => void;
22
14
  unmount: (id: string) => void;
23
15
  };
16
+ export default function (storage: StorageProvider): FeaturesProvider;
@@ -1,7 +1,33 @@
1
+ import {
2
+ featureComponents
3
+ } from "#blokkli-runtime/features";
1
4
  import { computed, ref } from "#imports";
2
- export default function() {
5
+ import { falsy } from "./index.js";
6
+ export default function(storage) {
3
7
  const mountedFeatures = ref([]);
8
+ const settingsSettings = storage.use(
9
+ "feature:settings:settings",
10
+ {}
11
+ );
12
+ const enabledBetaFeatures = computed(() => {
13
+ return Object.entries(settingsSettings.value).map(([key, value]) => {
14
+ const [a, b] = key.split(":");
15
+ if (a === "beta" && b && value === true) {
16
+ return b;
17
+ }
18
+ return null;
19
+ }).filter(falsy);
20
+ });
4
21
  const features = computed(() => mountedFeatures.value);
22
+ const betaFeatures = computed(
23
+ () => featureComponents.filter((v) => v.beta).map((v) => {
24
+ return {
25
+ id: v.id,
26
+ label: v.label,
27
+ description: v.description
28
+ };
29
+ })
30
+ );
5
31
  const unmount = (id) => {
6
32
  mountedFeatures.value = mountedFeatures.value.filter((v) => v.id !== id);
7
33
  };
@@ -10,6 +36,8 @@ export default function() {
10
36
  };
11
37
  return {
12
38
  features,
39
+ betaFeatures,
40
+ enabledBetaFeatures,
13
41
  mount,
14
42
  unmount
15
43
  };
@@ -26,6 +26,7 @@ export type StateProvider = {
26
26
  editMode: Readonly<Ref<EditMode>>;
27
27
  mutatedEntity: Readonly<Ref<any>>;
28
28
  canEdit: ComputedRef<boolean>;
29
+ stateAvailable: ComputedRef<boolean>;
29
30
  isLoading: Readonly<Ref<boolean>>;
30
31
  getFieldBlockCount: (key: string) => number;
31
32
  getBlockBundleCount: (bundle: string) => number;
@@ -12,6 +12,8 @@ import { falsy, getFieldKey } from "#blokkli/helpers";
12
12
  import { eventBus, emitMessage } from "#blokkli/helpers/eventBus";
13
13
  import { nextTick } from "#imports";
14
14
  export default async function(adapter, context, $t) {
15
+ const stateLoaded = ref(false);
16
+ const stateLoadError = ref(false);
15
17
  const owner = ref(null);
16
18
  const refreshKey = ref("");
17
19
  const mutatedFields = ref([]);
@@ -183,12 +185,22 @@ export default async function(adapter, context, $t) {
183
185
  return false;
184
186
  };
185
187
  async function loadState() {
186
- const state = await adapter.loadState();
187
- if (state) {
188
+ try {
189
+ const state = await adapter.loadState();
190
+ if (!state) {
191
+ throw new Error("Missing state.");
192
+ }
188
193
  setContext(adapter.mapState(state));
194
+ stateLoadError.value = false;
195
+ stateLoaded.value = true;
196
+ } catch {
197
+ stateLoadError.value = true;
198
+ stateLoaded.value = false;
189
199
  }
190
200
  }
191
- const canEdit = computed(() => !!owner.value?.currentUserIsOwner);
201
+ const canEdit = computed(
202
+ () => stateLoaded.value && !!owner.value?.currentUserIsOwner && !stateLoadError.value
203
+ );
192
204
  const isTranslation = computed(
193
205
  () => context.value.language !== translation.value.sourceLanguage && translation.value.isTranslatable
194
206
  );
@@ -204,13 +216,20 @@ export default async function(adapter, context, $t) {
204
216
  onBlokkliEvent("reloadState", async () => {
205
217
  await loadState();
206
218
  });
207
- onBlokkliEvent("reloadEntity", async () => {
219
+ onBlokkliEvent("reloadEntity", async (cb) => {
208
220
  await refreshNuxtData();
209
221
  await loadState();
222
+ if (cb) {
223
+ cb();
224
+ }
210
225
  });
211
226
  provide(INJECT_MUTATED_FIELDS_MAP, mutatedFieldsMap);
212
227
  await loadState();
228
+ const stateAvailable = computed(
229
+ () => stateLoaded.value && !stateLoadError.value
230
+ );
213
231
  return {
232
+ stateAvailable,
214
233
  refreshKey,
215
234
  owner: readonly(owner),
216
235
  mutatedFields,
@@ -2,6 +2,7 @@ import { type Ref, type ComputedRef } from 'vue';
2
2
  import type { StorageProvider } from './storageProvider.js';
3
3
  import type { AddListOrientation, Coord, Rectangle, Size } from '#blokkli/types';
4
4
  import type { Viewport } from '#blokkli/constants';
5
+ import type { StateProvider } from './stateProvider.js';
5
6
  export type UiProvider = {
6
7
  rootElement: () => HTMLElement;
7
8
  artboardElement: () => HTMLElement;
@@ -16,6 +17,9 @@ export type UiProvider = {
16
17
  isArtboard: () => boolean;
17
18
  isAnimating: Ref<boolean>;
18
19
  isProxyMode: Ref<boolean>;
20
+ isTransforming: ComputedRef<boolean>;
21
+ setTransform: (label?: string | null | undefined) => void;
22
+ transformLabel: ComputedRef<string>;
19
23
  useAnimations: ComputedRef<boolean>;
20
24
  lowPerformanceMode: ComputedRef<boolean>;
21
25
  toolbarHeight: ComputedRef<number>;
@@ -34,4 +38,4 @@ export type UiProvider = {
34
38
  getAbsoluteElementRect: (v: HTMLElement | Rectangle, scale?: number, offset?: Coord) => Rectangle;
35
39
  getViewportRelativeRect: (rect: Rectangle, scale?: number, offset?: Coord) => Rectangle;
36
40
  };
37
- export default function (storage: StorageProvider): UiProvider;
41
+ export default function (storage: StorageProvider, state: StateProvider): UiProvider;
@@ -9,13 +9,14 @@ import { eventBus } from "./eventBus.js";
9
9
  import { falsy } from "./index.js";
10
10
  const ARTBOARD_CLASS = "bk-is-artboard";
11
11
  const CLASS_PROXY_MODE = "bk-is-proxy-mode";
12
- export default function(storage) {
12
+ export default function(storage, state) {
13
13
  let cachedRootElement = null;
14
14
  let cachedArtboardElement = null;
15
15
  let cachedProviderElement = null;
16
16
  const isProxyMode = ref(false);
17
17
  const menuIsOpen = ref(false);
18
18
  const isAnimating = ref(false);
19
+ const transformLabel = ref("");
19
20
  const openContextMenu = ref("");
20
21
  const selectionTopLeft = ref({ x: 0, y: 0 });
21
22
  const useAnimationsSetting = storage.use("useAnimations", true);
@@ -27,6 +28,7 @@ export default function(storage) {
27
28
  const viewportBlockingRectsMap = ref(
28
29
  {}
29
30
  );
31
+ const isTransforming = computed(() => !!transformLabel.value);
30
32
  const artboardSize = ref({
31
33
  width: 1,
32
34
  height: 1
@@ -134,7 +136,7 @@ export default function(storage) {
134
136
  const visibleViewportX = computed(() => {
135
137
  let x = 0;
136
138
  if (!isMobile.value) {
137
- if (addListOrientation.value === "vertical") {
139
+ if (addListOrientation.value === "vertical" && state.editMode.value === "editing") {
138
140
  x += 70;
139
141
  }
140
142
  if (activeSidebarLeft.value) {
@@ -256,6 +258,9 @@ export default function(storage) {
256
258
  height: rect.height * scale
257
259
  };
258
260
  }
261
+ function setTransform(label) {
262
+ transformLabel.value = label || "";
263
+ }
259
264
  return {
260
265
  menu: {
261
266
  isOpen: menuIsOpen,
@@ -269,6 +274,9 @@ export default function(storage) {
269
274
  isDesktop,
270
275
  isArtboard,
271
276
  isAnimating,
277
+ isTransforming,
278
+ setTransform,
279
+ transformLabel: computed(() => transformLabel.value),
272
280
  useAnimations,
273
281
  visibleViewport,
274
282
  visibleViewportPadded,
@@ -0,0 +1 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><title>select-compare</title><path d="M13,23H11V1H13V23M9,19H5V5H9V3H5C3.89,3 3,3.89 3,5V19C3,20.11 3.9,21 5,21H9V19M19,7V9H21V7H19M19,5H21C21,3.89 20.1,3 19,3V5M21,15H19V17H21V15M19,11V13H21V11H19M17,3H15V5H17V3M19,21C20.11,21 21,20.11 21,19H19V21M17,19H15V21H17V19Z" /></svg>
@@ -0,0 +1 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><title>information-slab-circle</title><path d="M12 22C17.5 22 22 17.5 22 12C22 6.5 17.5 2 12 2C6.5 2 2 6.5 2 12C2 17.5 6.5 22 12 22M11 7H13V9H11V7M14 17H10V15H11V13H10V11H13V15H14V17Z" /></svg>
@@ -3,10 +3,6 @@ export type ModuleOptionsSettings = {
3
3
  disable?: boolean;
4
4
  default?: 'vertical' | 'horizontal' | 'sidebar';
5
5
  };
6
- 'feature:block-add-list:hideDisabledBlocks'?: {
7
- disable?: boolean;
8
- default?: boolean;
9
- };
10
6
  'feature:artboard:momentum'?: {
11
7
  disable?: boolean;
12
8
  default?: boolean;
@@ -19,6 +15,10 @@ export type ModuleOptionsSettings = {
19
15
  disable?: boolean;
20
16
  default?: number;
21
17
  };
18
+ 'feature:block-add-list:hideDisabledBlocks'?: {
19
+ disable?: boolean;
20
+ default?: boolean;
21
+ };
22
22
  'feature:clipboard:openSidebarOnPaste'?: {
23
23
  disable?: boolean;
24
24
  default?: boolean;
@@ -213,6 +213,23 @@ export type BlokkliDefinitionInputEditor<Options extends BlockDefinitionOptionsI
213
213
  * ```
214
214
  */
215
215
  fieldLayout?: string[][];
216
+ /**
217
+ * Define how this component's props should be rendered in the diff view.
218
+ *
219
+ * By default, the diff feature assumes all props to be text and will render
220
+ * plaintext props as HTML and convert complex props (such as arrays or objects)
221
+ * to string using JSON.stringify().
222
+ *
223
+ * You can instead return a string representation of each prop that is used
224
+ * to display the prop instead.
225
+ *
226
+ * For example, if the prop is an image, you may return the filename of the
227
+ * image instead. If the prop is a number, you can return the formatted number.
228
+ *
229
+ * You can also return HTML as the value. The feature uses an HTML differ to
230
+ * render the diff.
231
+ */
232
+ mapDiffProps?: (props?: any) => Record<string, string>;
216
233
  };
217
234
  export type BlockDefinitionRenderForParent = {
218
235
  parentBundle: BlockBundleWithNested;
@@ -680,6 +697,7 @@ export type AnimationFrameEvent = {
680
697
  fieldAreas: AnimationFrameFieldArea[];
681
698
  mouseX: number;
682
699
  mouseY: number;
700
+ time: number;
683
701
  };
684
702
  export type Message = {
685
703
  type: 'success' | 'error';
@@ -700,6 +718,7 @@ export type CanvasDrawEvent = {
700
718
  mouseY: number;
701
719
  artboardOffset: Coord;
702
720
  artboardScale: number;
721
+ time: number;
703
722
  };
704
723
  export type MakeReusableEvent = {
705
724
  label: string;
@@ -859,7 +878,8 @@ export type EventbusEvents = {
859
878
  editEntity: undefined;
860
879
  translateEntity: EntityTranslation;
861
880
  reloadState: undefined;
862
- reloadEntity: undefined;
881
+ reloadEntity: (() => void) | undefined;
882
+ 'entity:translated': string;
863
883
  'select:start': SelectStartEvent;
864
884
  'select:toggle': string;
865
885
  'select:shiftToggle': string;
@@ -971,6 +991,7 @@ export type FeatureDefinitionSettingRadios = {
971
991
  export type FeatureDefinitionSettingCheckbox = {
972
992
  type: 'checkbox';
973
993
  label: string;
994
+ description?: string;
974
995
  default: boolean;
975
996
  group?: SettingsGroup;
976
997
  viewports?: Viewport[];
@@ -994,15 +1015,52 @@ export type FeatureDefinitionSettingMethod = {
994
1015
  };
995
1016
  export type FeatureDefinitionSetting = FeatureDefinitionSettingCheckbox | FeatureDefinitionSettingRadios | FeatureDefinitionSettingMethod | FeatureDefinitionSettingSlider;
996
1017
  export type FeatureDefinition<Methods extends AdapterMethods[] = [], T extends string = ''> = {
1018
+ /**
1019
+ * The unique ID of the feature.
1020
+ */
997
1021
  id: T;
1022
+ /**
1023
+ * The label of the feature.
1024
+ */
998
1025
  label?: string;
1026
+ /**
1027
+ * The icon of the feature.
1028
+ */
999
1029
  icon: BlokkliIcon;
1030
+ /**
1031
+ * Description of the feature.
1032
+ */
1000
1033
  description?: string;
1034
+ /**
1035
+ * Dependencies of the feature.
1036
+ *
1037
+ * Loads this feature only after all of the given features have loaded.
1038
+ *
1039
+ * If one of the dependencies does not load, this feature won't load too.
1040
+ */
1001
1041
  dependencies?: T[];
1042
+ /**
1043
+ * The viewports for which this feature will be loaded.
1044
+ */
1002
1045
  viewports?: Viewport[];
1046
+ /**
1047
+ * The adapter methods required for this feature to work.
1048
+ *
1049
+ * If the adapter does not implement all methods, the feature won't load.
1050
+ */
1003
1051
  requiredAdapterMethods?: [...Methods];
1052
+ /**
1053
+ * Feature-specific settings that will be rendered in the settings dialog.
1054
+ */
1004
1055
  settings?: Record<string, FeatureDefinitionSetting>;
1056
+ /**
1057
+ * Name of the screenshot image file, relative to the feature directory.
1058
+ */
1005
1059
  screenshot?: string;
1060
+ /**
1061
+ * If true, the feature has to be explicitly enabled before it is loaded.
1062
+ */
1063
+ beta?: boolean;
1006
1064
  };
1007
1065
  export type KeyboardShortcut = {
1008
1066
  group?: string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@blokkli/editor",
3
- "version": "1.1.3",
3
+ "version": "1.3.0",
4
4
  "description": "Interactive page building experience for Nuxt",
5
5
  "repository": "blokkli/editor",
6
6
  "type": "module",
@@ -53,6 +53,7 @@
53
53
  "estree-walker-ts": "^1.0.1",
54
54
  "fzf": "^0.5.2",
55
55
  "get-video-id": "^4.1.7",
56
+ "html-diff-ts": "^1.4.2",
56
57
  "mitt": "^3.0.1",
57
58
  "qrcode.vue": "^3.4.1",
58
59
  "twgl.js": "^5.5.4"