@blokkli/editor 2.0.0-alpha.19 → 2.0.0-alpha.20

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/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.19",
4
+ "version": "2.0.0-alpha.20",
5
5
  "compatibility": {
6
6
  "nuxt": ">=3.15.0"
7
7
  },
package/dist/module.mjs CHANGED
@@ -15,7 +15,7 @@ import fs from 'node:fs';
15
15
  import { defu, createDefu } from 'defu';
16
16
 
17
17
  const name = "@blokkli/editor";
18
- const version = "2.0.0-alpha.19";
18
+ const version = "2.0.0-alpha.20";
19
19
 
20
20
  function sortObjectKeys(obj) {
21
21
  if (Array.isArray(obj)) {
@@ -2,6 +2,7 @@ fragment paragraphsFieldItem on Paragraph {
2
2
  uuid
3
3
  bundle: entityBundle
4
4
  options: paragraphsBlokkliOptions
5
+ isVisible: paragraphsBlokkliIsVisible
5
6
  editContext: paragraphsBlokkliEditContext {
6
7
  ...paragraphsBlokkliParagraphEditContext
7
8
  }
@@ -22,7 +22,7 @@ import {
22
22
  } from "#blokkli/helpers/symbols";
23
23
  const props = defineProps({
24
24
  name: { type: String, required: true },
25
- value: { type: String, required: true },
25
+ value: { type: String, required: false, default: "" },
26
26
  tag: { type: String, required: false, default: "div" }
27
27
  });
28
28
  defineSlots();
@@ -36,7 +36,7 @@ const isInReusable = inject(INJECT_IS_IN_REUSABLE, false);
36
36
  if (!entity) {
37
37
  throw new Error("Missing entity context.");
38
38
  }
39
- const renderedValue = computed(() => valueOverride.value || props.value);
39
+ const renderedValue = computed(() => valueOverride.value || props.value || "");
40
40
  const onEditableUpdateValue = (e) => {
41
41
  if (e.name === props.name && e.entityUuid === entity.uuid) {
42
42
  valueOverride.value = e.value;
@@ -1,6 +1,6 @@
1
1
  type __VLS_Props = {
2
2
  name: string;
3
- value: string;
3
+ value?: string;
4
4
  tag?: string;
5
5
  };
6
6
  type __VLS_Slots = {
@@ -9,6 +9,7 @@ type __VLS_Slots = {
9
9
  }): any;
10
10
  };
11
11
  declare const __VLS_component: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {
12
+ value: string;
12
13
  tag: string;
13
14
  }, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
14
15
  declare const _default: __VLS_WithSlots<typeof __VLS_component, __VLS_Slots>;
@@ -4,23 +4,23 @@
4
4
  :is="DraggableList"
5
5
  v-if="DraggableList && isEditing && canEdit && !isInReusable && entity"
6
6
  :list="filteredList"
7
- :name="name"
8
- :entity="entity"
9
- :field-key="fieldKey"
10
- :allowed-fragments="allowedFragments"
11
- :nesting-level="nestingLevel"
12
- :drop-alignment="dropAlignment"
13
- :field-list-type="fieldListType"
7
+ :name
8
+ :entity
9
+ :field-key
10
+ :allowed-fragments
11
+ :nesting-level
12
+ :drop-alignment
13
+ :field-list-type
14
14
  :class="[
15
15
  attrs.class,
16
16
  listClass,
17
17
  editClass,
18
18
  { [nonEmptyClass]: filteredList.length }
19
19
  ]"
20
- :is-nested="isNested"
20
+ :is-nested
21
21
  :language="providerEntity?.language"
22
- :proxy-mode="proxyMode"
23
- :tag="tag"
22
+ :proxy-mode
23
+ :tag
24
24
  :global-proxy-mode="!!isGlobalProxyMode"
25
25
  :should-render-item="shouldRenderItem"
26
26
  />
@@ -81,6 +81,20 @@ if (import.meta.hot) {
81
81
  import.meta.hot.accept("#blokkli/helpers/runtimeHelpers", () => {
82
82
  });
83
83
  }
84
+ const props = defineProps({
85
+ name: { type: String, required: true },
86
+ list: { type: [Array, Object, null], required: false, default: () => [] },
87
+ tag: { type: String, required: false, default: "div" },
88
+ fieldListType: { type: null, required: false, default: "default" },
89
+ editOnly: { type: Boolean, required: false },
90
+ listClass: { type: [String, Object, Array], required: false, default: "" },
91
+ editClass: { type: [String, Object, Array], required: false, default: "" },
92
+ nonEmptyClass: { type: String, required: false, default: "" },
93
+ allowedFragments: { type: null, required: false, default: () => [] },
94
+ dropAlignment: { type: String, required: false, default: void 0 },
95
+ proxyMode: { type: Boolean, required: false },
96
+ shouldRenderItem: { type: Function, required: false, default: void 0 }
97
+ });
84
98
  const DraggableList = inject(
85
99
  INJECT_EDIT_FIELD_LIST_COMPONENT,
86
100
  null
@@ -116,26 +130,12 @@ if (!providerEntity) {
116
130
  "Missing bl\xF6kkli injection: " + INJECT_PROVIDER_CONTEXT.toString()
117
131
  );
118
132
  }
119
- const props = defineProps({
120
- name: { type: String, required: true },
121
- list: { type: [Array, Object, null], required: false, default: () => [] },
122
- tag: { type: String, required: false, default: "div" },
123
- fieldListType: { type: null, required: false, default: "default" },
124
- editOnly: { type: Boolean, required: false },
125
- listClass: { type: String, required: false, default: "" },
126
- editClass: { type: String, required: false, default: "" },
127
- nonEmptyClass: { type: String, required: false, default: "" },
128
- allowedFragments: { type: Array, required: false, default: () => [] },
129
- dropAlignment: { type: String, required: false, default: void 0 },
130
- proxyMode: { type: Boolean, required: false },
131
- shouldRenderItem: { type: Function, required: false, default: void 0 }
132
- });
133
133
  const canEdit = ref(true);
134
134
  const fieldKey = computed(() => {
135
135
  if (canEdit.value) {
136
136
  return entity.uuid + ":" + props.name;
137
137
  }
138
- return void 0;
138
+ return "";
139
139
  });
140
140
  const fieldListType = computed(() => props.fieldListType);
141
141
  function filterVisible(item) {
@@ -145,6 +145,9 @@ function filterVisible(item) {
145
145
  if (isEditing) {
146
146
  return true;
147
147
  }
148
+ if (!item.isVisible) {
149
+ return false;
150
+ }
148
151
  const isVisible = isVisibleByOptions(item, providerEntity.value.language);
149
152
  const isVisibleCustom = props.shouldRenderItem ? props.shouldRenderItem(item) : true;
150
153
  return isVisible && isVisibleCustom;
@@ -1,27 +1,63 @@
1
1
  import type { BlokkliFragmentName } from '#blokkli-build/definitions';
2
- import type { FieldListItem, FieldDropAlignment } from '#blokkli/types';
2
+ import type { FieldListItem, FieldDropAlignment, VueClassProp } from '#blokkli/types';
3
3
  import type { ValidFieldListTypes, FieldListItemTyped } from '#blokkli-build/generated-types';
4
- type __VLS_Slots = {
5
- default(props: {
6
- items: FieldListItemTyped[];
7
- }): any;
8
- after(props: {
9
- items: FieldListItemTyped[];
10
- }): any;
11
- };
12
4
  type __VLS_Props = {
5
+ /**
6
+ * The name of the field.
7
+ */
13
8
  name: string;
9
+ /**
10
+ * The field list items. Can be an array or a single item, also allows nullable values in an array.
11
+ */
14
12
  list?: Array<FieldListItem | null | undefined> | FieldListItem | null;
13
+ /**
14
+ * The tag to use for rendering the root element.
15
+ */
15
16
  tag?: string;
17
+ /**
18
+ * The field list types. The available types can be defined in the "fieldListTypes" module option.
19
+ */
16
20
  fieldListType?: ValidFieldListTypes;
21
+ /**
22
+ * If true, the field list items are only rendered in edit mode.
23
+ * In normal mode, you are responsible yourself to render the items.
24
+ */
17
25
  editOnly?: boolean;
18
- listClass?: string;
19
- editClass?: string;
26
+ /**
27
+ * The classes to render for the list. Same as passing classes via the :class prop.
28
+ */
29
+ listClass?: VueClassProp;
30
+ /**
31
+ * Classes only applied during editing.
32
+ */
33
+ editClass?: VueClassProp;
34
+ /**
35
+ * Classes to apply if the field is not empty.
36
+ */
20
37
  nonEmptyClass?: string;
21
- allowedFragments?: BlokkliFragmentName[];
38
+ /**
39
+ * Define which fragments are allowed in this field.
40
+ *
41
+ * Note that this is only used during editing. It defines which fragments
42
+ * can be added here. If you change this prop but there are existing
43
+ * fragments already in the field list, they will continue to be rendered.
44
+ *
45
+ * Note that in addition, also the "blokkli_fragment" block must be allowed
46
+ * as a bundle in this field.
47
+ */
48
+ allowedFragments?: BlokkliFragmentName[] | BlokkliFragmentName;
49
+ /**
50
+ * Force an alignment during drag and drop interactions.
51
+ */
22
52
  dropAlignment?: FieldDropAlignment;
23
53
  /**
24
54
  * Renders proxy blocks during editing.
55
+ *
56
+ * Doing this will *not* render the actual block components.
57
+ *
58
+ * During editing, a separate element is rendered with "position: absolute"
59
+ * that contains "proxy blocks" for drag and drop interactions. This means
60
+ * that you need to have a wrapper somewhere with "position: relative".
25
61
  */
26
62
  proxyMode?: boolean;
27
63
  /**
@@ -29,15 +65,23 @@ type __VLS_Props = {
29
65
  */
30
66
  shouldRenderItem?: (item: FieldListItem | FieldListItemTyped) => boolean;
31
67
  };
68
+ type __VLS_Slots = {
69
+ default(props: {
70
+ items: FieldListItemTyped[];
71
+ }): any;
72
+ after(props: {
73
+ items: FieldListItemTyped[];
74
+ }): any;
75
+ };
32
76
  declare const __VLS_component: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {
33
77
  list: Array<FieldListItem | null | undefined> | FieldListItem | null;
34
78
  fieldListType: ValidFieldListTypes;
35
- allowedFragments: BlokkliFragmentName[];
79
+ allowedFragments: BlokkliFragmentName[] | BlokkliFragmentName;
36
80
  dropAlignment: FieldDropAlignment;
37
81
  tag: string;
38
82
  shouldRenderItem: (item: FieldListItem | FieldListItemTyped) => boolean;
39
- listClass: string;
40
- editClass: string;
83
+ listClass: VueClassProp;
84
+ editClass: VueClassProp;
41
85
  nonEmptyClass: string;
42
86
  }, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
43
87
  declare const _default: __VLS_WithSlots<typeof __VLS_component, __VLS_Slots>;
@@ -80,6 +80,19 @@ import {
80
80
  INJECT_ENTITY_CONTEXT,
81
81
  INJECT_PROVIDER_CONTEXT
82
82
  } from "../helpers/symbols";
83
+ const props = defineProps({
84
+ entityType: { type: String, required: true },
85
+ entityBundle: { type: String, required: true },
86
+ entityUuid: { type: String, required: true },
87
+ tag: { type: String, required: false, default: "div" },
88
+ language: { type: String, required: false, default: "" },
89
+ editLabel: { type: String, required: false, default: "" },
90
+ editPath: { type: String, required: false, default: void 0 },
91
+ hostOptions: { type: Object, required: false, default: void 0 },
92
+ permissions: { type: Array, required: false, default: () => [] },
93
+ isolate: { type: Boolean, required: false },
94
+ entity: { type: null, required: false, default: void 0 }
95
+ });
83
96
  defineSlots();
84
97
  const providerEl = useTemplateRef("providerEl");
85
98
  const PreviewProvider = defineAsyncComponent(
@@ -96,21 +109,6 @@ const EditIndicator = defineAsyncComponent(
96
109
  );
97
110
  const route = useRoute();
98
111
  const router = useRouter();
99
- const props = defineProps({
100
- entity: { type: null, required: false, default: void 0 },
101
- entityType: { type: String, required: true },
102
- entityBundle: { type: String, required: true },
103
- entityUuid: { type: String, required: true },
104
- tag: { type: String, required: false, default: "div" },
105
- language: { type: String, required: false, default: "" },
106
- editLabel: { type: String, required: false, default: "" },
107
- editPath: { type: String, required: false, default: void 0 },
108
- hostOptions: { type: null, required: false, default: void 0 },
109
- permissions: { type: Array, required: false, default: () => {
110
- return [];
111
- } },
112
- isolate: { type: Boolean, required: false }
113
- });
114
112
  const shouldRender = ref(false);
115
113
  const isInEditor = computed(
116
114
  () => props.entityUuid && props.entityType && props.entityBundle && (isPreviewing.value || isEditing.value)
@@ -1,21 +1,57 @@
1
1
  import type { EditPermission } from '#blokkli/types';
2
- declare const _default: <T extends object>(__VLS_props: NonNullable<Awaited<typeof __VLS_setup>>["props"], __VLS_ctx?: __VLS_PrettifyLocal<Pick<NonNullable<Awaited<typeof __VLS_setup>>, "attrs" | "emit" | "slots">>, __VLS_expose?: NonNullable<Awaited<typeof __VLS_setup>>["expose"], __VLS_setup?: Promise<{
3
- props: __VLS_PrettifyLocal<Pick<Partial<{}> & Omit<{} & import("vue").VNodeProps & import("vue").AllowedComponentProps & import("vue").ComponentCustomProps, never>, never> & {
4
- entity?: T;
2
+ declare const _default: <T>(__VLS_props: NonNullable<Awaited<typeof __VLS_setup>>["props"], __VLS_ctx?: __VLS_PrettifyLocal<Pick<NonNullable<Awaited<typeof __VLS_setup>>, "attrs" | "emit" | "slots">>, __VLS_expose?: NonNullable<Awaited<typeof __VLS_setup>>["expose"], __VLS_setup?: Promise<{
3
+ props: __VLS_PrettifyLocal<Pick<Partial<{}> & Omit<{} & import("vue").VNodeProps & import("vue").AllowedComponentProps & import("vue").ComponentCustomProps, never>, never> & ({
4
+ /**
5
+ * The entity type.
6
+ */
5
7
  entityType: string;
8
+ /**
9
+ * The entity bundle.
10
+ */
6
11
  entityBundle: string;
12
+ /**
13
+ * The entity UUID.
14
+ */
7
15
  entityUuid: string;
16
+ /**
17
+ * The tag to use for the root element.
18
+ */
8
19
  tag?: string;
20
+ /**
21
+ * The current language code.
22
+ */
9
23
  language?: string;
24
+ /**
25
+ * The override label for the edit button.
26
+ */
10
27
  editLabel?: string;
28
+ /**
29
+ * The path to use to open the editor. Defaults to the current route.path value.
30
+ */
11
31
  editPath?: string;
12
- hostOptions?: any;
32
+ /**
33
+ * The host options as a key value object.
34
+ */
35
+ hostOptions?: Record<string, any>;
36
+ /**
37
+ * The edit permissions.
38
+ */
13
39
  permissions?: EditPermission[];
14
40
  /**
15
- * When set to true, during editing, everything except the provider element will be hidden.
41
+ * Whether to isolate the provider element during editing.
16
42
  */
17
43
  isolate?: boolean;
18
- } & Partial<{}>> & import("vue").PublicProps;
44
+ } & ({
45
+ /**
46
+ * The entity data. Will be merged with the mutatedEntity data during editing.
47
+ */
48
+ entity: T;
49
+ } | {
50
+ /**
51
+ * The entity data. Will be merged with the mutatedEntity data during editing.
52
+ */
53
+ entity?: never;
54
+ })) & Partial<{}>> & import("vue").PublicProps;
19
55
  expose(exposed: import("vue").ShallowUnwrapRef<{}>): void;
20
56
  attrs: any;
21
57
  slots: {
@@ -23,7 +59,7 @@ declare const _default: <T extends object>(__VLS_props: NonNullable<Awaited<type
23
59
  isEditing: boolean;
24
60
  canEdit: boolean;
25
61
  isPreview: boolean;
26
- entity?: T | undefined;
62
+ entity: T;
27
63
  }): any;
28
64
  };
29
65
  emit: {};
@@ -12,7 +12,6 @@
12
12
  <div
13
13
  ref="root"
14
14
  class="bk-field-list-proxy-list bk-draggable-list-container"
15
- v-bind="fieldAttributes"
16
15
  >
17
16
  <BlokkliItem
18
17
  v-for="(item, i) in list"
@@ -45,7 +44,6 @@
45
44
  v-else
46
45
  ref="root"
47
46
  :class="['bk-draggable-list-container', attrs.class]"
48
- v-bind="fieldAttributes"
49
47
  >
50
48
  <BlokkliItem
51
49
  v-for="(item, i) in list"
@@ -91,7 +89,7 @@ import {
91
89
  INJECT_FIELD_PROXY_MODE,
92
90
  INJECT_IS_EDITING
93
91
  } from "#blokkli/helpers/symbols";
94
- const { dom, types, runtimeConfig, selection, definitions } = useBlokkli();
92
+ const { dom, runtimeConfig, selection, definitions } = useBlokkli();
95
93
  const root = ref(null);
96
94
  const props = defineProps({
97
95
  name: { type: String, required: true },
@@ -102,7 +100,9 @@ const props = defineProps({
102
100
  tag: { type: String, required: false, default: "div" },
103
101
  isNested: { type: Boolean, required: true },
104
102
  fieldListType: { type: null, required: true },
105
- allowedFragments: { type: Array, required: false, default: void 0 },
103
+ allowedFragments: { type: null, required: false, default: () => {
104
+ return [];
105
+ } },
106
106
  dropAlignment: { type: String, required: false, default: void 0 },
107
107
  proxyMode: { type: Boolean, required: false },
108
108
  globalProxyMode: { type: Boolean, required: false },
@@ -115,45 +115,6 @@ provide(INJECT_IS_EDITING, true);
115
115
  const proxyVisible = computed(
116
116
  () => props.proxyMode && (selection.uuids.value.length || selection.isDragging.value || selection.isMultiSelecting.value)
117
117
  );
118
- const fieldConfig = computed(() => {
119
- const match = types.getFieldConfig(
120
- props.entity.type,
121
- props.entity.bundle,
122
- props.name
123
- );
124
- if (!match) {
125
- throw new Error(
126
- `Missing field configuration for field "${props.name}" on entity type "${props.entity.type}" with bundle "${props.entity.bundle}". Make sure the "name" prop passed to <BlokkliField> is correct.`
127
- );
128
- }
129
- return match;
130
- });
131
- const allowedBundles = computed(() => {
132
- const bundles = fieldConfig.value.allowedBundles;
133
- if (!bundles.length) {
134
- console.error(
135
- `Field with name "${props.name}" on entity "${props.entity.type}" with bundle "${props.entity.bundle}" does not define any allowed bundles.`
136
- );
137
- }
138
- return bundles.join(",");
139
- });
140
- const fieldAttributes = computed(() => {
141
- return {
142
- "data-field-name": props.name,
143
- "data-field-label": fieldConfig.value.label,
144
- "data-field-is-nested": props.isNested,
145
- "data-bk-nesting-level": props.nestingLevel,
146
- "data-host-entity-type": props.entity.type,
147
- "data-host-entity-uuid": props.entity.uuid,
148
- "data-host-entity-bundle": props.entity.bundle,
149
- "data-field-key": props.fieldKey,
150
- "data-field-drop-alignment": props.dropAlignment,
151
- "data-allowed-fragments": props.allowedFragments ? props.allowedFragments.join(",") : void 0,
152
- "data-field-allowed-bundles": allowedBundles.value,
153
- "data-field-list-type": props.fieldListType,
154
- "data-field-cardinality": fieldConfig.value.cardinality
155
- };
156
- });
157
118
  function isMuted(item) {
158
119
  if (!item) {
159
120
  return true;
@@ -166,9 +127,10 @@ function isMuted(item) {
166
127
  return !(isVisible && isVisibleCustom);
167
128
  }
168
129
  const data = computed(() => {
130
+ const allowedFragments = Array.isArray(props.allowedFragments) ? props.allowedFragments : [props.allowedFragments];
169
131
  return {
170
132
  fieldListType: props.fieldListType,
171
- allowedFragments: props.allowedFragments ?? [],
133
+ allowedFragments,
172
134
  isNested: props.isNested,
173
135
  nestingLevel: props.nestingLevel,
174
136
  dropAlignment: props.dropAlignment ?? null
@@ -10,7 +10,7 @@ type __VLS_Props = {
10
10
  tag?: string;
11
11
  isNested: boolean;
12
12
  fieldListType: ValidFieldListTypes;
13
- allowedFragments?: BlokkliFragmentName[];
13
+ allowedFragments?: BlokkliFragmentName[] | BlokkliFragmentName;
14
14
  dropAlignment?: FieldDropAlignment;
15
15
  proxyMode?: boolean;
16
16
  globalProxyMode?: boolean;
@@ -18,7 +18,7 @@ type __VLS_Props = {
18
18
  shouldRenderItem?: (item: FieldListItem | FieldListItemTyped) => boolean;
19
19
  };
20
20
  declare const _default: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {
21
- allowedFragments: BlokkliFragmentName[];
21
+ allowedFragments: BlokkliFragmentName[] | BlokkliFragmentName;
22
22
  dropAlignment: FieldDropAlignment;
23
23
  tag: string;
24
24
  language: string;
@@ -160,9 +160,14 @@ const keyboard = keyboardProvider(animation);
160
160
  const types = await typesProvider(adapter, selection, context);
161
161
  const indicators = indicatorsProvider();
162
162
  const plugins = pluginProvider();
163
- const directive = directiveProvider(ui);
163
+ const directive = directiveProvider(debug, ui);
164
164
  const fields = fieldsProvider(state, dom, types);
165
- const mutatedEntity = computed(() => state.mutatedEntity.value || props.entity);
165
+ const mutatedEntity = computed(() => {
166
+ return {
167
+ ...props.entity ?? {},
168
+ ...state.mutatedEntity.value ?? {}
169
+ };
170
+ });
166
171
  const isReady = computed(
167
172
  () => !isInitializing.value && dom.isReady.value && directive.isReady.value && toolbarLoaded.value
168
173
  );
@@ -193,13 +198,14 @@ addElementClasses(
193
198
  shouldIsolate
194
199
  );
195
200
  const baseLogger = debug.createLogger("EditProvider");
196
- onMounted(() => {
201
+ onMounted(async () => {
197
202
  window.addEventListener("contextmenu", onContextMenu);
198
203
  document.documentElement.addEventListener("touchmove", onTouchMove);
199
204
  document.documentElement.addEventListener("touchstart", onTouchStart);
200
205
  baseLogger.log("EditProvider mounted");
201
206
  dom.init();
202
207
  directive.init();
208
+ await nextTick();
203
209
  isInitializing.value = false;
204
210
  broadcast.emit("editorLoaded", { uuid: props.entityUuid });
205
211
  });