Skip to content
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

feat: pre release modal #637

Merged
merged 1 commit into from
Dec 4, 2023
Merged
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: 2 additions & 0 deletions src/lib/components/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,3 +60,5 @@ export { default as SvgIcon } from './svgIcon.svelte';
export { default as MigrationBox } from './migrationBox.svelte';
export { default as FloatingActionBar } from './floatingActionBar.svelte';
export { default as LoadingDots } from './loadingDots.svelte';
export { default as ModalWrapper } from './modalWrapper.svelte';
export { default as ModalSideCol } from './modalSideCol.svelte';
Comment on lines +63 to +64
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would it be better to not expose these and only use ?

192 changes: 64 additions & 128 deletions src/lib/components/modal.svelte
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
<script lang="ts">
import { createEventDispatcher, onDestroy, onMount } from 'svelte';
import { Alert } from '$lib/components';
import { Alert, ModalWrapper } from '$lib/components';
import { trackEvent } from '$lib/actions/analytics';
import { Form } from '$lib/elements/forms';
import { disableCommands } from '$lib/commandCenter';
Expand All @@ -18,144 +17,81 @@
export let title = '';
export let description = '';

let dialog: HTMLDialogElement;
let alert: HTMLElement;

const dispatch = createEventDispatcher();

onMount(() => {
if (show) openModal();
});

onDestroy(() => {
if (show) closeModal();
});

function handleBLur(event: MouseEvent) {
if (event.target === dialog) {
trackEvent('click_close_modal', {
from: 'backdrop'
});
closeModal();
}
}
function openModal() {
if (dialog && !dialog.open) {
dialog.showModal();
document.documentElement.classList.add('u-overflow-hidden');
}
}

function closeModal() {
if (closable) {
if (dialog && dialog.open) {
dispatch('close');
dialog.close();
show = false;
document.documentElement.classList.remove('u-overflow-hidden');
}
}
}

function handleKeydown(event: KeyboardEvent) {
if (event.key === 'Escape') {
event.preventDefault();
trackEvent('click_close_modal', {
from: 'escape'
});
closeModal();
}
}

$: if (show) {
openModal();
} else {
closeModal();
}

$: $disableCommands(show);

$: if (error) {
alert?.scrollIntoView({ behavior: 'smooth', block: 'start', inline: 'nearest' });
}
</script>

<svelte:window on:mousedown={handleBLur} on:keydown={handleKeydown} />

<dialog
class="modal"
class:is-small={size === 'small'}
class:is-big={size === 'big'}
class:is-separate-header={headerDivider}
bind:this={dialog}
on:cancel|preventDefault>
{#if show}
<Form isModal {onSubmit}>
<header class="modal-header">
<div class="u-flex u-main-space-between u-cross-center u-gap-16">
<div class="u-flex u-cross-center u-gap-16">
{#if icon}
<div
class="avatar is-medium"
class:is-success={state === 'success'}
class:is-warning={state === 'warning'}
class:is-danger={state === 'error'}
class:is-info={state === 'info'}>
<span class={`icon-${icon}`} aria-hidden="true" />
</div>
{/if}

<h4 class="modal-title heading-level-5">
<slot name="title">
{title}
</slot>
</h4>
</div>
{#if closable}
<button
type="button"
class="button is-text is-only-icon"
style="--button-size:1.5rem;"
aria-label="Close Modal"
title="Close Modal"
on:click={() =>
trackEvent('click_close_modal', {
from: 'button'
})}
on:click={closeModal}>
<span class="icon-x" aria-hidden="true" />
</button>
<ModalWrapper bind:show {size} {headerDivider} let:close>
<Form isModal {onSubmit}>
<header class="modal-header">
<div class="u-flex u-main-space-between u-cross-center u-gap-16">
<div class="u-flex u-cross-center u-gap-16">
{#if icon}
<div
class="avatar is-medium"
class:is-success={state === 'success'}
class:is-warning={state === 'warning'}
class:is-danger={state === 'error'}
class:is-info={state === 'info'}>
<span class={`icon-${icon}`} aria-hidden="true" />
</div>
{/if}

<h4 class="modal-title heading-level-5">
<slot name="title">
{title}
</slot>
</h4>
</div>
<p class="u-margin-block-start-4">
<slot name="description">
{description}
</slot>
</p>
</header>
<div class="modal-content">
{#if error}
<div bind:this={alert}>
<Alert
dismissible
type="warning"
on:dismiss={() => {
error = null;
}}>
{error}
</Alert>
</div>
{#if closable}
<button
type="button"
class="button is-text is-only-icon"
style="--button-size:1.5rem;"
aria-label="Close Modal"
title="Close Modal"
on:click={() =>
trackEvent('click_close_modal', {
from: 'button'
})}
on:click={close}>
<span class="icon-x" aria-hidden="true" />
</button>
{/if}
<slot />
</div>

{#if $$slots.footer}
<div class="modal-footer">
<div class="u-flex u-main-end u-gap-16">
<slot name="footer" />
</div>
<p class="u-margin-block-start-4">
<slot name="description">
{description}
</slot>
</p>
</header>
<div class="modal-content">
{#if error}
<div bind:this={alert}>
<Alert
dismissible
type="warning"
on:dismiss={() => {
error = null;
}}>
{error}
</Alert>
</div>
{/if}
</Form>
{/if}
</dialog>
<slot />
</div>

{#if $$slots.footer}
<div class="modal-footer">
<div class="u-flex u-main-end u-gap-16">
<slot name="footer" />
</div>
</div>
{/if}
</Form>
</ModalWrapper>
67 changes: 67 additions & 0 deletions src/lib/components/modalSideCol.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
<script lang="ts">
import { ModalWrapper } from '$lib/components';
import { trackEvent } from '$lib/actions/analytics';

export let show = false;
export let title = '';
export let description = '';
export let style = '';
</script>

<ModalWrapper bind:show let:close {style}>
<div class="grid-1-1 u-width-full-line mk-grid">
<div class="mk-grid-item-1 u-width-full-line">
<slot name="side" />
</div>
<div class="u-padding-32 mk-grid-item-2">
<header class="modal-header">
<div class="u-flex u-main-space-between u-gap-16">
<h4 class="modal-title heading-level-5">
<slot name="title">
{title}
</slot>
</h4>
<button
type="button"
class="button is-text is-only-icon"
style="--button-size:1.5rem;"
aria-label="Close Modal"
title="Close Modal"
on:click={() =>
trackEvent('click_close_modal', {
from: 'button'
})}
on:click={close}>
<span class="icon-x" aria-hidden="true" />
</button>
</div>
<p class="u-margin-block-start-4">
<slot name="description">
{description}
</slot>
</p>
</header>
<div class="modal-content">
<slot />
</div>
</div>
</div>
</ModalWrapper>

<style lang="scss">
.mk-grid {
overflow: hidden;
}
@media screen and (max-width: 768px) {
.mk-grid {
&-item-1 {
order: 2;
max-height: 16rem;
}

&-item-2 {
order: 1;
}
}
}
</style>
82 changes: 82 additions & 0 deletions src/lib/components/modalWrapper.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
<script lang="ts">
import { createEventDispatcher, onDestroy, onMount } from 'svelte';
import { trackEvent } from '$lib/actions/analytics';
import { disableCommands } from '$lib/commandCenter';

export let show = false;
export let size: 'small' | 'big' = null;
export let closable = true;
export let headerDivider = true;
export let style = '';

let dialog: HTMLDialogElement;

const dispatch = createEventDispatcher();

onMount(() => {
if (show) openModal();
});

onDestroy(() => {
if (show) closeModal();
});

function handleBLur(event: MouseEvent) {
if (event.target === dialog) {
trackEvent('click_close_modal', {
from: 'backdrop'
});
closeModal();
}
}
function openModal() {
if (dialog && !dialog.open) {
dialog.showModal();
document.documentElement.classList.add('u-overflow-hidden');
}
}

function closeModal() {
if (closable) {
if (dialog && dialog.open) {
dispatch('close');
dialog.close();
show = false;
document.documentElement.classList.remove('u-overflow-hidden');
}
}
}

function handleKeydown(event: KeyboardEvent) {
if (event.key === 'Escape') {
event.preventDefault();
trackEvent('click_close_modal', {
from: 'escape'
});
closeModal();
}
}

$: if (show) {
openModal();
} else {
closeModal();
}

$: $disableCommands(show);
</script>

<svelte:window on:mousedown={handleBLur} on:keydown={handleKeydown} />

<dialog
class="modal"
class:is-small={size === 'small'}
class:is-big={size === 'big'}
class:is-separate-header={headerDivider}
{style}
bind:this={dialog}
on:cancel|preventDefault>
{#if show}
<slot close={closeModal} />
{/if}
</dialog>
Loading