mirror of
https://github.com/carbon-design-system/carbon-components-svelte.git
synced 2025-09-15 18:31:06 +00:00
Merge branch 'master' into tabs
This commit is contained in:
commit
d2878983dc
73 changed files with 1558 additions and 333 deletions
|
@ -1,13 +1,13 @@
|
|||
<script>
|
||||
let className = undefined;
|
||||
export { className as class };
|
||||
export let props = {};
|
||||
export let style = undefined;
|
||||
|
||||
import { cx } from '../../lib';
|
||||
|
||||
const _class = cx('--form-item', '--checkbox-wrapper', className);
|
||||
</script>
|
||||
|
||||
<div {...props} class={_class}>
|
||||
<div on:click on:mouseover on:mouseenter on:mouseleave class={_class} {style}>
|
||||
<span class={cx('--checkbox-label', '--skeleton')} />
|
||||
</div>
|
||||
|
|
|
@ -1,19 +1,13 @@
|
|||
<script>
|
||||
export let story = undefined;
|
||||
const { labelText, indeterminate, disabled, hideLabel, wrapperClassName } = $$props;
|
||||
|
||||
import { cx } from '../../lib';
|
||||
import Layout from '../../internal/ui/Layout.svelte';
|
||||
import Checkbox from './Checkbox.svelte';
|
||||
import CheckboxSkeleton from './Checkbox.Skeleton.svelte';
|
||||
|
||||
const checkboxProps = {
|
||||
labelText,
|
||||
indeterminate,
|
||||
disabled,
|
||||
hideLabel,
|
||||
wrapperClassName
|
||||
};
|
||||
const { labelText, indeterminate, disabled, hideLabel, wrapperClassName } = $$props;
|
||||
const checkboxProps = { labelText, indeterminate, disabled, hideLabel, wrapperClassName };
|
||||
</script>
|
||||
|
||||
<Layout>
|
||||
|
|
|
@ -26,7 +26,4 @@ export const Unchecked = () => ({
|
|||
}
|
||||
});
|
||||
|
||||
export const Skeleton = () => ({
|
||||
Component,
|
||||
props: { story: 'skeleton' }
|
||||
});
|
||||
export const Skeleton = () => ({ Component, props: { story: 'skeleton' } });
|
||||
|
|
|
@ -4,13 +4,13 @@
|
|||
export let checked = false;
|
||||
export let indeterminate = false;
|
||||
export let disabled = false;
|
||||
export let id = undefined;
|
||||
export let id = Math.random();
|
||||
export let labelText = undefined;
|
||||
export let hideLabel = false;
|
||||
export let title = '';
|
||||
export let wrapperClassName = undefined;
|
||||
export { wrapperClassName as wrapperClass };
|
||||
export let props = {};
|
||||
export let style = undefined;
|
||||
|
||||
import { createEventDispatcher } from 'svelte';
|
||||
import { cx } from '../../lib';
|
||||
|
@ -20,17 +20,26 @@
|
|||
const _innerLabelClass = cx('--checkbox-label-text', hideLabel && '--visually-hidden');
|
||||
const _wrapperClass = cx('--form-item', '--checkbox-wrapper', wrapperClassName);
|
||||
|
||||
function handleChange(event) {
|
||||
dispatch('change', { checked: event.target.checked, id, event });
|
||||
let inputRef = undefined;
|
||||
|
||||
$: {
|
||||
dispatch('check', { id, checked });
|
||||
|
||||
if (inputRef) {
|
||||
inputRef.checked = checked;
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class={_wrapperClass}>
|
||||
<div on:click on:mouseover on:mouseenter on:mouseleave class={_wrapperClass} {style}>
|
||||
<input
|
||||
{...props}
|
||||
bind:this={inputRef}
|
||||
type="checkbox"
|
||||
class={cx('--checkbox')}
|
||||
on:change={handleChange}
|
||||
on:change
|
||||
on:change={() => {
|
||||
checked = !checked;
|
||||
}}
|
||||
{indeterminate}
|
||||
{disabled}
|
||||
{checked}
|
||||
|
|
54
src/components/Notification/InlineNotification.svelte
Normal file
54
src/components/Notification/InlineNotification.svelte
Normal file
|
@ -0,0 +1,54 @@
|
|||
<script>
|
||||
let className = undefined;
|
||||
export { className as class };
|
||||
export let kind = 'error';
|
||||
export let title = 'provide a title';
|
||||
export let subtitle = ''; // TODO: support subtitle slot?
|
||||
export let role = 'alert';
|
||||
export let notificationType = 'inline';
|
||||
export let iconDescription = 'closes notification';
|
||||
export let hideCloseButton = false;
|
||||
export let lowContrast = false;
|
||||
export let style = undefined;
|
||||
|
||||
import { createEventDispatcher } from 'svelte';
|
||||
import NotificationIcon from './NotificationIcon.svelte';
|
||||
import NotificationTextDetails from './NotificationTextDetails.svelte';
|
||||
import NotificationButton from './NotificationButton.svelte';
|
||||
import { cx } from '../../lib';
|
||||
|
||||
const dispatch = createEventDispatcher();
|
||||
const _class = cx(
|
||||
'--inline-notification',
|
||||
lowContrast && '--inline-notification--low-contrast',
|
||||
kind && `--inline-notification--${kind}`,
|
||||
hideCloseButton && '--inline-notification--hide-close-button',
|
||||
className
|
||||
);
|
||||
|
||||
let open = true;
|
||||
|
||||
$: if (!open) {
|
||||
dispatch('close');
|
||||
}
|
||||
</script>
|
||||
|
||||
{#if open}
|
||||
<div on:click on:mouseover on:mouseenter on:mouseleave class={_class} {style} {role} {kind}>
|
||||
<div class={cx('--inline-notification__details')}>
|
||||
<NotificationIcon {notificationType} {kind} {iconDescription} />
|
||||
<NotificationTextDetails {title} {subtitle} {notificationType}>
|
||||
<slot />
|
||||
</NotificationTextDetails>
|
||||
</div>
|
||||
<slot name="actions" />
|
||||
{#if !hideCloseButton}
|
||||
<NotificationButton
|
||||
{iconDescription}
|
||||
{notificationType}
|
||||
on:click={() => {
|
||||
open = false;
|
||||
}} />
|
||||
{/if}
|
||||
</div>
|
||||
{/if}
|
20
src/components/Notification/Notification.Story.svelte
Normal file
20
src/components/Notification/Notification.Story.svelte
Normal file
|
@ -0,0 +1,20 @@
|
|||
<script>
|
||||
export let story = undefined;
|
||||
|
||||
import Layout from '../../internal/ui/Layout.svelte';
|
||||
import InlineNotification from './InlineNotification.svelte';
|
||||
import ToastNotification from './ToastNotification.svelte';
|
||||
import NotificationActionButton from './NotificationActionButton.svelte';
|
||||
</script>
|
||||
|
||||
<Layout>
|
||||
{#if story === 'inline'}
|
||||
<InlineNotification {...$$props}>
|
||||
<div slot="actions">
|
||||
<NotificationActionButton>{$$props.action}</NotificationActionButton>
|
||||
</div>
|
||||
</InlineNotification>
|
||||
{:else if story === 'toast'}
|
||||
<ToastNotification {...$$props} style="min-width: 30rem; margin-bottom: .5rem" />
|
||||
{/if}
|
||||
</Layout>
|
42
src/components/Notification/Notification.stories.js
Normal file
42
src/components/Notification/Notification.stories.js
Normal file
|
@ -0,0 +1,42 @@
|
|||
import { withKnobs, select, boolean, text } from '@storybook/addon-knobs';
|
||||
import Component from './Notification.Story.svelte';
|
||||
|
||||
export default { title: 'Notification', decorators: [withKnobs] };
|
||||
|
||||
const kinds = {
|
||||
'Error (error)': 'error',
|
||||
'Info (info)': 'info',
|
||||
'Success (success)': 'success',
|
||||
'Warning (warning)': 'warning'
|
||||
};
|
||||
|
||||
export const Toast = () => ({
|
||||
Component,
|
||||
props: {
|
||||
story: 'toast',
|
||||
kind: select('The notification kind (kind)', kinds, 'info'),
|
||||
lowContrast: boolean('Use low contrast variant (lowContrast)', false),
|
||||
role: text('ARIA role (role)', 'alert'),
|
||||
title: text('Title (title)', 'Notification title'),
|
||||
subtitle: text('Subtitle (subtitle)', 'Subtitle text goes here.'),
|
||||
caption: text('Caption (caption)', 'Time stamp [00:00:00]'),
|
||||
iconDescription: text('Icon description (iconDescription)', 'describes the close button'),
|
||||
hideCloseButton: boolean('Hide close button (hideCloseButton)', false)
|
||||
}
|
||||
});
|
||||
|
||||
export const Inline = () => ({
|
||||
Component,
|
||||
props: {
|
||||
story: 'inline',
|
||||
kind: select('The notification kind (kind)', kinds, 'info'),
|
||||
lowContrast: boolean('Use low contrast variant (lowContrast)', false),
|
||||
role: text('ARIA role (role)', 'alert'),
|
||||
title: text('Title (title)', 'Notification title'),
|
||||
subtitle: text('Subtitle (subtitle)', 'Subtitle text goes here.'),
|
||||
caption: text('Caption (caption)', 'Time stamp [00:00:00]'),
|
||||
iconDescription: text('Icon description (iconDescription)', 'describes the close button'),
|
||||
hideCloseButton: boolean('Hide close button (hideCloseButton)', false),
|
||||
action: text('Action (NotificationActionButton > $$slot#action)', 'Action')
|
||||
}
|
||||
});
|
22
src/components/Notification/NotificationActionButton.svelte
Normal file
22
src/components/Notification/NotificationActionButton.svelte
Normal file
|
@ -0,0 +1,22 @@
|
|||
<script>
|
||||
let className = undefined;
|
||||
export { className as class };
|
||||
export let style = undefined;
|
||||
|
||||
import Button from '../Button';
|
||||
import { cx } from '../../lib';
|
||||
|
||||
const _class = cx('--inline-notification__action-button', className);
|
||||
</script>
|
||||
|
||||
<Button
|
||||
kind="ghost"
|
||||
size="small"
|
||||
on:click
|
||||
on:mouseover
|
||||
on:mouseenter
|
||||
on:mouseleave
|
||||
class={_class}
|
||||
{style}>
|
||||
<slot />
|
||||
</Button>
|
36
src/components/Notification/NotificationButton.svelte
Normal file
36
src/components/Notification/NotificationButton.svelte
Normal file
|
@ -0,0 +1,36 @@
|
|||
<script>
|
||||
let className = undefined;
|
||||
export { className as class };
|
||||
export let notificationType = 'toast';
|
||||
export let type = 'button';
|
||||
export let iconDescription = 'close icon';
|
||||
export let renderIcon = Close20;
|
||||
export let title = undefined;
|
||||
export let style = undefined;
|
||||
|
||||
import Close20 from 'carbon-icons-svelte/lib/Close20';
|
||||
import { cx } from '../../lib';
|
||||
|
||||
const _class = cx(
|
||||
notificationType === 'toast' && '--toast-notification__close-button',
|
||||
notificationType === 'inline' && '--inline-notification__close-button',
|
||||
className
|
||||
);
|
||||
const _iconClass = cx(
|
||||
notificationType === 'toast' && '--toast-notification__close-icon',
|
||||
notificationType === 'inline' && '--inline-notification__close-icon'
|
||||
);
|
||||
</script>
|
||||
|
||||
<button
|
||||
on:click
|
||||
on:mouseover
|
||||
on:mouseenter
|
||||
on:mouseleave
|
||||
aria-label={iconDescription}
|
||||
title={iconDescription}
|
||||
class={_class}
|
||||
{style}
|
||||
{type}>
|
||||
<svelte:component this={renderIcon} class={_iconClass} {title} />
|
||||
</button>
|
21
src/components/Notification/NotificationIcon.svelte
Normal file
21
src/components/Notification/NotificationIcon.svelte
Normal file
|
@ -0,0 +1,21 @@
|
|||
<script>
|
||||
export let kind = 'error';
|
||||
export let notificationType = 'toast';
|
||||
export let iconDescription = 'closes notification';
|
||||
|
||||
import ErrorFilled20 from 'carbon-icons-svelte/lib/ErrorFilled20';
|
||||
import CheckmarkFilled20 from 'carbon-icons-svelte/lib/CheckmarkFilled20';
|
||||
import WarningFilled20 from 'carbon-icons-svelte/lib/WarningFilled20';
|
||||
import { cx } from '../../lib';
|
||||
|
||||
const icons = {
|
||||
error: ErrorFilled20,
|
||||
success: CheckmarkFilled20,
|
||||
warning: WarningFilled20
|
||||
};
|
||||
</script>
|
||||
|
||||
<svelte:component
|
||||
this={icons[kind]}
|
||||
class={cx(`--${notificationType}-notification__icon`)}
|
||||
title={iconDescription} />
|
25
src/components/Notification/NotificationTextDetails.svelte
Normal file
25
src/components/Notification/NotificationTextDetails.svelte
Normal file
|
@ -0,0 +1,25 @@
|
|||
<script>
|
||||
export let title = 'title';
|
||||
export let subtitle = '';
|
||||
export let caption = 'caption';
|
||||
export let notificationType = 'toast';
|
||||
|
||||
import { cx } from '../../lib';
|
||||
</script>
|
||||
|
||||
{#if notificationType === 'toast'}
|
||||
<div class={cx('--toast-notification__details')}>
|
||||
<h3 class={cx('--toast-notification__title')}>{title}</h3>
|
||||
<div class={cx('--toast-notification__subtitle')}>{subtitle}</div>
|
||||
<div class={cx('--toast-notification__caption')}>{caption}</div>
|
||||
<slot />
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
{#if notificationType === 'inline'}
|
||||
<div class={cx('--inline-notification__text-wrapper')}>
|
||||
<p class={cx('--inline-notification__title')}>{title}</p>
|
||||
<div class={cx('--inline-notification__subtitle')}>{subtitle}</div>
|
||||
<slot />
|
||||
</div>
|
||||
{/if}
|
60
src/components/Notification/ToastNotification.svelte
Normal file
60
src/components/Notification/ToastNotification.svelte
Normal file
|
@ -0,0 +1,60 @@
|
|||
<script>
|
||||
let className = undefined;
|
||||
export { className as class };
|
||||
export let kind = 'error';
|
||||
export let title = 'provide a title';
|
||||
export let subtitle = ''; // TODO: support subtitle slot?
|
||||
export let caption = 'provide a caption';
|
||||
export let role = 'alert';
|
||||
export let notificationType = 'toast';
|
||||
export let iconDescription = 'closes notification';
|
||||
export let hideCloseButton = false;
|
||||
export let lowContrast = false;
|
||||
export let timeout = 0;
|
||||
export let style = undefined;
|
||||
|
||||
import { createEventDispatcher, onMount } from 'svelte';
|
||||
import NotificationIcon from './NotificationIcon.svelte';
|
||||
import NotificationTextDetails from './NotificationTextDetails.svelte';
|
||||
import NotificationButton from './NotificationButton.svelte';
|
||||
import { cx } from '../../lib';
|
||||
|
||||
const dispatch = createEventDispatcher();
|
||||
const _class = cx(
|
||||
'--toast-notification',
|
||||
lowContrast && '--toast-notification--low-contrast',
|
||||
kind && `--toast-notification--${kind}`,
|
||||
className
|
||||
);
|
||||
|
||||
let open = true;
|
||||
|
||||
onMount(() => {
|
||||
if (timeout) {
|
||||
window.setTimeout(() => {
|
||||
open = false;
|
||||
}, timeout);
|
||||
}
|
||||
});
|
||||
|
||||
$: if (!open) {
|
||||
dispatch('close');
|
||||
}
|
||||
</script>
|
||||
|
||||
{#if open}
|
||||
<div on:click on:mouseover on:mouseenter on:mouseleave class={_class} {style} {role} {kind}>
|
||||
<NotificationIcon {notificationType} {kind} {iconDescription} />
|
||||
<NotificationTextDetails {title} {subtitle} {caption} {notificationType}>
|
||||
<slot />
|
||||
</NotificationTextDetails>
|
||||
{#if !hideCloseButton}
|
||||
<NotificationButton
|
||||
{iconDescription}
|
||||
{notificationType}
|
||||
on:click={() => {
|
||||
open = false;
|
||||
}} />
|
||||
{/if}
|
||||
</div>
|
||||
{/if}
|
6
src/components/Notification/index.js
Normal file
6
src/components/Notification/index.js
Normal file
|
@ -0,0 +1,6 @@
|
|||
export { default as ToastNotification } from './ToastNotification.svelte';
|
||||
export { default as InlineNotification } from './InlineNotification.svelte';
|
||||
export { default as NotificationActionButton } from './NotificationActionButton.svelte';
|
||||
export { default as NotificationButton } from './NotificationButton.svelte';
|
||||
export { default as NotificationIcon } from './NotificationIcon.svelte';
|
||||
export { default as NotificationTextDetails } from './NotificationTextDetails.svelte';
|
|
@ -1,7 +1,7 @@
|
|||
import { withKnobs } from '@storybook/addon-knobs';
|
||||
import Component from './OrderedList.Story.svelte';
|
||||
|
||||
export default { title: 'Ordered List', decorators: [withKnobs] };
|
||||
export default { title: 'OrderedList', decorators: [withKnobs] };
|
||||
|
||||
export const Default = () => ({ Component });
|
||||
|
||||
|
|
|
@ -0,0 +1,24 @@
|
|||
<script>
|
||||
let className = undefined;
|
||||
export { className as class };
|
||||
export let vertical = false;
|
||||
export let style = undefined;
|
||||
|
||||
import { cx } from '../../lib';
|
||||
|
||||
const _class = cx('--progress', vertical && '--progress--vertical', '--skeleton', className);
|
||||
</script>
|
||||
|
||||
<ul on:click on:mouseover on:mouseenter on:mouseleave class={_class} {style}>
|
||||
{#each [0, 1, 2, 3] as item, i (item)}
|
||||
<li class={cx('--progress-step', '--progress-step--incomplete')}>
|
||||
<div class={cx('--progress-step-button', '--progress-step-button--unclickable')}>
|
||||
<svg>
|
||||
<path d="M 7, 7 m -7, 0 a 7,7 0 1,0 14,0 a 7,7 0 1,0 -14,0" />
|
||||
</svg>
|
||||
<p class={cx('--progress-label')} />
|
||||
<span class={cx('--progress-line')} />
|
||||
</div>
|
||||
</li>
|
||||
{/each}
|
||||
</ul>
|
|
@ -0,0 +1,51 @@
|
|||
<script>
|
||||
export let story = undefined;
|
||||
|
||||
import Layout from '../../internal/ui/Layout.svelte';
|
||||
import ProgressIndicator from './ProgressIndicator.svelte';
|
||||
import ProgressStep from './ProgressStep.svelte';
|
||||
import ProgressIndicatorSkeleton from './ProgressIndicator.Skeleton.svelte';
|
||||
</script>
|
||||
|
||||
<Layout>
|
||||
<div>
|
||||
{#if story === 'skeleton'}
|
||||
<ProgressIndicatorSkeleton {...$$props} />
|
||||
{:else if story === 'interactive'}
|
||||
<ProgressIndicator {...$$props}>
|
||||
<ProgressStep description="Step 1: Register a onChange event" let:props>
|
||||
<div {...props}>Click me</div>
|
||||
</ProgressStep>
|
||||
<ProgressStep
|
||||
label="Really long label"
|
||||
description="The progress indicator will listen for clicks on the steps" />
|
||||
<ProgressStep
|
||||
label="Tooltip and really long label"
|
||||
description="The progress indicator will listen for clicks on the steps" />
|
||||
</ProgressIndicator>
|
||||
{:else}
|
||||
<ProgressIndicator {...$$props}>
|
||||
<ProgressStep
|
||||
label="First step"
|
||||
description="Step 1: Getting started with Carbon Design System"
|
||||
secondaryLabel="Optional label" />
|
||||
<ProgressStep
|
||||
label="Second step with tooltip"
|
||||
description="Step 2: Getting started with Carbon Design System"
|
||||
secondaryLabel="Optional label" />
|
||||
<ProgressStep
|
||||
label="Third step with tooltip"
|
||||
description="Step 3: Getting started with Carbon Design System" />
|
||||
<ProgressStep
|
||||
label="Fourth step"
|
||||
description="Step 4: Getting started with Carbon Design System"
|
||||
invalid
|
||||
secondaryLabel="Example invalid step" />
|
||||
<ProgressStep
|
||||
label="Fifth step"
|
||||
description="Step 5: Getting started with Carbon Design System"
|
||||
disabled />
|
||||
</ProgressIndicator>
|
||||
{/if}
|
||||
</div>
|
||||
</Layout>
|
|
@ -0,0 +1,29 @@
|
|||
import { withKnobs, boolean, text, number } from '@storybook/addon-knobs';
|
||||
import Component from './ProgressIndicator.Story.svelte';
|
||||
|
||||
export default { title: 'ProgressIndicator', decorators: [withKnobs] };
|
||||
|
||||
export const Default = () => ({
|
||||
Component,
|
||||
props: {
|
||||
currentIndex: number('Current progress (currentIndex)', 1),
|
||||
vertical: boolean('Vertical orientation (vertical)', false)
|
||||
}
|
||||
});
|
||||
|
||||
export const Interactive = () => ({
|
||||
Component,
|
||||
props: {
|
||||
story: 'interactive',
|
||||
currentIndex: number('Current progress (currentIndex)', 1),
|
||||
vertical: boolean('Vertical orientation (vertical)', false)
|
||||
}
|
||||
});
|
||||
|
||||
export const Skeleton = () => ({
|
||||
Component,
|
||||
props: {
|
||||
story: 'skeleton',
|
||||
vertical: boolean('Vertical orientation (vertical)', false)
|
||||
}
|
||||
});
|
39
src/components/ProgressIndicator/ProgressIndicator.svelte
Normal file
39
src/components/ProgressIndicator/ProgressIndicator.svelte
Normal file
|
@ -0,0 +1,39 @@
|
|||
<script>
|
||||
let className = undefined;
|
||||
export { className as class };
|
||||
export let currentIndex = 0;
|
||||
export let vertical = false;
|
||||
export let style = undefined;
|
||||
|
||||
import { createEventDispatcher, setContext } from 'svelte';
|
||||
import { writable, derived } from 'svelte/store';
|
||||
import { cx } from '../../lib';
|
||||
|
||||
const dispatch = createEventDispatcher();
|
||||
const _class = cx('--progress', vertical && '--progress--vertical', className);
|
||||
let steps = writable([]);
|
||||
let stepsById = derived(steps, $steps => $steps.reduce((a, c) => ({ ...a, [c.id]: c }), {}));
|
||||
|
||||
setContext('ProgressIndicator', {
|
||||
steps,
|
||||
stepsById,
|
||||
add: step => {
|
||||
steps.update(_ => [
|
||||
..._,
|
||||
{
|
||||
...step,
|
||||
index: _.length,
|
||||
current: _.length === currentIndex,
|
||||
complete: _.length <= currentIndex
|
||||
}
|
||||
]);
|
||||
},
|
||||
change: index => {
|
||||
dispatch('change', index);
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<ul on:click on:mouseover on:mouseenter on:mouseleave class={_class} {style}>
|
||||
<slot />
|
||||
</ul>
|
82
src/components/ProgressIndicator/ProgressStep.svelte
Normal file
82
src/components/ProgressIndicator/ProgressStep.svelte
Normal file
|
@ -0,0 +1,82 @@
|
|||
<script>
|
||||
let className = undefined;
|
||||
export { className as class };
|
||||
export let label = '';
|
||||
export let current = false;
|
||||
export let complete = false;
|
||||
export let description = '';
|
||||
export let invalid = false;
|
||||
export let secondaryLabel = '';
|
||||
export let disabled = false;
|
||||
export let style = undefined;
|
||||
|
||||
import { createEventDispatcher, getContext } from 'svelte';
|
||||
import Warning16 from 'carbon-icons-svelte/lib/Warning16';
|
||||
import CheckmarkOutline16 from 'carbon-icons-svelte/lib/CheckmarkOutline16';
|
||||
import { cx } from '../../lib';
|
||||
|
||||
const dispatch = createEventDispatcher();
|
||||
const id = Math.random();
|
||||
const { stepsById, add, change } = getContext('ProgressIndicator');
|
||||
|
||||
add({ id, disabled });
|
||||
|
||||
$: step = $stepsById[id];
|
||||
$: {
|
||||
current = step.current;
|
||||
complete = step.complete;
|
||||
}
|
||||
$: _class = cx(
|
||||
'--progress-step',
|
||||
current && '--progress-step--current',
|
||||
complete && '--progress-step--complete',
|
||||
!complete && !current && '--progress-step--incomplete',
|
||||
disabled && '--progress-step--disabled',
|
||||
className
|
||||
);
|
||||
$: _buttonClass = cx('--progress-step-button', current && '--progress-step-button--unclickable');
|
||||
</script>
|
||||
|
||||
<li aria-disabled={disabled} class={_class} {style}>
|
||||
<div
|
||||
role="button"
|
||||
class={_buttonClass}
|
||||
tabindex={current ? '-1' : '0'}
|
||||
on:click={() => {
|
||||
change(step.index);
|
||||
}}
|
||||
on:mouseover
|
||||
on:mouseenter
|
||||
on:mouseleave
|
||||
on:keydown
|
||||
on:keydown={event => {
|
||||
if (event.key === ' ' || event.key === 'Enter') {
|
||||
change(step.index);
|
||||
}
|
||||
}}>
|
||||
{#if invalid}
|
||||
<Warning16 class={cx('--progress__warning')} />
|
||||
{:else if current}
|
||||
<svg>
|
||||
<path d="M 7, 7 m -7, 0 a 7,7 0 1,0 14,0 a 7,7 0 1,0 -14,0" />
|
||||
<title>{description}</title>
|
||||
</svg>
|
||||
{:else if complete}
|
||||
<CheckmarkOutline16 title={description} />
|
||||
{:else}
|
||||
<svg>
|
||||
<title>{description}</title>
|
||||
<path
|
||||
d="M8 1C4.1 1 1 4.1 1 8s3.1 7 7 7 7-3.1 7-7-3.1-7-7-7zm0 13c-3.3 0-6-2.7-6-6s2.7-6 6-6 6
|
||||
2.7 6 6-2.7 6-6 6z" />
|
||||
</svg>
|
||||
{/if}
|
||||
<slot props={{ class: cx('--progress-label') }}>
|
||||
<p class={cx('--progress-label')}>{label}</p>
|
||||
</slot>
|
||||
{#if secondaryLabel}
|
||||
<p class={cx('--progress-optional')}>{secondaryLabel}</p>
|
||||
{/if}
|
||||
<span class={cx('--progress-line')} />
|
||||
</div>
|
||||
</li>
|
5
src/components/ProgressIndicator/index.js
Normal file
5
src/components/ProgressIndicator/index.js
Normal file
|
@ -0,0 +1,5 @@
|
|||
import ProgressIndicator from './ProgressIndicator.svelte';
|
||||
|
||||
export default ProgressIndicator;
|
||||
export { default as ProgressIndicatorSkeleton } from './ProgressIndicator.Skeleton.svelte';
|
||||
export { default as ProgressStep } from './ProgressStep.svelte';
|
|
@ -1,14 +1,14 @@
|
|||
<script>
|
||||
let className = undefined;
|
||||
export { className as class };
|
||||
export let props = {};
|
||||
export let style = undefined;
|
||||
|
||||
import { cx } from '../../lib';
|
||||
|
||||
const _class = cx('--radio-button-wrapper', className);
|
||||
</script>
|
||||
|
||||
<div {...props} class={_class}>
|
||||
<div on:click on:mouseover on:mouseenter on:mouseleave class={_class} {style}>
|
||||
<div class={cx('--radio-button', '--skeleton')} />
|
||||
<span class={cx('--radio-button__label', '--skeleton')} />
|
||||
</div>
|
||||
|
|
|
@ -8,11 +8,8 @@
|
|||
</script>
|
||||
|
||||
<Layout>
|
||||
|
||||
{#if story === 'skeleton'}
|
||||
<div>
|
||||
<RadioButtonSkeleton />
|
||||
</div>
|
||||
<RadioButtonSkeleton />
|
||||
{:else}
|
||||
<RadioButton {...$$props} id="radio-1" />
|
||||
{/if}
|
||||
|
|
|
@ -9,26 +9,38 @@
|
|||
export let hideLabel = false;
|
||||
export let labelPosition = 'right';
|
||||
export let name = '';
|
||||
export let props = {};
|
||||
export let style = undefined;
|
||||
|
||||
import { getContext } from 'svelte';
|
||||
import { writable } from 'svelte/store';
|
||||
import { cx } from '../../lib';
|
||||
|
||||
const ctx = getContext('RadioButtonGroup');
|
||||
const _class = cx(
|
||||
'--radio-button-wrapper',
|
||||
labelPosition !== 'right' && `--radio-button-wrapper--label-${labelPosition}`,
|
||||
className
|
||||
);
|
||||
const _innerLabelClass = cx(hideLabel && '--visually-hidden');
|
||||
|
||||
let selected = ctx ? ctx.selected : writable(checked ? value : undefined);
|
||||
|
||||
if (ctx) {
|
||||
ctx.add({ id, checked, disabled, value });
|
||||
}
|
||||
|
||||
$: checked = $selected === value;
|
||||
</script>
|
||||
|
||||
<div class={_class}>
|
||||
<div class={_class} {style}>
|
||||
<input
|
||||
{...props}
|
||||
type="radio"
|
||||
class={cx('--radio-button')}
|
||||
on:change
|
||||
on:change={event => {
|
||||
value = event.target.value;
|
||||
on:change={() => {
|
||||
if (ctx) {
|
||||
ctx.update(value);
|
||||
}
|
||||
}}
|
||||
{id}
|
||||
{name}
|
||||
|
|
|
@ -0,0 +1,16 @@
|
|||
<script>
|
||||
import Layout from '../../internal/ui/Layout.svelte';
|
||||
import RadioButtonGroup from './RadioButtonGroup.svelte';
|
||||
import RadioButton from '../RadioButton';
|
||||
import { FormGroup } from '../Form';
|
||||
</script>
|
||||
|
||||
<Layout>
|
||||
<FormGroup legendText="Radio Button heading">
|
||||
<RadioButtonGroup {...$$props.group} defaultSelected="default-selected" legend="Group Legend">
|
||||
<RadioButton {...$$props.radio} value="standard" id="radio-1" />
|
||||
<RadioButton {...$$props.radio} value="default-selected" id="radio-2" />
|
||||
<RadioButton {...$$props.radio} value="disabled" id="radio-3" />
|
||||
</RadioButtonGroup>
|
||||
</FormGroup>
|
||||
</Layout>
|
40
src/components/RadioButtonGroup/RadioButtonGroup.stories.js
Normal file
40
src/components/RadioButtonGroup/RadioButtonGroup.stories.js
Normal file
|
@ -0,0 +1,40 @@
|
|||
import { withKnobs, text, select, boolean } from '@storybook/addon-knobs';
|
||||
import Component from './RadioButtonGroup.Story.svelte';
|
||||
|
||||
export default { title: 'RadioButtonGroup', decorators: [withKnobs] };
|
||||
|
||||
const values = {
|
||||
standard: 'standard',
|
||||
'default-selected': 'default-selected',
|
||||
disabled: 'disabled'
|
||||
};
|
||||
|
||||
const orientations = {
|
||||
'Horizontal (horizontal)': 'horizontal',
|
||||
'Vertical (vertical)': 'vertical'
|
||||
};
|
||||
|
||||
const labelPositions = {
|
||||
'Left (left)': 'left',
|
||||
'Right (right)': 'right'
|
||||
};
|
||||
|
||||
export const Default = () => ({
|
||||
Component,
|
||||
props: {
|
||||
group: {
|
||||
name: text('The form control name (name in <RadioButtonGroup>)', 'radio-button-group'),
|
||||
valueSelected: select(
|
||||
'Value of the selected button (valueSelected in <RadioButtonGroup>)',
|
||||
values,
|
||||
'default-selected'
|
||||
),
|
||||
orientation: select('Radio button orientation (orientation)', orientations, 'horizontal'),
|
||||
labelPosition: select('Label position (labelPosition)', labelPositions, 'right')
|
||||
},
|
||||
radio: {
|
||||
disabled: boolean('Disabled (disabled in <RadioButton>)', false),
|
||||
labelText: text('Label text (labelText in <RadioButton>)', 'Radio button label')
|
||||
}
|
||||
}
|
||||
});
|
46
src/components/RadioButtonGroup/RadioButtonGroup.svelte
Normal file
46
src/components/RadioButtonGroup/RadioButtonGroup.svelte
Normal file
|
@ -0,0 +1,46 @@
|
|||
<script>
|
||||
let className = undefined;
|
||||
export { className as class };
|
||||
export let orientation = 'horizontal';
|
||||
export let labelPosition = 'right';
|
||||
export let defaultSelected = undefined;
|
||||
export let disabled = false;
|
||||
export let style = undefined;
|
||||
|
||||
import { createEventDispatcher, setContext } from 'svelte';
|
||||
import { writable } from 'svelte/store';
|
||||
import { cx } from '../../lib';
|
||||
|
||||
const dispatch = createEventDispatcher();
|
||||
const _class = cx(
|
||||
'--radio-button-group',
|
||||
orientation === 'vertical' && `--radio-button-group--${orientation}`,
|
||||
labelPosition && `--radio-button-group--label-${labelPosition}`,
|
||||
className
|
||||
);
|
||||
|
||||
let selected = writable(defaultSelected);
|
||||
|
||||
setContext('RadioButtonGroup', {
|
||||
selected,
|
||||
add: ({ checked, value }) => {
|
||||
if (checked) {
|
||||
selected.set(value);
|
||||
}
|
||||
},
|
||||
update: value => {
|
||||
selected.set(value);
|
||||
}
|
||||
});
|
||||
|
||||
$: {
|
||||
defaultSelected = $selected;
|
||||
dispatch('change', $selected);
|
||||
}
|
||||
</script>
|
||||
|
||||
<div on:click on:mouseover on:mouseenter on:mouseleave class={cx('--form-item')} {style}>
|
||||
<div class={_class} {disabled}>
|
||||
<slot />
|
||||
</div>
|
||||
</div>
|
3
src/components/RadioButtonGroup/index.js
Normal file
3
src/components/RadioButtonGroup/index.js
Normal file
|
@ -0,0 +1,3 @@
|
|||
import RadioButtonGroup from './RadioButtonGroup.svelte';
|
||||
|
||||
export default RadioButtonGroup;
|
19
src/components/Select/Select.Skeleton.svelte
Normal file
19
src/components/Select/Select.Skeleton.svelte
Normal file
|
@ -0,0 +1,19 @@
|
|||
<script>
|
||||
let className = undefined;
|
||||
export { className as class };
|
||||
export let hideLabel = false;
|
||||
export let style = undefined;
|
||||
|
||||
import { cx } from '../../lib';
|
||||
|
||||
const _class = cx('--form-item', className);
|
||||
</script>
|
||||
|
||||
<div on:click on:mouseover on:mouseenter on:mouseleave class={_class} {style}>
|
||||
{#if !hideLabel}
|
||||
<span class={cx('--label', '--skeleton')} />
|
||||
{/if}
|
||||
<div class={cx('--select', '--skeleton')}>
|
||||
<div class={cx('--select-input')} />
|
||||
</div>
|
||||
</div>
|
29
src/components/Select/Select.Story.svelte
Normal file
29
src/components/Select/Select.Story.svelte
Normal file
|
@ -0,0 +1,29 @@
|
|||
<script>
|
||||
export let story = undefined;
|
||||
|
||||
import Layout from '../../internal/ui/Layout.svelte';
|
||||
import Select from './Select.svelte';
|
||||
import SelectItem from './SelectItem.svelte';
|
||||
import SelectSkeleton from './Select.Skeleton.svelte';
|
||||
import SelectItemGroup from './SelectItemGroup.svelte';
|
||||
</script>
|
||||
|
||||
<Layout>
|
||||
<div>
|
||||
{#if story === 'skeleton'}
|
||||
<SelectSkeleton {...$$props} />
|
||||
{:else}
|
||||
<Select {...$$props.select} id="select-1" defaultValue="placeholder-item">
|
||||
<SelectItem value="placeholder-item" text="Choose an option" disabled hidden />
|
||||
<SelectItemGroup {...$$props.group} label="Category 1">
|
||||
<SelectItem value="option-1" text="Option 1" />
|
||||
<SelectItem value="option-2" text="Option 2" />
|
||||
</SelectItemGroup>
|
||||
<SelectItemGroup {...$$props.group} label="Category 2">
|
||||
<SelectItem value="option-3" text="Option 3" />
|
||||
<SelectItem value="option-4" text="Option 4" />
|
||||
</SelectItemGroup>
|
||||
</Select>
|
||||
{/if}
|
||||
</div>
|
||||
</Layout>
|
36
src/components/Select/Select.stories.js
Normal file
36
src/components/Select/Select.stories.js
Normal file
|
@ -0,0 +1,36 @@
|
|||
import { withKnobs, text, boolean } from '@storybook/addon-knobs';
|
||||
import Component from './Select.Story.svelte';
|
||||
|
||||
export default { title: 'Select', decorators: [withKnobs] };
|
||||
|
||||
const labelPositions = {
|
||||
'Left (left)': 'left',
|
||||
'Right (right)': 'right'
|
||||
};
|
||||
|
||||
export const Default = () => ({
|
||||
Component,
|
||||
props: {
|
||||
select: {
|
||||
light: boolean('Light variant (light in <Select>)', false),
|
||||
inline: boolean('Put control in-line with label (inline in <Select>)', false),
|
||||
disabled: boolean('Disabled (disabled in <Select>)', false),
|
||||
hideLabel: boolean('No label (hideLabel in <Select>)', false),
|
||||
invalid: boolean('Show form validation UI (invalid in <Select>)', false),
|
||||
invalidText: text(
|
||||
'Form validation UI content (invalidText in <Select>)',
|
||||
'A valid value is required'
|
||||
),
|
||||
labelText: text('Label text (helperText)', 'Select'),
|
||||
helperText: text('Helper text (helperText)', 'Optional helper text.')
|
||||
},
|
||||
group: {
|
||||
disabled: boolean('Disabled (disabled in <SelectItemGroup>)', false)
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
export const Skeleton = () => ({
|
||||
Component,
|
||||
props: { story: 'skeleton', hideLabel: boolean('No label (hideLabel in <Select>)', false) }
|
||||
});
|
110
src/components/Select/Select.svelte
Normal file
110
src/components/Select/Select.svelte
Normal file
|
@ -0,0 +1,110 @@
|
|||
<script>
|
||||
let className = undefined;
|
||||
export { className as class };
|
||||
export let id = Math.random();
|
||||
export let inline = false;
|
||||
export let labelText = '';
|
||||
export let disabled = false;
|
||||
export let defaultValue = undefined;
|
||||
export let hideLabel = false;
|
||||
export let invalid = false;
|
||||
export let invalidText = '';
|
||||
export let helperText = '';
|
||||
export let light = false;
|
||||
export let noLabel = false;
|
||||
export let style = undefined;
|
||||
|
||||
import { createEventDispatcher, setContext } from 'svelte';
|
||||
import { writable } from 'svelte/store';
|
||||
import ChevronDown16 from 'carbon-icons-svelte/lib/ChevronDown16';
|
||||
import WarningFilled16 from 'carbon-icons-svelte/lib/WarningFilled16';
|
||||
import { cx } from '../../lib';
|
||||
|
||||
const dispatch = createEventDispatcher();
|
||||
const errorId = `error-${id}`;
|
||||
const _class = cx(
|
||||
'--select',
|
||||
inline && '--select--inline',
|
||||
light && '--select--light',
|
||||
invalid && '--select--invalid',
|
||||
disabled && '--select--disabled',
|
||||
className
|
||||
);
|
||||
const _labelClass = cx(
|
||||
'--label',
|
||||
hideLabel && '--visually-hidden',
|
||||
disabled && '--label--disabled'
|
||||
);
|
||||
const _helperTextClass = cx('--form__helper-text', disabled && '--form__helper-text--disabled');
|
||||
|
||||
let selected = writable(defaultValue);
|
||||
|
||||
setContext('Select', { selected });
|
||||
|
||||
$: {
|
||||
defaultValue = $selected;
|
||||
dispatch('change', $selected);
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class={cx('--form-item')} {style}>
|
||||
<div class={_class}>
|
||||
{#if !noLabel}
|
||||
<label for={id} class={_labelClass}>{labelText}</label>
|
||||
{/if}
|
||||
{#if !inline && helperText}
|
||||
<div class={_helperTextClass}>{helperText}</div>
|
||||
{/if}
|
||||
{#if inline}
|
||||
<div class={cx('--select-input--inline__wrapper')}>
|
||||
<div class={cx('--select-input__wrapper')} data-invalid={invalid || undefined}>
|
||||
<select
|
||||
class={cx('--select-input')}
|
||||
aria-describedby={invalid ? errorId : undefined}
|
||||
disabled={disabled || undefined}
|
||||
aria-invalid={invalid || undefined}
|
||||
on:change={event => {
|
||||
selected.set(event.target.value);
|
||||
}}
|
||||
{id}>
|
||||
<slot />
|
||||
</select>
|
||||
<ChevronDown16 class={cx('--select__arrow')} />
|
||||
{#if invalid}
|
||||
<WarningFilled16 class={cx('--select__invalid-icon')} />
|
||||
{/if}
|
||||
</div>
|
||||
{#if invalid}
|
||||
<div class={cx('--form-requirement')} id={errorId}>{invalidText}</div>
|
||||
{/if}
|
||||
</div>
|
||||
{#if helperText}
|
||||
<div class={_helperTextClass}>{helperText}</div>
|
||||
{/if}
|
||||
{/if}
|
||||
|
||||
{#if !inline}
|
||||
<div class={cx('--select-input__wrapper')} data-invalid={invalid || undefined}>
|
||||
<select
|
||||
class={cx('--select-input')}
|
||||
aria-describedby={invalid ? errorId : undefined}
|
||||
disabled={disabled || undefined}
|
||||
aria-invalid={invalid || undefined}
|
||||
on:change
|
||||
on:change={event => {
|
||||
selected.set(event.target.value);
|
||||
}}
|
||||
{id}>
|
||||
<slot />
|
||||
</select>
|
||||
<ChevronDown16 class={cx('--select__arrow')} />
|
||||
{#if invalid}
|
||||
<WarningFilled16 class={cx('--select__invalid-icon')} />
|
||||
{/if}
|
||||
</div>
|
||||
{#if invalid}
|
||||
<div class={cx('--form-requirement')} id={errorId}>{invalidText}</div>
|
||||
{/if}
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
19
src/components/Select/SelectItem.svelte
Normal file
19
src/components/Select/SelectItem.svelte
Normal file
|
@ -0,0 +1,19 @@
|
|||
<script>
|
||||
let className = undefined;
|
||||
export { className as class };
|
||||
export let value = '';
|
||||
export let text = '';
|
||||
export let disabled = false;
|
||||
export let hidden = false;
|
||||
export let style = undefined;
|
||||
|
||||
import { getContext } from 'svelte';
|
||||
import { cx } from '../../lib';
|
||||
|
||||
const { selected } = getContext('Select');
|
||||
const _class = cx('--select-option', className);
|
||||
</script>
|
||||
|
||||
<option class={_class} {value} {disabled} {hidden} {style} selected={$selected === value}>
|
||||
{text}
|
||||
</option>
|
15
src/components/Select/SelectItemGroup.svelte
Normal file
15
src/components/Select/SelectItemGroup.svelte
Normal file
|
@ -0,0 +1,15 @@
|
|||
<script>
|
||||
let className = undefined;
|
||||
export { className as class };
|
||||
export let disabled = false;
|
||||
export let label = 'Provide label';
|
||||
export let style = undefined;
|
||||
|
||||
import { cx } from '../../lib';
|
||||
|
||||
const _class = cx('--select-optgroup', className);
|
||||
</script>
|
||||
|
||||
<optgroup class={_class} {label} {disabled} {style}>
|
||||
<slot />
|
||||
</optgroup>
|
6
src/components/Select/index.js
Normal file
6
src/components/Select/index.js
Normal file
|
@ -0,0 +1,6 @@
|
|||
import Select from './Select.svelte';
|
||||
|
||||
export default Select;
|
||||
export { default as SelectSkeleton } from './Select.Skeleton.svelte';
|
||||
export { default as SelectItem } from './SelectItem.svelte';
|
||||
export { default as SelectItemGroup } from './SelectItemGroup.svelte';
|
42
src/components/StructuredList/StructuredList.Skeleton.svelte
Normal file
42
src/components/StructuredList/StructuredList.Skeleton.svelte
Normal file
|
@ -0,0 +1,42 @@
|
|||
<script>
|
||||
let className = undefined;
|
||||
export { className as class };
|
||||
export let border = false;
|
||||
export let rowCount = 5;
|
||||
export let style = undefined;
|
||||
|
||||
import { cx } from '../../lib';
|
||||
|
||||
const _class = cx(
|
||||
'--skeleton',
|
||||
'--structured-list',
|
||||
border && '--structured-list--border',
|
||||
className
|
||||
);
|
||||
const rows = Array.from({ length: rowCount - 1 }, (_, i) => i);
|
||||
</script>
|
||||
|
||||
<section on:click on:mouseover on:mouseenter on:mouseleave class={_class} {style}>
|
||||
<div class={cx('--structured-list-thead')}>
|
||||
<div class={cx('--structured-list-row', '--structured-list-row--header-row')}>
|
||||
<div class={cx('--structured-list-th')}>
|
||||
<span />
|
||||
</div>
|
||||
<div class={cx('--structured-list-th')}>
|
||||
<span />
|
||||
</div>
|
||||
<div class={cx('--structured-list-th')}>
|
||||
<span />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class={cx('--structured-list-tbody')}>
|
||||
{#each rows as row, i (row)}
|
||||
<div class={cx('--structured-list-row')}>
|
||||
<div class={cx('--structured-list-td')} />
|
||||
<div class={cx('--structured-list-td')} />
|
||||
<div class={cx('--structured-list-td')} />
|
||||
</div>
|
||||
{/each}
|
||||
</div>
|
||||
</section>
|
90
src/components/StructuredList/StructuredList.Story.svelte
Normal file
90
src/components/StructuredList/StructuredList.Story.svelte
Normal file
|
@ -0,0 +1,90 @@
|
|||
<script>
|
||||
export let story = undefined;
|
||||
|
||||
import CheckmarkFilled16 from 'carbon-icons-svelte/lib/CheckmarkFilled16';
|
||||
import Layout from '../../internal/ui/Layout.svelte';
|
||||
import { cx } from '../../lib';
|
||||
import StructuredListBody from './StructuredListBody.svelte';
|
||||
import StructuredListCell from './StructuredListCell.svelte';
|
||||
import StructuredListHead from './StructuredListHead.svelte';
|
||||
import StructuredListInput from './StructuredListInput.svelte';
|
||||
import StructuredListRow from './StructuredListRow.svelte';
|
||||
import StructuredListWrapper from './StructuredListWrapper.svelte';
|
||||
import StructuredListSkeleton from './StructuredList.Skeleton.svelte';
|
||||
</script>
|
||||
|
||||
<Layout>
|
||||
<div>
|
||||
{#if story === 'skeleton'}
|
||||
<div style="width: 800px">
|
||||
<StructuredListSkeleton />
|
||||
<StructuredListSkeleton border />
|
||||
</div>
|
||||
{:else if story === 'selection'}
|
||||
<StructuredListWrapper selection border defaultSelected="row-1-value">
|
||||
<StructuredListHead>
|
||||
<StructuredListRow head>
|
||||
<StructuredListCell head>ColumnA</StructuredListCell>
|
||||
<StructuredListCell head>ColumnB</StructuredListCell>
|
||||
<StructuredListCell head>ColumnC</StructuredListCell>
|
||||
<StructuredListCell head>{''}</StructuredListCell>
|
||||
</StructuredListRow>
|
||||
</StructuredListHead>
|
||||
<StructuredListBody>
|
||||
{#each [0, 1, 2, 3] as item, i (item)}
|
||||
<StructuredListRow label for={`row-${i}`}>
|
||||
<StructuredListCell>Row {i}</StructuredListCell>
|
||||
<StructuredListCell>Row {i}</StructuredListCell>
|
||||
<StructuredListCell>
|
||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc dui magna, finibus id
|
||||
tortor sed, aliquet bibendum augue. Aenean posuere sem vel euismod dignissim. Nulla
|
||||
ut cursus dolor. Pellentesque vulputate nisl a porttitor interdum.
|
||||
</StructuredListCell>
|
||||
<StructuredListInput
|
||||
id={`row-${i}`}
|
||||
value={`row-${i}-value`}
|
||||
title={`row-${i}-title`}
|
||||
name={`row-${i}-name`} />
|
||||
<StructuredListCell>
|
||||
<CheckmarkFilled16
|
||||
class={cx('--structured-list-svg')}
|
||||
aria-label="select an option"
|
||||
title="select an option" />
|
||||
</StructuredListCell>
|
||||
</StructuredListRow>
|
||||
{/each}
|
||||
</StructuredListBody>
|
||||
</StructuredListWrapper>
|
||||
{:else}
|
||||
<StructuredListWrapper>
|
||||
<StructuredListHead>
|
||||
<StructuredListRow head>
|
||||
<StructuredListCell head>ColumnA</StructuredListCell>
|
||||
<StructuredListCell head>ColumnB</StructuredListCell>
|
||||
<StructuredListCell head>ColumnC</StructuredListCell>
|
||||
</StructuredListRow>
|
||||
</StructuredListHead>
|
||||
<StructuredListBody>
|
||||
<StructuredListRow>
|
||||
<StructuredListCell noWrap>Row 1</StructuredListCell>
|
||||
<StructuredListCell>Row 1</StructuredListCell>
|
||||
<StructuredListCell>
|
||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc dui magna, finibus id
|
||||
tortor sed, aliquet bibendum augue. Aenean posuere sem vel euismod dignissim. Nulla ut
|
||||
cursus dolor. Pellentesque vulputate nisl a porttitor interdum.
|
||||
</StructuredListCell>
|
||||
</StructuredListRow>
|
||||
<StructuredListRow>
|
||||
<StructuredListCell noWrap>Row 2</StructuredListCell>
|
||||
<StructuredListCell>Row 2</StructuredListCell>
|
||||
<StructuredListCell>
|
||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc dui magna, finibus id
|
||||
tortor sed, aliquet bibendum augue. Aenean posuere sem vel euismod dignissim. Nulla ut
|
||||
cursus dolor. Pellentesque vulputate nisl a porttitor interdum.
|
||||
</StructuredListCell>
|
||||
</StructuredListRow>
|
||||
</StructuredListBody>
|
||||
</StructuredListWrapper>
|
||||
{/if}
|
||||
</div>
|
||||
</Layout>
|
10
src/components/StructuredList/StructuredList.stories.js
Normal file
10
src/components/StructuredList/StructuredList.stories.js
Normal file
|
@ -0,0 +1,10 @@
|
|||
import { withKnobs, select, boolean, text } from '@storybook/addon-knobs';
|
||||
import Component from './StructuredList.Story.svelte';
|
||||
|
||||
export default { title: 'StructuredList', decorators: [withKnobs] };
|
||||
|
||||
export const Default = () => ({ Component });
|
||||
|
||||
export const Selection = () => ({ Component, props: { story: 'selection' } });
|
||||
|
||||
export const Skeleton = () => ({ Component, props: { story: 'skeleton' } });
|
13
src/components/StructuredList/StructuredListBody.svelte
Normal file
13
src/components/StructuredList/StructuredListBody.svelte
Normal file
|
@ -0,0 +1,13 @@
|
|||
<script>
|
||||
let className = undefined;
|
||||
export { className as class };
|
||||
export let style = undefined;
|
||||
|
||||
import { cx } from '../../lib';
|
||||
|
||||
const _class = cx('--structured-list-tbody', className);
|
||||
</script>
|
||||
|
||||
<div on:click on:mouseover on:mouseenter on:mouseleave class={_class} {style}>
|
||||
<slot />
|
||||
</div>
|
20
src/components/StructuredList/StructuredListCell.svelte
Normal file
20
src/components/StructuredList/StructuredListCell.svelte
Normal file
|
@ -0,0 +1,20 @@
|
|||
<script>
|
||||
let className = undefined;
|
||||
export { className as class };
|
||||
export let head = false;
|
||||
export let noWrap = false;
|
||||
export let style = undefined;
|
||||
|
||||
import { cx } from '../../lib';
|
||||
|
||||
const _class = cx(
|
||||
head && '--structured-list-th',
|
||||
!head && '--structured-list-td',
|
||||
noWrap && '--structured-list-content--nowrap',
|
||||
className
|
||||
);
|
||||
</script>
|
||||
|
||||
<div on:click on:mouseover on:mouseenter on:mouseleave class={_class} {style}>
|
||||
<slot />
|
||||
</div>
|
13
src/components/StructuredList/StructuredListHead.svelte
Normal file
13
src/components/StructuredList/StructuredListHead.svelte
Normal file
|
@ -0,0 +1,13 @@
|
|||
<script>
|
||||
let className = undefined;
|
||||
export { className as class };
|
||||
export let style = undefined;
|
||||
|
||||
import { cx } from '../../lib';
|
||||
|
||||
const _class = cx('--structured-list-thead', className);
|
||||
</script>
|
||||
|
||||
<div on:click on:mouseover on:mouseenter on:mouseleave class={_class} {style}>
|
||||
<slot />
|
||||
</div>
|
37
src/components/StructuredList/StructuredListInput.svelte
Normal file
37
src/components/StructuredList/StructuredListInput.svelte
Normal file
|
@ -0,0 +1,37 @@
|
|||
<script>
|
||||
let className = undefined;
|
||||
export { className as class };
|
||||
export let id = Math.random();
|
||||
export let value = 'value';
|
||||
export let title = 'title';
|
||||
export let name = '';
|
||||
export let checked = false;
|
||||
export let style = undefined;
|
||||
|
||||
import { getContext } from 'svelte';
|
||||
import { cx } from '../../lib';
|
||||
|
||||
const _class = cx('--structured-list-input', className);
|
||||
|
||||
const { selected, update } = getContext('StructuredListWrapper');
|
||||
|
||||
if (checked) {
|
||||
update(value);
|
||||
}
|
||||
|
||||
$: checked = $selected === value;
|
||||
</script>
|
||||
|
||||
<input
|
||||
type="radio"
|
||||
tabindex="-1"
|
||||
class={_class}
|
||||
on:change={() => {
|
||||
update(value);
|
||||
}}
|
||||
{value}
|
||||
{name}
|
||||
{title}
|
||||
{style}
|
||||
{id}
|
||||
{checked} />
|
36
src/components/StructuredList/StructuredListRow.svelte
Normal file
36
src/components/StructuredList/StructuredListRow.svelte
Normal file
|
@ -0,0 +1,36 @@
|
|||
<script>
|
||||
let className = undefined;
|
||||
export { className as class };
|
||||
export let head = false;
|
||||
export let label = false;
|
||||
export let tabindex = '0';
|
||||
export let style = undefined;
|
||||
|
||||
import { cx } from '../../lib';
|
||||
|
||||
const _class = cx(
|
||||
'--structured-list-row',
|
||||
head && '--structured-list-row--header-row',
|
||||
className
|
||||
);
|
||||
</script>
|
||||
|
||||
{#if label}
|
||||
<label
|
||||
role="presentation"
|
||||
on:click
|
||||
on:mouseover
|
||||
on:mouseenter
|
||||
on:mouseleave
|
||||
on:keydown
|
||||
class={_class}
|
||||
for={$$props.for}
|
||||
{tabindex}
|
||||
{style}>
|
||||
<slot />
|
||||
</label>
|
||||
{:else}
|
||||
<div on:click on:mouseover on:mouseenter on:mouseleave class={_class} {style}>
|
||||
<slot />
|
||||
</div>
|
||||
{/if}
|
45
src/components/StructuredList/StructuredListWrapper.svelte
Normal file
45
src/components/StructuredList/StructuredListWrapper.svelte
Normal file
|
@ -0,0 +1,45 @@
|
|||
<script>
|
||||
let className = undefined;
|
||||
export { className as class };
|
||||
export let defaultSelected = undefined;
|
||||
export let border = false;
|
||||
export let selection = false;
|
||||
export let style = undefined;
|
||||
|
||||
import { createEventDispatcher, setContext } from 'svelte';
|
||||
import { writable } from 'svelte/store';
|
||||
import { cx } from '../../lib';
|
||||
|
||||
const dispatch = createEventDispatcher();
|
||||
const _class = cx(
|
||||
'--structured-list',
|
||||
border && '--structured-list--border',
|
||||
selection && '--structured-list--selection',
|
||||
className
|
||||
);
|
||||
|
||||
let selected = writable(defaultSelected);
|
||||
|
||||
setContext('StructuredListWrapper', {
|
||||
selected,
|
||||
update: value => {
|
||||
selected.set(value);
|
||||
}
|
||||
});
|
||||
|
||||
$: {
|
||||
defaultSelected = $selected;
|
||||
dispatch('change', $selected);
|
||||
}
|
||||
</script>
|
||||
|
||||
<section
|
||||
on:click
|
||||
on:mouseover
|
||||
on:mouseenter
|
||||
on:mouseleave
|
||||
class={_class}
|
||||
aria-label={$$props['aria-label'] || 'Structured list section'}
|
||||
{style}>
|
||||
<slot />
|
||||
</section>
|
7
src/components/StructuredList/index.js
Normal file
7
src/components/StructuredList/index.js
Normal file
|
@ -0,0 +1,7 @@
|
|||
export { default as StructuredListSkeleton } from './StructuredList.Skeleton.svelte';
|
||||
export { default as StructuredListBody } from './StructuredListBody.svelte';
|
||||
export { default as StructuredListHead } from './StructuredListHead.svelte';
|
||||
export { default as StructuredListCell } from './StructuredListCell.svelte';
|
||||
export { default as StructuredListRow } from './StructuredListRow.svelte';
|
||||
export { default as StructuredListInput } from './StructuredListInput.svelte';
|
||||
export { default as StructuredListWrapper } from './StructuredListWrapper.svelte';
|
|
@ -16,17 +16,14 @@
|
|||
export let tooltipAlignment = 'center';
|
||||
export let hidePasswordLabel = 'Hide password';
|
||||
export let showPasswordLabel = 'Show password';
|
||||
export let props = {};
|
||||
export let style = undefined;
|
||||
|
||||
import { createEventDispatcher } from 'svelte';
|
||||
import WarningFilled16 from 'carbon-icons-svelte/lib/WarningFilled16';
|
||||
import View16 from 'carbon-icons-svelte/lib/View16';
|
||||
import ViewOff16 from 'carbon-icons-svelte/lib/ViewOff16';
|
||||
import { cx } from '../../lib';
|
||||
|
||||
const dispatch = createEventDispatcher();
|
||||
const errorId = `${id}-error`;
|
||||
const passwordIsVisible = type === 'text';
|
||||
const _labelClass = cx(
|
||||
'--label',
|
||||
hideLabel && '--visually-hidden',
|
||||
|
@ -48,13 +45,14 @@
|
|||
tooltipPosition && `--tooltip--${tooltipPosition}`,
|
||||
tooltipAlignment && `--tooltip--align-${tooltipAlignment}`
|
||||
);
|
||||
|
||||
$: passwordIsVisible = type === 'text';
|
||||
</script>
|
||||
|
||||
<div class={cx('--form-item', '--text-input-wrapper', '--password-input-wrapper')}>
|
||||
<div class={cx('--form-item', '--text-input-wrapper', '--password-input-wrapper')} {style}>
|
||||
{#if labelText}
|
||||
<label for={id} class={_labelClass}>{labelText}</label>
|
||||
{/if}
|
||||
|
||||
{#if helperText}
|
||||
<div class={_helperTextClass}>{helperText}</div>
|
||||
{/if}
|
||||
|
@ -63,23 +61,12 @@
|
|||
<WarningFilled16 class={cx('--text-input__invalid-icon')} />
|
||||
{/if}
|
||||
<input
|
||||
{...props}
|
||||
class={_textInputClass}
|
||||
on:click={event => {
|
||||
if (!disabled) {
|
||||
dispatch('click', event);
|
||||
}
|
||||
}}
|
||||
on:change={event => {
|
||||
if (!disabled) {
|
||||
dispatch('change', event);
|
||||
}
|
||||
}}
|
||||
on:click
|
||||
on:change
|
||||
on:input
|
||||
on:input={event => {
|
||||
value = event.target.value;
|
||||
if (!disabled) {
|
||||
dispatch('input', event);
|
||||
}
|
||||
}}
|
||||
data-invalid={invalid || undefined}
|
||||
aria-invalid={invalid || undefined}
|
||||
|
|
|
@ -2,14 +2,14 @@
|
|||
let className = undefined;
|
||||
export { className as class };
|
||||
export let hideLabel = false;
|
||||
export let props = {};
|
||||
export let style = undefined;
|
||||
|
||||
import { cx } from '../../lib';
|
||||
|
||||
const _class = cx('--form-item', className);
|
||||
</script>
|
||||
|
||||
<div {...props} class={_class}>
|
||||
<div on:click on:mouseover on:mouseenter on:mouseleave class={_class} {style}>
|
||||
{#if !hideLabel}
|
||||
<span class={cx('--label', '--skeleton')} />
|
||||
{/if}
|
||||
|
|
|
@ -36,6 +36,11 @@
|
|||
</button>
|
||||
</div>
|
||||
{:else}
|
||||
<TextInput {...$$props} bind:value />
|
||||
<TextInput
|
||||
{...$$props}
|
||||
bind:value
|
||||
on:change={() => {
|
||||
console.log('change');
|
||||
}} />
|
||||
{/if}
|
||||
</Layout>
|
||||
|
|
|
@ -12,13 +12,11 @@
|
|||
export let helperText = '';
|
||||
export let hideLabel = false;
|
||||
export let light = false;
|
||||
export let props = {};
|
||||
export let style = undefined;
|
||||
|
||||
import { createEventDispatcher } from 'svelte';
|
||||
import WarningFilled16 from 'carbon-icons-svelte/lib/WarningFilled16';
|
||||
import { cx } from '../../lib';
|
||||
|
||||
const dispatch = createEventDispatcher();
|
||||
const errorId = `${id}-error`;
|
||||
const _labelClass = cx(
|
||||
'--label',
|
||||
|
@ -34,7 +32,7 @@
|
|||
);
|
||||
</script>
|
||||
|
||||
<div class={cx('--form-item', '--text-input-wrapper')}>
|
||||
<div class={cx('--form-item', '--text-input-wrapper')} {style}>
|
||||
{#if labelText}
|
||||
<label for={id} class={_labelClass}>{labelText}</label>
|
||||
{/if}
|
||||
|
@ -46,23 +44,11 @@
|
|||
<WarningFilled16 class={cx('--text-input__invalid-icon')} />
|
||||
{/if}
|
||||
<input
|
||||
{...props}
|
||||
class={_textInputClass}
|
||||
on:click={event => {
|
||||
if (!disabled) {
|
||||
dispatch('click', event);
|
||||
}
|
||||
}}
|
||||
on:change={event => {
|
||||
if (!disabled) {
|
||||
dispatch('change', event);
|
||||
}
|
||||
}}
|
||||
on:click
|
||||
on:change
|
||||
on:input={event => {
|
||||
value = event.target.value;
|
||||
if (!disabled) {
|
||||
dispatch('input', event);
|
||||
}
|
||||
}}
|
||||
data-invalid={invalid || undefined}
|
||||
aria-invalid={invalid || undefined}
|
||||
|
|
|
@ -4,7 +4,5 @@
|
|||
</script>
|
||||
|
||||
<Layout>
|
||||
<div>
|
||||
<TooltipDefinition {...$$props}>Defintion Tooltip</TooltipDefinition>
|
||||
</div>
|
||||
<TooltipDefinition {...$$props}>Defintion Tooltip</TooltipDefinition>
|
||||
</Layout>
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
export let triggerClassName = undefined;
|
||||
export { triggerClassName as triggerClass };
|
||||
export let tooltipText = '';
|
||||
export let props = {};
|
||||
export let style = undefined;
|
||||
|
||||
import { cx } from '../../lib';
|
||||
|
||||
|
@ -22,7 +22,7 @@
|
|||
);
|
||||
</script>
|
||||
|
||||
<div {...props} class={_class}>
|
||||
<div class={_class} {style}>
|
||||
<button
|
||||
on:click
|
||||
on:mouseover
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
export let align = 'center';
|
||||
export let id = Math.random();
|
||||
export let tooltipText = '';
|
||||
export let props = {};
|
||||
export let style = undefined;
|
||||
|
||||
import { cx } from '../../lib';
|
||||
|
||||
|
@ -19,13 +19,13 @@
|
|||
</script>
|
||||
|
||||
<button
|
||||
{...props}
|
||||
on:click
|
||||
on:mouseover
|
||||
on:mouseenter
|
||||
on:mouseleave
|
||||
aria-describedby={id}
|
||||
class={_class}
|
||||
aria-describedby={id}>
|
||||
{style}>
|
||||
<span class={cx('--assistive-text')} {id}>{tooltipText}</span>
|
||||
<slot />
|
||||
</button>
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { withKnobs } from '@storybook/addon-knobs';
|
||||
import Component from './UnorderedList.Story.svelte';
|
||||
|
||||
export default { title: 'Unordered List', decorators: [withKnobs] };
|
||||
export default { title: 'UnorderedList', decorators: [withKnobs] };
|
||||
|
||||
export const Default = () => ({ Component });
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue