Merge pull request #46 from metonym/tile

feat(tile): complete RadioTile, forward events
This commit is contained in:
Eric Liu 2019-12-20 09:12:44 -08:00 committed by GitHub
commit 8f1271088f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 153 additions and 102 deletions

View file

@ -43,6 +43,16 @@ Currently, the following components are supported:
- TextInput
- TextInputSkeleton
- PasswordInput
- Tile
- ClickableTile
- SelectableTile
- ExpandableTile
- TileAboveTheFoldContent
- TileBelowTheFoldContent
- RadioTile
- Tile
- TileGroup
- RadioTile
- Toggle
- ToggleSkeleton
- ToggleSmall

View file

@ -5,28 +5,10 @@
export let rel = undefined;
export let light = false;
export let clicked = false;
export let props = {};
export let style = undefined;
import { createEventDispatcher, tick } from 'svelte';
import { cx } from '../../lib';
const dispatch = createEventDispatcher();
async function handleClick(event) {
clicked = !clicked;
await tick();
dispatch('click', event);
}
async function handleKeyDown(event) {
if (event.key === ' ' || event.key === 'Enter') {
clicked = !clicked;
await tick();
}
dispatch('keydown', event);
}
$: _class = cx(
'--link',
'--tile',
@ -37,6 +19,23 @@
);
</script>
<a {...props} class={_class} on:click={handleClick} on:keydown={handleKeyDown} {href} {rel}>
<a
class={_class}
on:click
on:click={() => {
clicked = !clicked;
}}
on:keydown
on:keydown={event => {
if (event.key === ' ' || event.key === 'Enter') {
clicked = !clicked;
}
}}
on:mouseover
on:mouseenter
on:mouseleave
{style}
{href}
{rel}>
<slot />
</a>

View file

@ -7,9 +7,9 @@
export let tileExpandedIconText = 'Interact to collapse Tile';
export let tileMaxHeight = 0;
export let tilePadding = 0;
export let tabIndex = 0;
export let tabindex = '0';
export let light = false;
export let props = {};
export let style = undefined;
import { createEventDispatcher, tick, onMount } from 'svelte';
import ChevronDown16 from 'carbon-icons-svelte/lib/ChevronDown16';
@ -63,14 +63,19 @@
</script>
<div
{...props}
bind:this={tile}
style={tileStyle}
class={_class}
on:click
on:click={handleClick}
on:keypress
on:keypress={handleKeyPress}
tabindex={tabIndex}
{id}>
on:mouseover
on:mouseenter
on:mouseleave
{tabindex}
{id}
{style}>
<div bind:this={tileContent}>
<div bind:this={aboveTheFold} class={cx('--tile-content')}>
<slot name="above" />

View file

@ -1,5 +1,4 @@
<script>
// TODO: compose as "children" components
let className = undefined;
export { className as class };
export let checked = false;
@ -7,29 +6,19 @@
export let name = '';
export let iconDescription = 'Tile checkmark';
export let value = '';
export let tabIndex = 0;
export let tabindex = '0';
export let light = false;
export let props = {};
export let style = undefined;
import { createEventDispatcher } from 'svelte';
import { getContext } from 'svelte';
import CheckmarkFilled16 from 'carbon-icons-svelte/lib/CheckmarkFilled16';
import { cx } from '../../lib';
const dispatch = createEventDispatcher();
const { addTile, updateSelected, selected } = getContext('TileGroup');
function handleChange(event) {
dispatch('change', event);
}
function handleKeyDown(event) {
if (event.key === ' ' || event.key === 'Enter') {
event.preventDefault();
handleChange(event);
}
dispatch('keydown', event);
}
addTile({ id, value, checked });
$: checked = value === $selected.value;
$: _class = cx(
'--tile',
'--tile--selectable',
@ -40,16 +29,32 @@
</script>
<input
{...props}
type="radio"
class={cx('--tile-input')}
on:change
on:change={handleChange}
on:change={() => {
updateSelected({ id, value });
}}
{id}
{name}
{value}
{checked} />
<label for={id} class={_class} tabindex={tabIndex} on:keydown={handleKeyDown}>
<label
for={id}
class={_class}
on:click
on:mouseover
on:mouseenter
on:mouseleave
on:keydown
on:keydown={event => {
if (event.key === ' ' || event.key === 'Enter') {
event.preventDefault();
updateSelected({ id, value });
}
}}
{tabindex}
{style}>
<span class={cx('--tile__checkmark')}>
<CheckmarkFilled16 aria-label={iconDescription} title={iconDescription} />
</span>

View file

@ -1,5 +1,4 @@
<script>
// TODO: emit current selected tile
let className = undefined;
export { className as class };
export let selected = false;
@ -8,40 +7,19 @@
export let title = 'title';
export let name = '';
export let iconDescription = 'Tile checkmark';
export let tabIndex = 0;
export let tabindex = '0';
export let light = false;
export let props = {};
export let style = undefined;
import { createEventDispatcher, tick } from 'svelte';
import { createEventDispatcher } from 'svelte';
import CheckmarkFilled16 from 'carbon-icons-svelte/lib/CheckmarkFilled16';
import { cx } from '../../lib';
let input = undefined;
const dispatch = createEventDispatcher();
function handleChange(event) {
dispatch('change', event);
$: if (selected) {
dispatch('select', id);
}
async function handleClick(event) {
if (event.target !== input) {
selected = !selected;
await tick();
}
dispatch('click', event);
}
async function handleKeyDown(event) {
if (event.key === ' ' || event.key === 'Enter') {
event.preventDefault();
selected = !selected;
await tick();
}
dispatch('keydown', event);
}
$: _class = cx(
'--tile',
'--tile--selectable',
@ -52,23 +30,34 @@
</script>
<input
bind:this={input}
type="checkbox"
tabindex={-1}
tabindex="-1"
class={cx('--tile-input')}
on:change={handleChange}
on:change
checked={selected}
{id}
{value}
{name}
{title} />
<label
{...props}
for={id}
class={_class}
tabindex={tabIndex}
on:click|preventDefault={handleClick}
on:keydown={handleKeyDown}>
on:click
on:click|preventDefault={() => {
selected = !selected;
}}
on:mouseover
on:mouseenter
on:mouseleave
on:keydown
on:keydown={event => {
if (event.key === ' ' || event.key === 'Enter') {
event.preventDefault();
selected = !selected;
}
}}
{tabindex}
{style}>
<span class={cx('--tile__checkmark')}>
<CheckmarkFilled16 aria-label={iconDescription} title={iconDescription} />
</span>

View file

@ -17,7 +17,7 @@
{ value: 'selected', id: 'tile-3', labelText: 'Selectable Tile' }
];
let selected = radioTiles[1].value;
let defaultSelected = radioTiles[1];
</script>
<Layout>
@ -28,24 +28,14 @@
<ClickableTile {...$$props}>Clickable Tile</ClickableTile>
{:else if story === 'multi-select'}
<div role="group" aria-label="selectable tiles">
<SelectableTile id="tile-1" name="tiles" {...$$props}>Multi-select Tile</SelectableTile>
<SelectableTile id="tile-2" name="tiles" {...$$props}>Multi-select Tile</SelectableTile>
<SelectableTile id="tile-3" name="tiles" {...$$props}>Multi-select Tile</SelectableTile>
<SelectableTile {...$$props} id="tile-1" name="tiles">Multi-select Tile</SelectableTile>
<SelectableTile {...$$props} id="tile-2" name="tiles">Multi-select Tile</SelectableTile>
<SelectableTile {...$$props} id="tile-3" name="tiles">Multi-select Tile</SelectableTile>
</div>
{:else if story === 'selectable'}
<TileGroup legend="Selectable Tile Group">
<TileGroup legend="Selectable Tile Group" bind:defaultSelected>
{#each radioTiles as { value, id, labelText }, i (id)}
<RadioTile
{...$$props}
checked={selected === value}
on:change={() => {
selected = value;
}}
{value}
{id}
{labelText}>
Selectable Tile
</RadioTile>
<RadioTile {...$$props} {value} {id} {labelText}>Selectable Tile</RadioTile>
{/each}
</TileGroup>
{:else if story === 'expandable'}

View file

@ -2,13 +2,13 @@
let className = undefined;
export { className as class };
export let light = false;
export let props = {};
export let style = undefined;
import { cx } from '../../lib';
$: _class = cx('--tile', light && '--tile--light', className);
const _class = cx('--tile', light && '--tile--light', className);
</script>
<div class={_class} {...props}>
<div on:click on:mouseover on:mouseenter on:mouseleave class={_class} {style}>
<slot />
</div>

View file

@ -1,7 +1,14 @@
<script>
import { cx } from '../../lib';
export let style = undefined;
</script>
<span class={cx('--tile-content__above-the-fold')}>
<span
on:click
on:mouseover
on:mouseenter
on:mouseleave
class={cx('--tile-content__above-the-fold')}
{style}>
<slot />
</span>

View file

@ -1,7 +1,14 @@
<script>
import { cx } from '../../lib';
export let style = undefined;
</script>
<span class={cx('--tile-content__below-the-fold')}>
<span
on:click
on:mouseover
on:mouseenter
on:mouseleave
class={cx('--tile-content__below-the-fold')}
{style}>
<slot />
</span>

View file

@ -1,15 +1,54 @@
<script>
let className = undefined;
export { className as class };
export let defaultSelected = { value: undefined };
export let disabled = false;
export let legend = '';
export let style = undefined;
import { createEventDispatcher, setContext } from 'svelte';
import { writable } from 'svelte/store';
import { cx } from '../../lib';
$: _class = cx('--tile-group', className);
const dispatch = createEventDispatcher();
let tiles = [];
let selected = writable(defaultSelected);
setContext('TileGroup', {
selected,
addTile: tile => {
tiles = [...tiles, tile];
},
updateSelected: tile => {
selected.set(tile);
}
});
$: {
const checkedTiles = tiles.filter(tile => tile.checked);
if (checkedTiles.length > 1) {
console.warn('Multiple RadioTiles cannot be checked.');
if (defaultSelected.value) {
console.warn('Using `defaultSelected`:', defaultSelected);
} else {
console.warn('Using `RadioTile`:', checkedTiles[0]);
selected.set(checkedTiles[0]);
}
} else if (checkedTiles.length === 1) {
selected.set(checkedTiles[0]);
tiles = [];
}
defaultSelected = $selected;
dispatch('select', $selected);
}
const _class = cx('--tile-group', className);
</script>
<fieldset class={_class} {disabled}>
<fieldset class={_class} {disabled} {style}>
{#if legend}
<legend>{legend}</legend>
{/if}