Skip to content

Commit

Permalink
feat(components): add atom component modal
Browse files Browse the repository at this point in the history
  • Loading branch information
hong-IT-99 authored and toantranmei committed Apr 5, 2024
1 parent e2ca1c4 commit e1b4563
Show file tree
Hide file tree
Showing 6 changed files with 221 additions and 3 deletions.
5 changes: 5 additions & 0 deletions playground/pages/button.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<template>
<div>
button: <mei-button>Button</mei-button>
</div>
</template>
20 changes: 20 additions & 0 deletions playground/pages/modal.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<script setup lang="ts">
const isOpen = ref(false)
</script>

<template>
<div>
<mei-button
label="Open"
@click="isOpen = true"
/>

<mei-modal
v-model="isOpen"
fullscreen
>
aasas
</mei-modal>
</div>
</template>

6 changes: 3 additions & 3 deletions src/runtime/components/atoms/button.vue
Original file line number Diff line number Diff line change
Expand Up @@ -62,8 +62,8 @@ import appConfig from "#build/app.config";
import { button } from "#mei-ui/ui-configs";
const config = mergeConfig<typeof button>(
appConfig.ui.strategy,
appConfig.ui.button,
appConfig.meiUI.strategy,
appConfig.meiUI.button,
button,
);
Expand Down Expand Up @@ -110,7 +110,7 @@ export default defineComponent({
type: String as PropType<ButtonColor>,
default: () => config.default.color,
validator(value: string) {
return [...appConfig.ui.colors, ...Object.keys(config.color)].includes(
return [...appConfig.meiUI.colors, ...Object.keys(config.color)].includes(
value,
);
},
Expand Down
155 changes: 155 additions & 0 deletions src/runtime/components/atoms/modal.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
<template>
<TransitionRoot
:appear="appear"
:show="isOpen"
as="template"
@after-leave="onAfterLeave"
>
<HDialog
:class="ui.wrapper"
v-bind="attrs"
@close="close"
>
<TransitionChild
v-if="overlay"
as="template"
:appear="appear"
v-bind="ui.overlay.transition"
>
<div :class="[ui.overlay.base, ui.overlay.background]" />
</TransitionChild>

<div :class="ui.inner">
<div :class="[ui.container, !fullscreen && ui.padding]">
<TransitionChild
as="template"
:appear="appear"
v-bind="transitionClass"
>
<HDialogPanel
:class="[
ui.base,
ui.background,
ui.ring,
ui.shadow,
fullscreen ? ui.fullscreen : [ui.width, ui.height, ui.rounded, ui.margin],
]"
>
<slot />
</HDialogPanel>
</TransitionChild>
</div>
</div>
</HDialog>
</TransitionRoot>
</template>

<script lang="ts">
import { computed, toRef, defineComponent } from 'vue'
import type { PropType } from 'vue'
import { Dialog as HDialog, DialogPanel as HDialogPanel, TransitionRoot, TransitionChild, provideUseId } from '@headlessui/vue'
import { useMeiUI } from "../../composables/use-mei-ui";
import { mergeConfig } from '../../utils'
import type { Strategy } from '../../types'
// @ts-expect-error
import appConfig from '#build/app.config'
import { modal } from '#mei-ui/ui-configs'
import { useId } from '#imports'
const config = mergeConfig<typeof modal>(appConfig.meiUI.strategy, appConfig.meiUI.modal, modal)
export default defineComponent({
components: {
HDialog,
HDialogPanel,
TransitionRoot,
TransitionChild
},
inheritAttrs: false,
props: {
modelValue: {
type: Boolean,
default: false
},
appear: {
type: Boolean,
default: false
},
overlay: {
type: Boolean,
default: true
},
transition: {
type: Boolean,
default: true
},
preventClose: {
type: Boolean,
default: false
},
fullscreen: {
type: Boolean,
default: false
},
class: {
type: [String, Object, Array] as PropType<any>,
default: () => ''
},
ui: {
type: Object as PropType<Partial<typeof config> & { strategy?: Strategy }>,
default: () => ({})
}
},
emits: ['update:modelValue', 'close', 'close-prevented', 'after-leave'],
setup (props, { emit }) {
const { ui, attrs } = useMeiUI('modal', toRef(props, 'ui'), config, toRef(props, 'class'))
const isOpen = computed({
get () {
return props.modelValue
},
set (value) {
emit('update:modelValue', value)
}
})
const transitionClass = computed(() => {
if (!props.transition) {
return {}
}
return {
...ui.value.transition
}
})
function close (value: boolean) {
if (props.preventClose) {
emit('close-prevented')
return
}
isOpen.value = value
emit('close')
}
const onAfterLeave = () => {
emit('after-leave')
}
provideUseId(() => useId())
return {
// eslint-disable-next-line vue/no-dupe-keys
ui,
attrs,
isOpen,
transitionClass,
onAfterLeave,
close
}
}
})
</script>
1 change: 1 addition & 0 deletions src/runtime/ui-configs/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,4 @@ export { default as tooltip } from "./tooltip";
export { default as kbd } from "./kbd";
export { default as dropdown } from "./dropdown";
export { default as avatar } from "./avatar";
export { default as modal } from "./modal";
37 changes: 37 additions & 0 deletions src/runtime/ui-configs/modal.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
export default {
wrapper: 'relative z-50',
inner: 'fixed inset-0 overflow-y-auto',
container: 'flex min-h-full items-end sm:items-center justify-center text-center',
padding: 'p-4 sm:p-0',
margin: 'sm:my-8',
base: 'relative text-left rtl:text-right flex flex-col',
overlay: {
base: 'fixed inset-0 transition-opacity',
background: 'bg-gray-200/75 dark:bg-gray-800/75',
// Syntax for `<TransitionRoot>` component https://headlessui.com/vue/transition#basic-example
transition: {
enter: 'ease-out duration-300',
enterFrom: 'opacity-0',
enterTo: 'opacity-100',
leave: 'ease-in duration-200',
leaveFrom: 'opacity-100',
leaveTo: 'opacity-0'
}
},
background: 'bg-white dark:bg-gray-900',
ring: '',
rounded: 'rounded-lg',
shadow: 'shadow-xl',
width: 'w-full sm:max-w-lg',
height: '',
fullscreen: 'w-screen h-screen',
// Syntax for `<TransitionRoot>` component https://headlessui.com/vue/transition#basic-example
transition: {
enter: 'ease-out duration-300',
enterFrom: 'opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95',
enterTo: 'opacity-100 translate-y-0 sm:scale-100',
leave: 'ease-in duration-200',
leaveFrom: 'opacity-100 translate-y-0 sm:scale-100',
leaveTo: 'opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95'
}
}

0 comments on commit e1b4563

Please sign in to comment.