@neatui/vue 2.4.0 → 2.5.1

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@neatui/vue",
3
- "version": "2.4.0",
3
+ "version": "2.5.1",
4
4
  "description": "basic component ui",
5
5
  "main": "./src/index.ts",
6
6
  "license": "MIT",
@@ -13,6 +13,7 @@
13
13
  },
14
14
  "devDependencies": {
15
15
  "@rollup/plugin-typescript": "^11.1.6",
16
+ "@types/sortablejs": "^1.15.8",
16
17
  "postcss-scss": "^4.0.9",
17
18
  "rollup-plugin-scss": "^4.0.0",
18
19
  "rollup-plugin-terser": "^7.0.2",
@@ -36,8 +37,8 @@
36
37
  "rollup": "^4.18.0",
37
38
  "rollup-plugin-postcss": "^4.0.2",
38
39
  "rollup-plugin-vue": "^6.0.0",
40
+ "sortablejs": "^1.15.6",
39
41
  "swiper": "^11.0.4",
40
- "vue-cropper": "^0.6.4",
41
- "vuedraggable": "^4.1.0"
42
+ "vue-cropper": "^0.6.4"
42
43
  }
43
44
  }
@@ -1,84 +1,106 @@
1
1
  <template>
2
- <ul>
3
- <li
4
- v-for="(item, idx) in list || []"
5
- :key="idx"
6
- class="pr drag-page-move n-sm"
7
- draggable="true"
8
- @dragstart.self="fMoveSta($event, list, idx)"
9
- @dragend.self="fMoveEnd($event, list, idx)"
10
- @dragenter.self="fMoveInt($event, list, idx)"
11
- @dragover.prevent="fMoveIng($event)"
12
- @dragleave="fMoveOut($event)"
13
- >
2
+ <ul ref="listRef" class="drag-list">
3
+ <li v-for="(item, idx) in props.lists" :key="item.id ?? item.field ?? idx" class="pr drag-page-move">
14
4
  <slot :item="item" :idx="idx">{{ item.label }}</slot>
15
5
  </li>
16
6
  </ul>
17
7
  </template>
18
8
 
19
9
  <script setup lang="ts">
20
- import { reactive, PropType } from 'vue';
10
+ import { ref, PropType, onMounted, onBeforeUnmount, nextTick, watch } from 'vue';
11
+ import Sortable, { SortableEvent } from 'sortablejs';
12
+
21
13
  const props = defineProps({
22
- list: {
14
+ lists: {
23
15
  type: Array as PropType<any[]>,
24
16
  default: () => []
25
17
  }
26
18
  });
27
- const state: any = reactive({});
19
+ const emit = defineEmits(['update:lists']);
28
20
 
29
- // 按下
30
- const fMoveSta = (e: any, arr: any, idx: any) => {
31
- state.__page_moveing = 1;
32
- state.__page_moveStaNode = { e, arr, idx };
33
- };
34
- // 移动
35
- const fMoveIng = (e: any) => {
36
- if (state.__page_moveing) {
37
- const _h = e?.target?.getBoundingClientRect()?.height || 0;
38
- const _v = _h / 2 > 0 ? _h / 2 : 0;
39
- state.__page_moveEndNodeIsNext = e?.layerY > _v ? 1 : 0;
40
- console.log(40, e, _v, e?.layerY > _v ? 'next' : 'prev');
41
- e?.target?.setAttribute('data-ins', e?.layerY > _v ? 'next' : 'prev');
42
- }
43
- };
44
- // 移入
45
- const fMoveInt = (e: any, arr: any, idx: any, page: any = '') => {
46
- if (state.__page_moveing) {
47
- state.__page_moveEndNode = { e, arr, idx, page };
48
- }
49
- };
50
- // 移出
51
- const fMoveOut = (e: any) => {
52
- if (state.__page_moveing) {
53
- e?.target?.removeAttribute('data-ins');
54
- }
55
- };
56
- // 松开
57
- const fMoveEnd = (_e: any, arr: any, i2: any) => {
58
- if (state.__page_moveing) {
59
- if (state.__page_moveEndNode) {
60
- const [item] = arr.splice(i2, 1);
61
- let idx = state.__page_moveEndNode?.idx || 0;
62
- if (state.__page_moveEndNodeIsNext && i2 >= idx) {
63
- idx = idx + 1;
64
- }
65
- if (!state.__page_moveEndNodeIsNext && i2 < idx) {
66
- idx = idx - 1;
67
- }
68
- state.__page_moveEndNode?.arr?.splice(idx, 0, item);
69
- fMoveOut(state.__page_moveEndNode?.e);
21
+ const listRef = ref<HTMLElement | null>(null);
22
+ let sortable: Sortable | null = null;
23
+
24
+ // 添加调试日志
25
+ watch(
26
+ () => props.lists,
27
+ (newVal, oldVal) => {
28
+ console.log('IDraggable props.lists changed:', {
29
+ newLength: newVal?.length,
30
+ oldLength: oldVal?.length,
31
+ newVal: newVal?.map((item) => item.label || item.field),
32
+ oldVal: oldVal?.map((item) => item.label || item.field)
33
+ });
34
+ },
35
+ { deep: true }
36
+ );
37
+
38
+ onMounted(() => {
39
+ nextTick(() => {
40
+ if (listRef.value) {
41
+ sortable = Sortable.create(listRef.value, {
42
+ animation: 200,
43
+ ghostClass: 'drag-ghost',
44
+ chosenClass: 'drag-chosen',
45
+ dragClass: 'drag-dragging',
46
+ onEnd(evt: SortableEvent) {
47
+ console.log('Sortable onEnd:', { oldIndex: evt.oldIndex, newIndex: evt.newIndex });
48
+
49
+ if (evt.oldIndex !== undefined && evt.newIndex !== undefined && evt.oldIndex !== evt.newIndex) {
50
+ // 创建新的数组顺序
51
+ const newList = [...props.lists];
52
+ const moved = newList.splice(evt.oldIndex, 1)[0];
53
+ newList.splice(evt.newIndex, 0, moved);
54
+
55
+ console.log(
56
+ 'Emitting new list:',
57
+ newList.map((item) => item.label || item.field)
58
+ );
59
+
60
+ // 通知父组件更新数据
61
+ emit('update:lists', newList);
62
+ }
63
+ }
64
+ });
70
65
  }
71
- state.__page_moveing = 0;
66
+ });
67
+ });
68
+
69
+ onBeforeUnmount(() => {
70
+ if (sortable) {
71
+ sortable.destroy();
72
+ sortable = null;
72
73
  }
73
- };
74
+ });
74
75
  </script>
76
+
75
77
  <style lang="scss">
78
+ .drag-list {
79
+ list-style: none;
80
+ padding: 0;
81
+ margin: 0;
82
+ }
76
83
  .drag-page-move {
77
- &[data-ins='prev'] {
78
- box-shadow: inset 0 1px 0 0 #000;
79
- }
80
- &[data-ins='next'] {
81
- box-shadow: inset 0 -1px 0 0 #000;
84
+ cursor: move;
85
+ transition: background-color 0.2s ease;
86
+
87
+ &:hover {
88
+ background: rgba(0, 0, 0, 0.02);
82
89
  }
83
90
  }
91
+ .drag-ghost {
92
+ opacity: 0.4;
93
+ background: rgba(0, 0, 0, 0.05);
94
+ border: 2px dashed #ddd;
95
+ }
96
+ .drag-chosen {
97
+ background: rgba(24, 144, 255, 0.08);
98
+ }
99
+ .drag-dragging {
100
+ opacity: 0.8;
101
+ background: #fff;
102
+ box-shadow: 0 2px 12px rgba(0, 0, 0, 0.15);
103
+ border-radius: 4px;
104
+ z-index: 1000;
105
+ }
84
106
  </style>
@@ -3,24 +3,24 @@
3
3
  <slot>
4
4
  <button ui-btn="@a s case :border"><i class="icon icon-dropdown"></i></button>
5
5
  </slot>
6
- </div>
7
- <Teleport to="#ifollow" v-if="$slots.tips">
8
- <div
9
- ref="tip"
10
- :class="tipClass"
11
- :style="`position: fixed; pointer-events: none; ${tipStyle}`"
12
- ui-tips="@a"
13
- :ui-tips-view="state.show ? 1 : 0"
14
- @mouseover="hovershow"
15
- @mouseout="hoverhide"
16
- @click="clickhide"
17
- >
18
- <div ref="box" :ui-tips-box="state.pos" :class="tipBoxClass" :style="tipBoxStyle" @mousedown="downdom">
19
- <slot name="tips"></slot>
20
- <div v-if="arrow" ui-tips-arrow="" v-bind="arrow"></div>
6
+ <Teleport to="#ifollow" v-if="$slots.tips">
7
+ <div
8
+ ref="tip"
9
+ :class="tipClass"
10
+ :style="`position: fixed; pointer-events: none; ${tipStyle}`"
11
+ ui-tips="@a"
12
+ :ui-tips-view="state.show ? 1 : 0"
13
+ @mouseover="hovershow"
14
+ @mouseout="hoverhide"
15
+ @click="clickhide"
16
+ >
17
+ <div ref="box" :ui-tips-box="state.pos" :class="tipBoxClass" :style="tipBoxStyle" @mousedown="downdom">
18
+ <slot name="tips"></slot>
19
+ <div v-if="arrow" ui-tips-arrow="" v-bind="arrow"></div>
20
+ </div>
21
21
  </div>
22
- </div>
23
- </Teleport>
22
+ </Teleport>
23
+ </div>
24
24
  </template>
25
25
  <script setup lang="ts">
26
26
  import { reactive, ref, onMounted, onUnmounted, watch } from 'vue';
@@ -1,13 +1,13 @@
1
1
  <template>
2
2
  <div ui-flex="row" class="mc-upload">
3
3
  <template v-if="files && files.length > 0">
4
- <draggable :list="files" @update="update" :force-fallback="false" item-key="name" chosen-class="chosen" animation="200" class="mc-upload-img">
5
- <template #item="{ element, index }">
4
+ <IDraggable v-model:lists="files" @update:lists="update" class="mc-upload-img">
5
+ <template #default="{ item: element, idx: index }">
6
6
  <div class="mc-upload-img-item">
7
7
  <Image :src="element" :files="files" :initialSlide="index" v-bind="$attrs" @delImg="delImg" />
8
8
  </div>
9
9
  </template>
10
- </draggable>
10
+ </IDraggable>
11
11
  </template>
12
12
  <template v-if="(!multiple && files && files.length === 0) || (multiple && (!limit || (limit && files && files.length < limit)))">
13
13
  <slot>
@@ -33,7 +33,7 @@
33
33
  <script setup lang="ts">
34
34
  import { ref, watch } from 'vue';
35
35
  import { Image, PhotoEditor } from '../display';
36
- import draggable from 'vuedraggable';
36
+ import IDraggable from '../basic/IDraggable.vue';
37
37
  import Compressor from 'compressorjs';
38
38
  import { Layer, LayerById } from '../basic';
39
39
  import { isArray } from '@fekit/utils';
@@ -0,0 +1,318 @@
1
+ <template>
2
+ <div id="layer-loader-root" :path="path" :class="`${!path ? '' : 'pr nl-ms'}`" :ui-lines="path ? line : null">
3
+ <template v-for="(item, idx) in data" :key="idx">
4
+ <div
5
+ ui-flex="row xm"
6
+ class="fekit-layer-loader-item ux-hover nx-ss r-ss pr z1"
7
+ :data-move="item._move"
8
+ :class="`${store.active === paths(idx) ? (store.error ? 'bg-risk+o-ss co-risk' : 'bg-main+o-ss co-main fekit-layer-node-active') : ''}${item?.attrs?.hide ? ' o-mm' : ''}`"
9
+ @mousedown="fMoveSta($event, data, idx, paths(idx))"
10
+ @mousemove="fMoveIng($event, item, paths(idx), false, item.child?.length && !item.__folding)"
11
+ @mouseout="fMoveOut($event, paths(idx))"
12
+ @mouseup="fMoveEnd($event, data, item, idx, paths(idx))"
13
+ >
14
+ <div class="hover:co-main" :ui-arrow="`${item.child ? '1' : '0'}`" :ui-folding="item.__folding" @click="item.__folding = item.child && !item.__folding"></div>
15
+ <div :id="`LID${path.replace(/\./g, '')}-${idx}`" :path="paths(idx)" ui-flex="row lt" class="flex-block ny-ss" @click="store.active = paths(idx)">
16
+ <slot name="prefix" :item="item" :path="paths(idx)">
17
+ <i :class="`ml-ss mr-xs o-ms icon icon-model-${!path ? 'label' : item.model || (item.child ? 'area' : 'null')}`"></i>
18
+ </slot>
19
+ <slot name="item" :item="item" :path="paths(idx)">
20
+ <span class="ux-none" ui-omit="1">
21
+ {{ (item.model === 'text' || (!item.model && !item.child) ? item.value : null) || item.label || word(label(item.model)) || '‐‐' }}{{ item.__folding ? ' ⋯' : '' }}
22
+ </span>
23
+ </slot>
24
+ <slot name="suffix" :item="item" :path="paths(idx)"></slot>
25
+ </div>
26
+ <slot name="tools" :data="data" :item="item" :path="paths(idx)">
27
+ <div ui-flex="row rm" class="layer-loader-tool parent-hover:show fs-xs" :data-model="item.model">
28
+ <div ui-tips="@a co:well ux:hover">
29
+ <button ui-btn="@a none s :square">
30
+ <i class="icon icon-add"></i>
31
+ </button>
32
+ <div ui-tips-box="bl">
33
+ <div class="n-sm nowrap fs-ss">
34
+ <ul class="nx-sm-sub ny-ss-sub">
35
+ <li class="r-sm ux-hover" @click="fAddArea(item, data, path, idx)">用容器包裹</li>
36
+ <li class="b-solid bk-line bb-xs n-no my-ss" v-if="isBoxNode(item.model)"></li>
37
+ <li class="r-sm ux-hover" v-if="isBoxNode(item.model)" @click="fAddNode(item, data, path, idx)">添加到内部</li>
38
+ <li class="b-solid bk-line bb-xs n-no my-ss"></li>
39
+ <li class="r-sm ux-hover" @click="fAddNode(item, data, path, idx, 'prev')">添加到前面</li>
40
+ <li class="r-sm ux-hover" @click="fAddNode(item, data, path, idx, 'next')">添加到后面</li>
41
+ <li class="b-solid bk-line bb-xs n-no my-ss"></li>
42
+ <li class="r-sm ux-hover" @click="fAddNode(item, data, path, idx, 'prev', 1)">复制到前面</li>
43
+ <li class="r-sm ux-hover" @click="fAddNode(item, data, path, idx, 'next', 1)">复制到后面</li>
44
+ </ul>
45
+ </div>
46
+ </div>
47
+ </div>
48
+ <button ui-btn="@a none s :square" @click="fDelNode(item, data, idx)"><i class="icon icon-delete"></i></button>
49
+ </div>
50
+ <button ui-btn="@a none s :square" class="layer-loader-tool fs-xs" :class="item?.attrs?.hide ? '' : 'parent-hover:show'" @click="fhideNode(item)">
51
+ <i class="icon" :class="item?.attrs?.hide ? 'icon-hide' : 'icon-view'"></i>
52
+ </button>
53
+ </slot>
54
+ </div>
55
+ <LayerLoader v-if="item.child && !item.__folding" :data="item.child" :path="paths(idx)" :class="`${item?.attrs?.hide ? ' o-mm' : ''}`">
56
+ <template #prefix="{ item = {}, path = '' }: any = {}"><slot name="prefix" :item="item" :path="path"></slot></template>
57
+ <template #item="{ item = {}, path = '' }: any = {}"><slot name="item" :item="item" :path="path"></slot></template>
58
+ <template #suffix="{ item = {}, path = '' }: any = {}"><slot name="suffix" :item="item" :path="path"></slot></template>
59
+ <template #tools="{ item = {}, path = '' }: any = {}"><slot name="tools" :item="item" :path="path"></slot></template>
60
+ </LayerLoader>
61
+ <div
62
+ v-if="item.child?.length && !item.__folding"
63
+ ui-flex="row lm"
64
+ class="pr z1"
65
+ style="height: 0.5em"
66
+ :data-label="(item.model === 'text' || (!item.model && !item.child) ? item.value : null) || item.label || item.model || '‐‐'"
67
+ :data-move="item._move"
68
+ @mousemove="fMoveIng($event, item, paths(idx), true)"
69
+ @mouseout="fMoveOut($event, paths(idx))"
70
+ @mouseup="fMoveEnd($event, data, item, idx, paths(idx))"
71
+ ></div>
72
+ </template>
73
+ </div>
74
+ </template>
75
+ <script setup lang="ts">
76
+ import { nextTick, reactive, ref, watch, onMounted } from 'vue';
77
+ import LayerLoader from './LayerLoader.vue';
78
+ import { useBaseStore, useWorksStore, storeToRefs } from '@/store';
79
+ import { deepcopy } from '@fekit/utils';
80
+ import scrollto from '@fekit/scrollto';
81
+
82
+ // 事件定义
83
+ const store: any = useWorksStore();
84
+ const base: any = useBaseStore();
85
+ const { word } = base;
86
+
87
+ // 类型定义
88
+ interface Props {
89
+ data?: Array<any>;
90
+ path?: string;
91
+ line?: boolean;
92
+ }
93
+ // 外部入参
94
+ const props: any = withDefaults(defineProps<Props>(), {
95
+ data: () => [],
96
+ path: '',
97
+ line: true,
98
+ });
99
+
100
+ // 内部状态
101
+ const state: any = reactive({});
102
+ const tools: any = ref(null);
103
+
104
+ const ph = ref(0);
105
+ onMounted(() => {
106
+ const side = document.getElementById('side-layerloader');
107
+ ph.value = side?.clientHeight || 0;
108
+ });
109
+
110
+ // 计算路径
111
+ const paths = (idx: number) => {
112
+ return props.path ? `${props.path}-${idx}` : `${idx}`;
113
+ };
114
+
115
+ function unfoldActivePath(data: any, activePath: any) {
116
+ if (!activePath) return;
117
+ const indices = activePath.split('-').map(Number);
118
+ let cur = data;
119
+ for (let i = 0; i < indices.length; i++) {
120
+ const idx = indices[i];
121
+ if (!cur || !cur[idx]) break;
122
+ cur[idx].__folding = false;
123
+ cur = cur[idx].child;
124
+ }
125
+ }
126
+
127
+ if (!props.path) {
128
+ watch(
129
+ () => store.active,
130
+ (newActive) => {
131
+ unfoldActivePath(props.data, newActive);
132
+
133
+ nextTick(() => {
134
+ const el = document.getElementById(`LID${newActive.replace(/\./g, '')}`);
135
+ if (el && !store.isMouseInLayer) {
136
+ scrollto({
137
+ el: '#side-layerloader',
138
+ to: {
139
+ y: el,
140
+ },
141
+ offset: {
142
+ y: -(ph.value / 2.5),
143
+ },
144
+ time: 600,
145
+ });
146
+ }
147
+ });
148
+ },
149
+ );
150
+ }
151
+
152
+ // 查找枚举
153
+ const label = (item: any) => {
154
+ return base.enums?.sys_models?.find((e: any) => e.value === item)?.label || item;
155
+ };
156
+
157
+ // 是容器节点
158
+ const isBoxNode = (model: string) => {
159
+ return !['data', 'text', 'icon', 'code', 'draw'].includes(model);
160
+ };
161
+
162
+ // 添加节点
163
+ const fAddNode = async (item: any = {}, _data: any = [], _path: any = '', _idx: number = 0, pos: any = null, copy: any = 0) => {
164
+ if (pos) {
165
+ if (pos === 'prev') {
166
+ // 加到前面
167
+ _data.splice(
168
+ _idx,
169
+ 0,
170
+ copy
171
+ ? deepcopy(item)
172
+ : {
173
+ label: '',
174
+ model: '',
175
+ value: '',
176
+ attrs: {},
177
+ },
178
+ );
179
+ store.active = `${_path}-${_idx}`;
180
+ } else if (pos === 'next') {
181
+ // 加到后面
182
+ _data.splice(
183
+ _idx + 1,
184
+ 0,
185
+ copy
186
+ ? deepcopy(item)
187
+ : {
188
+ label: '',
189
+ model: '',
190
+ value: '',
191
+ attrs: {},
192
+ },
193
+ );
194
+ store.active = `${_path}-${_idx + 1}`;
195
+ }
196
+ } else {
197
+ if (!item.child) {
198
+ item.child = [];
199
+ }
200
+ await item.child.push({
201
+ label: '',
202
+ model: '',
203
+ value: '',
204
+ attrs: {},
205
+ });
206
+ store.active = `${_path}-${_idx}-${item.child.length - 1}`;
207
+ }
208
+ };
209
+
210
+ // 包裹容器
211
+ const fAddArea = (item: any = {}, data: any = [], path: any = '', idx: number = 0, pos: any = null, copy: any = 0) => {
212
+ // 1. 构造新的 area 节点
213
+ const areaNode = {
214
+ model: 'area',
215
+ attrs: {},
216
+ child: [item],
217
+ param: {},
218
+ };
219
+ // 2. 替换 data 中的当前节点
220
+ data.splice(idx, 1, areaNode);
221
+ // 3. 设置 active 到新节点
222
+ store.active = path ? `${path}-${idx}` : `${idx}`;
223
+ };
224
+
225
+ // 删除节点
226
+ const fDelNode = (_item: any = {}, data: any = [], idx: number = 0) => {
227
+ if (data.length > 0) {
228
+ data.splice(idx, 1);
229
+ }
230
+ };
231
+ const fhideNode = (_item: any = {}) => {
232
+ _item.attrs.hide = _item.attrs.hide ? 0 : 1;
233
+ };
234
+
235
+ // 是否同祖
236
+ function inform(from: string, data: string) {
237
+ const _form = from.split('.');
238
+ const _data = data.split('.');
239
+ return _form.every((part, index) => part === _data[index]);
240
+ }
241
+
242
+ // 按住
243
+ const fMoveSta = (ev: any, data: any, idx: number, paths: any) => {
244
+ if (paths.length > 1) {
245
+ store.layer.moveing = true;
246
+ store.layer.from = { data, idx, dom: ev?.currentTarget, y: ev.clientY, paths };
247
+ }
248
+ };
249
+ const fMoveIng = (ev: any, item: any, paths: any, isend: boolean = false, ischildandnofold: boolean = false) => {
250
+ if (!store.layer.moveing || paths.length <= 1) return;
251
+ const dom = ev?.currentTarget;
252
+ if (!dom || dom === store.layer.from.dom) return;
253
+ const rect = dom.getBoundingClientRect();
254
+ const thirdHeight = rect.height / 3 || 1;
255
+ const offsetY = ev?.layerY ?? ev?.offsetY ?? 0;
256
+ let mode = 'prev';
257
+ if (offsetY > thirdHeight * 2 || isend) {
258
+ mode = ischildandnofold ? 'inset' : 'next';
259
+ } else if (offsetY > thirdHeight && offsetY < thirdHeight * 2) {
260
+ if (isBoxNode(item.model)) {
261
+ mode = 'inset';
262
+ }
263
+ }
264
+ store.layer.correct = mode;
265
+ dom.setAttribute('data-ins', mode);
266
+ };
267
+ // 移出
268
+ const fMoveOut = (ev: any, paths: any) => {
269
+ if (store.layer.moveing && paths.length > 1) {
270
+ ev?.currentTarget?.removeAttribute('data-ins');
271
+ }
272
+ };
273
+ // 松开
274
+ const fMoveEnd = (ev: any, data: any, item: any, idx: number, paths: any) => {
275
+ console.log(207, data, item);
276
+ if (store.layer.moveing && paths.length > 1 && !inform(store.layer.from.paths, paths)) {
277
+ const from = store.layer.from;
278
+ if (from.data && from.dom !== ev?.currentTarget) {
279
+ const isAdjacent =
280
+ (store.layer.correct === 'prev' && from.dom?.nextElementSibling === ev?.currentTarget) ||
281
+ (store.layer.correct === 'next' && from.dom?.previousElementSibling === ev?.currentTarget) ||
282
+ (store.layer.correct === 'inset' && (from.dom?.contains(ev?.currentTarget) || ev?.currentTarget?.contains(from.dom)));
283
+
284
+ if (!isAdjacent) {
285
+ const [node] = from.data.splice(from.idx, 1);
286
+ let newPath = paths;
287
+
288
+ // Adjust target index if it's after the removed item in the same array
289
+ let targetIdx = idx;
290
+ if (from.data === data && from.idx < idx) {
291
+ targetIdx -= 1;
292
+ }
293
+
294
+ if (store.layer.correct === 'prev') {
295
+ data.splice(targetIdx, 0, node);
296
+ newPath = props.path ? `${props.path}-${targetIdx}` : `${targetIdx}`;
297
+ } else if (store.layer.correct === 'next') {
298
+ const insertIndex = targetIdx + 1;
299
+ data.splice(insertIndex, 0, node);
300
+ newPath = props.path ? `${props.path}-${insertIndex}` : `${insertIndex}`;
301
+ } else if (store.layer.correct === 'inset') {
302
+ if (!item.child) item.child = [];
303
+ const targetIndex = item.child.length;
304
+ item.child.push(node);
305
+ newPath = paths + '-' + targetIndex;
306
+ }
307
+
308
+ requestAnimationFrame(() => {
309
+ store.active = newPath;
310
+ });
311
+ }
312
+ }
313
+ }
314
+
315
+ ev?.currentTarget?.removeAttribute('data-ins');
316
+ store.layer.moveing = false;
317
+ };
318
+ </script>
@@ -0,0 +1,2 @@
1
+ import LayerLoader from './LayerLoader.vue';
2
+ export default LayerLoader;
@@ -0,0 +1,77 @@
1
+ .fekit-layer-loader-item {
2
+ user-select: none;
3
+ line-height: 1.2;
4
+ }
5
+
6
+ // 箭头
7
+ [ui-arrow] {
8
+ position: relative;
9
+ width: 1em;
10
+ height: 1em;
11
+ left: 0.1em;
12
+
13
+ // &[ui-arrow~='0'] {
14
+ // &::before {
15
+ // position: absolute;
16
+ // display: inline-block;
17
+ // content: '';
18
+ // width: 0.5em;
19
+ // height: 0.5em;
20
+ // border: 1px solid currentColor;
21
+ // top: 0.25em;
22
+ // left: 0.3em;
23
+ // border-radius: 50%;
24
+ // }
25
+ // }
26
+ &[ui-arrow~='0'] {
27
+ height: 1px;
28
+ border-bottom: 1px dotted var(--co-case);
29
+ position: relative;
30
+ left: -5px;
31
+ }
32
+
33
+ &[ui-arrow~='1'] {
34
+ &::before {
35
+ position: absolute;
36
+ display: inline-block;
37
+ content: '';
38
+ width: 0;
39
+ height: 0;
40
+ border-width: 0.35em 0 0.35em 0.35em;
41
+ border-style: solid;
42
+ border-color: transparent;
43
+ border-left-color: transparent;
44
+ border-left-color: currentColor;
45
+ top: 0.2em;
46
+ left: 0.35em;
47
+ transform: rotate(90deg);
48
+ border-radius: 25%;
49
+ }
50
+ }
51
+
52
+ &[ui-folding~='true']::before {
53
+ transform: rotate(0deg);
54
+ }
55
+ }
56
+
57
+ // 线条
58
+ [ui-lines] {
59
+ position: relative;
60
+ &::before {
61
+ position: absolute;
62
+ content: '';
63
+ display: block;
64
+ width: 5px;
65
+ height: 100%;
66
+ left: 0.85em;
67
+
68
+ border-left: 1px dotted var(--co-case);
69
+ border-bottom: 1px dotted var(--co-case);
70
+ }
71
+ }
72
+
73
+ .fekit-layer-node-active {
74
+ .layer-loader-tool {
75
+ opacity: 1;
76
+ }
77
+ }