chore: lift components folder

This commit is contained in:
Eric Liu 2020-07-19 09:06:08 -07:00
commit 2200b29b92
301 changed files with 57 additions and 76 deletions

View file

@ -0,0 +1,157 @@
<script>
export let story = undefined;
const { modalBody } = $$props;
import { Button } from "../Button";
import ComposedModal from "./ComposedModal.svelte";
import ModalHeader from "./ModalHeader.svelte";
import ModalBody from "./ModalBody.svelte";
import ModalFooter from "./ModalFooter.svelte";
$: open = false;
</script>
{#if story === undefined}
<ComposedModal {...$$props.composedModal}>
<ModalHeader {...$$props.modalHeader} />
<ModalBody
{...$$props.modalBody}
aria-label={modalBody.hasScrollingContent ? 'Modal content' : undefined}>
<p>
Please see ModalWrapper for more examples and demo of the functionality.
</p>
{#if modalBody.hasScrollingContent}
<p>
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aenean id
accumsan augue. Phasellus consequat augue vitae tellus tincidunt
posuere. Curabitur justo urna, consectetur vel elit iaculis, ultrices
condimentum risus. Nulla facilisi. Etiam venenatis molestie tellus.
Quisque consectetur non risus eu rutrum.{' '}
</p>
{/if}
</ModalBody>
<ModalFooter {...$$props.modalFooter} />
</ComposedModal>
{/if}
{#if story === 'child nodes'}
<ComposedModal {...$$props.composedModal}>
<ModalHeader {...$$props.modalHeader}>
<h1>Testing</h1>
</ModalHeader>
<ModalBody
{...$$props.modalBody}
aria-label={modalBody.hasScrollingContent ? 'Modal content' : undefined}>
<p>
Please see ModalWrapper for more examples and demo of the functionality.
</p>
{#if modalBody.hasScrollingContent}
<p>
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aenean id
accumsan augue. Phasellus consequat augue vitae tellus tincidunt
posuere. Curabitur justo urna, consectetur vel elit iaculis, ultrices
condimentum risus. Nulla facilisi. Etiam venenatis molestie tellus.
Quisque consectetur non risus eu rutrum.{' '}
</p>
{/if}
</ModalBody>
<ModalFooter>
<Button kind="secondary">Cancel</Button>
<Button kind={$$props.composedModal.danger ? 'danger' : 'primary'}>
Primary
</Button>
</ModalFooter>
</ComposedModal>
{/if}
{#if story === 'title'}
<ComposedModal
{...$$props.composedModal}
open
on:close={() => {}}
on:submit={() => {}}>
<ModalHeader
{...$$props.modalHeader}
title="Passive modal title as the message. Should be direct and 3 lines or
less." />
<ModalBody {...$$props.modalBody} />
<ModalFooter {...$$props.modalFooter} />
</ComposedModal>
{/if}
{#if story === 'trigger'}
<div>
<Button
on:click={() => {
open = true;
}}>
Launch composed modal
</Button>
</div>
<ComposedModal
{...$$props.composedModal}
{open}
on:close={() => (open = false)}>
<ModalHeader {...$$props.modalHeader} />
<ModalBody
{...$$props.modalBody}
aria-label={modalBody.hasScrollingContent ? 'Modal content' : undefined}>
<p>
Please see ModalWrapper for more examples and demo of the functionality.
</p>
{#if modalBody.hasScrollingContent}
<p>
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aenean id
accumsan augue. Phasellus consequat augue vitae tellus tincidunt
posuere. Curabitur justo urna, consectetur vel elit iaculis, ultrices
condimentum risus. Nulla facilisi. Etiam venenatis molestie tellus.
Quisque consectetur non risus eu rutrum.{' '}
</p>
<p>
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aenean id
accumsan augue. Phasellus consequat augue vitae tellus tincidunt
posuere. Curabitur justo urna, consectetur vel elit iaculis, ultrices
condimentum risus. Nulla facilisi. Etiam venenatis molestie tellus.
Quisque consectetur non risus eu rutrum.{' '}
</p>
<p>
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aenean id
accumsan augue. Phasellus consequat augue vitae tellus tincidunt
posuere. Curabitur justo urna, consectetur vel elit iaculis, ultrices
condimentum risus. Nulla facilisi. Etiam venenatis molestie tellus.
Quisque consectetur non risus eu rutrum.{' '}
</p>
<h3>Lorem ipsum</h3>
<p>
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aenean id
accumsan augue. Phasellus consequat augue vitae tellus tincidunt
posuere. Curabitur justo urna, consectetur vel elit iaculis, ultrices
condimentum risus. Nulla facilisi. Etiam venenatis molestie tellus.
Quisque consectetur non risus eu rutrum.{' '}
</p>
<p>
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aenean id
accumsan augue. Phasellus consequat augue vitae tellus tincidunt
posuere. Curabitur justo urna, consectetur vel elit iaculis, ultrices
condimentum risus. Nulla facilisi. Etiam venenatis molestie tellus.
Quisque consectetur non risus eu rutrum.{' '}
</p>
<p>
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aenean id
accumsan augue. Phasellus consequat augue vitae tellus tincidunt
posuere. Curabitur justo urna, consectetur vel elit iaculis, ultrices
condimentum risus. Nulla facilisi. Etiam venenatis molestie tellus.
Quisque consectetur non risus eu rutrum.{' '}
</p>
<p>
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aenean id
accumsan augue. Phasellus consequat augue vitae tellus tincidunt
posuere. Curabitur justo urna, consectetur vel elit iaculis, ultrices
condimentum risus. Nulla facilisi. Etiam venenatis molestie tellus.
Quisque consectetur non risus eu rutrum.{' '}
</p>
{/if}
</ModalBody>
<ModalFooter {...$$props.modalFooter} />
</ComposedModal>
{/if}

View file

@ -0,0 +1,177 @@
import { withKnobs, select, boolean, text } from "@storybook/addon-knobs";
import Component from "./ComposedModal.Story.svelte";
export default { title: "ComposedModal", decorators: [withKnobs] };
const sizes = {
Default: "",
"Extra small (xs)": "xs",
"Small (sm)": "sm",
"Large (lg)": "lg",
};
export const Default = () => ({
Component,
props: {
composedModal: {
open: boolean("Open (open in <ComposedModal>)", true),
danger: boolean("Danger mode (danger)", false),
selectorPrimaryFocus: text(
"Primary focus element selector (selectorPrimaryFocus)",
"[data-modal-primary-focus]"
),
size: select("Size (size)", sizes, "sm"),
},
modalHeader: {
label: text("Optional Label (label in <ModalHeader>)", "Optional Label"),
title: text("Optional title (title in <ModalHeader>)", "Example"),
iconDescription: text(
"Close icon description (iconDescription in <ModalHeader>)",
"Close"
),
},
modalBody: {
hasScrollingContent: boolean(
"Modal contains scrollable content (hasScrollingContent)",
true
),
"aria-label": text("ARIA label for content", "Example modal content"),
},
modalFooter: {
primaryButtonText: text(
"Primary button text (primaryButtonText in <ModalFooter>)",
"Save"
),
primaryButtonDisabled: boolean(
"Primary button disabled (primaryButtonDisabled in <ModalFooter>)",
false
),
secondaryButtonText: text(
"Secondary button text (secondaryButtonText in <ModalFooter>)",
""
),
},
},
});
export const ChildNodes = () => ({
Component,
props: {
story: "child nodes",
composedModal: {
open: boolean("Open (open in <ComposedModal>)", true),
danger: boolean("Danger mode (danger)", false),
selectorPrimaryFocus: text(
"Primary focus element selector (selectorPrimaryFocus)",
"[data-modal-primary-focus]"
),
size: select("Size (size)", sizes, "sm"),
},
modalHeader: {
label: text("Optional Label (label in <ModalHeader>)", "Optional Label"),
title: text("Optional title (title in <ModalHeader>)", "Example"),
iconDescription: text(
"Close icon description (iconDescription in <ModalHeader>)",
"Close"
),
},
modalBody: {
hasScrollingContent: boolean(
"Modal contains scrollable content (hasScrollingContent)",
true
),
"aria-label": text("ARIA label for content", "Example modal content"),
},
modalFooter: {},
},
});
export const TitleOnly = () => ({
Component,
props: {
story: "title",
composedModal: {
open: boolean("Open (open in <ComposedModal>)", true),
danger: boolean("Danger mode (danger)", false),
selectorPrimaryFocus: text(
"Primary focus element selector (selectorPrimaryFocus)",
"[data-modal-primary-focus]"
),
size: select("Size (size)", sizes, "sm"),
},
modalHeader: {
label: text("Optional Label (label in <ModalHeader>)", "Optional Label"),
title: text("Optional title (title in <ModalHeader>)", "Example"),
iconDescription: text(
"Close icon description (iconDescription in <ModalHeader>)",
"Close"
),
},
modalBody: {
hasScrollingContent: boolean(
"Modal contains scrollable content (hasScrollingContent)",
true
),
"aria-label": text("ARIA label for content", "Example modal content"),
},
modalFooter: {
primaryButtonText: text(
"Primary button text (primaryButtonText in <ModalFooter>)",
"Save"
),
primaryButtonDisabled: boolean(
"Primary button disabled (primaryButtonDisabled in <ModalFooter>)",
false
),
secondaryButtonText: text(
"Secondary button text (secondaryButtonText in <ModalFooter>)",
""
),
},
},
});
export const Trigger = () => ({
Component,
props: {
story: "trigger",
composedModal: {
open: boolean("Open (open in <ComposedModal>)", true),
danger: boolean("Danger mode (danger)", false),
selectorPrimaryFocus: text(
"Primary focus element selector (selectorPrimaryFocus)",
"[data-modal-primary-focus]"
),
size: select("Size (size)", sizes, "sm"),
},
modalHeader: {
label: text("Optional Label (label in <ModalHeader>)", "Optional Label"),
title: text("Optional title (title in <ModalHeader>)", "Example"),
iconDescription: text(
"Close icon description (iconDescription in <ModalHeader>)",
"Close"
),
},
modalBody: {
hasScrollingContent: boolean(
"Modal contains scrollable content (hasScrollingContent)",
true
),
"aria-label": text("ARIA label for content", "Example modal content"),
},
modalFooter: {
primaryButtonText: text(
"Primary button text (primaryButtonText in <ModalFooter>)",
"Save"
),
primaryButtonDisabled: boolean(
"Primary button disabled (primaryButtonDisabled in <ModalFooter>)",
false
),
secondaryButtonText: text(
"Secondary button text (secondaryButtonText in <ModalFooter>)",
""
),
},
},
});

View file

@ -0,0 +1,98 @@
<script>
export let open = false;
export let danger = false;
export let size = undefined; // "xs" | "sm" | "lg"
export let containerClass = "";
export let selectorPrimaryFocus = "[data-modal-primary-focus]";
export let ref = null;
import {
createEventDispatcher,
tick,
setContext,
onMount,
afterUpdate
} from "svelte";
const dispatch = createEventDispatcher();
let buttonRef = null;
let innerModal = null;
setContext("ComposedModal", {
closeModal: () => {
open = false;
},
submit: () => {
dispatch("submit");
},
declareRef: ref => {
buttonRef = ref;
}
});
function focus(element) {
const node =
(element || innerModal).querySelector(selectorPrimaryFocus) || buttonRef;
node.focus();
}
$: opened = false;
$: didOpen = open;
onMount(async () => {
await tick();
focus();
return () => {
document.body.classList.remove("bx--body--with-modal-open");
};
});
afterUpdate(() => {
if (opened) {
if (!open) {
opened = false;
dispatch("close");
document.body.classList.add("bx--body--with-modal-open");
}
} else if (open) {
opened = true;
dispatch("open");
document.body.classList.remove("bx--body--with-modal-open");
}
});
</script>
<div
bind:this={ref}
role="presentation"
tabindex="-1"
class:bx--modal={true}
class:is-visible={open}
class:bx--modal--danger={danger}
{...$$restProps}
on:click
on:click={({ target }) => {
if (!innerModal.contains(target)) {
open = false;
}
}}
on:mouseover
on:mouseenter
on:mouseleave
on:transitionend
on:transitionend={({ currentTarget }) => {
if (didOpen) {
focus(currentTarget);
didOpen = false;
}
}}>
<div
bind:this={innerModal}
class:bx--modal-container={true}
class="{size && `bx--modal-container--${size}`}
{containerClass}">
<slot />
</div>
</div>

View file

@ -0,0 +1,16 @@
<script>
export let hasForm = false;
export let hasScrollingContent = false;
</script>
<div
tabindex={hasScrollingContent ? '0' : undefined}
role={hasScrollingContent ? 'region' : undefined}
class:bx--modal-content={true}
class:bx--modal-content--with-form={hasForm}
{...$$restProps}>
<slot />
</div>
{#if hasScrollingContent}
<div class:bx--modal-content--overflow-indicator={true} />
{/if}

View file

@ -0,0 +1,31 @@
<script>
export let primaryClass = undefined;
export let primaryButtonText = "";
export let primaryButtonDisabled = false;
export let secondaryClass = undefined;
export let secondaryButtonText = "";
export let danger = false;
import { getContext } from "svelte";
import { Button } from "../Button";
const { closeModal, submit } = getContext("ComposedModal");
</script>
<div class:bx--modal-footer={true} {...$$restProps}>
{#if secondaryButtonText}
<Button kind="secondary" class={secondaryClass} on:click={closeModal}>
{secondaryButtonText}
</Button>
{/if}
{#if primaryButtonText}
<Button
kind={danger ? 'danger' : 'primary'}
disabled={primaryButtonDisabled}
class={primaryClass}
on:click={submit}>
{primaryButtonText}
</Button>
{/if}
<slot />
</div>

View file

@ -0,0 +1,44 @@
<script>
export let title = "";
export let label = "";
export let labelClass = "";
export let titleClass = "";
export let closeClass = "";
export let closeIconClass = "";
export let iconDescription = "Close";
import { getContext } from "svelte";
import Close20 from "carbon-icons-svelte/lib/Close20";
const { closeModal } = getContext("ComposedModal");
</script>
<div class:bx--modal-header={true} {...$$restProps}>
{#if label}
<p
class:bx--modal-header__label={true}
class:bx--type-delta={true}
class:labelClass>
{label}
</p>
{/if}
{#if title}
<p
class:bx--modal-header__heading={true}
class:bx--type-beta={true}
class:titleClass>
{title}
</p>
{/if}
<slot />
<button
type="button"
title={iconDescription}
aria-label={iconDescription}
class:bx--modal-close={true}
class:closeClass
on:click
on:click={closeModal}>
<Close20 class="bx--modal-close__icon {closeIconClass}" />
</button>
</div>

View file

@ -0,0 +1,4 @@
export { default as ComposedModal } from "./ComposedModal.svelte";
export { default as ModalHeader } from "./ModalHeader.svelte";
export { default as ModalBody } from "./ModalBody.svelte";
export { default as ModalFooter } from "./ModalFooter.svelte";