rimelight-components 2.1.77 → 2.1.78
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 +1 -1
- package/dist/module.mjs +1 -1
- package/dist/runtime/components/blocks/BlockEditor.vue +37 -2
- package/dist/runtime/components/dashboard/QuickActions.vue +1 -1
- package/dist/runtime/components/notes/NoteModal.vue +31 -3
- package/dist/runtime/components/page/modals/CreatePageModal.d.vue.ts +9 -3
- package/dist/runtime/components/page/modals/CreatePageModal.vue +9 -4
- package/dist/runtime/components/page/modals/CreatePageModal.vue.d.ts +9 -3
- package/dist/runtime/composables/pages/useBlockEditor.js +99 -0
- package/dist/runtime/composables/pages/useBlockEditor.mjs +99 -0
- package/package.json +1 -1
package/dist/module.json
CHANGED
package/dist/module.mjs
CHANGED
|
@@ -4,7 +4,7 @@ import { readdirSync } from 'node:fs';
|
|
|
4
4
|
import { basename } from 'node:path';
|
|
5
5
|
|
|
6
6
|
const name = "rimelight-components";
|
|
7
|
-
const version = "2.1.
|
|
7
|
+
const version = "2.1.78";
|
|
8
8
|
const homepage = "https://rimelight.com/tools/rimelight-components";
|
|
9
9
|
|
|
10
10
|
const defaultOptions = {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<script setup>
|
|
2
|
-
import { provide } from "vue";
|
|
2
|
+
import { provide, computed } from "vue";
|
|
3
3
|
import { useBlockEditor } from "../../composables";
|
|
4
4
|
import { tv } from "../../internal/tv";
|
|
5
5
|
import { useRC } from "../../composables";
|
|
@@ -10,6 +10,16 @@ const { historyLimit, rc: rcProp } = defineProps({
|
|
|
10
10
|
const blocks = defineModel({ type: Array, ...{ required: true } });
|
|
11
11
|
const emit = defineEmits(["save"]);
|
|
12
12
|
const slots = defineSlots();
|
|
13
|
+
const blockTypes = [
|
|
14
|
+
{ label: "Paragraph", value: "ParagraphBlock", icon: "i-lucide-pilcrow" },
|
|
15
|
+
{ label: "Section", value: "SectionBlock", icon: "i-lucide-heading" },
|
|
16
|
+
{ label: "Image", value: "ImageBlock", icon: "i-lucide-image" },
|
|
17
|
+
{ label: "Callout", value: "CalloutBlock", icon: "i-lucide-info" },
|
|
18
|
+
{ label: "Quote", value: "QuoteBlock", icon: "i-lucide-quote" },
|
|
19
|
+
{ label: "List", value: "UnorderedListBlock", icon: "i-lucide-list" },
|
|
20
|
+
{ label: "Card", value: "CardBlock", icon: "i-lucide-square" },
|
|
21
|
+
{ label: "Collapsible Card", value: "CollapsibleCardBlock", icon: "i-lucide-chevron-right-square" }
|
|
22
|
+
];
|
|
13
23
|
const { rc } = useRC("BlockEditor", rcProp);
|
|
14
24
|
const {
|
|
15
25
|
removeBlock,
|
|
@@ -22,6 +32,13 @@ const {
|
|
|
22
32
|
canUndo,
|
|
23
33
|
canRedo
|
|
24
34
|
} = useBlockEditor(blocks, { maxHistorySize: historyLimit });
|
|
35
|
+
const dropdownItems = computed(() => [
|
|
36
|
+
blockTypes.map((type) => ({
|
|
37
|
+
label: type.label,
|
|
38
|
+
icon: type.icon,
|
|
39
|
+
click: () => insertBlock(type.value)
|
|
40
|
+
}))
|
|
41
|
+
]);
|
|
25
42
|
provide("block-editor-api", {
|
|
26
43
|
removeBlock,
|
|
27
44
|
moveBlock,
|
|
@@ -37,5 +54,23 @@ defineExpose({ undo, redo, canUndo, canRedo });
|
|
|
37
54
|
</script>
|
|
38
55
|
|
|
39
56
|
<template>
|
|
40
|
-
<
|
|
57
|
+
<div class="flex flex-col gap-8 w-full">
|
|
58
|
+
<RCBlockEditRenderer :blocks="blocks" />
|
|
59
|
+
|
|
60
|
+
<div class="flex flex-col items-center justify-center p-4 border-t border-neutral-200 dark:border-neutral-800 border-dashed rounded-lg">
|
|
61
|
+
<span class="text-sm text-dimmed mb-2">Append new block to page</span>
|
|
62
|
+
<UDropdown
|
|
63
|
+
:items="dropdownItems"
|
|
64
|
+
:popper="{ placement: 'bottom' }"
|
|
65
|
+
>
|
|
66
|
+
<UButton
|
|
67
|
+
color="white"
|
|
68
|
+
label="Add Block"
|
|
69
|
+
trailing-icon="i-heroicons-chevron-down-20-solid"
|
|
70
|
+
variant="solid"
|
|
71
|
+
icon="i-lucide-plus"
|
|
72
|
+
/>
|
|
73
|
+
</UDropdown>
|
|
74
|
+
</div>
|
|
75
|
+
</div>
|
|
41
76
|
</template>
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
<script setup>
|
|
2
|
-
import {
|
|
3
|
-
import { computed, reactive, ref, watch } from "vue";
|
|
2
|
+
import { computed, reactive, ref, watch, onUnmounted } from "vue";
|
|
4
3
|
import { useApi, $api } from "../../composables";
|
|
5
4
|
const open = defineModel("open", { type: Boolean, ...{ default: false } });
|
|
6
5
|
const { note } = defineProps({
|
|
@@ -58,8 +57,16 @@ const syncState = () => {
|
|
|
58
57
|
}
|
|
59
58
|
};
|
|
60
59
|
watch(() => note, syncState);
|
|
60
|
+
const saveTimeout = ref(null);
|
|
61
|
+
const isSaving = ref(false);
|
|
62
|
+
const hasPendingSave = ref(false);
|
|
61
63
|
const saveNote = async () => {
|
|
62
64
|
if (!state.title.trim() && !state.content.trim()) return;
|
|
65
|
+
if (isSaving.value) {
|
|
66
|
+
hasPendingSave.value = true;
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
isSaving.value = true;
|
|
63
70
|
try {
|
|
64
71
|
let savedNote;
|
|
65
72
|
const payload = {
|
|
@@ -96,6 +103,12 @@ const saveNote = async () => {
|
|
|
96
103
|
emit("saved", savedNote);
|
|
97
104
|
} catch (e) {
|
|
98
105
|
console.error("Failed to save note", e);
|
|
106
|
+
} finally {
|
|
107
|
+
isSaving.value = false;
|
|
108
|
+
if (hasPendingSave.value) {
|
|
109
|
+
hasPendingSave.value = false;
|
|
110
|
+
saveNote();
|
|
111
|
+
}
|
|
99
112
|
}
|
|
100
113
|
};
|
|
101
114
|
const createLabel = async (newLabelName) => {
|
|
@@ -112,7 +125,14 @@ const createLabel = async (newLabelName) => {
|
|
|
112
125
|
console.error("Failed to create new label", e);
|
|
113
126
|
}
|
|
114
127
|
};
|
|
115
|
-
const debouncedSave =
|
|
128
|
+
const debouncedSave = () => {
|
|
129
|
+
if (saveTimeout.value) {
|
|
130
|
+
clearTimeout(saveTimeout.value);
|
|
131
|
+
}
|
|
132
|
+
saveTimeout.value = setTimeout(() => {
|
|
133
|
+
saveNote();
|
|
134
|
+
}, 1e3);
|
|
135
|
+
};
|
|
116
136
|
watch(
|
|
117
137
|
() => [
|
|
118
138
|
state.title,
|
|
@@ -129,10 +149,18 @@ watch(open, (isOpen) => {
|
|
|
129
149
|
if (isOpen) {
|
|
130
150
|
syncState();
|
|
131
151
|
} else {
|
|
152
|
+
if (saveTimeout.value) {
|
|
153
|
+
clearTimeout(saveTimeout.value);
|
|
154
|
+
}
|
|
132
155
|
saveNote();
|
|
133
156
|
emit("close");
|
|
134
157
|
}
|
|
135
158
|
});
|
|
159
|
+
onUnmounted(() => {
|
|
160
|
+
if (saveTimeout.value) {
|
|
161
|
+
clearTimeout(saveTimeout.value);
|
|
162
|
+
}
|
|
163
|
+
});
|
|
136
164
|
</script>
|
|
137
165
|
|
|
138
166
|
<template>
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { type PageDefinition, type Page } from "../../../types/index.js";
|
|
2
2
|
export interface CreatePageModalProps {
|
|
3
|
-
isOpen: boolean;
|
|
4
3
|
definitions: Record<string, PageDefinition>;
|
|
5
4
|
loading?: boolean;
|
|
6
5
|
rc?: {
|
|
@@ -12,6 +11,7 @@ export interface CreatePageModalProps {
|
|
|
12
11
|
footer?: string;
|
|
13
12
|
};
|
|
14
13
|
}
|
|
14
|
+
type __VLS_Props = CreatePageModalProps;
|
|
15
15
|
export interface CreatePageModalEmits {
|
|
16
16
|
close: [];
|
|
17
17
|
confirm: [page: Partial<Page>];
|
|
@@ -20,14 +20,20 @@ export interface CreatePageModalSlots {
|
|
|
20
20
|
default: (props: {}) => any;
|
|
21
21
|
}
|
|
22
22
|
type __VLS_Slots = CreatePageModalSlots;
|
|
23
|
-
|
|
23
|
+
type __VLS_ModelProps = {
|
|
24
|
+
"open"?: boolean;
|
|
25
|
+
};
|
|
26
|
+
type __VLS_PublicProps = __VLS_Props & __VLS_ModelProps;
|
|
27
|
+
declare const __VLS_base: import("vue").DefineComponent<__VLS_PublicProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
24
28
|
close: () => any;
|
|
29
|
+
"update:open": (value: boolean) => any;
|
|
25
30
|
confirm: (page: Partial<{
|
|
26
31
|
type: "Default";
|
|
27
32
|
properties: import("../../../types/index.js").BasePageProperties;
|
|
28
33
|
} & import("../../../types/index.js").BasePage>) => any;
|
|
29
|
-
}, string, import("vue").PublicProps, Readonly<
|
|
34
|
+
}, string, import("vue").PublicProps, Readonly<__VLS_PublicProps> & Readonly<{
|
|
30
35
|
onClose?: (() => any) | undefined;
|
|
36
|
+
"onUpdate:open"?: ((value: boolean) => any) | undefined;
|
|
31
37
|
onConfirm?: ((page: Partial<{
|
|
32
38
|
type: "Default";
|
|
33
39
|
properties: import("../../../types/index.js").BasePageProperties;
|
|
@@ -4,8 +4,8 @@ import {} from "../../../types";
|
|
|
4
4
|
import { tv } from "../../../internal/tv";
|
|
5
5
|
import { useRC } from "../../../composables";
|
|
6
6
|
import { useI18n } from "vue-i18n";
|
|
7
|
-
const
|
|
8
|
-
|
|
7
|
+
const open = defineModel("open", { type: Boolean, ...{ default: false } });
|
|
8
|
+
const { loading, definitions, rc: rcProp } = defineProps({
|
|
9
9
|
definitions: { type: Object, required: true },
|
|
10
10
|
loading: { type: Boolean, required: false },
|
|
11
11
|
rc: { type: Object, required: false }
|
|
@@ -37,7 +37,7 @@ const title = ref("");
|
|
|
37
37
|
const slug = ref("");
|
|
38
38
|
const typeOptions = computed(() => {
|
|
39
39
|
return Object.entries(definitions).map(([key, def]) => ({
|
|
40
|
-
label: t(def.typeLabelKey),
|
|
40
|
+
label: t(def.typeLabelKey) === def.typeLabelKey ? key : t(def.typeLabelKey),
|
|
41
41
|
value: key
|
|
42
42
|
}));
|
|
43
43
|
});
|
|
@@ -67,10 +67,15 @@ const handleConfirm = () => {
|
|
|
67
67
|
};
|
|
68
68
|
emit("confirm", newPage);
|
|
69
69
|
};
|
|
70
|
+
watch(open, (isOpen) => {
|
|
71
|
+
if (!isOpen) {
|
|
72
|
+
emit("close");
|
|
73
|
+
}
|
|
74
|
+
});
|
|
70
75
|
</script>
|
|
71
76
|
|
|
72
77
|
<template>
|
|
73
|
-
<UModal
|
|
78
|
+
<UModal v-model:open="open">
|
|
74
79
|
<slot />
|
|
75
80
|
<template #content>
|
|
76
81
|
<UCard>
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { type PageDefinition, type Page } from "../../../types/index.js";
|
|
2
2
|
export interface CreatePageModalProps {
|
|
3
|
-
isOpen: boolean;
|
|
4
3
|
definitions: Record<string, PageDefinition>;
|
|
5
4
|
loading?: boolean;
|
|
6
5
|
rc?: {
|
|
@@ -12,6 +11,7 @@ export interface CreatePageModalProps {
|
|
|
12
11
|
footer?: string;
|
|
13
12
|
};
|
|
14
13
|
}
|
|
14
|
+
type __VLS_Props = CreatePageModalProps;
|
|
15
15
|
export interface CreatePageModalEmits {
|
|
16
16
|
close: [];
|
|
17
17
|
confirm: [page: Partial<Page>];
|
|
@@ -20,14 +20,20 @@ export interface CreatePageModalSlots {
|
|
|
20
20
|
default: (props: {}) => any;
|
|
21
21
|
}
|
|
22
22
|
type __VLS_Slots = CreatePageModalSlots;
|
|
23
|
-
|
|
23
|
+
type __VLS_ModelProps = {
|
|
24
|
+
"open"?: boolean;
|
|
25
|
+
};
|
|
26
|
+
type __VLS_PublicProps = __VLS_Props & __VLS_ModelProps;
|
|
27
|
+
declare const __VLS_base: import("vue").DefineComponent<__VLS_PublicProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
24
28
|
close: () => any;
|
|
29
|
+
"update:open": (value: boolean) => any;
|
|
25
30
|
confirm: (page: Partial<{
|
|
26
31
|
type: "Default";
|
|
27
32
|
properties: import("../../../types/index.js").BasePageProperties;
|
|
28
33
|
} & import("../../../types/index.js").BasePage>) => any;
|
|
29
|
-
}, string, import("vue").PublicProps, Readonly<
|
|
34
|
+
}, string, import("vue").PublicProps, Readonly<__VLS_PublicProps> & Readonly<{
|
|
30
35
|
onClose?: (() => any) | undefined;
|
|
36
|
+
"onUpdate:open"?: ((value: boolean) => any) | undefined;
|
|
31
37
|
onConfirm?: ((page: Partial<{
|
|
32
38
|
type: "Default";
|
|
33
39
|
properties: import("../../../types/index.js").BasePageProperties;
|
|
@@ -20,6 +20,95 @@ function regenerateIds(block) {
|
|
|
20
20
|
block.props.children.forEach((child) => regenerateIds(child));
|
|
21
21
|
}
|
|
22
22
|
}
|
|
23
|
+
function createDefaultBlock(type) {
|
|
24
|
+
const id = uuidv7();
|
|
25
|
+
switch (type) {
|
|
26
|
+
case "SectionBlock":
|
|
27
|
+
return {
|
|
28
|
+
id,
|
|
29
|
+
type: "SectionBlock",
|
|
30
|
+
props: {
|
|
31
|
+
level: 2,
|
|
32
|
+
title: "New Section",
|
|
33
|
+
children: []
|
|
34
|
+
}
|
|
35
|
+
};
|
|
36
|
+
case "ParagraphBlock":
|
|
37
|
+
return {
|
|
38
|
+
id,
|
|
39
|
+
type: "ParagraphBlock",
|
|
40
|
+
props: {
|
|
41
|
+
text: []
|
|
42
|
+
}
|
|
43
|
+
};
|
|
44
|
+
case "CalloutBlock":
|
|
45
|
+
return {
|
|
46
|
+
id,
|
|
47
|
+
type: "CalloutBlock",
|
|
48
|
+
props: {
|
|
49
|
+
variant: "info",
|
|
50
|
+
children: [
|
|
51
|
+
{
|
|
52
|
+
id: uuidv7(),
|
|
53
|
+
type: "ParagraphBlock",
|
|
54
|
+
props: { text: [{ type: "text", id: uuidv7(), props: { content: "Callout content" } }] }
|
|
55
|
+
}
|
|
56
|
+
]
|
|
57
|
+
}
|
|
58
|
+
};
|
|
59
|
+
case "ImageBlock":
|
|
60
|
+
return {
|
|
61
|
+
id,
|
|
62
|
+
type: "ImageBlock",
|
|
63
|
+
props: {
|
|
64
|
+
src: "https://placehold.co/600x400",
|
|
65
|
+
alt: "Placeholder Image"
|
|
66
|
+
}
|
|
67
|
+
};
|
|
68
|
+
case "QuoteBlock":
|
|
69
|
+
return {
|
|
70
|
+
id,
|
|
71
|
+
type: "QuoteBlock",
|
|
72
|
+
props: {
|
|
73
|
+
quote: "Quote text...",
|
|
74
|
+
source: "Source"
|
|
75
|
+
}
|
|
76
|
+
};
|
|
77
|
+
case "UnorderedListBlock":
|
|
78
|
+
return {
|
|
79
|
+
id,
|
|
80
|
+
type: "UnorderedListBlock",
|
|
81
|
+
props: {
|
|
82
|
+
items: []
|
|
83
|
+
}
|
|
84
|
+
};
|
|
85
|
+
case "CardBlock":
|
|
86
|
+
return {
|
|
87
|
+
id,
|
|
88
|
+
type: "CardBlock",
|
|
89
|
+
props: {
|
|
90
|
+
title: "New Card",
|
|
91
|
+
children: []
|
|
92
|
+
}
|
|
93
|
+
};
|
|
94
|
+
case "CollapsibleCardBlock":
|
|
95
|
+
return {
|
|
96
|
+
id,
|
|
97
|
+
type: "CollapsibleCardBlock",
|
|
98
|
+
props: {
|
|
99
|
+
openText: "Show Less",
|
|
100
|
+
closeText: "Show More",
|
|
101
|
+
children: []
|
|
102
|
+
}
|
|
103
|
+
};
|
|
104
|
+
default:
|
|
105
|
+
return {
|
|
106
|
+
id,
|
|
107
|
+
type: "ParagraphBlock",
|
|
108
|
+
props: { text: [] }
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
}
|
|
23
112
|
export function useBlockEditor(initialBlocks, { maxHistorySize = 100, onMutation } = {}) {
|
|
24
113
|
const history = shallowRef([]);
|
|
25
114
|
const future = shallowRef([]);
|
|
@@ -124,6 +213,16 @@ export function useBlockEditor(initialBlocks, { maxHistorySize = 100, onMutation
|
|
|
124
213
|
};
|
|
125
214
|
const insertBlock = (newBlockType, targetId = null, position = "after") => {
|
|
126
215
|
executeMutation(() => {
|
|
216
|
+
const newBlock = createDefaultBlock(newBlockType);
|
|
217
|
+
if (!targetId) {
|
|
218
|
+
initialBlocks.value.push(newBlock);
|
|
219
|
+
return;
|
|
220
|
+
}
|
|
221
|
+
const loc = findBlockLocation(initialBlocks.value, targetId);
|
|
222
|
+
if (!loc) return;
|
|
223
|
+
const { parentArray, index } = loc;
|
|
224
|
+
const insertIndex = position === "after" ? index + 1 : index;
|
|
225
|
+
parentArray.splice(insertIndex, 0, newBlock);
|
|
127
226
|
});
|
|
128
227
|
};
|
|
129
228
|
const commitChanges = () => {
|
|
@@ -20,6 +20,95 @@ function regenerateIds(block) {
|
|
|
20
20
|
block.props.children.forEach((child) => regenerateIds(child));
|
|
21
21
|
}
|
|
22
22
|
}
|
|
23
|
+
function createDefaultBlock(type) {
|
|
24
|
+
const id = uuidv7();
|
|
25
|
+
switch (type) {
|
|
26
|
+
case "SectionBlock":
|
|
27
|
+
return {
|
|
28
|
+
id,
|
|
29
|
+
type: "SectionBlock",
|
|
30
|
+
props: {
|
|
31
|
+
level: 2,
|
|
32
|
+
title: "New Section",
|
|
33
|
+
children: []
|
|
34
|
+
}
|
|
35
|
+
};
|
|
36
|
+
case "ParagraphBlock":
|
|
37
|
+
return {
|
|
38
|
+
id,
|
|
39
|
+
type: "ParagraphBlock",
|
|
40
|
+
props: {
|
|
41
|
+
text: []
|
|
42
|
+
}
|
|
43
|
+
};
|
|
44
|
+
case "CalloutBlock":
|
|
45
|
+
return {
|
|
46
|
+
id,
|
|
47
|
+
type: "CalloutBlock",
|
|
48
|
+
props: {
|
|
49
|
+
variant: "info",
|
|
50
|
+
children: [
|
|
51
|
+
{
|
|
52
|
+
id: uuidv7(),
|
|
53
|
+
type: "ParagraphBlock",
|
|
54
|
+
props: { text: [{ type: "text", id: uuidv7(), props: { content: "Callout content" } }] }
|
|
55
|
+
}
|
|
56
|
+
]
|
|
57
|
+
}
|
|
58
|
+
};
|
|
59
|
+
case "ImageBlock":
|
|
60
|
+
return {
|
|
61
|
+
id,
|
|
62
|
+
type: "ImageBlock",
|
|
63
|
+
props: {
|
|
64
|
+
src: "https://placehold.co/600x400",
|
|
65
|
+
alt: "Placeholder Image"
|
|
66
|
+
}
|
|
67
|
+
};
|
|
68
|
+
case "QuoteBlock":
|
|
69
|
+
return {
|
|
70
|
+
id,
|
|
71
|
+
type: "QuoteBlock",
|
|
72
|
+
props: {
|
|
73
|
+
quote: "Quote text...",
|
|
74
|
+
source: "Source"
|
|
75
|
+
}
|
|
76
|
+
};
|
|
77
|
+
case "UnorderedListBlock":
|
|
78
|
+
return {
|
|
79
|
+
id,
|
|
80
|
+
type: "UnorderedListBlock",
|
|
81
|
+
props: {
|
|
82
|
+
items: []
|
|
83
|
+
}
|
|
84
|
+
};
|
|
85
|
+
case "CardBlock":
|
|
86
|
+
return {
|
|
87
|
+
id,
|
|
88
|
+
type: "CardBlock",
|
|
89
|
+
props: {
|
|
90
|
+
title: "New Card",
|
|
91
|
+
children: []
|
|
92
|
+
}
|
|
93
|
+
};
|
|
94
|
+
case "CollapsibleCardBlock":
|
|
95
|
+
return {
|
|
96
|
+
id,
|
|
97
|
+
type: "CollapsibleCardBlock",
|
|
98
|
+
props: {
|
|
99
|
+
openText: "Show Less",
|
|
100
|
+
closeText: "Show More",
|
|
101
|
+
children: []
|
|
102
|
+
}
|
|
103
|
+
};
|
|
104
|
+
default:
|
|
105
|
+
return {
|
|
106
|
+
id,
|
|
107
|
+
type: "ParagraphBlock",
|
|
108
|
+
props: { text: [] }
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
}
|
|
23
112
|
export function useBlockEditor(initialBlocks, { maxHistorySize = 100, onMutation } = {}) {
|
|
24
113
|
const history = shallowRef([]);
|
|
25
114
|
const future = shallowRef([]);
|
|
@@ -124,6 +213,16 @@ export function useBlockEditor(initialBlocks, { maxHistorySize = 100, onMutation
|
|
|
124
213
|
};
|
|
125
214
|
const insertBlock = (newBlockType, targetId = null, position = "after") => {
|
|
126
215
|
executeMutation(() => {
|
|
216
|
+
const newBlock = createDefaultBlock(newBlockType);
|
|
217
|
+
if (!targetId) {
|
|
218
|
+
initialBlocks.value.push(newBlock);
|
|
219
|
+
return;
|
|
220
|
+
}
|
|
221
|
+
const loc = findBlockLocation(initialBlocks.value, targetId);
|
|
222
|
+
if (!loc) return;
|
|
223
|
+
const { parentArray, index } = loc;
|
|
224
|
+
const insertIndex = position === "after" ? index + 1 : index;
|
|
225
|
+
parentArray.splice(insertIndex, 0, newBlock);
|
|
127
226
|
});
|
|
128
227
|
};
|
|
129
228
|
const commitChanges = () => {
|