-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
16 changed files
with
1,232 additions
and
4 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
133 changes: 133 additions & 0 deletions
133
packages/vlossom/src/components/vs-drawer/VsDrawer.scss
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,133 @@ | ||
$sizes: xs, sm, md, lg, xl; | ||
|
||
.vs-drawer { | ||
.dimmed { | ||
position: fixed; | ||
top: 0; | ||
left: 0; | ||
width: 100%; | ||
height: 100%; | ||
z-index: var(--vs-drawer-z-index); | ||
background-color: var(--vs-dimmed-backgroundColor); | ||
|
||
&.has-container { | ||
position: absolute; | ||
} | ||
} | ||
|
||
.vs-drawer-content { | ||
position: fixed; | ||
width: 100%; | ||
height: 100%; | ||
z-index: var(--vs-drawer-z-index); | ||
background-color: var(--vs-drawer-backgroundColor, var(--vs-plain-backgroundColor)); | ||
color: var(--vs-drawer-color, var(--vs-font-color)); | ||
display: flex; | ||
flex-direction: column; | ||
|
||
&.has-container { | ||
position: absolute; | ||
} | ||
|
||
.drawer-body { | ||
overflow-y: auto; | ||
flex: 1; | ||
|
||
&.hide-scroll { | ||
overflow: scroll; | ||
-ms-overflow-style: none; /* IE and Edge */ | ||
scrollbar-width: none; /* Firefox */ | ||
&::-webkit-scrollbar { | ||
display: none; | ||
} | ||
} | ||
} | ||
|
||
// placement | ||
&.top { | ||
top: 0; | ||
left: 0; | ||
} | ||
|
||
&.right { | ||
top: 0; | ||
right: 0; | ||
} | ||
|
||
&.bottom { | ||
bottom: 0; | ||
left: 0; | ||
} | ||
|
||
&.left { | ||
top: 0; | ||
left: 0; | ||
} | ||
|
||
// size | ||
&.left, | ||
&.right { | ||
max-width: var(--vs-drawer-width, var(--vs-drawer-width-sm)); | ||
max-height: var(--vs-drawer-height); | ||
|
||
@each $size in $sizes { | ||
&.#{$size} { | ||
max-width: var(--vs-drawer-width-#{$size}); | ||
} | ||
} | ||
} | ||
|
||
&.top, | ||
&.bottom { | ||
max-width: var(--vs-drawer-width); | ||
max-height: var(--vs-drawer-height, var(--vs-drawer-height-sm)); | ||
|
||
@each $size in $sizes { | ||
&.#{$size} { | ||
max-height: var(--vs-drawer-height-#{$size}); | ||
} | ||
} | ||
} | ||
} | ||
} | ||
|
||
.fade-enter-active, | ||
.fade-leave-active { | ||
transition: all 0.3s; | ||
} | ||
|
||
.fade-enter-form, | ||
.fade-leave-to { | ||
opacity: 0; | ||
} | ||
|
||
.slide-left-enter-active, | ||
.slide-left-leave-active, | ||
.slide-right-enter-active, | ||
.slide-right-leave-active, | ||
.slide-top-enter-active, | ||
.slide-top-leave-active, | ||
.slide-bottom-enter-active, | ||
.slide-bottom-leave-active { | ||
transition: all 0.3s; | ||
} | ||
|
||
.slide-left-enter-from, | ||
.slide-left-leave-to { | ||
transform: translateX(-100%); | ||
} | ||
|
||
.slide-right-enter-from, | ||
.slide-right-leave-to { | ||
transform: translateX(100%); | ||
} | ||
|
||
.slide-bottom-enter-from, | ||
.slide-bottom-leave-to { | ||
transform: translateY(100%); | ||
} | ||
|
||
.slide-top-enter-from, | ||
.slide-top-leave-to { | ||
transform: translateY(-100%); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,153 @@ | ||
<template> | ||
<Teleport to="body" :disabled="hasContainer"> | ||
<div class="vs-drawer"> | ||
<Transition name="fade"> | ||
<div | ||
v-if="isOpen && dimmed" | ||
:class="['dimmed', { 'has-container': hasContainer }]" | ||
aria-hidden="true" | ||
@click.stop="clickDimmed()" | ||
/> | ||
</Transition> | ||
<Transition :name="`slide-${placement}`"> | ||
<vs-focus-trap v-if="isOpen" :focus-lock="dimmed" :initialFocusRef="initialFocusRef"> | ||
<div | ||
:class="[ | ||
'vs-drawer-content', | ||
placement, | ||
hasSpecifiedSize ? '' : size, | ||
{ 'has-container': hasContainer }, | ||
]" | ||
:style="{ ...customProperties, ...sizeProperty }" | ||
role="dialog" | ||
:aria-labelledby="hasHeader ? 'vs-drawer-title' : undefined" | ||
aria-describedby="vs-drawer-body" | ||
:aria-label="hasHeader ? undefined : 'Dialog'" | ||
:aria-modal="dimmed" | ||
> | ||
<header v-if="hasHeader" id="vs-drawer-title" aria-label="Dialog Header"> | ||
<slot name="header" /> | ||
</header> | ||
|
||
<div :class="['drawer-body', { 'hide-scroll': hideScroll }]" id="vs-drawer-body"> | ||
<slot /> | ||
</div> | ||
|
||
<footer v-if="hasFooter" aria-label="Dialog Footer"> | ||
<slot name="footer" /> | ||
</footer> | ||
</div> | ||
</vs-focus-trap> | ||
</Transition> | ||
</div> | ||
</Teleport> | ||
</template> | ||
|
||
<script lang="ts"> | ||
import { defineComponent, ref, toRefs, watch, computed, onMounted, onBeforeUnmount, type PropType } from 'vue'; | ||
import { useCustomStyle } from '@/composables'; | ||
import { VsComponent, Placement, PLACEMENTS, Size, SIZES } from '@/declaration'; | ||
import { VsFocusTrap } from '@/components'; | ||
import type { VsDrawerStyleSet } from './types'; | ||
const name = VsComponent.VsDrawer; | ||
export default defineComponent({ | ||
name, | ||
components: { VsFocusTrap }, | ||
props: { | ||
styleSet: { type: [String, Object] as PropType<string | VsDrawerStyleSet>, default: '' }, | ||
closeOnDimmedClick: { type: Boolean, default: true }, | ||
closeOnEsc: { type: Boolean, default: true }, | ||
dimmed: { type: Boolean, default: true }, | ||
hasContainer: { type: Boolean, default: false }, | ||
hideScroll: { type: Boolean, default: false }, | ||
initialFocusRef: { type: [Object, undefined] as PropType<HTMLElement | null>, default: null }, | ||
placement: { | ||
type: String as PropType<Placement>, | ||
default: 'left', | ||
validator: (val: Placement) => PLACEMENTS.includes(val), | ||
}, | ||
size: { type: String as PropType<Size | string>, default: '' }, | ||
// v-model | ||
modelValue: { type: Boolean, default: false }, | ||
}, | ||
emits: ['update:modelValue'], | ||
setup(props, { emit, slots }) { | ||
const { styleSet, modelValue, closeOnEsc, closeOnDimmedClick, placement, size } = toRefs(props); | ||
const { customProperties } = useCustomStyle<VsDrawerStyleSet>(name, styleSet); | ||
const hasSpecifiedSize = computed(() => size.value && !SIZES.includes(size.value as Size)); | ||
const sizeProperty = computed(() => { | ||
if (hasSpecifiedSize.value) { | ||
if (placement.value === 'top' || placement.value === 'bottom') { | ||
return { '--vs-drawer-height': size.value }; | ||
} | ||
if (placement.value === 'left' || placement.value === 'right') { | ||
return { '--vs-drawer-width': size.value }; | ||
} | ||
} | ||
return {}; | ||
}); | ||
const hasHeader = computed(() => !!slots['header']); | ||
const hasFooter = computed(() => !!slots['footer']); | ||
const isOpen = ref(modelValue.value); | ||
watch(modelValue, (val) => { | ||
isOpen.value = val; | ||
}); | ||
function clickDimmed() { | ||
if (closeOnDimmedClick.value) { | ||
isOpen.value = false; | ||
} | ||
} | ||
function onPressEsc(event: KeyboardEvent) { | ||
if (event.key === 'Escape') { | ||
isOpen.value = false; | ||
} | ||
} | ||
watch(isOpen, (val) => { | ||
if (closeOnEsc.value) { | ||
if (val) { | ||
document.addEventListener('keydown', onPressEsc); | ||
} else { | ||
document.removeEventListener('keydown', onPressEsc); | ||
} | ||
} | ||
emit('update:modelValue', val); | ||
}); | ||
onMounted(() => { | ||
if (isOpen.value && closeOnEsc.value) { | ||
document.addEventListener('keydown', onPressEsc); | ||
} | ||
}); | ||
onBeforeUnmount(() => { | ||
document.removeEventListener('keydown', onPressEsc); | ||
}); | ||
return { | ||
customProperties, | ||
hasSpecifiedSize, | ||
sizeProperty, | ||
isOpen, | ||
clickDimmed, | ||
hasHeader, | ||
hasFooter, | ||
}; | ||
}, | ||
}); | ||
</script> | ||
|
||
<style lang="scss" scoped src="./VsDrawer.scss" /> |
Oops, something went wrong.