rimelight-components 2.1.93 → 2.1.95
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/Block.vue +6 -1
- package/dist/runtime/components/blocks/BlockEditRenderer.d.vue.ts +20 -1
- package/dist/runtime/components/blocks/BlockEditRenderer.vue +148 -34
- package/dist/runtime/components/blocks/BlockEditRenderer.vue.d.ts +20 -1
- package/dist/runtime/components/blocks/BlockEditor.d.vue.ts +10 -0
- package/dist/runtime/components/blocks/BlockEditor.vue +45 -5
- package/dist/runtime/components/blocks/BlockEditor.vue.d.ts +10 -0
- package/dist/runtime/components/blocks/editor/CalloutBlockEditor.vue +30 -7
- package/dist/runtime/components/blocks/editor/SectionBlockEditor.vue +33 -16
- package/dist/runtime/components/page/PageEditor.vue +14 -2
- package/dist/runtime/composables/pages/useBlockEditor.d.ts +1 -0
- package/dist/runtime/composables/pages/useBlockEditor.js +57 -18
- package/dist/runtime/composables/pages/useBlockEditor.mjs +57 -18
- package/dist/runtime/composables/pages/usePageEditor.d.ts +2 -0
- package/dist/runtime/composables/pages/usePageEditor.js +16 -1
- package/dist/runtime/composables/pages/usePageEditor.mjs +16 -1
- package/package.json +3 -2
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.95";
|
|
8
8
|
const homepage = "https://rimelight.com/tools/rimelight-components";
|
|
9
9
|
|
|
10
10
|
const defaultOptions = {
|
|
@@ -72,7 +72,12 @@ const items = ref([
|
|
|
72
72
|
<div :class="root({ class: rc.root })">
|
|
73
73
|
<div :class="menuContainer({ class: rc.menuContainer })">
|
|
74
74
|
<UDropdownMenu :items="items">
|
|
75
|
-
<UButton
|
|
75
|
+
<UButton
|
|
76
|
+
icon="lucide:grip-vertical"
|
|
77
|
+
variant="ghost"
|
|
78
|
+
color="neutral"
|
|
79
|
+
class="drag-handle cursor-grab active:cursor-grabbing"
|
|
80
|
+
/>
|
|
76
81
|
</UDropdownMenu>
|
|
77
82
|
</div>
|
|
78
83
|
|
|
@@ -1,16 +1,35 @@
|
|
|
1
1
|
import type { Block } from "../../types/index.js";
|
|
2
2
|
export interface BlockEditRendererProps {
|
|
3
3
|
blocks: Block[];
|
|
4
|
+
containerId?: string | null;
|
|
4
5
|
rc?: {
|
|
5
6
|
root?: string;
|
|
6
7
|
};
|
|
7
8
|
}
|
|
9
|
+
type __VLS_Props = BlockEditRendererProps;
|
|
8
10
|
export interface BlockEditRendererEmits {
|
|
11
|
+
start: [];
|
|
12
|
+
end: [];
|
|
13
|
+
change: [any];
|
|
9
14
|
}
|
|
10
15
|
export interface BlockEditRendererSlots {
|
|
11
16
|
}
|
|
12
17
|
type __VLS_Slots = BlockEditRendererSlots;
|
|
13
|
-
|
|
18
|
+
type __VLS_ModelProps = {
|
|
19
|
+
'blocks': Block[];
|
|
20
|
+
};
|
|
21
|
+
type __VLS_PublicProps = __VLS_Props & __VLS_ModelProps;
|
|
22
|
+
declare const __VLS_base: import("vue").DefineComponent<__VLS_PublicProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
23
|
+
start: () => any;
|
|
24
|
+
end: () => any;
|
|
25
|
+
change: (args_0: any) => any;
|
|
26
|
+
"update:blocks": (value: Block[]) => any;
|
|
27
|
+
}, string, import("vue").PublicProps, Readonly<__VLS_PublicProps> & Readonly<{
|
|
28
|
+
onStart?: (() => any) | undefined;
|
|
29
|
+
onEnd?: (() => any) | undefined;
|
|
30
|
+
onChange?: ((args_0: any) => any) | undefined;
|
|
31
|
+
"onUpdate:blocks"?: ((value: Block[]) => any) | undefined;
|
|
32
|
+
}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
14
33
|
declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
|
|
15
34
|
declare const _default: typeof __VLS_export;
|
|
16
35
|
export default _default;
|
|
@@ -1,21 +1,59 @@
|
|
|
1
1
|
<script setup>
|
|
2
|
-
import {} from "vue";
|
|
2
|
+
import { watch, ref, inject } from "vue";
|
|
3
|
+
import draggable from "vuedraggable";
|
|
3
4
|
import { getBlockEditorComponent } from "../../internal/blockMapper";
|
|
4
5
|
import { tv } from "../../internal/tv";
|
|
5
6
|
import { useRC } from "../../composables";
|
|
6
|
-
const
|
|
7
|
+
const props = defineProps({
|
|
7
8
|
blocks: { type: Array, required: true },
|
|
9
|
+
containerId: { type: [String, null], required: false },
|
|
8
10
|
rc: { type: Object, required: false }
|
|
9
11
|
});
|
|
10
|
-
const
|
|
12
|
+
const { rc: rcProp, containerId = null } = props;
|
|
13
|
+
const blocks = defineModel("blocks", { type: Array, ...{ required: true } });
|
|
14
|
+
const emit = defineEmits(["start", "end", "change"]);
|
|
11
15
|
const slots = defineSlots();
|
|
12
16
|
const { rc } = useRC("BlockEditRenderer", rcProp);
|
|
17
|
+
const rendererId = Math.random().toString(36).substring(7);
|
|
18
|
+
console.log("[BlockEditRenderer] Instance created with ID:", rendererId, "containerId:", containerId, "initial blocks:", blocks.value.length);
|
|
19
|
+
const editorApi = inject("block-editor-api");
|
|
20
|
+
const isDraggingOver = ref(false);
|
|
21
|
+
const dragCounter = ref(0);
|
|
22
|
+
const onDragEnter = () => {
|
|
23
|
+
dragCounter.value++;
|
|
24
|
+
isDraggingOver.value = true;
|
|
25
|
+
};
|
|
26
|
+
const onDragLeave = () => {
|
|
27
|
+
dragCounter.value--;
|
|
28
|
+
if (dragCounter.value <= 0) {
|
|
29
|
+
isDraggingOver.value = false;
|
|
30
|
+
dragCounter.value = 0;
|
|
31
|
+
}
|
|
32
|
+
};
|
|
33
|
+
const onDrop = () => {
|
|
34
|
+
dragCounter.value = 0;
|
|
35
|
+
isDraggingOver.value = false;
|
|
36
|
+
};
|
|
13
37
|
const blockEditRendererStyles = tv({
|
|
14
38
|
slots: {
|
|
15
|
-
root: "flex flex-col
|
|
39
|
+
root: "flex flex-col w-full min-h-32 transition-all border-l-2 border-neutral-200/50 p-4 pl-6 rounded-r-lg"
|
|
40
|
+
},
|
|
41
|
+
variants: {
|
|
42
|
+
isDraggingOver: {
|
|
43
|
+
true: {
|
|
44
|
+
root: "border-l-4 border-primary-500 bg-primary-50/30 ring-1 ring-primary-500/10 z-10"
|
|
45
|
+
}
|
|
46
|
+
}
|
|
16
47
|
}
|
|
17
48
|
});
|
|
18
49
|
const { root } = blockEditRendererStyles();
|
|
50
|
+
watch(blocks, (newBlocks, oldBlocks) => {
|
|
51
|
+
console.log(`[BlockEditRenderer ${rendererId}] Blocks changed:`, {
|
|
52
|
+
oldCount: oldBlocks?.length || 0,
|
|
53
|
+
newCount: newBlocks?.length || 0,
|
|
54
|
+
blockIds: newBlocks?.map((b) => ({ id: b.id, type: b.type }))
|
|
55
|
+
});
|
|
56
|
+
}, { deep: true });
|
|
19
57
|
const getComponent = (block) => {
|
|
20
58
|
if (!block || !block.type || block.type.length === 0) {
|
|
21
59
|
console.error("Block object is missing the critical 'type' field.");
|
|
@@ -28,40 +66,116 @@ const getComponent = (block) => {
|
|
|
28
66
|
}
|
|
29
67
|
return resolvedComponent;
|
|
30
68
|
};
|
|
69
|
+
const handleStart = () => {
|
|
70
|
+
console.log(`[BlockEditRenderer ${rendererId}] Drag START - current blocks:`, blocks.value.length);
|
|
71
|
+
emit("start");
|
|
72
|
+
};
|
|
73
|
+
const handleEnd = () => {
|
|
74
|
+
console.log(`[BlockEditRenderer ${rendererId}] Drag END - current blocks:`, blocks.value.length);
|
|
75
|
+
emit("end");
|
|
76
|
+
};
|
|
77
|
+
const handleChange = (event) => {
|
|
78
|
+
console.log(`[BlockEditRenderer ${rendererId}] Drag CHANGE event:`, {
|
|
79
|
+
event,
|
|
80
|
+
added: event.added,
|
|
81
|
+
removed: event.removed,
|
|
82
|
+
moved: event.moved,
|
|
83
|
+
currentBlocks: blocks.value.length,
|
|
84
|
+
containerId,
|
|
85
|
+
blockIds: blocks.value.map((b) => ({ id: b.id, type: b.type }))
|
|
86
|
+
});
|
|
87
|
+
if (event.added) {
|
|
88
|
+
console.log(`[BlockEditRenderer ${rendererId}] Block ADDED to this container:`, event.added.element.id);
|
|
89
|
+
}
|
|
90
|
+
if (event.removed) {
|
|
91
|
+
console.log(`[BlockEditRenderer ${rendererId}] Block REMOVED from this container:`, event.removed.element.id);
|
|
92
|
+
}
|
|
93
|
+
if (event.moved) {
|
|
94
|
+
console.log(`[BlockEditRenderer ${rendererId}] Block MOVED within same container`);
|
|
95
|
+
}
|
|
96
|
+
emit("change", event);
|
|
97
|
+
};
|
|
31
98
|
</script>
|
|
32
99
|
|
|
33
100
|
<template>
|
|
34
|
-
<div
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
101
|
+
<div
|
|
102
|
+
:class="[root({ isDraggingOver }), rc.root, 'relative', { 'is-empty': blocks.length === 0 }]"
|
|
103
|
+
@dragenter="onDragEnter"
|
|
104
|
+
@dragover.prevent
|
|
105
|
+
@dragleave="onDragLeave"
|
|
106
|
+
@drop="onDrop"
|
|
107
|
+
>
|
|
108
|
+
<draggable
|
|
109
|
+
v-model="blocks"
|
|
110
|
+
item-key="id"
|
|
111
|
+
handle=".drag-handle"
|
|
112
|
+
:group="{ name: 'blocks', pull: true, put: true }"
|
|
113
|
+
:animation="200"
|
|
114
|
+
:force-fallback="true"
|
|
115
|
+
fallback-class="drag-fallback"
|
|
116
|
+
ghost-class="drag-placeholder"
|
|
117
|
+
@start="handleStart"
|
|
118
|
+
@end="handleEnd"
|
|
119
|
+
@change="handleChange"
|
|
120
|
+
class="flex flex-col w-full flex-1"
|
|
121
|
+
:class="[blocks && blocks.length > 0 ? 'gap-lg min-h-16 pb-32' : 'gap-0 min-h-32']"
|
|
122
|
+
>
|
|
123
|
+
<template #header>
|
|
124
|
+
<div
|
|
125
|
+
v-if="!blocks || blocks.length === 0"
|
|
126
|
+
class="w-full p-4 flex items-center justify-center transition-all rounded-lg border-2 border-transparent"
|
|
127
|
+
:class="[isDraggingOver ? 'bg-primary-50/50 border-dashed border-primary-500/50' : '']"
|
|
128
|
+
>
|
|
129
|
+
<UEmpty
|
|
130
|
+
icon="i-lucide-layers"
|
|
131
|
+
title="Empty Section"
|
|
132
|
+
description="This area has no blocks yet. Drag items here or click to add your first block."
|
|
133
|
+
variant="naked"
|
|
134
|
+
class="w-full"
|
|
135
|
+
:ui="{ root: 'transition-transform px-4', title: isDraggingOver ? 'text-primary-600 font-bold' : '' }"
|
|
136
|
+
:class="[isDraggingOver ? 'scale-[1.02]' : '']"
|
|
137
|
+
>
|
|
138
|
+
<template #actions>
|
|
139
|
+
<UButton
|
|
140
|
+
label="Add Block"
|
|
141
|
+
icon="i-lucide-plus"
|
|
142
|
+
color="neutral"
|
|
143
|
+
variant="subtle"
|
|
144
|
+
@click="editorApi?.openAddBlockModal()"
|
|
145
|
+
/>
|
|
146
|
+
</template>
|
|
147
|
+
</UEmpty>
|
|
148
|
+
</div>
|
|
149
|
+
</template>
|
|
150
|
+
|
|
151
|
+
<template #item="{ element: block }">
|
|
152
|
+
<div class="w-full">
|
|
153
|
+
<template v-if="getComponent(block)">
|
|
154
|
+
<RCBlock :id="block.id" :type="block.type" class="w-full">
|
|
155
|
+
<component
|
|
156
|
+
:is="getComponent(block)"
|
|
157
|
+
:id="block.id"
|
|
158
|
+
v-bind="block.props"
|
|
159
|
+
:type="block.type"
|
|
160
|
+
class="w-full"
|
|
161
|
+
/>
|
|
162
|
+
</RCBlock>
|
|
163
|
+
</template>
|
|
164
|
+
<template v-else>
|
|
165
|
+
<UAlert
|
|
166
|
+
color="error"
|
|
167
|
+
variant="subtle"
|
|
168
|
+
icon="lucide:octagon-alert"
|
|
169
|
+
title="Rendering Error"
|
|
170
|
+
:description="`Block component for type \'${block.type || 'UNKNOWN_OR_MISSING'}\' was not found. This block will be skipped or the type is invalid/empty.`"
|
|
52
171
|
/>
|
|
53
|
-
</
|
|
54
|
-
</
|
|
55
|
-
<template v-else>
|
|
56
|
-
<UAlert
|
|
57
|
-
color="error"
|
|
58
|
-
variant="subtle"
|
|
59
|
-
icon="lucide:octagon-alert"
|
|
60
|
-
title="Rendering Error"
|
|
61
|
-
:description="`Block component for type \'${block.type || 'UNKNOWN_OR_MISSING'}\' was not found. This block will be skipped or the type is invalid/empty.`"
|
|
62
|
-
/>
|
|
63
|
-
</template>
|
|
172
|
+
</template>
|
|
173
|
+
</div>
|
|
64
174
|
</template>
|
|
65
|
-
</
|
|
175
|
+
</draggable>
|
|
66
176
|
</div>
|
|
67
177
|
</template>
|
|
178
|
+
|
|
179
|
+
<style scoped>
|
|
180
|
+
:deep(.drag-placeholder){background:#3b82f6;border-radius:2px;height:4px;margin-bottom:8px;margin-top:8px;opacity:1;overflow:hidden}:deep(.drag-fallback){background-color:#fff;border-radius:.5rem;box-shadow:0 10px 15px -3px rgba(0,0,0,.1),0 4px 6px -2px rgba(0,0,0,.05);opacity:.9;transform:scale(1.01);z-index:9999}:deep(.drag-placeholder>*){display:none!important}.is-empty :deep(.drag-placeholder){border:0!important;display:none!important;height:0!important;margin:0!important;padding:0!important;visibility:hidden!important}
|
|
181
|
+
</style>
|
|
@@ -1,16 +1,35 @@
|
|
|
1
1
|
import type { Block } from "../../types/index.js";
|
|
2
2
|
export interface BlockEditRendererProps {
|
|
3
3
|
blocks: Block[];
|
|
4
|
+
containerId?: string | null;
|
|
4
5
|
rc?: {
|
|
5
6
|
root?: string;
|
|
6
7
|
};
|
|
7
8
|
}
|
|
9
|
+
type __VLS_Props = BlockEditRendererProps;
|
|
8
10
|
export interface BlockEditRendererEmits {
|
|
11
|
+
start: [];
|
|
12
|
+
end: [];
|
|
13
|
+
change: [any];
|
|
9
14
|
}
|
|
10
15
|
export interface BlockEditRendererSlots {
|
|
11
16
|
}
|
|
12
17
|
type __VLS_Slots = BlockEditRendererSlots;
|
|
13
|
-
|
|
18
|
+
type __VLS_ModelProps = {
|
|
19
|
+
'blocks': Block[];
|
|
20
|
+
};
|
|
21
|
+
type __VLS_PublicProps = __VLS_Props & __VLS_ModelProps;
|
|
22
|
+
declare const __VLS_base: import("vue").DefineComponent<__VLS_PublicProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
23
|
+
start: () => any;
|
|
24
|
+
end: () => any;
|
|
25
|
+
change: (args_0: any) => any;
|
|
26
|
+
"update:blocks": (value: Block[]) => any;
|
|
27
|
+
}, string, import("vue").PublicProps, Readonly<__VLS_PublicProps> & Readonly<{
|
|
28
|
+
onStart?: (() => any) | undefined;
|
|
29
|
+
onEnd?: (() => any) | undefined;
|
|
30
|
+
onChange?: ((args_0: any) => any) | undefined;
|
|
31
|
+
"onUpdate:blocks"?: ((value: Block[]) => any) | undefined;
|
|
32
|
+
}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
14
33
|
declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
|
|
15
34
|
declare const _default: typeof __VLS_export;
|
|
16
35
|
export default _default;
|
|
@@ -1,12 +1,16 @@
|
|
|
1
1
|
import type { Block } from "../../types/index.js";
|
|
2
2
|
export interface BlockEditorProps {
|
|
3
3
|
historyLimit?: number;
|
|
4
|
+
containerId?: string | null;
|
|
4
5
|
rc?: {};
|
|
5
6
|
}
|
|
6
7
|
type __VLS_Props = BlockEditorProps;
|
|
7
8
|
export interface BlockEditorEmits {
|
|
8
9
|
save: [];
|
|
9
10
|
mutation: [];
|
|
11
|
+
start: [];
|
|
12
|
+
end: [];
|
|
13
|
+
change: [any];
|
|
10
14
|
}
|
|
11
15
|
type __VLS_ModelProps = {
|
|
12
16
|
modelValue: Block[];
|
|
@@ -18,11 +22,17 @@ declare const __VLS_export: import("vue").DefineComponent<__VLS_PublicProps, {
|
|
|
18
22
|
canUndo: import("vue").ComputedRef<boolean>;
|
|
19
23
|
canRedo: import("vue").ComputedRef<boolean>;
|
|
20
24
|
}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
25
|
+
start: () => any;
|
|
26
|
+
end: () => any;
|
|
21
27
|
save: () => any;
|
|
28
|
+
change: (args_0: any) => any;
|
|
22
29
|
mutation: () => any;
|
|
23
30
|
"update:modelValue": (value: Block[]) => any;
|
|
24
31
|
}, string, import("vue").PublicProps, Readonly<__VLS_PublicProps> & Readonly<{
|
|
32
|
+
onStart?: (() => any) | undefined;
|
|
33
|
+
onEnd?: (() => any) | undefined;
|
|
25
34
|
onSave?: (() => any) | undefined;
|
|
35
|
+
onChange?: ((args_0: any) => any) | undefined;
|
|
26
36
|
onMutation?: (() => any) | undefined;
|
|
27
37
|
"onUpdate:modelValue"?: ((value: Block[]) => any) | undefined;
|
|
28
38
|
}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
@@ -1,14 +1,23 @@
|
|
|
1
1
|
<script setup>
|
|
2
|
-
import { provide, ref } from "vue";
|
|
2
|
+
import { provide, inject, ref, watch, nextTick } from "vue";
|
|
3
|
+
import { v7 as uuidv7 } from "uuid";
|
|
3
4
|
import { useBlockEditor, useRC } from "../../composables";
|
|
4
5
|
import {} from "../../utils/blocks";
|
|
5
6
|
import { useI18n } from "vue-i18n";
|
|
6
|
-
|
|
7
|
+
function regenerateIds(block) {
|
|
8
|
+
block.id = uuidv7();
|
|
9
|
+
if (block.props && "children" in block.props && Array.isArray(block.props.children)) {
|
|
10
|
+
block.props.children.forEach((child) => regenerateIds(child));
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
const { historyLimit, containerId = null, rc: rcProp } = defineProps({
|
|
7
14
|
historyLimit: { type: Number, required: false },
|
|
15
|
+
containerId: { type: [String, null], required: false },
|
|
8
16
|
rc: { type: Object, required: false }
|
|
9
17
|
});
|
|
10
18
|
const blocks = defineModel({ type: Array, ...{ required: true } });
|
|
11
|
-
|
|
19
|
+
console.log("[BlockEditor] Component mounted with", blocks.value.length, "blocks");
|
|
20
|
+
const emit = defineEmits(["save", "mutation", "start", "end", "change"]);
|
|
12
21
|
const { t } = useI18n();
|
|
13
22
|
const { rc } = useRC("BlockEditor", rcProp);
|
|
14
23
|
const {
|
|
@@ -17,6 +26,7 @@ const {
|
|
|
17
26
|
duplicateBlock,
|
|
18
27
|
updateBlockProps,
|
|
19
28
|
insertBlock,
|
|
29
|
+
relocateBlock,
|
|
20
30
|
undo,
|
|
21
31
|
redo,
|
|
22
32
|
canUndo,
|
|
@@ -37,20 +47,50 @@ provide("block-editor-api", {
|
|
|
37
47
|
duplicateBlock,
|
|
38
48
|
updateBlockProps,
|
|
39
49
|
insertBlock,
|
|
50
|
+
relocateBlock,
|
|
40
51
|
canUndo,
|
|
41
52
|
canRedo,
|
|
42
53
|
undo,
|
|
43
54
|
redo,
|
|
44
55
|
openAddBlockModal
|
|
45
56
|
});
|
|
57
|
+
const handleDragStart = () => {
|
|
58
|
+
console.log("[BlockEditor] Drag started");
|
|
59
|
+
emit("start");
|
|
60
|
+
};
|
|
61
|
+
const handleDragEnd = async () => {
|
|
62
|
+
console.log("[BlockEditor] Drag ended");
|
|
63
|
+
emit("end");
|
|
64
|
+
emit("mutation");
|
|
65
|
+
};
|
|
66
|
+
const handleBlockChange = (event) => {
|
|
67
|
+
console.log("[BlockEditor] handleBlockChange:", event);
|
|
68
|
+
if (event.added) {
|
|
69
|
+
const block = event.added.element;
|
|
70
|
+
if (block) {
|
|
71
|
+
console.log("[BlockEditor] Regenerating IDs for added block:", block.id);
|
|
72
|
+
regenerateIds(block);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
emit("change", event);
|
|
76
|
+
if (event.added || event.removed || event.moved) {
|
|
77
|
+
emit("mutation");
|
|
78
|
+
}
|
|
79
|
+
};
|
|
46
80
|
defineExpose({ undo, redo, canUndo, canRedo });
|
|
47
81
|
</script>
|
|
48
82
|
|
|
49
83
|
<template>
|
|
50
84
|
<div class="flex flex-col gap-8 w-full">
|
|
51
|
-
<RCBlockEditRenderer
|
|
85
|
+
<RCBlockEditRenderer
|
|
86
|
+
v-model:blocks="blocks"
|
|
87
|
+
:container-id="containerId"
|
|
88
|
+
@start="handleDragStart"
|
|
89
|
+
@end="handleDragEnd"
|
|
90
|
+
@change="handleBlockChange"
|
|
91
|
+
/>
|
|
52
92
|
|
|
53
|
-
<div class="flex flex-col items-center justify-center gap-md p-sm">
|
|
93
|
+
<div v-if="blocks && blocks.length > 0" class="flex flex-col items-center justify-center gap-md p-sm">
|
|
54
94
|
<UButton
|
|
55
95
|
color="neutral"
|
|
56
96
|
:label="t('page_editor.add_block', 'Add Block')"
|
|
@@ -1,12 +1,16 @@
|
|
|
1
1
|
import type { Block } from "../../types/index.js";
|
|
2
2
|
export interface BlockEditorProps {
|
|
3
3
|
historyLimit?: number;
|
|
4
|
+
containerId?: string | null;
|
|
4
5
|
rc?: {};
|
|
5
6
|
}
|
|
6
7
|
type __VLS_Props = BlockEditorProps;
|
|
7
8
|
export interface BlockEditorEmits {
|
|
8
9
|
save: [];
|
|
9
10
|
mutation: [];
|
|
11
|
+
start: [];
|
|
12
|
+
end: [];
|
|
13
|
+
change: [any];
|
|
10
14
|
}
|
|
11
15
|
type __VLS_ModelProps = {
|
|
12
16
|
modelValue: Block[];
|
|
@@ -18,11 +22,17 @@ declare const __VLS_export: import("vue").DefineComponent<__VLS_PublicProps, {
|
|
|
18
22
|
canUndo: import("vue").ComputedRef<boolean>;
|
|
19
23
|
canRedo: import("vue").ComputedRef<boolean>;
|
|
20
24
|
}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
25
|
+
start: () => any;
|
|
26
|
+
end: () => any;
|
|
21
27
|
save: () => any;
|
|
28
|
+
change: (args_0: any) => any;
|
|
22
29
|
mutation: () => any;
|
|
23
30
|
"update:modelValue": (value: Block[]) => any;
|
|
24
31
|
}, string, import("vue").PublicProps, Readonly<__VLS_PublicProps> & Readonly<{
|
|
32
|
+
onStart?: (() => any) | undefined;
|
|
33
|
+
onEnd?: (() => any) | undefined;
|
|
25
34
|
onSave?: (() => any) | undefined;
|
|
35
|
+
onChange?: ((args_0: any) => any) | undefined;
|
|
26
36
|
onMutation?: (() => any) | undefined;
|
|
27
37
|
"onUpdate:modelValue"?: ((value: Block[]) => any) | undefined;
|
|
28
38
|
}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
<script setup>
|
|
2
|
-
import { inject, computed } from "vue";
|
|
2
|
+
import { inject, computed, ref, watch, nextTick, shallowRef } from "vue";
|
|
3
3
|
import { useI18n } from "vue-i18n";
|
|
4
4
|
import { useAppConfig } from "#imports";
|
|
5
5
|
import { tv } from "../../../internal/tv";
|
|
6
6
|
import { useRC } from "../../../composables";
|
|
7
|
-
const
|
|
7
|
+
const props = defineProps({
|
|
8
8
|
id: { type: String, required: true },
|
|
9
9
|
rc: { type: Object, required: false },
|
|
10
10
|
variant: { type: String, required: true },
|
|
@@ -12,6 +12,7 @@ const { id, variant, children, to, target, rc: rcProp } = defineProps({
|
|
|
12
12
|
to: { type: String, required: false },
|
|
13
13
|
target: { type: String, required: false }
|
|
14
14
|
});
|
|
15
|
+
const { rc: rcProp } = props;
|
|
15
16
|
const emit = defineEmits([]);
|
|
16
17
|
const slots = defineSlots();
|
|
17
18
|
const { rc } = useRC("CalloutBlockEditor", rcProp);
|
|
@@ -33,8 +34,8 @@ const variants = [
|
|
|
33
34
|
];
|
|
34
35
|
const appConfig = useAppConfig();
|
|
35
36
|
const { t } = useI18n();
|
|
36
|
-
const getVariantConfig = (
|
|
37
|
-
return appConfig.rimelightComponents?.callouts?.[
|
|
37
|
+
const getVariantConfig = (variant) => {
|
|
38
|
+
return appConfig.rimelightComponents?.callouts?.[variant] ?? {
|
|
38
39
|
icon: "lucide:alert-circle",
|
|
39
40
|
title: "Callout",
|
|
40
41
|
tooltip: "Callout"
|
|
@@ -49,17 +50,30 @@ const items = computed(() => [
|
|
|
49
50
|
description: t(config.description || config.tooltip),
|
|
50
51
|
onSelect: () => {
|
|
51
52
|
if (editorApi) {
|
|
52
|
-
editorApi.updateBlockProps(id, { variant: type });
|
|
53
|
+
editorApi.updateBlockProps(props.id, { variant: type });
|
|
53
54
|
}
|
|
54
55
|
}
|
|
55
56
|
};
|
|
56
57
|
})
|
|
57
58
|
]);
|
|
59
|
+
const localChildren = computed({
|
|
60
|
+
get: () => props.children ?? [],
|
|
61
|
+
set: (newChildren) => {
|
|
62
|
+
console.log("[CalloutBlockEditor] localChildren setter called:", newChildren.length);
|
|
63
|
+
if (editorApi && props.id) {
|
|
64
|
+
const childrenCopy = JSON.parse(JSON.stringify(newChildren));
|
|
65
|
+
editorApi.updateBlockProps(props.id, { children: childrenCopy });
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
});
|
|
69
|
+
const handleChildrenMutation = () => {
|
|
70
|
+
console.log("[CalloutBlockEditor] Mutation event received (handled by setter)");
|
|
71
|
+
};
|
|
58
72
|
</script>
|
|
59
73
|
|
|
60
74
|
<template>
|
|
61
75
|
<div :class="root({ class: rc.root })">
|
|
62
|
-
<RCCallout :variant="variant" :to="to" :target="target">
|
|
76
|
+
<RCCallout :variant="props.variant" :to="props.to" :target="props.target">
|
|
63
77
|
<template #leading="{ icon, iconClass }">
|
|
64
78
|
<UDropdownMenu :items="items" :ui="{ content: 'w-64' }">
|
|
65
79
|
<template #item="{ item }">
|
|
@@ -79,7 +93,16 @@ const items = computed(() => [
|
|
|
79
93
|
/>
|
|
80
94
|
</UDropdownMenu>
|
|
81
95
|
</template>
|
|
82
|
-
<
|
|
96
|
+
<template #default>
|
|
97
|
+
<div class="w-full mt-2">
|
|
98
|
+
<RCBlockEditor
|
|
99
|
+
v-model="localChildren"
|
|
100
|
+
:container-id="props.id"
|
|
101
|
+
@mutation="handleChildrenMutation"
|
|
102
|
+
@end="handleChildrenMutation"
|
|
103
|
+
/>
|
|
104
|
+
</div>
|
|
105
|
+
</template>
|
|
83
106
|
</RCCallout>
|
|
84
107
|
</div>
|
|
85
108
|
</template>
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
<script setup>
|
|
2
|
-
import { inject, ref, computed, watch } from "vue";
|
|
2
|
+
import { inject, ref, computed, watch, nextTick, shallowRef } from "vue";
|
|
3
3
|
import {} from "../../../types";
|
|
4
4
|
import { tv } from "../../../internal/tv";
|
|
5
5
|
import { useRC } from "../../../composables";
|
|
6
|
-
const
|
|
6
|
+
const props = defineProps({
|
|
7
7
|
id: { type: String, required: true },
|
|
8
8
|
rc: { type: Object, required: false },
|
|
9
9
|
level: { type: Number, required: true },
|
|
@@ -11,6 +11,7 @@ const { level, title, description, children, id, rc: rcProp } = defineProps({
|
|
|
11
11
|
description: { type: String, required: false },
|
|
12
12
|
children: { type: Array, required: true }
|
|
13
13
|
});
|
|
14
|
+
const { rc: rcProp } = props;
|
|
14
15
|
const emit = defineEmits([]);
|
|
15
16
|
const slots = defineSlots();
|
|
16
17
|
const { rc } = useRC("SectionBlockEditor", rcProp);
|
|
@@ -22,11 +23,10 @@ const sectionBlockEditorStyles = tv({
|
|
|
22
23
|
}
|
|
23
24
|
});
|
|
24
25
|
const { root, headerContainer, titleInput } = sectionBlockEditorStyles();
|
|
25
|
-
const hasChildren = computed(() => children && children.length > 0);
|
|
26
26
|
const editorApi = inject("block-editor-api");
|
|
27
|
-
const localLevel = ref(level);
|
|
28
|
-
const localTitle = ref(title);
|
|
29
|
-
const localDescription = ref(description);
|
|
27
|
+
const localLevel = ref(props.level);
|
|
28
|
+
const localTitle = ref(props.title);
|
|
29
|
+
const localDescription = ref(props.description);
|
|
30
30
|
const levelItems = [
|
|
31
31
|
{ label: "H1", value: 1 },
|
|
32
32
|
{ label: "H2", value: 2 },
|
|
@@ -36,25 +36,25 @@ const updateLocalTitle = (e) => {
|
|
|
36
36
|
localTitle.value = e.target.value;
|
|
37
37
|
};
|
|
38
38
|
const commitTitleOnBlur = () => {
|
|
39
|
-
if (editorApi && id && localTitle.value !== title) {
|
|
40
|
-
editorApi.updateBlockProps(id, { title: localTitle.value });
|
|
39
|
+
if (editorApi && props.id && localTitle.value !== props.title) {
|
|
40
|
+
editorApi.updateBlockProps(props.id, { title: localTitle.value });
|
|
41
41
|
}
|
|
42
42
|
};
|
|
43
43
|
const updateLocalDescription = (e) => {
|
|
44
44
|
localDescription.value = e.target.value;
|
|
45
45
|
};
|
|
46
46
|
const commitDescriptionOnBlur = () => {
|
|
47
|
-
if (editorApi && id && localDescription.value !== description) {
|
|
48
|
-
editorApi.updateBlockProps(id, { description: localDescription.value });
|
|
47
|
+
if (editorApi && props.id && localDescription.value !== props.description) {
|
|
48
|
+
editorApi.updateBlockProps(props.id, { description: localDescription.value });
|
|
49
49
|
}
|
|
50
50
|
};
|
|
51
51
|
watch(localLevel, (newLocalLevel) => {
|
|
52
|
-
if (editorApi && id && newLocalLevel !== level) {
|
|
53
|
-
editorApi.updateBlockProps(id, { level: newLocalLevel });
|
|
52
|
+
if (editorApi && props.id && newLocalLevel !== props.level) {
|
|
53
|
+
editorApi.updateBlockProps(props.id, { level: newLocalLevel });
|
|
54
54
|
}
|
|
55
55
|
});
|
|
56
56
|
watch(
|
|
57
|
-
() => title,
|
|
57
|
+
() => props.title,
|
|
58
58
|
(newVal) => {
|
|
59
59
|
if (newVal !== localTitle.value) {
|
|
60
60
|
localTitle.value = newVal;
|
|
@@ -62,7 +62,7 @@ watch(
|
|
|
62
62
|
}
|
|
63
63
|
);
|
|
64
64
|
watch(
|
|
65
|
-
() => level,
|
|
65
|
+
() => props.level,
|
|
66
66
|
(newVal) => {
|
|
67
67
|
if (newVal !== localLevel.value) {
|
|
68
68
|
localLevel.value = newVal;
|
|
@@ -70,13 +70,25 @@ watch(
|
|
|
70
70
|
}
|
|
71
71
|
);
|
|
72
72
|
watch(
|
|
73
|
-
() => description,
|
|
73
|
+
() => props.description,
|
|
74
74
|
(newVal) => {
|
|
75
75
|
if (newVal !== localDescription.value) {
|
|
76
76
|
localDescription.value = newVal;
|
|
77
77
|
}
|
|
78
78
|
}
|
|
79
79
|
);
|
|
80
|
+
const localChildren = computed({
|
|
81
|
+
get: () => props.children ?? [],
|
|
82
|
+
set: (newChildren) => {
|
|
83
|
+
if (editorApi && props.id) {
|
|
84
|
+
const childrenCopy = JSON.parse(JSON.stringify(newChildren));
|
|
85
|
+
editorApi.updateBlockProps(props.id, { children: childrenCopy });
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
});
|
|
89
|
+
const handleChildrenMutation = () => {
|
|
90
|
+
console.log("[SectionBlockEditor] Mutation event received (handled by setter)");
|
|
91
|
+
};
|
|
80
92
|
</script>
|
|
81
93
|
|
|
82
94
|
<template>
|
|
@@ -114,7 +126,12 @@ watch(
|
|
|
114
126
|
/>
|
|
115
127
|
</template>
|
|
116
128
|
<template #default>
|
|
117
|
-
<
|
|
129
|
+
<RCBlockEditor
|
|
130
|
+
v-model="localChildren"
|
|
131
|
+
:container-id="props.id"
|
|
132
|
+
@mutation="handleChildrenMutation"
|
|
133
|
+
@end="handleChildrenMutation"
|
|
134
|
+
/>
|
|
118
135
|
</template>
|
|
119
136
|
</RCSection>
|
|
120
137
|
</div>
|
|
@@ -83,7 +83,7 @@ const {
|
|
|
83
83
|
} = pageEditorStyles();
|
|
84
84
|
const { getTypeLabelKey } = usePageRegistry();
|
|
85
85
|
const { t, locale } = useI18n();
|
|
86
|
-
const { undo, redo, canUndo, canRedo, captureSnapshot, resetHistory } = usePageEditor(page);
|
|
86
|
+
const { undo, redo, canUndo, canRedo, captureSnapshot, resetHistory, pauseHistory, resumeHistory } = usePageEditor(page);
|
|
87
87
|
const { confirm } = useConfirm();
|
|
88
88
|
const handleViewPage = async () => {
|
|
89
89
|
if (canUndo.value) {
|
|
@@ -347,7 +347,19 @@ const handleTreeNavigate = (slug) => {
|
|
|
347
347
|
</div>
|
|
348
348
|
</template>
|
|
349
349
|
</UPageHeader>
|
|
350
|
-
<RCBlockEditor
|
|
350
|
+
<RCBlockEditor
|
|
351
|
+
ref="editor"
|
|
352
|
+
v-model="page.blocks"
|
|
353
|
+
@start="pauseHistory"
|
|
354
|
+
@mutation="() => {
|
|
355
|
+
resumeHistory();
|
|
356
|
+
if (!editorRef?.isDragging) {
|
|
357
|
+
captureSnapshot();
|
|
358
|
+
} else {
|
|
359
|
+
console.log('[PageEditor] Skipping snapshot - editor is dragging');
|
|
360
|
+
}
|
|
361
|
+
}"
|
|
362
|
+
/>
|
|
351
363
|
<template v-if="useSurround">
|
|
352
364
|
<div
|
|
353
365
|
v-if="surroundStatus === 'pending'"
|
|
@@ -9,6 +9,7 @@ export declare function useBlockEditor(initialBlocks: Ref<Block[]>, { maxHistory
|
|
|
9
9
|
moveBlock: (id: string, direction: -1 | 1) => void;
|
|
10
10
|
duplicateBlock: (id: string) => void;
|
|
11
11
|
insertBlock: (newBlockType: Block["type"], targetId?: string | null, position?: "before" | "after") => void;
|
|
12
|
+
relocateBlock: (blockId: string, targetContainerId: string | null, targetIndex: number) => void;
|
|
12
13
|
undo: () => void;
|
|
13
14
|
redo: () => void;
|
|
14
15
|
canUndo: import("vue").ComputedRef<boolean>;
|
|
@@ -47,13 +47,7 @@ function createDefaultBlock(type) {
|
|
|
47
47
|
type: "CalloutBlock",
|
|
48
48
|
props: {
|
|
49
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
|
-
]
|
|
50
|
+
children: []
|
|
57
51
|
}
|
|
58
52
|
};
|
|
59
53
|
case "ImageBlock":
|
|
@@ -125,23 +119,24 @@ export function useBlockEditor(initialBlocks, { maxHistorySize = 100, onMutation
|
|
|
125
119
|
const canUndo = computed(() => history.value.length > 0);
|
|
126
120
|
const canRedo = computed(() => future.value.length > 0);
|
|
127
121
|
const updateBlockProps = (id, newProps) => {
|
|
122
|
+
console.log("[useBlockEditor] updateBlockProps called for ID:", id, "Keys:", Object.keys(newProps));
|
|
123
|
+
if (newProps.children) {
|
|
124
|
+
console.log("[useBlockEditor] Updating children. Count:", newProps.children.length);
|
|
125
|
+
}
|
|
128
126
|
executeMutation(() => {
|
|
129
127
|
const loc = findBlockLocation(initialBlocks.value, id);
|
|
130
|
-
if (!loc)
|
|
128
|
+
if (!loc) {
|
|
129
|
+
console.warn("[useBlockEditor] Block not found for update:", id);
|
|
130
|
+
return;
|
|
131
|
+
}
|
|
131
132
|
const oldBlock = loc.parentArray[loc.index];
|
|
132
133
|
if (!oldBlock) return;
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
...newProps
|
|
136
|
-
};
|
|
137
|
-
const newBlock = {
|
|
134
|
+
Object.assign(oldBlock.props, newProps);
|
|
135
|
+
console.log("[useBlockEditor] Block props updated in place:", {
|
|
138
136
|
id: oldBlock.id,
|
|
139
|
-
// Explicitly carry over the required BaseBlock properties
|
|
140
137
|
type: oldBlock.type,
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
};
|
|
144
|
-
loc.parentArray.splice(loc.index, 1, newBlock);
|
|
138
|
+
childrenCount: oldBlock.props.children?.length
|
|
139
|
+
});
|
|
145
140
|
});
|
|
146
141
|
};
|
|
147
142
|
const removeBlock = (id) => {
|
|
@@ -194,6 +189,49 @@ export function useBlockEditor(initialBlocks, { maxHistorySize = 100, onMutation
|
|
|
194
189
|
committedBlocks.value = committedSnapshot;
|
|
195
190
|
return committedSnapshot;
|
|
196
191
|
};
|
|
192
|
+
const relocateBlock = (blockId, targetContainerId, targetIndex) => {
|
|
193
|
+
console.log("[useBlockEditor] relocateBlock called:", { blockId, targetContainerId, targetIndex });
|
|
194
|
+
executeMutation(() => {
|
|
195
|
+
const sourceLoc = findBlockLocation(initialBlocks.value, blockId);
|
|
196
|
+
if (!sourceLoc) {
|
|
197
|
+
console.warn("[useBlockEditor] Block not found for relocation:", blockId);
|
|
198
|
+
return;
|
|
199
|
+
}
|
|
200
|
+
const block = sourceLoc.parentArray[sourceLoc.index];
|
|
201
|
+
if (!block) {
|
|
202
|
+
console.warn("[useBlockEditor] Block is undefined at location");
|
|
203
|
+
return;
|
|
204
|
+
}
|
|
205
|
+
sourceLoc.parentArray.splice(sourceLoc.index, 1);
|
|
206
|
+
console.log("[useBlockEditor] Block removed from source, now inserting at target");
|
|
207
|
+
let targetArray;
|
|
208
|
+
if (targetContainerId === null) {
|
|
209
|
+
targetArray = initialBlocks.value;
|
|
210
|
+
} else {
|
|
211
|
+
const targetLoc = findBlockLocation(initialBlocks.value, targetContainerId);
|
|
212
|
+
if (!targetLoc) {
|
|
213
|
+
console.warn("[useBlockEditor] Target container not found:", targetContainerId);
|
|
214
|
+
sourceLoc.parentArray.splice(sourceLoc.index, 0, block);
|
|
215
|
+
return;
|
|
216
|
+
}
|
|
217
|
+
const targetBlock = targetLoc.parentArray[targetLoc.index];
|
|
218
|
+
if (!targetBlock || !("children" in targetBlock.props)) {
|
|
219
|
+
console.warn("[useBlockEditor] Target block does not have children prop");
|
|
220
|
+
sourceLoc.parentArray.splice(sourceLoc.index, 0, block);
|
|
221
|
+
return;
|
|
222
|
+
}
|
|
223
|
+
targetArray = targetBlock.props.children;
|
|
224
|
+
}
|
|
225
|
+
const safeIndex = Math.max(0, Math.min(targetIndex, targetArray.length));
|
|
226
|
+
targetArray.splice(safeIndex, 0, block);
|
|
227
|
+
console.log("[useBlockEditor] Block relocated successfully:", {
|
|
228
|
+
blockId,
|
|
229
|
+
targetContainerId,
|
|
230
|
+
targetIndex: safeIndex,
|
|
231
|
+
newTargetLength: targetArray.length
|
|
232
|
+
});
|
|
233
|
+
});
|
|
234
|
+
};
|
|
197
235
|
return {
|
|
198
236
|
// Mutations
|
|
199
237
|
updateBlockProps,
|
|
@@ -201,6 +239,7 @@ export function useBlockEditor(initialBlocks, { maxHistorySize = 100, onMutation
|
|
|
201
239
|
moveBlock,
|
|
202
240
|
duplicateBlock,
|
|
203
241
|
insertBlock,
|
|
242
|
+
relocateBlock,
|
|
204
243
|
// History
|
|
205
244
|
undo,
|
|
206
245
|
redo,
|
|
@@ -47,13 +47,7 @@ function createDefaultBlock(type) {
|
|
|
47
47
|
type: "CalloutBlock",
|
|
48
48
|
props: {
|
|
49
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
|
-
]
|
|
50
|
+
children: []
|
|
57
51
|
}
|
|
58
52
|
};
|
|
59
53
|
case "ImageBlock":
|
|
@@ -125,23 +119,24 @@ export function useBlockEditor(initialBlocks, { maxHistorySize = 100, onMutation
|
|
|
125
119
|
const canUndo = computed(() => history.value.length > 0);
|
|
126
120
|
const canRedo = computed(() => future.value.length > 0);
|
|
127
121
|
const updateBlockProps = (id, newProps) => {
|
|
122
|
+
console.log("[useBlockEditor] updateBlockProps called for ID:", id, "Keys:", Object.keys(newProps));
|
|
123
|
+
if (newProps.children) {
|
|
124
|
+
console.log("[useBlockEditor] Updating children. Count:", newProps.children.length);
|
|
125
|
+
}
|
|
128
126
|
executeMutation(() => {
|
|
129
127
|
const loc = findBlockLocation(initialBlocks.value, id);
|
|
130
|
-
if (!loc)
|
|
128
|
+
if (!loc) {
|
|
129
|
+
console.warn("[useBlockEditor] Block not found for update:", id);
|
|
130
|
+
return;
|
|
131
|
+
}
|
|
131
132
|
const oldBlock = loc.parentArray[loc.index];
|
|
132
133
|
if (!oldBlock) return;
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
...newProps
|
|
136
|
-
};
|
|
137
|
-
const newBlock = {
|
|
134
|
+
Object.assign(oldBlock.props, newProps);
|
|
135
|
+
console.log("[useBlockEditor] Block props updated in place:", {
|
|
138
136
|
id: oldBlock.id,
|
|
139
|
-
// Explicitly carry over the required BaseBlock properties
|
|
140
137
|
type: oldBlock.type,
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
};
|
|
144
|
-
loc.parentArray.splice(loc.index, 1, newBlock);
|
|
138
|
+
childrenCount: oldBlock.props.children?.length
|
|
139
|
+
});
|
|
145
140
|
});
|
|
146
141
|
};
|
|
147
142
|
const removeBlock = (id) => {
|
|
@@ -194,6 +189,49 @@ export function useBlockEditor(initialBlocks, { maxHistorySize = 100, onMutation
|
|
|
194
189
|
committedBlocks.value = committedSnapshot;
|
|
195
190
|
return committedSnapshot;
|
|
196
191
|
};
|
|
192
|
+
const relocateBlock = (blockId, targetContainerId, targetIndex) => {
|
|
193
|
+
console.log("[useBlockEditor] relocateBlock called:", { blockId, targetContainerId, targetIndex });
|
|
194
|
+
executeMutation(() => {
|
|
195
|
+
const sourceLoc = findBlockLocation(initialBlocks.value, blockId);
|
|
196
|
+
if (!sourceLoc) {
|
|
197
|
+
console.warn("[useBlockEditor] Block not found for relocation:", blockId);
|
|
198
|
+
return;
|
|
199
|
+
}
|
|
200
|
+
const block = sourceLoc.parentArray[sourceLoc.index];
|
|
201
|
+
if (!block) {
|
|
202
|
+
console.warn("[useBlockEditor] Block is undefined at location");
|
|
203
|
+
return;
|
|
204
|
+
}
|
|
205
|
+
sourceLoc.parentArray.splice(sourceLoc.index, 1);
|
|
206
|
+
console.log("[useBlockEditor] Block removed from source, now inserting at target");
|
|
207
|
+
let targetArray;
|
|
208
|
+
if (targetContainerId === null) {
|
|
209
|
+
targetArray = initialBlocks.value;
|
|
210
|
+
} else {
|
|
211
|
+
const targetLoc = findBlockLocation(initialBlocks.value, targetContainerId);
|
|
212
|
+
if (!targetLoc) {
|
|
213
|
+
console.warn("[useBlockEditor] Target container not found:", targetContainerId);
|
|
214
|
+
sourceLoc.parentArray.splice(sourceLoc.index, 0, block);
|
|
215
|
+
return;
|
|
216
|
+
}
|
|
217
|
+
const targetBlock = targetLoc.parentArray[targetLoc.index];
|
|
218
|
+
if (!targetBlock || !("children" in targetBlock.props)) {
|
|
219
|
+
console.warn("[useBlockEditor] Target block does not have children prop");
|
|
220
|
+
sourceLoc.parentArray.splice(sourceLoc.index, 0, block);
|
|
221
|
+
return;
|
|
222
|
+
}
|
|
223
|
+
targetArray = targetBlock.props.children;
|
|
224
|
+
}
|
|
225
|
+
const safeIndex = Math.max(0, Math.min(targetIndex, targetArray.length));
|
|
226
|
+
targetArray.splice(safeIndex, 0, block);
|
|
227
|
+
console.log("[useBlockEditor] Block relocated successfully:", {
|
|
228
|
+
blockId,
|
|
229
|
+
targetContainerId,
|
|
230
|
+
targetIndex: safeIndex,
|
|
231
|
+
newTargetLength: targetArray.length
|
|
232
|
+
});
|
|
233
|
+
});
|
|
234
|
+
};
|
|
197
235
|
return {
|
|
198
236
|
// Mutations
|
|
199
237
|
updateBlockProps,
|
|
@@ -201,6 +239,7 @@ export function useBlockEditor(initialBlocks, { maxHistorySize = 100, onMutation
|
|
|
201
239
|
moveBlock,
|
|
202
240
|
duplicateBlock,
|
|
203
241
|
insertBlock,
|
|
242
|
+
relocateBlock,
|
|
204
243
|
// History
|
|
205
244
|
undo,
|
|
206
245
|
redo,
|
|
@@ -40,9 +40,22 @@ export function usePageEditor(page, maxHistorySize = 100) {
|
|
|
40
40
|
const save = () => {
|
|
41
41
|
return JSON.parse(JSON.stringify(page.value));
|
|
42
42
|
};
|
|
43
|
+
let isPaused = false;
|
|
44
|
+
const pauseHistory = () => {
|
|
45
|
+
console.log("[usePageEditor] History paused");
|
|
46
|
+
isPaused = true;
|
|
47
|
+
};
|
|
48
|
+
const resumeHistory = () => {
|
|
49
|
+
console.log("[usePageEditor] History resumed");
|
|
50
|
+
isPaused = false;
|
|
51
|
+
};
|
|
43
52
|
watch(
|
|
44
53
|
[() => page.value.properties, () => page.value.title, () => page.value.blocks],
|
|
45
54
|
() => {
|
|
55
|
+
if (isPaused) {
|
|
56
|
+
console.log("[usePageEditor] Skipping auto-snapshot - history is paused");
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
46
59
|
captureSnapshot();
|
|
47
60
|
},
|
|
48
61
|
{ deep: true }
|
|
@@ -59,6 +72,8 @@ export function usePageEditor(page, maxHistorySize = 100) {
|
|
|
59
72
|
canRedo,
|
|
60
73
|
save,
|
|
61
74
|
captureSnapshot,
|
|
62
|
-
resetHistory
|
|
75
|
+
resetHistory,
|
|
76
|
+
pauseHistory,
|
|
77
|
+
resumeHistory
|
|
63
78
|
};
|
|
64
79
|
}
|
|
@@ -40,9 +40,22 @@ export function usePageEditor(page, maxHistorySize = 100) {
|
|
|
40
40
|
const save = () => {
|
|
41
41
|
return JSON.parse(JSON.stringify(page.value));
|
|
42
42
|
};
|
|
43
|
+
let isPaused = false;
|
|
44
|
+
const pauseHistory = () => {
|
|
45
|
+
console.log("[usePageEditor] History paused");
|
|
46
|
+
isPaused = true;
|
|
47
|
+
};
|
|
48
|
+
const resumeHistory = () => {
|
|
49
|
+
console.log("[usePageEditor] History resumed");
|
|
50
|
+
isPaused = false;
|
|
51
|
+
};
|
|
43
52
|
watch(
|
|
44
53
|
[() => page.value.properties, () => page.value.title, () => page.value.blocks],
|
|
45
54
|
() => {
|
|
55
|
+
if (isPaused) {
|
|
56
|
+
console.log("[usePageEditor] Skipping auto-snapshot - history is paused");
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
46
59
|
captureSnapshot();
|
|
47
60
|
},
|
|
48
61
|
{ deep: true }
|
|
@@ -59,6 +72,8 @@ export function usePageEditor(page, maxHistorySize = 100) {
|
|
|
59
72
|
canRedo,
|
|
60
73
|
save,
|
|
61
74
|
captureSnapshot,
|
|
62
|
-
resetHistory
|
|
75
|
+
resetHistory,
|
|
76
|
+
pauseHistory,
|
|
77
|
+
resumeHistory
|
|
63
78
|
};
|
|
64
79
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "rimelight-components",
|
|
3
|
-
"version": "2.1.
|
|
3
|
+
"version": "2.1.95",
|
|
4
4
|
"description": "A component library by Rimelight Entertainment.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"nuxt",
|
|
@@ -74,7 +74,8 @@
|
|
|
74
74
|
"defu": "^6.1.4",
|
|
75
75
|
"tailwind-merge": "^3.4.0",
|
|
76
76
|
"tailwind-variants": "^3.2.2",
|
|
77
|
-
"uuid": "^13.0.0"
|
|
77
|
+
"uuid": "^13.0.0",
|
|
78
|
+
"vuedraggable": "^4.1.0"
|
|
78
79
|
},
|
|
79
80
|
"devDependencies": {
|
|
80
81
|
"@commitlint/cli": "^20.4.1",
|