@neatui/vue 2.17.5 → 3.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.prettierrc +12 -0
- package/README.md +82 -0
- package/package.json +7 -4
- package/src/components/basic/IFollowView.vue +47 -34
- package/src/components/basic/IPickerView.vue +16 -8
- package/src/components/basic/IRouterView.vue +133 -74
- package/src/components/basic/IScrollView.vue +460 -52
- package/src/components/basic/LayerView/Layer.vue +33 -24
- package/src/components/basic/LayerView/index.ts +3 -1
- package/src/components/form/DateView@v3.vue +2 -1
- package/src/components/form/Input@v3.vue +9 -6
- package/src/components/form/TextArea.vue +3 -3
- package/src/components/loader/FormLoader/FormLoader.vue +29 -4
- package/src/components/loader/LayerLoader/LayerLoader.vue +2 -1
- package/src/components/loader/LimitLoader/LimitLoader@v3.vue +3 -3
- package/src/components/loader/TableLoader/TableLoader.vue +3 -3
- package/src/components/loader/index.ts +1 -1
- package/src/components/tools/FormDraftsView.vue +15 -11
- package/src/components/tools/FormVerifyView.vue +4 -3
- package/src/components/tools/MoreTools.vue +4 -3
- package/src/components/tools/Pagination@a.vue +74 -38
- package/src/components/tools/Pagination@b.vue +2 -1
- package/src/store/frame.ts +18 -10
- package/src/utils/theme.ts +3 -0
- package/src/components/basic/follow.ts +0 -133
- package/src/components/loader/FormLoader/FormLoader@v2.vue +0 -422
- package/src/components/loader/FormLoader/NodeLoader.vue +0 -85
- package/src/components/loader/FormLoader@v1/FormLoader.vue +0 -506
- package/src/components/loader/FormLoader@v1/FormRender.vue +0 -302
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<div :am-view="view" :am-mode="mode" class="iroute-view pr full" :view-full="full ? 1 : 0" @animationend="anim">
|
|
2
|
+
<div :am-view="view" :am-mode="mode" :am-animate="transitioning ? 1 : 0" class="iroute-view pr full" :view-full="full ? 1 : 0" @animationend="anim">
|
|
3
3
|
<div :class="listClass" :style="listStyle" am-view-item="list">
|
|
4
4
|
<slot name="list" :mode="mode"></slot>
|
|
5
5
|
</div>
|
|
6
|
-
<div v-if="
|
|
6
|
+
<div v-if="itemEverMounted" ref="itemRef" :class="itemClass" :style="itemStyle" am-view-item="item">
|
|
7
7
|
<div class="iroute-view-dark" @click="cancel"></div>
|
|
8
8
|
<div class="iroute-view-body" :style="mode === 'preview' || mode === 'pop-up' ? '' : 'width: 100%;'">
|
|
9
9
|
<slot name="item" :mode="mode"></slot>
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
</div>
|
|
13
13
|
</template>
|
|
14
14
|
<script setup lang="ts">
|
|
15
|
-
import { deepcopy } from '@fekit/utils';
|
|
15
|
+
import { deepcopy, env } from '@fekit/utils';
|
|
16
16
|
import { ref, watch, provide, reactive } from 'vue';
|
|
17
17
|
import { useRoute, useRouter } from 'vue-router';
|
|
18
18
|
const route = useRoute();
|
|
@@ -21,6 +21,7 @@
|
|
|
21
21
|
interface Props {
|
|
22
22
|
full?: boolean | 0 | 1;
|
|
23
23
|
once?: number;
|
|
24
|
+
animate?: boolean | 0 | 1;
|
|
24
25
|
mode?: 'default' | 'preview' | 'pop-up' | 'window';
|
|
25
26
|
queryName?: string;
|
|
26
27
|
listClass?: string;
|
|
@@ -31,6 +32,7 @@
|
|
|
31
32
|
const props: any = withDefaults(defineProps<Props>(), {
|
|
32
33
|
full: 0,
|
|
33
34
|
once: 0,
|
|
35
|
+
animate: 1,
|
|
34
36
|
mode: 'default',
|
|
35
37
|
queryName: 'id',
|
|
36
38
|
listClass: 'full',
|
|
@@ -39,64 +41,90 @@
|
|
|
39
41
|
itemStyle: '',
|
|
40
42
|
});
|
|
41
43
|
const state: any = reactive({
|
|
42
|
-
first: 1,
|
|
43
44
|
list: null,
|
|
44
45
|
item: null,
|
|
45
46
|
});
|
|
46
47
|
|
|
47
48
|
const evs = (v: any = 'list', p: any = 'item') => {
|
|
48
49
|
return (then: any = () => {}, param: any) => {
|
|
50
|
+
if (!env.client) return;
|
|
51
|
+
// 注册时已在目标视图、且对侧没留数据 → 视为初次挂载噪音,吞掉一次
|
|
52
|
+
// 对侧已经写入 state[v](如 item 退出前调用了 onitem(param))→ 不跳过,正常派发
|
|
53
|
+
let skipInitial = view.value === v && state[v] == null;
|
|
49
54
|
watch(
|
|
50
55
|
() => view.value,
|
|
51
56
|
() => {
|
|
52
|
-
if (view.value
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
}
|
|
57
|
+
if (view.value !== v) return;
|
|
58
|
+
if (skipInitial) {
|
|
59
|
+
skipInitial = false;
|
|
60
|
+
// 初始 list 仍写入 state.item:item 首次进入能拿到 list 的上下文。
|
|
61
|
+
// 初始 item 不写入 state.list:避免 deep-link 仅靠 item slot 挂载
|
|
62
|
+
// 就给 list 留下假的 "edit" 信号、cancel 回 list 触发误刷新。
|
|
63
|
+
if (v === 'list' && param) state[p] = param;
|
|
64
|
+
return;
|
|
61
65
|
}
|
|
66
|
+
if (param) state[p] = param;
|
|
67
|
+
then({ view: view.value, mode: props.mode, param: deepcopy(state[v] || {}) });
|
|
62
68
|
},
|
|
63
|
-
{
|
|
69
|
+
{ immediate: true },
|
|
64
70
|
);
|
|
65
71
|
};
|
|
66
72
|
};
|
|
67
73
|
|
|
74
|
+
const hasItemQuery = () => {
|
|
75
|
+
const value = route.query[props.queryName];
|
|
76
|
+
if (Array.isArray(value)) return value.some((item) => item !== undefined && item !== null && item !== '');
|
|
77
|
+
return value !== undefined && value !== null && value !== '';
|
|
78
|
+
};
|
|
79
|
+
|
|
68
80
|
const init = ref(0);
|
|
69
|
-
const
|
|
81
|
+
const currentHasItem = ref(hasItemQuery());
|
|
82
|
+
const transitioning = ref(false);
|
|
83
|
+
const view = ref(currentHasItem.value ? 'item' : 'list');
|
|
84
|
+
// item slot 只在首次进入 item 视图后才挂载,之后始终保持,保留表单状态等
|
|
85
|
+
// list slot 则始终挂载(模板无 v-if),保留勾选/滚动/筛选
|
|
86
|
+
const itemEverMounted = ref(view.value === 'item' || view.value === 'iteming' || view.value === 'listing');
|
|
87
|
+
watch(
|
|
88
|
+
() => view.value,
|
|
89
|
+
(v) => {
|
|
90
|
+
if (v === 'item' || v === 'iteming' || v === 'listing') itemEverMounted.value = true;
|
|
91
|
+
},
|
|
92
|
+
);
|
|
93
|
+
const showAnimations = ['iroute-show-default', 'iroute-show-preview', 'iroute-show-pop-up', 'iroute-show-window'];
|
|
94
|
+
const hideAnimations = ['iroute-hide-default', 'iroute-hide-preview', 'iroute-hide-pop-up', 'iroute-hide-window'];
|
|
70
95
|
const anim = (e: any) => {
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
e.animationName === 'am-hide-preview' ||
|
|
79
|
-
e.animationName === 'am-hide-pop-up'
|
|
80
|
-
) {
|
|
81
|
-
view.value = route.query[props.queryName] ? 'item' : 'list';
|
|
82
|
-
}
|
|
96
|
+
const isShow = showAnimations.includes(e.animationName);
|
|
97
|
+
const isHide = hideAnimations.includes(e.animationName);
|
|
98
|
+
if (!isShow && !isHide) return;
|
|
99
|
+
|
|
100
|
+
currentHasItem.value = hasItemQuery();
|
|
101
|
+
view.value = currentHasItem.value ? 'item' : 'list';
|
|
102
|
+
if (isShow || props.mode !== 'default') transitioning.value = false;
|
|
83
103
|
};
|
|
84
104
|
|
|
85
105
|
const a = () => {
|
|
106
|
+
const nextHasItem = hasItemQuery();
|
|
86
107
|
if (init.value) {
|
|
87
108
|
if (!props.once) {
|
|
88
|
-
|
|
109
|
+
const shouldAnimate = !!props.animate && nextHasItem !== currentHasItem.value;
|
|
110
|
+
currentHasItem.value = nextHasItem;
|
|
111
|
+
transitioning.value = shouldAnimate;
|
|
112
|
+
view.value = shouldAnimate ? (nextHasItem ? 'iteming' : 'listing') : nextHasItem ? 'item' : 'list';
|
|
89
113
|
}
|
|
90
114
|
} else {
|
|
91
|
-
|
|
115
|
+
currentHasItem.value = nextHasItem;
|
|
116
|
+
transitioning.value = false;
|
|
117
|
+
view.value = nextHasItem ? 'item' : 'list';
|
|
92
118
|
init.value = 1;
|
|
93
119
|
}
|
|
94
120
|
};
|
|
95
121
|
|
|
96
122
|
provide('onlist', evs('list', 'item'));
|
|
97
123
|
provide('onitem', evs('item', 'list'));
|
|
98
|
-
|
|
99
|
-
|
|
124
|
+
if (env.client) {
|
|
125
|
+
watch(() => route.query[props.queryName], a);
|
|
126
|
+
a();
|
|
127
|
+
}
|
|
100
128
|
|
|
101
129
|
// 取消
|
|
102
130
|
const cancel = () => {
|
|
@@ -125,18 +153,15 @@
|
|
|
125
153
|
width: 100%;
|
|
126
154
|
height: 100%;
|
|
127
155
|
& > * {
|
|
128
|
-
pointer-events:
|
|
129
|
-
& > * {
|
|
130
|
-
pointer-events: auto;
|
|
131
|
-
}
|
|
156
|
+
pointer-events: auto;
|
|
132
157
|
}
|
|
133
158
|
}
|
|
134
159
|
|
|
135
160
|
// 默认模式
|
|
136
|
-
|
|
161
|
+
.iroute-view[am-mode~='default'] {
|
|
137
162
|
overflow: hidden;
|
|
138
163
|
|
|
139
|
-
@keyframes
|
|
164
|
+
@keyframes iroute-show-default {
|
|
140
165
|
0% {
|
|
141
166
|
opacity: 0;
|
|
142
167
|
transform: translate3d(1em, 0, 0);
|
|
@@ -146,7 +171,7 @@
|
|
|
146
171
|
transform: translate3d(0, 0, 0);
|
|
147
172
|
}
|
|
148
173
|
}
|
|
149
|
-
@keyframes
|
|
174
|
+
@keyframes iroute-hide-default {
|
|
150
175
|
0% {
|
|
151
176
|
opacity: 1;
|
|
152
177
|
transform: translate3d(0, 0, 0);
|
|
@@ -177,39 +202,47 @@
|
|
|
177
202
|
& > [am-view-item~='list'] {
|
|
178
203
|
flex-direction: column;
|
|
179
204
|
display: flex;
|
|
180
|
-
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
&[am-animate='1'][am-view='list'] {
|
|
208
|
+
& > [am-view-item~='list'] {
|
|
209
|
+
animation: iroute-show-default 0.35s ease both;
|
|
181
210
|
}
|
|
182
211
|
}
|
|
183
212
|
&[am-view='listing'] {
|
|
184
213
|
& > [am-view-item~='item'] {
|
|
185
214
|
flex-direction: column;
|
|
186
215
|
display: flex;
|
|
187
|
-
animation:
|
|
216
|
+
animation: iroute-hide-default 0.3s ease-in-out both;
|
|
188
217
|
}
|
|
189
218
|
}
|
|
190
219
|
&[am-view='item'] {
|
|
191
220
|
& > [am-view-item~='item'] {
|
|
192
221
|
display: flex;
|
|
193
|
-
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
&[am-animate='1'][am-view='item'] {
|
|
225
|
+
& > [am-view-item~='item'] {
|
|
226
|
+
animation: iroute-show-default 0.35s ease both;
|
|
194
227
|
}
|
|
195
228
|
}
|
|
196
229
|
&[am-view='iteming'] {
|
|
197
230
|
& > [am-view-item~='list'] {
|
|
198
231
|
display: flex;
|
|
199
|
-
animation:
|
|
232
|
+
animation: iroute-hide-default 0.3s ease-in-out both;
|
|
200
233
|
}
|
|
201
234
|
}
|
|
202
235
|
}
|
|
203
236
|
|
|
204
|
-
//
|
|
205
|
-
|
|
237
|
+
// 预览模式
|
|
238
|
+
.iroute-view[am-mode~='preview'] {
|
|
206
239
|
overflow: hidden;
|
|
207
240
|
|
|
208
241
|
.iroute-view-body {
|
|
209
242
|
justify-content: end;
|
|
210
243
|
}
|
|
211
244
|
|
|
212
|
-
@keyframes
|
|
245
|
+
@keyframes iroute-show-preview {
|
|
213
246
|
0% {
|
|
214
247
|
opacity: 0;
|
|
215
248
|
transform: translate3d(110%, 0, 0);
|
|
@@ -219,7 +252,7 @@
|
|
|
219
252
|
transform: translate3d(0, 0, 0);
|
|
220
253
|
}
|
|
221
254
|
}
|
|
222
|
-
@keyframes
|
|
255
|
+
@keyframes iroute-hide-preview {
|
|
223
256
|
0% {
|
|
224
257
|
opacity: 1;
|
|
225
258
|
transform: translate3d(0, 0, 0);
|
|
@@ -256,18 +289,27 @@
|
|
|
256
289
|
pointer-events: none;
|
|
257
290
|
}
|
|
258
291
|
}
|
|
259
|
-
|
|
292
|
+
// list 视图:item 即便始终挂载也要隐藏(无 v-if 时需 CSS 兜底)
|
|
293
|
+
&[am-view='list'] {
|
|
294
|
+
& > [am-view-item~='item'] {
|
|
295
|
+
display: none;
|
|
296
|
+
}
|
|
297
|
+
}
|
|
260
298
|
&[am-view='listing'] {
|
|
261
299
|
& > [am-view-item~='item'] {
|
|
262
300
|
display: flex;
|
|
263
|
-
animation:
|
|
301
|
+
animation: iroute-hide-preview 0.5s ease-in-out both;
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
&[am-view='item'] {
|
|
305
|
+
& > [am-view-item~='item'] {
|
|
306
|
+
display: flex;
|
|
264
307
|
}
|
|
265
308
|
}
|
|
266
|
-
&[am-view='item'],
|
|
267
309
|
&[am-view='iteming'] {
|
|
268
310
|
& > [am-view-item~='item'] {
|
|
269
311
|
display: flex;
|
|
270
|
-
animation:
|
|
312
|
+
animation: iroute-show-preview 0.5s ease both;
|
|
271
313
|
}
|
|
272
314
|
}
|
|
273
315
|
|
|
@@ -284,7 +326,7 @@
|
|
|
284
326
|
}
|
|
285
327
|
|
|
286
328
|
// 弹出窗口
|
|
287
|
-
|
|
329
|
+
.iroute-view[am-mode~='pop-up'] {
|
|
288
330
|
overflow: hidden;
|
|
289
331
|
|
|
290
332
|
.iroute-view-body {
|
|
@@ -297,7 +339,7 @@
|
|
|
297
339
|
pointer-events: none;
|
|
298
340
|
}
|
|
299
341
|
|
|
300
|
-
@keyframes
|
|
342
|
+
@keyframes iroute-show-pop-up {
|
|
301
343
|
0% {
|
|
302
344
|
opacity: 0;
|
|
303
345
|
transform: translate3d(0, 0, 0) scale(0.95);
|
|
@@ -307,7 +349,7 @@
|
|
|
307
349
|
transform: translate3d(0, 0, 0);
|
|
308
350
|
}
|
|
309
351
|
}
|
|
310
|
-
@keyframes
|
|
352
|
+
@keyframes iroute-hide-pop-up {
|
|
311
353
|
0% {
|
|
312
354
|
opacity: 1;
|
|
313
355
|
transform: translate3d(0, 0, 0);
|
|
@@ -347,50 +389,56 @@
|
|
|
347
389
|
transition: all 0.35s;
|
|
348
390
|
}
|
|
349
391
|
}
|
|
350
|
-
|
|
392
|
+
// list 视图:item 即便始终挂载也要隐藏(无 v-if 时需 CSS 兜底)
|
|
393
|
+
&[am-view='list'] {
|
|
394
|
+
& > [am-view-item~='item'] {
|
|
395
|
+
display: none;
|
|
396
|
+
}
|
|
397
|
+
}
|
|
351
398
|
&[am-view='listing'] {
|
|
352
399
|
& > [am-view-item~='item'] {
|
|
353
400
|
display: flex;
|
|
354
401
|
opacity: 0;
|
|
355
402
|
& > * {
|
|
356
|
-
animation:
|
|
403
|
+
animation: iroute-hide-pop-up 0.35s ease both;
|
|
357
404
|
}
|
|
358
405
|
}
|
|
359
406
|
}
|
|
360
|
-
&[am-view='item']
|
|
407
|
+
&[am-view='item'] {
|
|
408
|
+
& > [am-view-item~='item'] {
|
|
409
|
+
display: flex;
|
|
410
|
+
opacity: 1;
|
|
411
|
+
}
|
|
412
|
+
}
|
|
361
413
|
&[am-view='iteming'] {
|
|
362
414
|
& > [am-view-item~='item'] {
|
|
363
415
|
display: flex;
|
|
364
416
|
opacity: 1;
|
|
365
417
|
& > * {
|
|
366
|
-
animation:
|
|
418
|
+
animation: iroute-show-pop-up 0.35s ease both;
|
|
367
419
|
}
|
|
368
420
|
}
|
|
369
421
|
}
|
|
370
422
|
}
|
|
371
423
|
|
|
372
|
-
//
|
|
373
|
-
|
|
424
|
+
// 窗口模式:item 撑满整个浏览器窗口的全屏 overlay,行为类似 pop-up 但内容撑满
|
|
425
|
+
.iroute-view[am-mode~='window'] {
|
|
374
426
|
overflow: hidden;
|
|
375
427
|
|
|
376
|
-
@keyframes
|
|
428
|
+
@keyframes iroute-show-window {
|
|
377
429
|
0% {
|
|
378
430
|
opacity: 0;
|
|
379
|
-
transform: translate3d(1em, 0, 0);
|
|
380
431
|
}
|
|
381
432
|
100% {
|
|
382
433
|
opacity: 1;
|
|
383
|
-
transform: translate3d(0, 0, 0);
|
|
384
434
|
}
|
|
385
435
|
}
|
|
386
|
-
@keyframes
|
|
436
|
+
@keyframes iroute-hide-window {
|
|
387
437
|
0% {
|
|
388
438
|
opacity: 1;
|
|
389
|
-
transform: translate3d(0, 0, 0);
|
|
390
439
|
}
|
|
391
440
|
100% {
|
|
392
441
|
opacity: 0;
|
|
393
|
-
transform: translate3d(1em, 0, 0);
|
|
394
442
|
}
|
|
395
443
|
}
|
|
396
444
|
|
|
@@ -409,31 +457,42 @@
|
|
|
409
457
|
&[am-view-item~='row'] {
|
|
410
458
|
flex-direction: row !important;
|
|
411
459
|
}
|
|
460
|
+
|
|
461
|
+
&[am-view-item~='item'] {
|
|
462
|
+
position: fixed;
|
|
463
|
+
top: 0;
|
|
464
|
+
right: 0;
|
|
465
|
+
bottom: 0;
|
|
466
|
+
left: 0;
|
|
467
|
+
z-index: 100;
|
|
468
|
+
pointer-events: none;
|
|
469
|
+
}
|
|
412
470
|
}
|
|
413
471
|
&[am-view='list'] {
|
|
414
|
-
[am-view-item~='list'] {
|
|
472
|
+
& > [am-view-item~='list'] {
|
|
415
473
|
flex-direction: column;
|
|
416
474
|
display: flex;
|
|
417
|
-
animation: am-show-default 0s ease both;
|
|
418
475
|
}
|
|
419
476
|
}
|
|
420
477
|
&[am-view='listing'] {
|
|
421
|
-
[am-view-item~='item'] {
|
|
422
|
-
flex-direction: column;
|
|
478
|
+
& > [am-view-item~='item'] {
|
|
423
479
|
display: flex;
|
|
424
|
-
|
|
480
|
+
& > * {
|
|
481
|
+
animation: iroute-hide-window 0.3s ease both;
|
|
482
|
+
}
|
|
425
483
|
}
|
|
426
484
|
}
|
|
427
485
|
&[am-view='item'] {
|
|
428
|
-
[am-view-item~='item'] {
|
|
486
|
+
& > [am-view-item~='item'] {
|
|
429
487
|
display: flex;
|
|
430
|
-
animation: am-show-default 0s ease both;
|
|
431
488
|
}
|
|
432
489
|
}
|
|
433
490
|
&[am-view='iteming'] {
|
|
434
|
-
[am-view-item~='
|
|
491
|
+
& > [am-view-item~='item'] {
|
|
435
492
|
display: flex;
|
|
436
|
-
|
|
493
|
+
& > * {
|
|
494
|
+
animation: iroute-show-window 0.3s ease both;
|
|
495
|
+
}
|
|
437
496
|
}
|
|
438
497
|
}
|
|
439
498
|
}
|