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

58
src/Tabs/Tab.svelte Normal file
View file

@ -0,0 +1,58 @@
<script>
export let disabled = false;
export let href = "#";
export let label = "";
export let role = "presentation";
export let tabindex = "0";
export let id = "ccs-" + Math.random().toString(36);
export let ref = null;
import { getContext } from "svelte";
const { selectedTab, add, update, change } = getContext("Tabs");
add({ id, label, disabled });
$: selected = $selectedTab === id;
$: if (selected && ref) {
ref.focus();
}
</script>
<li
tabindex="-1"
{role}
class:bx--tabs__nav-item={true}
class:bx--tabs__nav-item--disabled={disabled}
class:bx--tabs__nav-item--selected={selected}
{...$$restProps}
on:click|preventDefault={() => {
if (!disabled) {
update(id);
}
}}
on:mouseover
on:mouseenter
on:mouseleave
on:keydown={({ key }) => {
if (!disabled) {
if (key === 'ArrowRight') {
change(1);
} else if (key === 'ArrowLeft') {
change(-1);
} else if (key === ' ' || key === 'Enter') {
update(id);
}
}
}}>
<a
bind:this={ref}
role="tab"
tabindex={disabled ? '-1' : tabindex}
aria-selected={selected}
aria-disabled={disabled}
{href}
class:bx--tabs__nav-link={true}>
{label}
</a>
</li>

View file

@ -0,0 +1,19 @@
<script>
export let id = "ccs-" + Math.random().toString(36);
import { getContext } from "svelte";
const { selectedContent, addContent } = getContext("Tabs");
addContent({ id });
$: selected = $selectedContent === id;
</script>
<div
aria-hidden={!selected}
hidden={!selected}
class:bx--tab-content={true}
class={$$restProps.class}
style={$$restProps.style}>
<slot />
</div>

View file

@ -0,0 +1,40 @@
<script>
export let story = undefined;
import Tab from "./Tab.svelte";
import TabContent from "./TabContent.svelte";
import Tabs from "./Tabs.svelte";
import TabsSkeleton from "./TabsSkeleton.svelte";
const { tabProps, ...tabsProps } = $$props;
$: selected = 0;
</script>
{#if story === 'skeleton'}
<TabsSkeleton />
{:else if story === 'container'}
<Tabs {...tabsProps} type="container" bind:selected>
<Tab {...tabProps} label="Tab label 1" />
<Tab {...tabProps} label="Tab label 2" />
<Tab {...tabProps} label="Tab label 3" />
<div slot="content">
<TabContent>Content 1</TabContent>
<TabContent>Content 2</TabContent>
<TabContent>Content 3</TabContent>
</div>
</Tabs>
{:else}
<Tabs {...tabsProps} bind:selected>
<Tab {...tabProps} label="Tab label 1" />
<Tab {...tabProps} label="Tab label 2" />
<Tab {...tabProps} label="Tab label 3" disabled />
<Tab {...tabProps} label="Tab label 4" />
<div slot="content">
<TabContent>Content 1</TabContent>
<TabContent>Content 2</TabContent>
<TabContent>Content 3</TabContent>
<TabContent>Content 4</TabContent>
</div>
</Tabs>
{/if}

48
src/Tabs/Tabs.stories.js Normal file
View file

@ -0,0 +1,48 @@
import { withKnobs, boolean, number, text } from "@storybook/addon-knobs";
import Component from "./Tabs.Story.svelte";
export default { title: "Tabs", decorators: [withKnobs] };
export const Default = () => ({
Component,
props: {
tabProps: {
disabled: boolean("Disabled (disabled in <Tab>)", false),
href: text("The href for tab (href in <Tab>)", "#"),
role: text("ARIA role (role in <Tab>)", "presentation"),
tabindex: text("Tab index (tabindex in <Tab>)", "0"),
},
tabsProps: {
className: "some-class",
selected: number("The index of the selected tab (selected in <Tabs>)", 1),
triggerHref: text(
"The href of trigger button for narrow mode (triggerHref in <Tabs>)",
"#"
),
role: text("ARIA role (role in <Tabs>)", "navigation"),
iconDescription: text(
"The description of the trigger icon for narrow mode (iconDescription in <Tabs>)",
"show menu options"
),
tabContentClassName: text(
"The className for the child `<TabContent>` components",
"tab-content"
),
},
},
});
export const Container = () => ({
Component,
props: {
story: "container",
tabProps: {
disabled: boolean("Disabled (disabled in <Tab>)", false),
href: text("The href for tab (href in <Tab>)", "#"),
role: text("ARIA role (role in <Tab>)", "presentation"),
tabindex: text("Tab index (tabindex in <Tab>)", "0"),
},
},
});
export const Skeleton = () => ({ Component, props: { story: "skeleton" } });

122
src/Tabs/Tabs.svelte Normal file
View file

@ -0,0 +1,122 @@
<script>
export let iconDescription = "Show menu options";
export let role = "navigation";
export let selected = 0;
export let triggerHref = "#";
export let type = "default";
import { createEventDispatcher, afterUpdate, setContext } from "svelte";
import { writable, derived } from "svelte/store";
import ChevronDownGlyph from "carbon-icons-svelte/lib/ChevronDownGlyph";
const dispatch = createEventDispatcher();
let dropdownHidden = true;
let tabs = writable([]);
let tabsById = derived(tabs, _ =>
_.reduce((a, c) => ({ ...a, [c.id]: c }), {})
);
let currentIndex = selected;
let selectedTab = writable(undefined);
let content = writable([]);
let selectedContent = writable(undefined);
setContext("Tabs", {
selectedTab,
selectedContent,
add: data => {
tabs.update(_ => [..._, { ...data, index: _.length }]);
},
addContent: data => {
content.update(_ => [..._, { ...data, index: _.length }]);
},
update: id => {
currentIndex = $tabsById[id].index;
},
change: direction => {
let index = currentIndex + direction;
if (index < 0) {
index = $tabs.length - 1;
} else if (index >= $tabs.length) {
index = 0;
}
let disabled = $tabs[index].disabled;
while (disabled) {
index = index + direction;
if (index < 0) {
index = $tabs.length - 1;
} else if (index >= $tabs.length) {
index = 0;
}
disabled = $tabs[index].disabled;
}
currentIndex = index;
}
});
afterUpdate(() => {
selected = currentIndex;
});
$: currentIndex = selected;
$: currentTab = $tabs[currentIndex] || undefined;
$: currentContent = $content[currentIndex] || undefined;
$: {
dispatch("change", currentIndex);
if (currentTab) {
selectedTab.set(currentTab.id);
}
if (currentContent) {
selectedContent.set(currentContent.id);
}
}
$: if ($selectedTab) {
dropdownHidden = true;
}
</script>
<div
{role}
class:bx--tabs={true}
class:bx--tabs--container={type === 'container'}
{...$$restProps}>
<div
role="listbox"
tabindex="0"
class:bx--tabs-trigger={true}
aria-label={$$props['aria-label'] || 'listbox'}
on:click={() => {
dropdownHidden = !dropdownHidden;
}}
on:keypress
on:keypress={() => {
dropdownHidden = !dropdownHidden;
}}>
<a
tabindex="-1"
class:bx--tabs-trigger-text={true}
href={triggerHref}
on:click
on:click={() => {
dropdownHidden = !dropdownHidden;
}}>
{#if currentTab}{currentTab.label}{/if}
</a>
<ChevronDownGlyph aria-hidden="true" title={iconDescription} />
</div>
<ul
role="tablist"
class:bx--tabs__nav={true}
class:bx--tabs__nav--hidden={dropdownHidden}>
<slot />
</ul>
</div>
<slot name="content" />

View file

@ -0,0 +1,22 @@
<div
class:bx--tabs={true}
class:bx--skeleton={true}
{...$$restProps}
on:click
on:mouseover
on:mouseenter
on:mouseleave>
<div class:bx--tabs-trigger={true}>
<div class:bx--tabs-trigger-text={true}>&nbsp;</div>
<svg width="10" height="5" viewBox="0 0 10 5" fill-rule="evenodd">
<path d="M10 0L5 5 0 0z" />
</svg>
</div>
<ul class:bx--tabs__nav={true} class:bx--tabs__nav--hidden={true}>
{#each [0, 1, 2, 3] as item, i (item)}
<li class:bx--tabs__nav-item={true}>
<div class:bx--tabs__nav-link={true}>&nbsp;</div>
</li>
{/each}
</ul>
</div>

4
src/Tabs/index.js Normal file
View file

@ -0,0 +1,4 @@
export { default as Tabs } from "./Tabs.svelte";
export { default as Tab } from "./Tab.svelte";
export { default as TabContent } from "./TabContent.svelte";
export { default as TabsSkeleton } from "./TabsSkeleton.svelte";