Skip to content

Commit

Permalink
Add ipl-dialog component
Browse files Browse the repository at this point in the history
  • Loading branch information
inkfarer committed Aug 12, 2024
1 parent c3bcfdf commit b3fc1e9
Show file tree
Hide file tree
Showing 10 changed files with 262 additions and 74 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
# 3.5.0

- Add ipl-dialog component

# 3.4.0

- Add `prefix` prop to ipl-input to display arbitrary text before the text input
Expand Down
2 changes: 1 addition & 1 deletion docs/.vitepress/config.mts
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ export default defineConfig({
{ text: 'Progress Bar', link: '/ipl-progress-bar' },
{ text: 'Toggles', link: '/toggles' },
{ text: 'Loading Spinner', link: '/ipl-spinner' },
{ text: 'Sidebar', link: '/ipl-sidebar' },
{ text: 'Dialogs', link: '/dialogs' },
{ text: 'Pagination', link: '/ipl-pagination' }
]
}
Expand Down
10 changes: 8 additions & 2 deletions docs/ipl-sidebar.md → docs/dialogs.md
Original file line number Diff line number Diff line change
@@ -1,11 +1,17 @@
---
title: ipl-sidebar
title: Dialogs
---

# ipl-sidebar
# Dialogs

## ipl-sidebar

::: demo SidebarExample

## ipl-dialog

::: demo DialogExample

## Known issues

- The backdrop does not animate in Firefox ([Bugzilla](https://bugzilla.mozilla.org/show_bug.cgi?id=1725177))
Expand Down
53 changes: 53 additions & 0 deletions docs/examples/DialogExample.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
<template>
<div
style="position: relative; overflow: hidden; min-height: 150px"
class="sidebar-example-layout"
>
<!-- #region example -->
<ipl-dialog
v-model:is-open="dialogOpen"
style="width: 500px"
>
<div class="width-capped-content">
<ipl-space
color="light"
class="vertical-layout"
>
<div>Hello!</div>
<ipl-button
label="Button!"
/>
<ipl-button
label="Close dialog"
color="red"
@click="dialogOpen = false"
/>
</ipl-space>
</div>
</ipl-dialog>
<ipl-button
label="Open dialog"
@click="dialogOpen = true"
/>
<!-- #endregion example -->
</div>
</template>

<script setup lang="ts">
import { IplButton, IplSpace, IplDialog } from '../../src';
import { ref } from 'vue';
const dialogOpen = ref(false);
</script>

<style lang="scss">
.sidebar-example-layout {
display: flex;
align-items: center;
justify-content: center;
> .ipl-button {
width: auto;
}
}
</style>
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@iplsplatoon/vue-components",
"version": "3.4.0",
"version": "3.5.0",
"description": "Vue components for internal Inkling Performance Labs utilities.",
"homepage": "https://github.com/IPLSplatoon/vue-components",
"repository": "https://github.com/IPLSplatoon/vue-components",
Expand Down
104 changes: 104 additions & 0 deletions src/components/iplDialog.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
<template>
<dialog
ref="dialog"
@close="onClose"
@cancel.prevent="onCancel"
@click.self="onClick"
>
<div class="content">
<slot />
</div>
</dialog>
</template>

<script lang="ts">
import { defineComponent, onMounted, ref, watch } from 'vue';
import { dialogAnimationComplete } from '../helpers/dialogHelper';
export default defineComponent({
name: 'IplDialog',
props: {
isOpen: {
type: Boolean,
required: true
}
},
emits: ['update:isOpen'],
setup(props, { emit }) {
const dialog = ref<HTMLDialogElement | null>(null);
async function onClose() {
if (!dialog.value) return;
dialog.value.setAttribute('inert', '');
await dialogAnimationComplete(dialog.value);
dialog.value.close('dismiss');
}
onMounted(() => {
if (!props.isOpen) {
dialog.value?.setAttribute('inert', '');
} else {
dialog.value?.showModal();
}
watch(() => props.isOpen, newValue => {
if (newValue) {
dialog.value?.removeAttribute('inert');
dialog.value?.showModal();
} else {
onClose();
}
});
});
return {
dialog,
onClose() {
emit('update:isOpen', false);
},
onCancel() {
onClose();
},
onClick() {
onClose();
}
};
}
});
</script>

<style lang="scss" scoped>
@use 'src/styles/constants';
@use 'src/styles/dialogs';
dialog {
@include dialogs.dialog-common(constants.$transition-duration-low, constants.$transition-duration-med, constants.$transition-duration-low, linear, linear);
opacity: 0;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
border-radius: constants.$border-radius-outer;
}
@include dialogs.dialog-common-animation;
@keyframes dialog-enter {
to {
opacity: 1;
}
}
@keyframes dialog-exit {
0% {
opacity: 1;
}
100% {
opacity: 0;
}
}
</style>
81 changes: 11 additions & 70 deletions src/components/iplSidebar.vue
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,7 @@

<script lang="ts">
import { defineComponent, onMounted, ref, watch } from 'vue';
async function animationsComplete(element: HTMLElement): Promise<unknown> {
return Promise.allSettled(element.getAnimations().map(animation => animation.finished));
}
import { dialogAnimationComplete } from '../helpers/dialogHelper';
export default defineComponent({
name: 'IplSidebar',
Expand All @@ -36,7 +33,7 @@ export default defineComponent({
async function onClose() {
if (!dialog.value) return;
dialog.value.setAttribute('inert', '');
await animationsComplete(dialog.value);
await dialogAnimationComplete(dialog.value);
dialog.value.close();
}
Expand Down Expand Up @@ -75,65 +72,29 @@ export default defineComponent({

<style lang="scss" scoped>
@use 'src/styles/constants';
@use 'src/styles/dialogs';
dialog {
border: none;
background-color: var(--ipl-bg-primary);
color: var(--ipl-body-text-color);
@include dialogs.dialog-common;
transform: translateX(-85vw);
width: 85%;
height: 100%;
max-height: 100%;
box-sizing: border-box;
margin: 0;
padding: 0;
inset: 0;
display: block;
position: fixed;
// Unfortunately, if you want animation, you'll have to put up with this.
z-index: 999999;
transform: translateX(-85vw);
&:not([open]) {
pointer-events: none;
}
&[open] {
animation: slide-in constants.$transition-duration-med ease-out forwards;
&::backdrop {
animation: backdrop-fade-in constants.$transition-duration-med ease-out forwards;
}
&[inert] {
animation: slide-out constants.$transition-duration-med ease-in forwards;
&::backdrop {
animation: backdrop-fade-out constants.$transition-duration-med ease-out forwards;
}
}
}
&::backdrop {
background: var(--ipl-page-overlay-color);
}
> .content {
padding: 8px;
height: 100%;
}
&:focus-visible {
outline: var(--ipl-focus-outline-color) solid var(--ipl-focus-outline-width);
opacity: 0;
}
}
@keyframes slide-in {
@include dialogs.dialog-common-animation;
@keyframes dialog-enter {
to {
transform: translateX(0vw);
}
}
@keyframes slide-out {
@keyframes dialog-exit {
0% {
transform: translateX(0vw);
}
Expand All @@ -142,24 +103,4 @@ dialog {
transform: translateX(-85vw);
}
}
@keyframes backdrop-fade-in {
0% {
opacity: 0;
}
100% {
opacity: 1;
}
}
@keyframes backdrop-fade-out {
0% {
opacity: 1;
}
100% {
opacity: 0;
}
}
</style>
3 changes: 3 additions & 0 deletions src/helpers/dialogHelper.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export async function dialogAnimationComplete(element: HTMLElement): Promise<unknown> {
return Promise.allSettled(element.getAnimations({ subtree: true }).filter(anim => anim.effect instanceof KeyframeEffect && anim.effect.target === element && (anim.effect.pseudoElement == null || anim.effect.pseudoElement === '::backdrop')).map(animation => animation.finished));
}
1 change: 1 addition & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ export { default as IplMultiSelect } from './components/iplMultiSelect.vue';
export { default as IplProgressBar } from './components/iplProgressBar.vue';
export { default as IplSelect } from './components/iplSelect.vue';
export { default as IplSidebar } from './components/iplSidebar.vue';
export { default as IplDialog } from './components/iplDialog.vue';
export { default as IplSpace } from './components/iplSpace.vue';
export { default as IplToggle } from './components/iplToggle.vue';
export { default as IplToggleButton } from './components/iplToggleButton.vue';
Expand Down
Loading

0 comments on commit b3fc1e9

Please sign in to comment.