Alignment with Carbon version 10.30 (#559)

* feat(toolbar): forward "clear" event in ToolbarSearch

* docs(search): add on:clear example

* fix(ui-shell): set aria-hidden in SideNav

Ref c2b4f1f00

* chore(deps-dev): upgrade carbon-components to v10.30.0

* fix(text-input): use bx--text-input class for TextInputSkeleton

* fix(radio-button): only render span if labelText is truthy

* docs(password-input): add custom tooltip example

* feat(button): add isSelected prop for icon-only, ghost buttons

* feat(radio-button): add legendText prop to RadioButtonGroup

* docs(tag): add filterable (disabled) variant

* feat(tag): add interactive prop

* chore(number-input): deprecate the mobile variant

Mobile variant styles will no longer work.

* feat(button): set aria-pressed attribute if icon-only, ghost button is selected

* fix(multi-select): type dispatched select event

* fix(button): remove redundant "button" role

* feat(icon): deprecate Icon, IconSkeleton

* feat(ui-shell): make SideNavMenuItem text slottable

* fix(list-box): update styles for ListBoxSelection

* fix(list-box): temporarily apply override styles to ListBoxMenuIcon for chevron

* fix(tag): set disabled prop on interactive tag

* docs(button): extract selected, icon-only button example

* feat(tooltip): elevate z-index of tooltip when open

* feat: forward restProps to input element

* fix(types): fix TimePicker test to pass svelte-check

* feat: add ImageLoader component

* test: add ImageLoader

* feat: add LocalStorage component

* test(local-storage): fix invalid file

* chore(docs): use green tag type
This commit is contained in:
Eric Liu 2021-03-13 14:53:37 -08:00 committed by GitHub
commit 1b234ca2e3
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
68 changed files with 1079 additions and 217 deletions

View file

@ -17,6 +17,11 @@
*/
export let size = "default";
/**
* Set to `true` to enable the selected state for an icon-only, ghost button
*/
export let isSelected = false;
/**
* Set to `true` for the icon-only variant
* @deprecated inferred using the $$slots API
@ -85,11 +90,11 @@
}
$: hasIconOnly = icon && !$$slots.default;
$: buttonProps = {
role: "button",
type: href && !disabled ? undefined : type,
tabindex,
disabled,
href,
"aria-pressed": hasIconOnly && kind === "ghost" ? isSelected : undefined,
...$$restProps,
class: [
"bx--btn",
@ -104,6 +109,7 @@
hasIconOnly &&
tooltipAlignment &&
`bx--tooltip--align-${tooltipAlignment}`,
hasIconOnly && isSelected && kind === "ghost" && "bx--btn--selected",
$$restProps.class,
]
.filter(Boolean)

View file

@ -160,7 +160,7 @@
}
}}" />
<div class:bx--list-box__wrapper="{true}" {...$$restProps}>
<div class:bx--list-box__wrapper="{true}">
{#if titleText}
<label
for="{id}"
@ -209,6 +209,11 @@
aria-disabled="{disabled}"
aria-controls="{open ? menuId : undefined}"
aria-owns="{open ? menuId : undefined}"
disabled="{disabled}"
placeholder="{placeholder}"
id="{id}"
value="{inputValue}"
{...$$restProps}
class:bx--text-input="{true}"
class:bx--text-input--light="{light}"
class:bx--text-input--empty="{inputValue === ''}"
@ -246,10 +251,6 @@
ref.focus();
}
}}"
disabled="{disabled}"
placeholder="{placeholder}"
id="{id}"
value="{inputValue}"
/>
{#if invalid}
<WarningFilled16 class="bx--list-box__invalid-icon" />

View file

@ -51,6 +51,7 @@
{...$$restProps}
bind:ref
bind:value
on:clear
on:change
on:input
on:focus

View file

@ -77,7 +77,6 @@
<div
class:bx--date-picker-container="{true}"
class:bx--date-picker--nolabel="{!labelText}"
{...$$restProps}
>
{#if labelText}
<label
@ -97,13 +96,14 @@
<input
bind:this="{ref}"
data-invalid="{invalid || undefined}"
value="{!$range ? $inputValue : undefined}"
id="{id}"
name="{name}"
placeholder="{placeholder}"
type="{type}"
pattern="{pattern}"
disabled="{disabled}"
{...$$restProps}
value="{!$range ? $inputValue : undefined}"
class:bx--date-picker__input="{true}"
class:bx--date-picker__input--invalid="{invalid}"
class="{size && `bx--date-picker__input--${size}`}"

View file

@ -1,4 +1,10 @@
<script>
/**
* @deprecated
* This component will be removed in version 1.0.0.
* Use icons from "carbon-icons-svelte" instead
*/
/**
* @extends {"./IconSkeleton"} IconSkeletonProps
* @restProps {svg}

View file

@ -1,4 +1,9 @@
<script>
/**
* @deprecated
* This component will be removed in version 1.0.0.
*/
/** Set the size of the icon */
export let size = 16;
</script>

View file

@ -0,0 +1,113 @@
<script>
/**
* @event {any} load
* @event {any} error
*/
/**
* Specify the image source
*/
export let src = "";
/**
* Specify the image alt text
*/
export let alt = "";
/**
* Specify the aspect ratio for the image wrapper
* @type {"2x1" | "16x9" | "4x3" | "1x1" | "3x4" | "9x16" | "1x2"}
*/
export let ratio = undefined;
/**
* Set to `true` when `loaded` is `true` and `error` is false
*/
export let loading = false;
/**
* Set to `true` when the image is loaded
*/
export let loaded = false;
/**
* Set to `true` if an error occurs when loading the image
*/
export let error = false;
/**
* Set to `true` to fade in the image on load
* The duration uses the `fast-02` value following Carbon guidelines on motion
*/
export let fadeIn = false;
/**
* Method invoked to load the image provided a `src` value
* @type {(url?: string) => void}
*/
export const loadImage = (url) => {
if (image != null) image = null;
loaded = false;
error = false;
image = new Image();
image.src = url || src;
image.onload = () => (loaded = true);
image.onerror = () => (error = true);
};
import { onMount, createEventDispatcher } from "svelte";
import { fade } from "svelte/transition";
import AspectRatio from "../AspectRatio/AspectRatio.svelte";
const dispatch = createEventDispatcher();
// "fast-02" duration (ms) from Carbon motion recommended for fading micro-interactions
const fast02 = 110;
let image = null;
$: loading = !loaded && !error;
$: if (src) loadImage();
$: if (loaded) dispatch("load");
$: if (error) dispatch("error");
onMount(() => {
return () => (image = null);
});
</script>
{#if ratio === undefined}
{#if loading}
<slot name="loading" />
{/if}
{#if loaded}
<img
{...$$restProps}
style="width: 100%;{$$restProps.style}"
src="{src}"
alt="{alt}"
transition:fade="{{ duration: fadeIn ? fast02 : 0 }}"
/>
{/if}
{#if error}
<slot name="error" />
{/if}
{:else}
<AspectRatio ratio="{ratio}">
{#if loading}
<slot name="loading" />
{/if}
{#if loaded}
<img
{...$$restProps}
style="width: 100%;{$$restProps.style}"
src="{src}"
alt="{alt}"
transition:fade="{{ duration: fadeIn ? fast02 : 0 }}"
/>
{/if}
{#if error}
<slot name="error" />
{/if}
</AspectRatio>
{/if}

1
src/ImageLoader/index.js Normal file
View file

@ -0,0 +1 @@
export { default as ImageLoader } from "./ImageLoader.svelte";

View file

@ -30,6 +30,7 @@
class:bx--list-box__menu-icon--open="{open}"
{...$$restProps}
on:click|preventDefault
style="top: 0; bottom: 0; margin: auto;"
>
<ChevronDown16 aria-label="{description}" title="{description}" />
</div>

View file

@ -5,7 +5,7 @@
/**
* Specify the number of selected items
* @type {any}
* @type {number}
*/
export let selectionCount = undefined;
@ -46,27 +46,61 @@
: translateWithId("clearSelection");
</script>
<div
bind:this="{ref}"
role="button"
aria-label="Clear Selection"
tabindex="{disabled ? '-1' : '0'}"
title="{description}"
class:bx--list-box__selection="{true}"
class:bx--tag--filter="{selectionCount}"
class:bx--list-box__selection--multi="{selectionCount}"
{...$$restProps}
on:click|preventDefault|stopPropagation="{(e) => {
if (!disabled) {
dispatch('clear', e);
}
}}"
on:keydown|stopPropagation="{(e) => {
if (!disabled && e.key === 'Enter') {
dispatch('clear', e);
}
}}"
>
{#if selectionCount}{selectionCount}{/if}
<Close16 />
</div>
{#if selectionCount !== undefined}
<div
class:bx--tag="{true}"
class:bx--tag--filter="{true}"
class:bx--tag--high-contrast="{true}"
class:bx--tag--disabled="{disabled}"
>
<span class:bx--tag__label="{true}" title="{selectionCount}">
{selectionCount}
</span>
<div
bind:this="{ref}"
role="button"
tabIndex="{disabled ? -1 : 0}"
class:bx--tag__close-icon="{true}"
on:click|preventDefault|stopPropagation="{(e) => {
if (!disabled) {
dispatch('clear', e);
}
}}"
on:keydown|stopPropagation="{(e) => {
if (!disabled && e.key === 'Enter') {
dispatch('clear', e);
}
}}"
disabled="{disabled}"
aria-label="{translationIds.clearAll}"
title="{description}"
>
<Close16 />
</div>
</div>
{:else}
<div
bind:this="{ref}"
role="button"
aria-label="{description}"
title="{description}"
tabindex="{disabled ? '-1' : '0'}"
class:bx--list-box__selection="{true}"
class:bx--tag--filter="{selectionCount}"
class:bx--list-box__selection--multi="{selectionCount}"
{...$$restProps}
on:click|preventDefault|stopPropagation="{(e) => {
if (!disabled) {
dispatch('clear', e);
}
}}"
on:keydown|stopPropagation="{(e) => {
if (!disabled && e.key === 'Enter') {
dispatch('clear', e);
}
}}"
>
{#if selectionCount !== undefined}{selectionCount}{/if}
<Close16 />
</div>
{/if}

View file

@ -0,0 +1,55 @@
<script>
/**
* @event {any} save
* @event {{ prevValue: any; value: any; }} update
*/
/**
* Specify the local storage key
*/
export let key = "local-storage-key";
/**
* Provide a value to persist
* @type {any}
*/
export let value = "";
import { onMount, afterUpdate, createEventDispatcher } from "svelte";
const dispatch = createEventDispatcher();
let prevValue = value;
function setItem() {
if (typeof value === "object") {
localStorage.setItem(key, JSON.stringify(value));
} else {
localStorage.setItem(key, value);
}
}
onMount(() => {
const item = localStorage.getItem(key);
if (item != null) {
try {
value = JSON.parse(item);
} catch (e) {
value = item;
}
} else {
setItem(value);
dispatch("save");
}
});
afterUpdate(() => {
if (prevValue !== value) {
setItem(value);
dispatch("update", { prevValue, value });
}
prevValue = value;
});
</script>

View file

@ -0,0 +1 @@
export { default as LocalStorage } from "./LocalStorage.svelte";

View file

@ -121,6 +121,7 @@
* @typedef {string} MultiSelectItemId
* @typedef {string} MultiSelectItemText
* @typedef {{ id: MultiSelectItemId; text: MultiSelectItemText; }} MultiSelectItem
* @event {{ selectedIds: string[]; selected: MultiSelectItem[]; unselected: MultiSelectItem[]; }} select
*/
import { afterUpdate, createEventDispatcher, setContext } from "svelte";
@ -236,7 +237,6 @@
class:bx--multi-select__wrapper--inline="{inline}"
class:bx--list-box__wrapper--inline="{inline}"
class:bx--multi-select__wrapper--inline--invalid="{inline && invalid}"
{...$$restProps}
>
{#if titleText}
<label
@ -347,6 +347,7 @@
{#if filterable}
<input
bind:this="{inputRef}"
{...$$restProps}
role="combobox"
tabindex="0"
autocomplete="off"

View file

@ -37,7 +37,10 @@
/** Set to `true` for the input to be read-only */
export let readonly = false;
/** Set to `true` to enable the mobile variant */
/**
* Set to `true` to enable the mobile variant
* @deprecated
*/
export let mobile = false;
/** Set to `true` to allow for an empty value */
@ -141,7 +144,6 @@
<div
class:bx--form-item="{true}"
{...$$restProps}
on:click
on:mouseover
on:mouseenter
@ -192,10 +194,6 @@
type="number"
pattern="[0-9]*"
aria-label="{label ? undefined : ariaLabel}"
on:input
on:input="{({ target }) => {
inputValue = target.value;
}}"
disabled="{disabled}"
id="{id}"
name="{name}"
@ -204,6 +202,11 @@
step="{step}"
value="{value}"
readonly="{readonly}"
{...$$restProps}
on:input
on:input="{({ target }) => {
inputValue = target.value;
}}"
/>
<button
type="button"
@ -244,10 +247,6 @@
data-invalid="{invalid || undefined}"
aria-invalid="{invalid || undefined}"
aria-label="{label ? undefined : ariaLabel}"
on:input
on:input="{({ target }) => {
inputValue = target.value;
}}"
disabled="{disabled}"
id="{id}"
max="{max}"
@ -255,6 +254,11 @@
step="{step}"
value="{value}"
readonly="{readonly}"
{...$$restProps}
on:input
on:input="{({ target }) => {
inputValue = target.value;
}}"
/>
{#if invalid}
<WarningFilled16 class="bx--number__invalid" />

View file

@ -67,6 +67,8 @@
/>
<label class:bx--radio-button__label="{true}" for="{id}">
<span class:bx--radio-button__appearance="{true}"></span>
<span class:bx--visually-hidden="{hideLabel}">{labelText}</span>
{#if labelText}
<span class:bx--visually-hidden="{hideLabel}">{labelText}</span>
{/if}
</label>
</div>

View file

@ -8,6 +8,9 @@
/** Set to `true` to disable the radio buttons */
export let disabled = false;
/** Specify the legend text */
export let legendText = "";
/**
* Specify the label position
* @type {"right" | "left"}
@ -72,12 +75,18 @@
on:mouseenter
on:mouseleave
>
<div
<fieldset
class:bx--radio-button-group="{true}"
class:bx--radio-button-group--vertical="{orientation === 'vertical'}"
class="{labelPosition && `bx--radio-button-group--label-${labelPosition}`}"
class:bx--radio-button-group--label-left="{labelPosition === 'left'}"
class:bx--radio-button-group--label-right="{labelPosition === 'right'}"
disabled="{disabled}"
>
{#if legendText || $$slots.legendText}
<legend class:bx--label="{true}">
<slot name="legendText">{legendText}</slot>
</legend>
{/if}
<slot />
</div>
</fieldset>
</div>

View file

@ -98,7 +98,6 @@
class:bx--search--sm="{size === 'sm' || small}"
class:bx--search--lg="{size === 'lg'}"
class:bx--search--xl="{size === 'xl'}"
{...$$restProps}
>
<Search16 class="bx--search-magnifier" />
<label id="{id}-search" for="{id}" class:bx--label="{true}"
@ -116,7 +115,7 @@
placeholder="{placeholder}"
type="{type}"
value="{value}"
aria-hidden="{$$props['aria-hidden']}"
{...$$restProps}
on:change
on:input
on:input="{({ target }) => {

View file

@ -16,6 +16,9 @@
/** Set to `true` to disable a filterable tag */
export let disabled = false;
/** Set to `true` to render a `button` element instead of a `div` */
export let interactive = false;
/** Set to `true` to display the skeleton state */
export let skeleton = false;
@ -31,11 +34,10 @@
/** Set an id for the filterable tag */
export let id = "ccs-" + Math.random().toString(36);
import { createEventDispatcher } from "svelte";
import Close16 from "carbon-icons-svelte/lib/Close16/Close16.svelte";
import TagSkeleton from "./TagSkeleton.svelte";
import { createEventDispatcher } from "svelte";
const dispatch = createEventDispatcher();
</script>
@ -88,6 +90,42 @@
<Close16 />
</button>
</div>
{:else if interactive}
<button
id="{id}"
disabled="{disabled}"
aria-disabled="{disabled}"
tabindex="{disabled ? '-1' : undefined}"
class:bx--tag="{true}"
class:bx--tag--interactive="{true}"
class:bx--tag--disabled="{disabled}"
class:bx--tag--sm="{size === 'sm'}"
class:bx--tag--red="{type === 'red'}"
class:bx--tag--magenta="{type === 'magenta'}"
class:bx--tag--purple="{type === 'purple'}"
class:bx--tag--blue="{type === 'blue'}"
class:bx--tag--cyan="{type === 'cyan'}"
class:bx--tag--teal="{type === 'teal'}"
class:bx--tag--green="{type === 'green'}"
class:bx--tag--gray="{type === 'gray'}"
class:bx--tag--cool-gray="{type === 'cool-gray'}"
class:bx--tag--warm-gray="{type === 'warm-gray'}"
class:bx--tag--high-contrast="{type === 'high-contrast'}"
{...$$restProps}
on:click
on:mouseover
on:mouseenter
on:mouseleave
>
{#if icon}
<div class:bx--tag__custom-icon="{true}">
<svelte:component this="{icon}" />
</div>
{/if}
<span>
<slot />
</span>
</button>
{:else}
<div
id="{id}"

View file

@ -14,5 +14,5 @@
{#if !hideLabel}
<span class:bx--label="{true}" class:bx--skeleton="{true}"></span>
{/if}
<div class:bx--skeleton="{true}" class:bx--text-area="{true}"></div>
<div class:bx--skeleton="{true}" class:bx--text-input="{true}"></div>
</div>

View file

@ -59,7 +59,6 @@
<div
class:bx--form-item="{true}"
{...$$restProps}
on:click
on:mouseover
on:mouseenter
@ -94,6 +93,7 @@
type="{type}"
value="{value}"
disabled="{disabled}"
{...$$restProps}
class:bx--time-picker__input-field="{true}"
class:bx--text-input="{true}"
class:bx--text-input--light="{light}"

View file

@ -171,7 +171,10 @@
}
}}" />
<div {...$$restProps} style="{$$restProps.style}; position: relative;">
<div
{...$$restProps}
style="{open ? 'z-index: 1;' : ''}{$$restProps.style}; position: relative;"
>
{#if !hideIcon}
<div bind:this="{ref}" id="{triggerId}" class:bx--tooltip__label="{true}">
<slot name="triggerText">{triggerText}</slot>

View file

@ -30,6 +30,7 @@
></div>
{/if}
<nav
aria-hidden="{!isOpen}"
aria-label="{ariaLabel}"
class:bx--side-nav__navigation="{true}"
class:bx--side-nav="{true}"

View file

@ -30,6 +30,6 @@
{...$$restProps}
on:click
>
<span class:bx--side-nav__link-text="{true}">{text}</span>
<span class:bx--side-nav__link-text="{true}"><slot>{text}</slot></span>
</a>
</li>

View file

@ -48,6 +48,7 @@ export { FormItem } from "./FormItem";
export { FormLabel } from "./FormLabel";
export { Grid, Row, Column } from "./Grid";
export { Icon, IconSkeleton } from "./Icon";
export { ImageLoader } from "./ImageLoader";
export { InlineLoading } from "./InlineLoading";
export { Link, OutboundLink } from "./Link";
export {
@ -60,6 +61,7 @@ export {
} from "./ListBox";
export { ListItem } from "./ListItem";
export { Loading } from "./Loading";
export { LocalStorage } from "./LocalStorage";
export { MultiSelect } from "./MultiSelect";
export { Modal } from "./Modal";
export {