@neatui/vue 4.5.0 → 4.6.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/package.json
CHANGED
|
@@ -6,11 +6,14 @@
|
|
|
6
6
|
v-if="state.view"
|
|
7
7
|
:am-view="am"
|
|
8
8
|
:data-key="id"
|
|
9
|
-
:
|
|
9
|
+
:data-recess="state.recess || undefined"
|
|
10
|
+
:data-cover-dark="state.coverDark !== '' ? '' : undefined"
|
|
11
|
+
:style="layerStyle"
|
|
10
12
|
:view="state.view"
|
|
11
13
|
class="fekit-layer"
|
|
12
14
|
>
|
|
13
15
|
<div :ui-flex="`col ${flex}`" :style="wrapStyle" class="fekit-layer-wrap" @animationend="anim" @click="_sys_hide">
|
|
16
|
+
<div v-if="state.coverDark !== ''" class="fekit-layer-cover-dark"></div>
|
|
14
17
|
<slot :param="_tasks[id]?.params"></slot>
|
|
15
18
|
</div>
|
|
16
19
|
</div>
|
|
@@ -18,7 +21,7 @@
|
|
|
18
21
|
</div>
|
|
19
22
|
</template>
|
|
20
23
|
<script lang="ts" setup>
|
|
21
|
-
import { onBeforeUnmount, reactive, watch } from 'vue';
|
|
24
|
+
import { computed, nextTick, onBeforeUnmount, reactive, watch } from 'vue';
|
|
22
25
|
import { env, isFunction } from '@fekit/utils';
|
|
23
26
|
|
|
24
27
|
// 弹层队列
|
|
@@ -60,6 +63,21 @@
|
|
|
60
63
|
const SCROLL_LOCK_STATE = Symbol.for('@neatui/vue.Layer.scrollLock');
|
|
61
64
|
const ESCAPE_STACK = Symbol.for('@neatui/vue.Layer.escapeStack');
|
|
62
65
|
const ESCAPE_LISTENER = Symbol.for('@neatui/vue.Layer.escapeListener');
|
|
66
|
+
const AREA_GROUPS = Symbol.for('@neatui/vue.Layer.areaGroups');
|
|
67
|
+
|
|
68
|
+
type LayerMode = 'cover' | 'cascade' | 'displace' | 'replace' | 'queue';
|
|
69
|
+
|
|
70
|
+
type AreaGroup = {
|
|
71
|
+
dark: {
|
|
72
|
+
afterHide?: () => void;
|
|
73
|
+
el: HTMLElement | null;
|
|
74
|
+
listening: boolean;
|
|
75
|
+
owners: Set<string>;
|
|
76
|
+
view: number;
|
|
77
|
+
};
|
|
78
|
+
queue: Array<{ id: string; kind: 'open' | 'show'; params: any; then: any }>;
|
|
79
|
+
stack: string[];
|
|
80
|
+
};
|
|
63
81
|
|
|
64
82
|
const getScrollLockState = (): ScrollLockState => {
|
|
65
83
|
if (!_tasks[SCROLL_LOCK_STATE]) {
|
|
@@ -119,6 +137,199 @@
|
|
|
119
137
|
});
|
|
120
138
|
};
|
|
121
139
|
|
|
140
|
+
const getAreaGroups = (): Record<string, AreaGroup> => {
|
|
141
|
+
if (!_tasks[AREA_GROUPS]) {
|
|
142
|
+
Object.defineProperty(_tasks, AREA_GROUPS, {
|
|
143
|
+
configurable: true,
|
|
144
|
+
value: {},
|
|
145
|
+
});
|
|
146
|
+
}
|
|
147
|
+
return _tasks[AREA_GROUPS];
|
|
148
|
+
};
|
|
149
|
+
|
|
150
|
+
const getAreaGroup = (area: string): AreaGroup => {
|
|
151
|
+
const groups = getAreaGroups();
|
|
152
|
+
if (!groups[area]) {
|
|
153
|
+
groups[area] = {
|
|
154
|
+
dark: {
|
|
155
|
+
el: null,
|
|
156
|
+
listening: false,
|
|
157
|
+
owners: new Set<string>(),
|
|
158
|
+
view: 0,
|
|
159
|
+
},
|
|
160
|
+
queue: [],
|
|
161
|
+
stack: [],
|
|
162
|
+
};
|
|
163
|
+
}
|
|
164
|
+
return groups[area];
|
|
165
|
+
};
|
|
166
|
+
|
|
167
|
+
const resolveDarkOpacity = (value: string | number | undefined) => {
|
|
168
|
+
return `${value ?? ''}` === '' ? '0.75' : `${value}`;
|
|
169
|
+
};
|
|
170
|
+
|
|
171
|
+
const participatesInGroup = (dark: string | number | undefined) => `${dark ?? ''}` !== '0';
|
|
172
|
+
const DEFAULT_COVER_DARK = 0.32;
|
|
173
|
+
|
|
174
|
+
const resolveCoverDark = (mode: LayerMode, hasPrev: boolean, coverDark: unknown) => {
|
|
175
|
+
if (mode !== 'cover' || !hasPrev) return '';
|
|
176
|
+
if (coverDark === false || `${coverDark}` === '0') return '';
|
|
177
|
+
if (coverDark === undefined || coverDark === true || `${coverDark}` === '') return DEFAULT_COVER_DARK;
|
|
178
|
+
return coverDark as string | number;
|
|
179
|
+
};
|
|
180
|
+
|
|
181
|
+
const isBlockingView = (view: number) => view === 1 || view === 2 || view === 3;
|
|
182
|
+
|
|
183
|
+
const occupiesGlobalDark = (task: any) => {
|
|
184
|
+
if (!task?.participates) return false;
|
|
185
|
+
if (task.view === 2 || task.view === 3 || task.view === 4) return true;
|
|
186
|
+
return task.view === 1 && !!task.parkAfterHide;
|
|
187
|
+
};
|
|
188
|
+
|
|
189
|
+
const setGlobalDarkView = (group: AreaGroup, view: number) => {
|
|
190
|
+
group.dark.view = view;
|
|
191
|
+
if (group.dark.el) group.dark.el.setAttribute('view', `${view}`);
|
|
192
|
+
};
|
|
193
|
+
|
|
194
|
+
const ensureGlobalDarkEl = (area: string, group: AreaGroup) => {
|
|
195
|
+
if (!env.client) return null;
|
|
196
|
+
if (group.dark.el?.isConnected) return group.dark.el;
|
|
197
|
+
group.dark.el = null;
|
|
198
|
+
group.dark.listening = false;
|
|
199
|
+
const container = document.querySelector(area);
|
|
200
|
+
if (!container) return null;
|
|
201
|
+
let el = container.querySelector(':scope > .fekit-layer-dark') as HTMLElement | null;
|
|
202
|
+
if (!el) {
|
|
203
|
+
el = document.createElement('div');
|
|
204
|
+
el.className = 'fekit-layer-dark';
|
|
205
|
+
el.setAttribute('view', '0');
|
|
206
|
+
container.insertBefore(el, container.firstChild);
|
|
207
|
+
}
|
|
208
|
+
group.dark.el = el;
|
|
209
|
+
el.addEventListener('animationend', (ev) => {
|
|
210
|
+
if (ev.target !== el) return;
|
|
211
|
+
if (group.dark.view === 2) setGlobalDarkView(group, 3);
|
|
212
|
+
if (group.dark.view === 1) {
|
|
213
|
+
setGlobalDarkView(group, 0);
|
|
214
|
+
const afterHide = group.dark.afterHide;
|
|
215
|
+
group.dark.afterHide = undefined;
|
|
216
|
+
afterHide?.();
|
|
217
|
+
}
|
|
218
|
+
});
|
|
219
|
+
group.dark.listening = true;
|
|
220
|
+
return el;
|
|
221
|
+
};
|
|
222
|
+
|
|
223
|
+
const syncGlobalDarkOpacity = (area: string, group: AreaGroup) => {
|
|
224
|
+
let opacity = '0.75';
|
|
225
|
+
for (let index = group.stack.length - 1; index >= 0; index -= 1) {
|
|
226
|
+
const task = _tasks[group.stack[index]];
|
|
227
|
+
if (occupiesGlobalDark(task)) {
|
|
228
|
+
opacity = resolveDarkOpacity(task.dark);
|
|
229
|
+
break;
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
const el = group.dark.owners.size ? ensureGlobalDarkEl(area, group) : group.dark.el;
|
|
233
|
+
if (el) el.style.setProperty('--layer-dark', opacity);
|
|
234
|
+
};
|
|
235
|
+
|
|
236
|
+
const acquireGlobalDark = (area: string, group: AreaGroup, layerId: string, immediate = false) => {
|
|
237
|
+
if (!layerId) return;
|
|
238
|
+
if (group.dark.owners.has(layerId)) {
|
|
239
|
+
syncGlobalDarkOpacity(area, group);
|
|
240
|
+
return;
|
|
241
|
+
}
|
|
242
|
+
group.dark.owners.add(layerId);
|
|
243
|
+
const el = ensureGlobalDarkEl(area, group);
|
|
244
|
+
if (!el) return;
|
|
245
|
+
syncGlobalDarkOpacity(area, group);
|
|
246
|
+
if (group.dark.owners.size > 1) {
|
|
247
|
+
if (group.dark.view === 1) setGlobalDarkView(group, 3);
|
|
248
|
+
else if (group.dark.view === 0) setGlobalDarkView(group, immediate ? 3 : 2);
|
|
249
|
+
return;
|
|
250
|
+
}
|
|
251
|
+
if (immediate) {
|
|
252
|
+
setGlobalDarkView(group, 3);
|
|
253
|
+
return;
|
|
254
|
+
}
|
|
255
|
+
if (group.dark.view === 0) setGlobalDarkView(group, 2);
|
|
256
|
+
else if (group.dark.view === 1) setGlobalDarkView(group, 3);
|
|
257
|
+
};
|
|
258
|
+
|
|
259
|
+
const releaseGlobalDark = (area: string, group: AreaGroup, layerId: string, immediate = false) => {
|
|
260
|
+
if (!layerId || !group.dark.owners.delete(layerId)) {
|
|
261
|
+
syncGlobalDarkOpacity(area, group);
|
|
262
|
+
return;
|
|
263
|
+
}
|
|
264
|
+
syncGlobalDarkOpacity(area, group);
|
|
265
|
+
if (group.dark.owners.size > 0) return;
|
|
266
|
+
if (immediate || !group.dark.el) {
|
|
267
|
+
setGlobalDarkView(group, 0);
|
|
268
|
+
const afterHide = group.dark.afterHide;
|
|
269
|
+
group.dark.afterHide = undefined;
|
|
270
|
+
afterHide?.();
|
|
271
|
+
return;
|
|
272
|
+
}
|
|
273
|
+
if (group.dark.view === 0) return;
|
|
274
|
+
setGlobalDarkView(group, 1);
|
|
275
|
+
};
|
|
276
|
+
|
|
277
|
+
const visibleGroupIds = (group: AreaGroup) =>
|
|
278
|
+
group.stack.filter((layerId) => {
|
|
279
|
+
const view = _tasks[layerId]?.view;
|
|
280
|
+
return view === 2 || view === 3;
|
|
281
|
+
});
|
|
282
|
+
|
|
283
|
+
const groupHasBlocking = (group: AreaGroup, exceptId = '') =>
|
|
284
|
+
group.stack.some((layerId) => layerId !== exceptId && isBlockingView(_tasks[layerId]?.view));
|
|
285
|
+
|
|
286
|
+
const syncStackIndex = (group: AreaGroup) => {
|
|
287
|
+
group.stack.forEach((layerId, index) => {
|
|
288
|
+
_tasks[layerId]?.setStackIndex?.(index);
|
|
289
|
+
});
|
|
290
|
+
};
|
|
291
|
+
|
|
292
|
+
const recomputeRecess = (group: AreaGroup) => {
|
|
293
|
+
const visible = visibleGroupIds(group);
|
|
294
|
+
visible.forEach((layerId, index) => {
|
|
295
|
+
let depth = 0;
|
|
296
|
+
for (let next = index + 1; next < visible.length; next += 1) {
|
|
297
|
+
if (_tasks[visible[next]]?.openMode === 'cascade') depth += 1;
|
|
298
|
+
}
|
|
299
|
+
_tasks[layerId]?.setRecess?.(depth > 2 ? 2 : depth);
|
|
300
|
+
});
|
|
301
|
+
group.stack.forEach((layerId) => {
|
|
302
|
+
if (!visible.includes(layerId)) _tasks[layerId]?.setRecess?.(0);
|
|
303
|
+
});
|
|
304
|
+
};
|
|
305
|
+
|
|
306
|
+
const ensureOnStack = (group: AreaGroup, layerId: string) => {
|
|
307
|
+
const index = group.stack.indexOf(layerId);
|
|
308
|
+
if (index !== -1) group.stack.splice(index, 1);
|
|
309
|
+
group.stack.push(layerId);
|
|
310
|
+
syncStackIndex(group);
|
|
311
|
+
};
|
|
312
|
+
|
|
313
|
+
const removeFromStack = (group: AreaGroup, layerId: string) => {
|
|
314
|
+
const index = group.stack.indexOf(layerId);
|
|
315
|
+
if (index !== -1) group.stack.splice(index, 1);
|
|
316
|
+
syncStackIndex(group);
|
|
317
|
+
};
|
|
318
|
+
|
|
319
|
+
const removeFromQueue = (group: AreaGroup, layerId: string) => {
|
|
320
|
+
group.queue = group.queue.filter((job) => job.id !== layerId);
|
|
321
|
+
};
|
|
322
|
+
|
|
323
|
+
const getVisibleTop = (group: AreaGroup, exceptId = '') => {
|
|
324
|
+
for (let index = group.stack.length - 1; index >= 0; index -= 1) {
|
|
325
|
+
const layerId = group.stack[index];
|
|
326
|
+
if (layerId === exceptId) continue;
|
|
327
|
+
const task = _tasks[layerId];
|
|
328
|
+
if (task && (task.view === 2 || task.view === 3)) return task;
|
|
329
|
+
}
|
|
330
|
+
return undefined;
|
|
331
|
+
};
|
|
332
|
+
|
|
122
333
|
const hasInlineProperty = (style: CSSStyleDeclaration, property: string) => {
|
|
123
334
|
for (let index = 0; index < style.length; index += 1) {
|
|
124
335
|
if (style.item(index) === property) return true;
|
|
@@ -307,25 +518,78 @@
|
|
|
307
518
|
|
|
308
519
|
// 状态管理
|
|
309
520
|
const state = reactive({
|
|
310
|
-
|
|
521
|
+
coverDark: '' as string | number,
|
|
522
|
+
immediate: false,
|
|
523
|
+
openMode: 'cover' as LayerMode,
|
|
311
524
|
params: {},
|
|
525
|
+
parkAfterHide: false,
|
|
526
|
+
recess: 0,
|
|
527
|
+
stackIndex: 0,
|
|
528
|
+
view: 0,
|
|
312
529
|
});
|
|
313
530
|
const scrollLockOwner = {};
|
|
314
531
|
|
|
532
|
+
const layerStyle = computed(() => {
|
|
533
|
+
let style = '';
|
|
534
|
+
if (`${props.dark}` !== '') style += `--layer-dark:${props.dark};`;
|
|
535
|
+
if (`${state.coverDark}` !== '') style += `--layer-cover-dark:${state.coverDark};`;
|
|
536
|
+
if (props.zIndex) style += `z-index:${props.zIndex};`;
|
|
537
|
+
else if (state.stackIndex > 0) style += `z-index:${50 + state.stackIndex};`;
|
|
538
|
+
return style;
|
|
539
|
+
});
|
|
540
|
+
|
|
541
|
+
const syncTaskView = (view: number) => {
|
|
542
|
+
if (!_tasks[props.id]) return;
|
|
543
|
+
_tasks[props.id].view = view;
|
|
544
|
+
_tasks[props.id].openMode = state.openMode;
|
|
545
|
+
_tasks[props.id].parkAfterHide = state.parkAfterHide;
|
|
546
|
+
_tasks[props.id].participates = participatesInGroup(props.dark);
|
|
547
|
+
_tasks[props.id].dark = props.dark;
|
|
548
|
+
};
|
|
549
|
+
|
|
550
|
+
const syncOwnDarkOccupancy = () => {
|
|
551
|
+
if (!env.client || !participatesInGroup(props.dark) || !props.id) return;
|
|
552
|
+
const group = getAreaGroup(props.area);
|
|
553
|
+
const immediate = state.immediate;
|
|
554
|
+
if (
|
|
555
|
+
occupiesGlobalDark({
|
|
556
|
+
dark: props.dark,
|
|
557
|
+
parkAfterHide: state.parkAfterHide,
|
|
558
|
+
participates: true,
|
|
559
|
+
view: state.view,
|
|
560
|
+
})
|
|
561
|
+
) {
|
|
562
|
+
acquireGlobalDark(props.area, group, props.id, immediate);
|
|
563
|
+
} else {
|
|
564
|
+
releaseGlobalDark(props.area, group, props.id, immediate);
|
|
565
|
+
}
|
|
566
|
+
};
|
|
567
|
+
|
|
315
568
|
watch(
|
|
316
569
|
() => state.view,
|
|
317
570
|
(view: any) => {
|
|
318
|
-
|
|
319
|
-
_tasks[props.id].view = view;
|
|
320
|
-
}
|
|
571
|
+
syncTaskView(view);
|
|
321
572
|
if (view === 2 || view === 3) pushEscapeStack(props.id);
|
|
322
573
|
else removeEscapeStack(props.id);
|
|
323
574
|
if (view > 0) acquireScrollLock(scrollLockOwner);
|
|
324
575
|
else releaseScrollLock(scrollLockOwner);
|
|
576
|
+
syncOwnDarkOccupancy();
|
|
577
|
+
state.immediate = false;
|
|
578
|
+
if (participatesInGroup(props.dark) && props.id) {
|
|
579
|
+
nextTick(() => recomputeRecess(getAreaGroup(props.area)));
|
|
580
|
+
}
|
|
325
581
|
},
|
|
326
582
|
{ deep: true, immediate: true },
|
|
327
583
|
);
|
|
328
584
|
|
|
585
|
+
watch(
|
|
586
|
+
() => props.dark,
|
|
587
|
+
() => {
|
|
588
|
+
syncTaskView(state.view);
|
|
589
|
+
syncOwnDarkOccupancy();
|
|
590
|
+
},
|
|
591
|
+
);
|
|
592
|
+
|
|
329
593
|
watch(
|
|
330
594
|
() => props.escClose,
|
|
331
595
|
(escClose) => {
|
|
@@ -350,6 +614,138 @@
|
|
|
350
614
|
none: [],
|
|
351
615
|
};
|
|
352
616
|
|
|
617
|
+
const resolveMode = (params: any): LayerMode => {
|
|
618
|
+
const mode = params?.mode;
|
|
619
|
+
if (mode === 'cascade' || mode === 'displace' || mode === 'replace' || mode === 'queue') return mode;
|
|
620
|
+
return 'cover';
|
|
621
|
+
};
|
|
622
|
+
|
|
623
|
+
const bindOpenCallbacks = (params: any = {}, then = () => {}) => {
|
|
624
|
+
if (params?.on?.show) on.show.push(params.on.show);
|
|
625
|
+
if (params?.on?.hide) on.hide.push(params.on.hide);
|
|
626
|
+
on.show.push(then);
|
|
627
|
+
};
|
|
628
|
+
|
|
629
|
+
const runCallbacks = (key: 'show' | 'hide' | 'none') => {
|
|
630
|
+
on[key].forEach((fun: any) => {
|
|
631
|
+
if (isFunction(fun)) fun();
|
|
632
|
+
});
|
|
633
|
+
on[key].length = 0;
|
|
634
|
+
};
|
|
635
|
+
|
|
636
|
+
const flushQueue = (group: AreaGroup) => {
|
|
637
|
+
if (groupHasBlocking(group) || !group.queue.length) return;
|
|
638
|
+
const job = group.queue.shift();
|
|
639
|
+
if (!job) return;
|
|
640
|
+
const task = _tasks[job.id];
|
|
641
|
+
if (!task) {
|
|
642
|
+
flushQueue(group);
|
|
643
|
+
return;
|
|
644
|
+
}
|
|
645
|
+
const playParams = { ...job.params };
|
|
646
|
+
if (playParams.mode === 'queue') delete playParams.mode;
|
|
647
|
+
if (job.kind === 'open') task.open(playParams, job.then);
|
|
648
|
+
else task.show(playParams, job.then);
|
|
649
|
+
};
|
|
650
|
+
|
|
651
|
+
const scheduleFlushQueue = (group: AreaGroup) => {
|
|
652
|
+
const flush = () => flushQueue(group);
|
|
653
|
+
if (group.dark.view === 1) {
|
|
654
|
+
const prev = group.dark.afterHide;
|
|
655
|
+
group.dark.afterHide = () => {
|
|
656
|
+
prev?.();
|
|
657
|
+
flush();
|
|
658
|
+
};
|
|
659
|
+
return;
|
|
660
|
+
}
|
|
661
|
+
nextTick(flush);
|
|
662
|
+
};
|
|
663
|
+
|
|
664
|
+
const onGroupLayerClosed = (layerId: string) => {
|
|
665
|
+
if (!participatesInGroup(props.dark)) return;
|
|
666
|
+
const group = getAreaGroup(props.area);
|
|
667
|
+
removeFromStack(group, layerId);
|
|
668
|
+
const topId = group.stack[group.stack.length - 1];
|
|
669
|
+
if (topId && _tasks[topId]?.view === 4) _tasks[topId].unpark();
|
|
670
|
+
recomputeRecess(group);
|
|
671
|
+
scheduleFlushQueue(group);
|
|
672
|
+
};
|
|
673
|
+
|
|
674
|
+
const closeReplacedLayers = (mode: LayerMode, params: any, immediate: boolean) => {
|
|
675
|
+
if (mode !== 'replace' || !participatesInGroup(props.dark) || !props.id) return;
|
|
676
|
+
const group = getAreaGroup(props.area);
|
|
677
|
+
const prev = getVisibleTop(group, props.id);
|
|
678
|
+
const targets = params?.replace === 'all' ? group.stack.filter((layerId) => layerId !== props.id) : prev ? [prev.id] : [];
|
|
679
|
+
targets.forEach((layerId) => {
|
|
680
|
+
const task = _tasks[layerId];
|
|
681
|
+
if (!task) return;
|
|
682
|
+
if (immediate) task.none();
|
|
683
|
+
else task.hide();
|
|
684
|
+
});
|
|
685
|
+
};
|
|
686
|
+
|
|
687
|
+
const applyIncomingRelation = (mode: LayerMode, params: any, immediate: boolean) => {
|
|
688
|
+
if (!participatesInGroup(props.dark) || !props.id) {
|
|
689
|
+
state.coverDark = '';
|
|
690
|
+
state.recess = 0;
|
|
691
|
+
return;
|
|
692
|
+
}
|
|
693
|
+
const group = getAreaGroup(props.area);
|
|
694
|
+
const prev = getVisibleTop(group, props.id);
|
|
695
|
+
state.coverDark = resolveCoverDark(mode, !!prev, params?.coverDark);
|
|
696
|
+
state.recess = 0;
|
|
697
|
+
|
|
698
|
+
if (mode === 'displace' && prev) prev.park({ immediate });
|
|
699
|
+
ensureOnStack(group, props.id);
|
|
700
|
+
};
|
|
701
|
+
|
|
702
|
+
const syncGroupPresentation = () => {
|
|
703
|
+
if (!participatesInGroup(props.dark) || !props.id) return;
|
|
704
|
+
recomputeRecess(getAreaGroup(props.area));
|
|
705
|
+
};
|
|
706
|
+
|
|
707
|
+
const tryEnqueue = (kind: 'open' | 'show', params: any, then: any) => {
|
|
708
|
+
if (!participatesInGroup(props.dark) || resolveMode(params) !== 'queue' || !props.id) return false;
|
|
709
|
+
const group = getAreaGroup(props.area);
|
|
710
|
+
if (!groupHasBlocking(group, props.id)) return false;
|
|
711
|
+
removeFromQueue(group, props.id);
|
|
712
|
+
group.queue.push({ id: props.id, kind, params, then });
|
|
713
|
+
return true;
|
|
714
|
+
};
|
|
715
|
+
|
|
716
|
+
const setRecess = (depth: number) => {
|
|
717
|
+
state.recess = depth;
|
|
718
|
+
};
|
|
719
|
+
|
|
720
|
+
const setStackIndex = (index: number) => {
|
|
721
|
+
state.stackIndex = index;
|
|
722
|
+
};
|
|
723
|
+
|
|
724
|
+
const park = (options: any = {}) => {
|
|
725
|
+
if (options.immediate) {
|
|
726
|
+
state.parkAfterHide = false;
|
|
727
|
+
state.immediate = true;
|
|
728
|
+
state.view = 4;
|
|
729
|
+
return;
|
|
730
|
+
}
|
|
731
|
+
if (state.view === 2 || state.view === 3) {
|
|
732
|
+
state.parkAfterHide = true;
|
|
733
|
+
syncTaskView(state.view);
|
|
734
|
+
state.view = 1;
|
|
735
|
+
}
|
|
736
|
+
};
|
|
737
|
+
|
|
738
|
+
const unpark = (options: any = {}) => {
|
|
739
|
+
if (state.view !== 4) return;
|
|
740
|
+
state.parkAfterHide = false;
|
|
741
|
+
if (options.immediate) {
|
|
742
|
+
state.immediate = true;
|
|
743
|
+
state.view = 3;
|
|
744
|
+
return;
|
|
745
|
+
}
|
|
746
|
+
state.view = 2;
|
|
747
|
+
};
|
|
748
|
+
|
|
353
749
|
// 注入参数
|
|
354
750
|
const init = (params: any = {}) => {
|
|
355
751
|
_tasks[id].params = params;
|
|
@@ -364,68 +760,86 @@
|
|
|
364
760
|
|
|
365
761
|
// 显示弹层
|
|
366
762
|
const show = (params: any = {}, then = () => {}) => {
|
|
763
|
+
if (tryEnqueue('show', params, then)) return;
|
|
764
|
+
if (participatesInGroup(props.dark) && props.id) removeFromQueue(getAreaGroup(props.area), props.id);
|
|
765
|
+
bindOpenCallbacks(params, then);
|
|
766
|
+
state.openMode = resolveMode(params);
|
|
767
|
+
applyIncomingRelation(state.openMode, params, false);
|
|
768
|
+
state.parkAfterHide = false;
|
|
367
769
|
state.view = 2;
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
}
|
|
371
|
-
if (params?.on?.hide) {
|
|
372
|
-
on.hide.push(params.on.hide);
|
|
373
|
-
}
|
|
374
|
-
on.show.push(then);
|
|
770
|
+
closeReplacedLayers(state.openMode, params, false);
|
|
771
|
+
syncGroupPresentation();
|
|
375
772
|
};
|
|
376
773
|
|
|
377
774
|
// 隐藏弹层
|
|
378
775
|
const hide = (_params: any = {}, then = () => {}) => {
|
|
379
|
-
if (state.view ===
|
|
776
|
+
if (state.view === 4) {
|
|
777
|
+
on.hide.push(then);
|
|
778
|
+
state.parkAfterHide = false;
|
|
779
|
+
state.immediate = true;
|
|
780
|
+
state.view = 0;
|
|
781
|
+
runCallbacks('hide');
|
|
782
|
+
onGroupLayerClosed(id);
|
|
783
|
+
return;
|
|
784
|
+
}
|
|
785
|
+
if (state.view === 2 || state.view === 3) {
|
|
786
|
+
state.parkAfterHide = false;
|
|
787
|
+
syncTaskView(state.view);
|
|
380
788
|
state.view = 1;
|
|
381
789
|
on.hide.push(then);
|
|
382
790
|
}
|
|
383
791
|
};
|
|
384
792
|
|
|
385
793
|
// 打开弹层(没有动画过程)
|
|
386
|
-
const open = (
|
|
794
|
+
const open = (params: any = {}, then = () => {}) => {
|
|
795
|
+
if (tryEnqueue('open', params, then)) return;
|
|
796
|
+
if (participatesInGroup(props.dark) && props.id) removeFromQueue(getAreaGroup(props.area), props.id);
|
|
797
|
+
bindOpenCallbacks(params, then);
|
|
798
|
+
state.openMode = resolveMode(params);
|
|
799
|
+
applyIncomingRelation(state.openMode, params, true);
|
|
800
|
+
state.parkAfterHide = false;
|
|
801
|
+
state.immediate = true;
|
|
387
802
|
state.view = 3;
|
|
388
|
-
|
|
803
|
+
closeReplacedLayers(state.openMode, params, true);
|
|
804
|
+
syncGroupPresentation();
|
|
805
|
+
runCallbacks('show');
|
|
389
806
|
};
|
|
390
807
|
// 关闭弹层(没有动画过程)
|
|
391
808
|
const none = (_params: any = {}, then = () => {}) => {
|
|
809
|
+
const wasOpen = state.view > 0;
|
|
810
|
+
if (participatesInGroup(props.dark) && props.id) removeFromQueue(getAreaGroup(props.area), props.id);
|
|
811
|
+
state.parkAfterHide = false;
|
|
812
|
+
state.immediate = true;
|
|
392
813
|
state.view = 0;
|
|
393
814
|
on.none.push(then);
|
|
394
815
|
// 立即执行回调,因为没有动画
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
fun();
|
|
398
|
-
}
|
|
399
|
-
});
|
|
400
|
-
on.none.length = 0;
|
|
816
|
+
runCallbacks('none');
|
|
817
|
+
if (wasOpen) onGroupLayerClosed(id);
|
|
401
818
|
};
|
|
402
819
|
|
|
403
820
|
// 点暗层关闭
|
|
404
821
|
const _sys_hide = (ev: any) => {
|
|
405
822
|
if (props.darkClickClose && ev.target.className === 'fekit-layer-wrap' && state.view === 3) {
|
|
406
|
-
|
|
823
|
+
hide();
|
|
407
824
|
}
|
|
408
825
|
};
|
|
409
826
|
|
|
410
827
|
// 监听动画
|
|
411
|
-
const anim = () => {
|
|
828
|
+
const anim = (ev?: AnimationEvent) => {
|
|
829
|
+
if (ev && ev.target !== ev.currentTarget) return;
|
|
412
830
|
if (state.view === 1) {
|
|
831
|
+
if (state.parkAfterHide) {
|
|
832
|
+
state.parkAfterHide = false;
|
|
833
|
+
state.view = 4;
|
|
834
|
+
return;
|
|
835
|
+
}
|
|
413
836
|
state.view = 0;
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
fun();
|
|
417
|
-
}
|
|
418
|
-
});
|
|
419
|
-
on.hide.length = 0; // 清空回调数组
|
|
837
|
+
runCallbacks('hide');
|
|
838
|
+
onGroupLayerClosed(id);
|
|
420
839
|
}
|
|
421
840
|
if (state.view === 2) {
|
|
422
841
|
state.view = 3;
|
|
423
|
-
|
|
424
|
-
if (isFunction(fun)) {
|
|
425
|
-
fun();
|
|
426
|
-
}
|
|
427
|
-
});
|
|
428
|
-
on.show.length = 0; // 清空回调数组
|
|
842
|
+
runCallbacks('show');
|
|
429
843
|
}
|
|
430
844
|
};
|
|
431
845
|
|
|
@@ -435,7 +849,25 @@
|
|
|
435
849
|
console.error('Layer 有重复 id', id);
|
|
436
850
|
}
|
|
437
851
|
if (id) {
|
|
438
|
-
_tasks[id] = {
|
|
852
|
+
_tasks[id] = {
|
|
853
|
+
dark: props.dark,
|
|
854
|
+
darkClickClose: props.darkClickClose,
|
|
855
|
+
escClose: props.escClose,
|
|
856
|
+
hide,
|
|
857
|
+
id,
|
|
858
|
+
init,
|
|
859
|
+
none,
|
|
860
|
+
open,
|
|
861
|
+
openMode: state.openMode,
|
|
862
|
+
park,
|
|
863
|
+
parkAfterHide: state.parkAfterHide,
|
|
864
|
+
participates: participatesInGroup(props.dark),
|
|
865
|
+
setRecess,
|
|
866
|
+
setStackIndex,
|
|
867
|
+
show,
|
|
868
|
+
unpark,
|
|
869
|
+
view: state.view,
|
|
870
|
+
};
|
|
439
871
|
ensureEscapeListener();
|
|
440
872
|
} else {
|
|
441
873
|
console.error('Layer 必须填写全局统一的 id');
|
|
@@ -443,6 +875,17 @@
|
|
|
443
875
|
|
|
444
876
|
// 卸载弹层
|
|
445
877
|
onBeforeUnmount(() => {
|
|
878
|
+
if (participatesInGroup(props.dark) && id) {
|
|
879
|
+
const group = getAreaGroup(props.area);
|
|
880
|
+
removeFromQueue(group, id);
|
|
881
|
+
if (state.view > 0) {
|
|
882
|
+
state.immediate = true;
|
|
883
|
+
state.view = 0;
|
|
884
|
+
onGroupLayerClosed(id);
|
|
885
|
+
} else {
|
|
886
|
+
removeFromStack(group, id);
|
|
887
|
+
}
|
|
888
|
+
}
|
|
446
889
|
removeEscapeStack(id);
|
|
447
890
|
releaseScrollLock(scrollLockOwner);
|
|
448
891
|
delete _tasks[id];
|
|
@@ -453,24 +896,122 @@
|
|
|
453
896
|
@use '@neatui/css' as neatui;
|
|
454
897
|
|
|
455
898
|
// 弹层
|
|
899
|
+
@keyframes am-layer-dark-show {
|
|
900
|
+
0% {
|
|
901
|
+
opacity: 0;
|
|
902
|
+
}
|
|
903
|
+
100% {
|
|
904
|
+
opacity: 1;
|
|
905
|
+
}
|
|
906
|
+
}
|
|
907
|
+
|
|
908
|
+
@keyframes am-layer-dark-hide {
|
|
909
|
+
0% {
|
|
910
|
+
opacity: 1;
|
|
911
|
+
}
|
|
912
|
+
100% {
|
|
913
|
+
opacity: 0;
|
|
914
|
+
}
|
|
915
|
+
}
|
|
916
|
+
|
|
917
|
+
.fekit-layer-dark {
|
|
918
|
+
--layer-dark: 0.75;
|
|
919
|
+
position: fixed;
|
|
920
|
+
inset: 0;
|
|
921
|
+
z-index: 50;
|
|
922
|
+
pointer-events: none;
|
|
923
|
+
background-color: rgba(0, 0, 0, var(--layer-dark));
|
|
924
|
+
opacity: 0;
|
|
925
|
+
transition: background-color 180ms linear;
|
|
926
|
+
|
|
927
|
+
&[view='2'] {
|
|
928
|
+
animation: am-layer-dark-show 320ms cubic-bezier(0.4, 0, 0.2, 1) both;
|
|
929
|
+
}
|
|
930
|
+
|
|
931
|
+
&[view='3'] {
|
|
932
|
+
opacity: 1;
|
|
933
|
+
}
|
|
934
|
+
|
|
935
|
+
&[view='1'] {
|
|
936
|
+
animation: am-layer-dark-hide 260ms cubic-bezier(0.4, 0, 0.2, 1) both;
|
|
937
|
+
}
|
|
938
|
+
|
|
939
|
+
&[view='0'] {
|
|
940
|
+
opacity: 0;
|
|
941
|
+
}
|
|
942
|
+
}
|
|
943
|
+
|
|
456
944
|
.fekit-layer {
|
|
945
|
+
--layer-dark: 0.75;
|
|
946
|
+
--layer-cover-dark: 0.32;
|
|
457
947
|
position: fixed;
|
|
458
948
|
width: 100%;
|
|
459
949
|
height: 100%;
|
|
460
950
|
left: 0;
|
|
461
951
|
top: 0;
|
|
462
952
|
z-index: 50;
|
|
463
|
-
background-color:
|
|
953
|
+
background-color: transparent;
|
|
464
954
|
pointer-events: none;
|
|
465
955
|
|
|
956
|
+
.fekit-layer-cover-dark {
|
|
957
|
+
position: absolute;
|
|
958
|
+
inset: 0;
|
|
959
|
+
z-index: 0;
|
|
960
|
+
background-color: rgba(0, 0, 0, var(--layer-cover-dark));
|
|
961
|
+
opacity: 0;
|
|
962
|
+
pointer-events: none;
|
|
963
|
+
}
|
|
964
|
+
|
|
965
|
+
&[view='2'] .fekit-layer-cover-dark {
|
|
966
|
+
animation: am-layer-dark-show 320ms cubic-bezier(0.4, 0, 0.2, 1) both;
|
|
967
|
+
}
|
|
968
|
+
|
|
969
|
+
&[view='3'] .fekit-layer-cover-dark {
|
|
970
|
+
opacity: 1;
|
|
971
|
+
}
|
|
972
|
+
|
|
973
|
+
&[view='1'] .fekit-layer-cover-dark {
|
|
974
|
+
animation: am-layer-dark-hide 260ms cubic-bezier(0.4, 0, 0.2, 1) both;
|
|
975
|
+
}
|
|
976
|
+
|
|
977
|
+
&[view='4'] {
|
|
978
|
+
pointer-events: none;
|
|
979
|
+
|
|
980
|
+
.fekit-layer-wrap {
|
|
981
|
+
pointer-events: none;
|
|
982
|
+
|
|
983
|
+
& > * {
|
|
984
|
+
opacity: 0;
|
|
985
|
+
visibility: hidden;
|
|
986
|
+
}
|
|
987
|
+
}
|
|
988
|
+
}
|
|
989
|
+
|
|
990
|
+
&[view='3'][data-recess='1'] .fekit-layer-wrap > *:not(.fekit-layer-cover-dark) {
|
|
991
|
+
transform: scale(0.94);
|
|
992
|
+
opacity: 0.88;
|
|
993
|
+
transition:
|
|
994
|
+
transform 280ms cubic-bezier(0.4, 0, 0.2, 1),
|
|
995
|
+
opacity 280ms cubic-bezier(0.4, 0, 0.2, 1);
|
|
996
|
+
}
|
|
997
|
+
|
|
998
|
+
&[view='3'][data-recess='2'] .fekit-layer-wrap > *:not(.fekit-layer-cover-dark) {
|
|
999
|
+
transform: scale(0.88);
|
|
1000
|
+
opacity: 0.76;
|
|
1001
|
+
transition:
|
|
1002
|
+
transform 280ms cubic-bezier(0.4, 0, 0.2, 1),
|
|
1003
|
+
opacity 280ms cubic-bezier(0.4, 0, 0.2, 1);
|
|
1004
|
+
}
|
|
1005
|
+
|
|
466
1006
|
&-wrap {
|
|
467
1007
|
position: relative;
|
|
468
1008
|
width: 100%;
|
|
469
1009
|
height: 100%;
|
|
470
1010
|
pointer-events: auto;
|
|
471
1011
|
|
|
472
|
-
& >
|
|
1012
|
+
& > *:not(.fekit-layer-cover-dark) {
|
|
473
1013
|
position: relative !important;
|
|
1014
|
+
z-index: 1;
|
|
474
1015
|
|
|
475
1016
|
&.com-dialog {
|
|
476
1017
|
max-width: 80%;
|