Skip to content

refactor: model #1717

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 3 commits into
base: dev
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion packages/devui-vue/devui/modal/__tests__/modal.spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import DModal from '../src/modal';
import DModalHeader from '../src/components/header';
import DModalFooter from '../src/components/footer';
import DIcon from '../../icon/src/icon';
import { useNamespace } from '../../shared/hooks/use-namespace';
import { useNamespace } from '@devui/shared';
import { wait } from '../../shared/utils/';

const ns = useNamespace('modal', true);
Expand Down
2 changes: 1 addition & 1 deletion packages/devui-vue/devui/modal/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ export * from './src/modal-types';
export { Modal, ModalHeader, ModalBody, ModalFooter };

export default {
title: 'Modal 弹窗',
title: 'Modal 模态框',
category: '反馈',
status: '100%',
install(app: App): void {
Expand Down
2 changes: 1 addition & 1 deletion packages/devui-vue/devui/modal/src/components/body.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { defineComponent } from 'vue';
import { useNamespace } from '../../../shared/hooks/use-namespace';
import { useNamespace } from '@devui/shared';

export default defineComponent({
name: 'DModalBody',
Expand Down
2 changes: 1 addition & 1 deletion packages/devui-vue/devui/modal/src/components/footer.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { defineComponent } from 'vue';
import { useNamespace } from '../../../shared/hooks/use-namespace';
import { useNamespace } from '@devui/shared';

export default defineComponent({
name: 'DModalFooter',
Expand Down
2 changes: 1 addition & 1 deletion packages/devui-vue/devui/modal/src/components/header.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { defineComponent } from 'vue';
import { useNamespace } from '../../../shared/hooks/use-namespace';
import { useNamespace } from '@devui/shared';

export default defineComponent({
name: 'DModalHeader',
Expand Down
19 changes: 19 additions & 0 deletions packages/devui-vue/devui/modal/src/components/modal-icons.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
export function CloseIcon(): JSX.Element {
return (
<svg width="16px" height="16px" viewBox="0 0 16 16" version="1.1" xmlns="http://www.w3.org/2000/svg">
<g stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<path
d={`M14.6887175,1.25368865 C15.0770801,1.64205125 15.0121881,2.34244569 14.544513,2.81012074 L9.383,7.971 L14.544513,13.1322854
C14.9787827,13.5665551 15.0657548,14.2014859 14.7650189,14.6009195 L14.6887175,14.6887175 C14.3003549,15.0770801
13.5999604,15.0121881 13.1322854,14.544513 L13.1322854,14.544513 L7.971,9.383 L2.81012075,14.544513 C2.3424457,15.0121881
1.64205125,15.0770801 1.25368865,14.6887175 C0.865326051,14.3003549 0.930218063,13.5999605 1.39789313,13.1322854
L6.558,7.971 L1.39789311,2.81012074 C0.963623424,2.37585105 0.876651354,1.74092026 1.17738727,1.34148668
L1.25368865,1.25368865 C1.64205125,0.865326051 2.34244569,0.930218063 2.81012074,1.39789311 L2.81012074,1.39789311
L7.971,6.558 L13.1322854,1.39789311 C13.5999605,0.930218063 14.3003549,0.865326051 14.6887175,1.25368865 Z`}
fill="#8A8E99" fill-rule="nonzero"></path>
</g>
</svg>


)
}
67 changes: 42 additions & 25 deletions packages/devui-vue/devui/modal/src/composables/use-modal.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,32 @@
import { onMounted, onUnmounted, watch } from 'vue';
import { onUnmounted, watch, ref } from 'vue';
import { ModalProps, EmitEventFn, UseModal } from '../modal-types';
import { lockScroll } from '../../../shared/utils/lock-scroll';
import { useNamespace, focusStack } from '@devui/shared'
import type { FoucusLayer } from '@devui/shared'
import { ZINDEX } from '../const'

export function useModal(props: ModalProps, emit: EmitEventFn): UseModal {
let lockScrollCb: () => void;
const ns = useNamespace('modal')
const overlayZIndex = ref('')
const modalZIndex = ref('')
const paused = ref(false)
const layer: FoucusLayer = {
pause() {
paused.value = true
},
resume() {
paused.value = false
}
}

const removeAdditions = () => {
lockScrollCb?.()
props.escapable && window.removeEventListener('keyup', onKeydown)
setTimeout(() => {
focusStack.remove(layer)
});
}
function close(): void {
emit('update:modelValue', false);
emit('close');
Expand All @@ -12,44 +36,37 @@ export function useModal(props: ModalProps, emit: EmitEventFn): UseModal {
}

function onKeydown(event: KeyboardEvent) {
if (event.code === 'Escape') {
if (event.code === 'Escape' && !paused.value) {
execClose();
}
}

onMounted(() => {
if (props.escapable) {
window.addEventListener('keydown', onKeydown);
}
});

onUnmounted(() => {
if (props.escapable) {
window.addEventListener('keydown', onKeydown);
}
});

return { execClose };
}
function calculateZIndex() {
const modalDomsLength = document.querySelectorAll(`.${ns.b()}`).length
overlayZIndex.value = `calc(var(--devui-z-index-modal, 1050) + ${(modalDomsLength - 1) * ZINDEX} - 1)`
modalZIndex.value = `calc(var(--devui-z-index-modal, 1050) + ${(modalDomsLength - 1) * ZINDEX})`
}

export function useModalRender(props: ModalProps): void {
let lockScrollCb: () => void;
const removeBodyAdditions = () => {
lockScrollCb?.();
};
watch(
() => props.modelValue,
(val) => {
(val, oldVal) => {
if (val) {
calculateZIndex()
props.lockScroll && (lockScrollCb = lockScroll());
props.escapable && window.addEventListener('keyup', onKeydown)
focusStack.push(layer)
} else {
removeBodyAdditions();
oldVal !== undefined && removeAdditions()
}
},
{
immediate: true,
flush: 'post'
}
);

onUnmounted(removeBodyAdditions);
}
onUnmounted(removeAdditions);

return { execClose, overlayZIndex, modalZIndex };

}
1 change: 1 addition & 0 deletions packages/devui-vue/devui/modal/src/const.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export const ZINDEX = 1;
4 changes: 3 additions & 1 deletion packages/devui-vue/devui/modal/src/modal-types.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { PropType, ExtractPropTypes } from 'vue';
import type { PropType, ExtractPropTypes, Ref } from 'vue';

export type ModalType = 'success' | 'failed' | 'warning' | 'info' | '';

Expand Down Expand Up @@ -62,6 +62,8 @@ export type EmitEventFn = (event: EmitName, result?: boolean) => void;

export interface UseModal {
execClose: () => void;
overlayZIndex: Ref<string>;
modalZIndex: Ref<string>;
}

export type ModalProps = ExtractPropTypes<typeof modalProps>;
42 changes: 15 additions & 27 deletions packages/devui-vue/devui/modal/src/modal.scss
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
top: 50%;
left: 50%;
width: 300px;
border-radius: $devui-border-radius;
border-radius: $devui-border-radius-card;
border: none;
opacity: 1;
transform: translate(-50%, -50%);
Expand All @@ -17,27 +17,10 @@

.btn-close {
position: absolute;
right: 16px;
top: 20px;
width: 20px;
height: 20px;
line-height: 20px;
text-align: center;
cursor: pointer;
background: transparent;
border: 0;
right: 20px;
top: 18px;
-webkit-appearance: none;

&:hover {
color: $devui-icon-fill-active-hover;
background-color: $devui-list-item-hover-bg;
}

& i {
position: absolute;
right: 0;
top: 0;
}
z-index: calc(var(--devui-z-index-model, 1050) + 1);
}

.type-content {
Expand Down Expand Up @@ -70,12 +53,17 @@

.#{$devui-prefix}-modal__header {
width: 100%;
height: 56px;
height: 46px;
line-height: 26px;
padding: 20px 20px 0;
font-size: $devui-font-size-card-title;
font-size: $devui-font-size-modal-title;
font-weight: bold;
letter-spacing: 0;
box-sizing: border-box;
border: none;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
user-select: none;

.header-alert-icon {
display: inline-block;
Expand All @@ -97,10 +85,10 @@
width: 100%;
border-top: none;
text-align: center;
padding: 0 32px 24px;
padding: 0 20px 20px 20px;
box-sizing: border-box;

& > * {
&>* {
margin: 0 4px;
}
}
Expand All @@ -119,4 +107,4 @@
opacity: 0.2;
top: calc(50% - 24px);
}
}
}
23 changes: 9 additions & 14 deletions packages/devui-vue/devui/modal/src/modal.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
import { computed, defineComponent, nextTick, ref, Teleport, toRefs, Transition, watch } from 'vue';
import { modalProps, ModalProps, ModalType } from './modal-types';
import { Icon } from '../../icon';
import { Icon } from '@devui/shared/components/icon';
import { FixedOverlay } from '../../overlay';
import { useModal, useModalRender } from './composables/use-modal';
import { useModal } from './composables/use-modal';
import { useDraggable } from './composables/use-draggable';
import DModalHeader from './components/header';
import DModalBody from './components/body';
import { useNamespace } from '../../shared/hooks/use-namespace';
import { CloseIcon } from './components/modal-icons';
import { useNamespace } from '@devui/shared';
import './modal.scss';

interface TypeList {
Expand All @@ -24,8 +25,7 @@ export default defineComponent({
setup(props: ModalProps, { slots, attrs, emit }) {
const ns = useNamespace('modal');
const { modelValue, title, showClose, showOverlay, appendToBody, closeOnClickOverlay, keepLast } = toRefs(props);
const { execClose } = useModal(props, emit);
useModalRender(props);
const { execClose, overlayZIndex, modalZIndex } = useModal(props, emit);
const dialogRef = ref<HTMLElement>();
const headerRef = ref<HTMLElement>();
const draggable = computed(() => props.draggable);
Expand Down Expand Up @@ -90,11 +90,11 @@ export default defineComponent({
{showOverlay.value && (
<FixedOverlay
modelValue={modelValue.value}
{...{ 'onUpdate:modelValue': execClose }}
onUpdate:modelValue={execClose}
class={ns.e('overlay')}
lock-scroll={false}
close-on-click-overlay={closeOnClickOverlay.value}
style={{ zIndex: 'calc(var(--devui-z-index-modal, 1050) - 1)' }}
style={{ zIndex: overlayZIndex.value }}
/>
)}
<Transition name={props.showAnimation ? ns.m('wipe') : ''}>
Expand All @@ -103,13 +103,8 @@ export default defineComponent({
ref={dialogRef}
class={ns.b()}
{...attrs}
onClick={(e: Event) => e.stopPropagation()}
style={{ transform: modalPosition.value }}>
{showClose.value && (
<div onClick={execClose} class="btn-close">
<Icon name="close" size="20px"></Icon>
</div>
)}
style={{ transform: modalPosition.value, zIndex: modalZIndex.value }}>
{showClose.value && <Icon class="btn-close" operable component={CloseIcon()} onClick={execClose} ></Icon>}
{props.type ? (
renderType()
) : (
Expand Down