Compare commits
1 Commits
test
...
lite/neste
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
677a9c958c |
@@ -1,12 +1,13 @@
|
|||||||
<template>
|
<template>
|
||||||
<Teleport to="body">
|
<Teleport :disabled="isNested" to="body">
|
||||||
<form
|
<component
|
||||||
|
:is="isNested ? 'div' : 'form'"
|
||||||
:class="className"
|
:class="className"
|
||||||
class="ui-modal"
|
class="ui-modal"
|
||||||
v-bind="$attrs"
|
v-bind="$attrs"
|
||||||
@click.self="emit('close')"
|
@click.self="!isNested && emit('close')"
|
||||||
>
|
>
|
||||||
<div class="container">
|
<div :class="{ nested: isNested }" class="container">
|
||||||
<span v-if="onClose" class="close-icon" @click="emit('close')">
|
<span v-if="onClose" class="close-icon" @click="emit('close')">
|
||||||
<UiIcon :icon="faXmark" />
|
<UiIcon :icon="faXmark" />
|
||||||
</span>
|
</span>
|
||||||
@@ -24,22 +25,23 @@
|
|||||||
<div v-if="$slots.default" class="content">
|
<div v-if="$slots.default" class="content">
|
||||||
<slot />
|
<slot />
|
||||||
</div>
|
</div>
|
||||||
<UiButtonGroup :color="color">
|
<UiButtonGroup v-if="!isNested" :color="color">
|
||||||
<slot name="buttons" />
|
<slot name="buttons" />
|
||||||
</UiButtonGroup>
|
</UiButtonGroup>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</component>
|
||||||
</Teleport>
|
</Teleport>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import UiButtonGroup from "@/components/ui/UiButtonGroup.vue";
|
|
||||||
import UiIcon from "@/components/ui/icon/UiIcon.vue";
|
import UiIcon from "@/components/ui/icon/UiIcon.vue";
|
||||||
|
import UiButtonGroup from "@/components/ui/UiButtonGroup.vue";
|
||||||
import UiTitle from "@/components/ui/UiTitle.vue";
|
import UiTitle from "@/components/ui/UiTitle.vue";
|
||||||
|
import { IK_MODAL_NESTED } from "@/types/injection-keys";
|
||||||
import type { IconDefinition } from "@fortawesome/fontawesome-common-types";
|
import type { IconDefinition } from "@fortawesome/fontawesome-common-types";
|
||||||
import { faXmark } from "@fortawesome/free-solid-svg-icons";
|
import { faXmark } from "@fortawesome/free-solid-svg-icons";
|
||||||
import { useMagicKeys, whenever } from "@vueuse/core";
|
import { useMagicKeys, whenever } from "@vueuse/core";
|
||||||
import { computed } from "vue";
|
import { computed, inject, provide } from "vue";
|
||||||
|
|
||||||
const props = withDefaults(
|
const props = withDefaults(
|
||||||
defineProps<{
|
defineProps<{
|
||||||
@@ -54,27 +56,39 @@ const emit = defineEmits<{
|
|||||||
(event: "close"): void;
|
(event: "close"): void;
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
|
const isNested = inject(IK_MODAL_NESTED, false);
|
||||||
|
provide(IK_MODAL_NESTED, true);
|
||||||
|
|
||||||
const { escape } = useMagicKeys();
|
const { escape } = useMagicKeys();
|
||||||
whenever(escape, () => emit("close"));
|
whenever(escape, () => emit("close"));
|
||||||
|
|
||||||
const className = computed(() => {
|
const className = computed(() => {
|
||||||
return [`color-${props.color}`, { "has-icon": props.icon !== undefined }];
|
return [
|
||||||
|
`color-${props.color}`,
|
||||||
|
{
|
||||||
|
"has-icon": props.icon !== undefined,
|
||||||
|
nested: isNested,
|
||||||
|
},
|
||||||
|
];
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="postcss" scoped>
|
<style lang="postcss" scoped>
|
||||||
.ui-modal {
|
.ui-modal {
|
||||||
position: fixed;
|
|
||||||
z-index: 2;
|
|
||||||
top: 0;
|
|
||||||
right: 0;
|
|
||||||
bottom: 0;
|
|
||||||
left: 0;
|
|
||||||
display: flex;
|
display: flex;
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
background-color: #00000080;
|
|
||||||
|
&:not(.nested) {
|
||||||
|
background-color: #00000080;
|
||||||
|
position: fixed;
|
||||||
|
z-index: 2;
|
||||||
|
top: 0;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.color-success {
|
.color-success {
|
||||||
@@ -103,11 +117,23 @@ const className = computed(() => {
|
|||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
min-width: 40rem;
|
min-width: 40rem;
|
||||||
padding: 4.2rem;
|
|
||||||
text-align: center;
|
text-align: center;
|
||||||
border-radius: 1rem;
|
border-radius: 1rem;
|
||||||
background-color: var(--modal-background-color);
|
background-color: var(--modal-background-color);
|
||||||
box-shadow: var(--shadow-400);
|
margin: 1rem 2rem;
|
||||||
|
|
||||||
|
&.nested {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:not(.nested) {
|
||||||
|
box-shadow: var(--shadow-400);
|
||||||
|
padding: 4.2rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.container > div:last-child {
|
||||||
|
padding-bottom: 1rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.close-icon {
|
.close-icon {
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<ComponentStory
|
<ComponentStory
|
||||||
|
v-slot="{ properties, settings }"
|
||||||
:params="[
|
:params="[
|
||||||
colorProp(),
|
colorProp(),
|
||||||
iconProp(),
|
iconProp(),
|
||||||
@@ -11,17 +12,31 @@
|
|||||||
slot('buttons').help('Meant to receive UiButton components'),
|
slot('buttons').help('Meant to receive UiButton components'),
|
||||||
setting('title').preset('Modal Title').widget(),
|
setting('title').preset('Modal Title').widget(),
|
||||||
setting('subtitle').preset('Modal Subtitle').widget(),
|
setting('subtitle').preset('Modal Subtitle').widget(),
|
||||||
|
setting('nested_modal').widget(boolean()),
|
||||||
]"
|
]"
|
||||||
v-slot="{ properties, settings }"
|
|
||||||
>
|
>
|
||||||
<UiButton type="button" @click="open">Open Modal</UiButton>
|
<UiButton type="button" @click="open">Open Modal</UiButton>
|
||||||
|
|
||||||
<UiModal v-bind="properties" v-if="isOpen">
|
<UiModal v-if="isOpen" v-bind="properties">
|
||||||
<template #title>{{ settings.title }}</template>
|
<template #title>{{ settings.title }}</template>
|
||||||
<template #subtitle>{{ settings.subtitle }}</template>
|
<template #subtitle>{{ settings.subtitle }}</template>
|
||||||
<template #buttons>
|
<template #buttons>
|
||||||
<UiButton @click="close">Discard</UiButton>
|
<UiButton @click="close">Discard</UiButton>
|
||||||
</template>
|
</template>
|
||||||
|
<template v-if="settings.nested_modal">
|
||||||
|
<UiModal :icon="faWarning" color="warning">
|
||||||
|
<template #title>Warning</template>
|
||||||
|
<template #subtitle> This is a warning "nested" modal.</template>
|
||||||
|
<UiModal :icon="faInfoCircle" color="info">
|
||||||
|
<template #title>Info</template>
|
||||||
|
<template #subtitle> This is an info "nested" modal.</template>
|
||||||
|
</UiModal>
|
||||||
|
</UiModal>
|
||||||
|
<UiModal :icon="faCheck" color="success">
|
||||||
|
<template #title>Success</template>
|
||||||
|
<template #subtitle> This is a success "deep nested" modal.</template>
|
||||||
|
</UiModal>
|
||||||
|
</template>
|
||||||
</UiModal>
|
</UiModal>
|
||||||
</ComponentStory>
|
</ComponentStory>
|
||||||
</template>
|
</template>
|
||||||
@@ -38,6 +53,12 @@ import {
|
|||||||
setting,
|
setting,
|
||||||
slot,
|
slot,
|
||||||
} from "@/libs/story/story-param";
|
} from "@/libs/story/story-param";
|
||||||
|
import {
|
||||||
|
faCheck,
|
||||||
|
faInfoCircle,
|
||||||
|
faWarning,
|
||||||
|
} from "@fortawesome/free-solid-svg-icons";
|
||||||
|
import { boolean } from "@/libs/story/story-widget";
|
||||||
|
|
||||||
const { open, close, isOpen } = useModal();
|
const { open, close, isOpen } = useModal();
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
import type { InjectionKey } from "vue";
|
import type { InjectionKey } from "vue";
|
||||||
|
|
||||||
export const IK_MENU_TELEPORTED = Symbol() as InjectionKey<boolean>;
|
export const IK_MENU_TELEPORTED = Symbol() as InjectionKey<boolean>;
|
||||||
|
export const IK_MODAL_NESTED = Symbol() as InjectionKey<boolean>;
|
||||||
|
|||||||
Reference in New Issue
Block a user