mirror of
https://github.com/carbon-design-system/carbon-components-svelte.git
synced 2025-09-15 10:21:05 +00:00
Alignment with Carbon version 10.32 (#588)
* feat(code-snippet): add copy functionality - docs: add custom feedback copy text example * feat(tile): support disabled state for SelectableTile, RadioTile Closes #539 * build(rollup): add clipboard-copy to globals * feat(copy-button): add copy functionality * feat(content-switcher): deprecate the light prop - docs: remove the light variant example * fix(toolbar-search): remove outer div * feat(search): add searchClass prop * fix(composed-modal): set hasScrollingContent class on ModalBody * docs(data-table): add expandable size examples * feat(tooltip): add TooltipFooter component * fix(time-picker): correctly display invalidText * feat(breadcrumb): support overflow menu * feat(multi-select): export inputRef prop * chore(deps-dev): upgrade carbon-components to v10.32.0 * feat(form): add noMargin prop to FormGroup * docs(tooltip): document TooltipFooter * feat(context-menu): support danger kind for ContextMenuOption * feat(data-table): support rendering empty table header in skeleton * refactor(types): use shorter import path in DataTableSkeleton * feat(data-table): allow sorting to be disabled for a specific header * docs(data-table): update example to desort the Protocol header As an example, it makes more sense because all the values ("http") are the same. * fix(context-menu): set initial y offset of context menu based on window height #577 * fix(context-menu): render submenu based on viewport constraints #577
This commit is contained in:
parent
f13e3b100e
commit
fa9b90cd79
61 changed files with 825 additions and 233 deletions
|
@ -13,6 +13,10 @@
|
|||
export let isCurrentPage = false;
|
||||
|
||||
import Link from "../Link/Link.svelte";
|
||||
|
||||
import { setContext } from "svelte";
|
||||
|
||||
setContext("BreadcrumbItem", {});
|
||||
</script>
|
||||
|
||||
<li
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
/**
|
||||
* Set the code snippet text
|
||||
* Alternatively, use the default slot (e.g., <CodeSnippet>{`code`}</CodeSnippet>)
|
||||
* You must use the `code` prop to copy the code
|
||||
* @type {string}
|
||||
*/
|
||||
export let code = undefined;
|
||||
|
@ -75,18 +76,26 @@
|
|||
/** Obtain a reference to the pre HTML element */
|
||||
export let ref = null;
|
||||
|
||||
import { tick } from "svelte";
|
||||
import { createEventDispatcher, tick } from "svelte";
|
||||
import copy from "clipboard-copy";
|
||||
import ChevronDown16 from "carbon-icons-svelte/lib/ChevronDown16/ChevronDown16.svelte";
|
||||
import Button from "../Button/Button.svelte";
|
||||
import Copy from "../Copy/Copy.svelte";
|
||||
import CopyButton from "../CopyButton/CopyButton.svelte";
|
||||
import CodeSnippetSkeleton from "./CodeSnippetSkeleton.svelte";
|
||||
|
||||
const dispatch = createEventDispatcher();
|
||||
|
||||
function setShowMoreLess() {
|
||||
const { height } = ref.getBoundingClientRect();
|
||||
if (height > 0) showMoreLess = ref.getBoundingClientRect().height > 255;
|
||||
}
|
||||
|
||||
function copyCode() {
|
||||
copy(code);
|
||||
dispatch("copy");
|
||||
}
|
||||
|
||||
$: expandText = expanded ? showLessText : showMoreText;
|
||||
$: if (type === "multi" && ref) {
|
||||
if (code === undefined) setShowMoreLess();
|
||||
|
@ -138,6 +147,7 @@
|
|||
{wrapText && 'bx--snippet--wraptext'}"
|
||||
{...$$restProps}
|
||||
on:click
|
||||
on:click="{copyCode}"
|
||||
on:mouseover
|
||||
on:mouseenter
|
||||
on:mouseleave
|
||||
|
@ -182,6 +192,7 @@
|
|||
feedbackTimeout="{feedbackTimeout}"
|
||||
iconDescription="{copyButtonDescription}"
|
||||
on:click
|
||||
on:click="{copyCode}"
|
||||
on:animationend
|
||||
/>
|
||||
{/if}
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
role="{hasScrollingContent ? 'region' : undefined}"
|
||||
class:bx--modal-content="{true}"
|
||||
class:bx--modal-content--with-form="{hasForm}"
|
||||
class:bx--modal-scroll-content="{hasScrollingContent}"
|
||||
{...$$restProps}
|
||||
>
|
||||
<slot />
|
||||
|
|
|
@ -6,7 +6,10 @@
|
|||
/** Set the selected index of the switch item */
|
||||
export let selectedIndex = 0;
|
||||
|
||||
/** Set to `true` to enable the light variant */
|
||||
/**
|
||||
* Set to `true` to enable the light variant
|
||||
* @deprecated
|
||||
*/
|
||||
export let light = false;
|
||||
|
||||
/**
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
const position = writable([x, y]);
|
||||
const currentIndex = writable(-1);
|
||||
const hasPopup = writable(false);
|
||||
const menuOffsetX = writable(0);
|
||||
const ctx = getContext("ContextMenu");
|
||||
|
||||
let options = [];
|
||||
|
@ -44,6 +45,7 @@
|
|||
}
|
||||
|
||||
setContext("ContextMenu", {
|
||||
menuOffsetX,
|
||||
currentIndex,
|
||||
position,
|
||||
close,
|
||||
|
@ -77,8 +79,26 @@
|
|||
<svelte:window
|
||||
on:contextmenu|preventDefault="{(e) => {
|
||||
if (level > 1) return;
|
||||
if (open || x === 0) x = e.x;
|
||||
if (open || y === 0) y = e.y;
|
||||
|
||||
const { height, width } = ref.getBoundingClientRect();
|
||||
|
||||
if (open || x === 0) {
|
||||
if (window.innerWidth - width < e.x) {
|
||||
x = e.x - width;
|
||||
} else {
|
||||
x = e.x;
|
||||
}
|
||||
}
|
||||
|
||||
if (open || y === 0) {
|
||||
menuOffsetX.set(e.x);
|
||||
|
||||
if (window.innerHeight - height < e.y) {
|
||||
y = e.y - height;
|
||||
} else {
|
||||
y = e.y;
|
||||
}
|
||||
}
|
||||
position.set([x, y]);
|
||||
open = true;
|
||||
}}"
|
||||
|
|
|
@ -1,4 +1,10 @@
|
|||
<script>
|
||||
/**
|
||||
* Specify the kind of option
|
||||
* @type {"default" | "danger"}
|
||||
*/
|
||||
export let kind = "default";
|
||||
|
||||
/** Set to `true` to enable the disabled state */
|
||||
export let disabled = false;
|
||||
|
||||
|
@ -64,11 +70,16 @@
|
|||
let role = "menuitem";
|
||||
let submenuOpen = false;
|
||||
let submenuPosition = [0, 0];
|
||||
let menuOffsetX = 0;
|
||||
|
||||
const unsubPosition = ctx.position.subscribe((position) => {
|
||||
rootMenuPosition = position;
|
||||
});
|
||||
|
||||
const unsubMenuOffsetX = ctx.menuOffsetX.subscribe((_menuOffsetX) => {
|
||||
menuOffsetX = _menuOffsetX;
|
||||
});
|
||||
|
||||
function handleClick(opts = {}) {
|
||||
if (disabled) return ctx.close();
|
||||
if (subOptions) return;
|
||||
|
@ -106,6 +117,7 @@
|
|||
|
||||
return () => {
|
||||
unsubPosition();
|
||||
unsubMenuOffsetX();
|
||||
if (unsubCurrentIds) unsubCurrentIds();
|
||||
if (unsubCurrentId) unsubCurrentId();
|
||||
if (typeof timeoutHover === "number") clearTimeout(timeoutHover);
|
||||
|
@ -118,7 +130,13 @@
|
|||
$: ctx.setPopup(submenuOpen);
|
||||
$: if (submenuOpen) {
|
||||
const { width, y } = ref.getBoundingClientRect();
|
||||
submenuPosition = [rootMenuPosition[0] + width, y];
|
||||
let x = rootMenuPosition[0] + width;
|
||||
|
||||
if (window.innerWidth - menuOffsetX < width) {
|
||||
x = rootMenuPosition[0] - width;
|
||||
}
|
||||
|
||||
submenuPosition = [x, y];
|
||||
}
|
||||
$: {
|
||||
if (isSelectable) {
|
||||
|
@ -158,6 +176,7 @@
|
|||
class:bx--context-menu-option="{true}"
|
||||
class:bx--context-menu-option--disabled="{true}"
|
||||
class:bx--context-menu-option--active="{subOptions && submenuOpen}"
|
||||
class:bx--context-menu-option--danger="{!subOptions && kind === 'danger'}"
|
||||
indented="{indented}"
|
||||
aria-checked="{isSelectable || isRadio ? selected : undefined}"
|
||||
data-nested="{ref &&
|
||||
|
|
|
@ -4,8 +4,18 @@
|
|||
/** Set the title and ARIA label for the copy button */
|
||||
export let iconDescription = "Copy to clipboard";
|
||||
|
||||
import { Copy } from "../Copy";
|
||||
import Copy16 from "carbon-icons-svelte/lib/Copy16";
|
||||
/**
|
||||
* Specify the text to copy
|
||||
* @type {string}
|
||||
*/
|
||||
export let text = undefined;
|
||||
|
||||
import Copy from "../Copy/Copy.svelte";
|
||||
import Copy16 from "carbon-icons-svelte/lib/Copy16/Copy16.svelte";
|
||||
import copy from "clipboard-copy";
|
||||
import { createEventDispatcher } from "svelte";
|
||||
|
||||
const dispatch = createEventDispatcher();
|
||||
</script>
|
||||
|
||||
<Copy
|
||||
|
@ -14,6 +24,12 @@
|
|||
title="{iconDescription}"
|
||||
{...$$restProps}
|
||||
on:click
|
||||
on:click="{() => {
|
||||
if (text !== undefined) {
|
||||
copy(text);
|
||||
dispatch('copy');
|
||||
}
|
||||
}}"
|
||||
on:animationend
|
||||
>
|
||||
<Copy16 class="bx--snippet__icon" />
|
||||
|
|
|
@ -2,8 +2,8 @@
|
|||
/**
|
||||
* @typedef {string} DataTableKey
|
||||
* @typedef {any} DataTableValue
|
||||
* @typedef {{ key: DataTableKey; empty: boolean; display?: (item: Value) => DataTableValue; sort?: (a: DataTableValue, b: DataTableValue) => (0 | -1 | 1); columnMenu?: boolean; }} DataTableEmptyHeader
|
||||
* @typedef {{ key: DataTableKey; value: DataTableValue; display?: (item: Value) => DataTableValue; sort?: (a: DataTableValue, b: DataTableValue) => (0 | -1 | 1); columnMenu?: boolean; }} DataTableNonEmptyHeader
|
||||
* @typedef {{ key: DataTableKey; empty: boolean; display?: (item: Value) => DataTableValue; sort?: false | ((a: DataTableValue, b: DataTableValue) => (0 | -1 | 1)); columnMenu?: boolean; }} DataTableEmptyHeader
|
||||
* @typedef {{ key: DataTableKey; value: DataTableValue; display?: (item: Value) => DataTableValue; sort?: false | ((a: DataTableValue, b: DataTableValue) => (0 | -1 | 1)); columnMenu?: boolean; }} DataTableNonEmptyHeader
|
||||
* @typedef {DataTableNonEmptyHeader | DataTableEmptyHeader} DataTableHeader
|
||||
* @typedef {{ id: any; [key: string]: DataTableValue; }} DataTableRow
|
||||
* @typedef {string} DataTableRowId
|
||||
|
@ -13,7 +13,7 @@
|
|||
* @slot {{ row: DataTableRow; cell: DataTableCell; }} cell
|
||||
* @event {{ header?: DataTableHeader; row?: DataTableRow; cell?: DataTableCell; }} click
|
||||
* @event {{ expanded: boolean; }} click:header--expand
|
||||
* @event {{ header: DataTableHeader; sortDirection: "ascending" | "descending" | "none" }} click:header
|
||||
* @event {{ header: DataTableHeader; sortDirection?: "ascending" | "descending" | "none" }} click:header
|
||||
* @event {DataTableRow} click:row
|
||||
* @event {DataTableRow} mouseenter:row
|
||||
* @event {DataTableRow} mouseleave:row
|
||||
|
@ -250,20 +250,26 @@
|
|||
<th scope="col"></th>
|
||||
{:else}
|
||||
<TableHeader
|
||||
disableSorting="{header.sort === false}"
|
||||
on:click="{() => {
|
||||
dispatch('click', { header });
|
||||
let active = header.key === $sortHeader.key;
|
||||
let currentSortDirection = active
|
||||
? $sortHeader.sortDirection
|
||||
: 'none';
|
||||
let sortDirection = sortDirectionMap[currentSortDirection];
|
||||
dispatch('click:header', { header, sortDirection });
|
||||
sortHeader.set({
|
||||
id: sortDirection === 'none' ? null : $thKeys[header.key],
|
||||
key: header.key,
|
||||
sort: header.sort,
|
||||
sortDirection,
|
||||
});
|
||||
|
||||
if (header.sort === false) {
|
||||
dispatch('click:header', { header });
|
||||
} else {
|
||||
let active = header.key === $sortHeader.key;
|
||||
let currentSortDirection = active
|
||||
? $sortHeader.sortDirection
|
||||
: 'none';
|
||||
let sortDirection = sortDirectionMap[currentSortDirection];
|
||||
dispatch('click:header', { header, sortDirection });
|
||||
sortHeader.set({
|
||||
id: sortDirection === 'none' ? null : $thKeys[header.key],
|
||||
key: header.key,
|
||||
sort: header.sort,
|
||||
sortDirection,
|
||||
});
|
||||
}
|
||||
}}"
|
||||
>
|
||||
<slot name="cell-header" header="{header}">{header.value}</slot>
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<script>
|
||||
/** @extends {"../DataTable/DataTable"} DataTableHeader */
|
||||
/** @extends {"./DataTable"} DataTableHeader */
|
||||
|
||||
/**
|
||||
* Specify the number of columns
|
||||
|
@ -77,7 +77,11 @@
|
|||
<thead>
|
||||
<tr>
|
||||
{#each cols as col (col)}
|
||||
<th>{values[col] || ""}</th>
|
||||
{#if typeof values[col] === "object" && values[col].empty === true}
|
||||
<th></th>
|
||||
{:else}
|
||||
<th>{values[col] || ""}</th>
|
||||
{/if}
|
||||
{/each}
|
||||
</tr>
|
||||
</thead>
|
||||
|
|
|
@ -1,4 +1,7 @@
|
|||
<script>
|
||||
/** Set to `true` to disable sorting on this specific cell */
|
||||
export let disableSorting = false;
|
||||
|
||||
/** Specify the `scope` attribute */
|
||||
export let scope = "col";
|
||||
|
||||
|
@ -12,8 +15,8 @@
|
|||
export let id = "ccs-" + Math.random().toString(36);
|
||||
|
||||
import { getContext } from "svelte";
|
||||
import ArrowUp20 from "carbon-icons-svelte/lib/ArrowUp20";
|
||||
import ArrowsVertical20 from "carbon-icons-svelte/lib/ArrowsVertical20";
|
||||
import ArrowUp20 from "carbon-icons-svelte/lib/ArrowUp20/ArrowUp20.svelte";
|
||||
import ArrowsVertical20 from "carbon-icons-svelte/lib/ArrowsVertical20/ArrowsVertical20.svelte";
|
||||
|
||||
const { sortHeader, tableSortable, add } = getContext("DataTable");
|
||||
|
||||
|
@ -24,7 +27,7 @@
|
|||
$: ariaLabel = translateWithId();
|
||||
</script>
|
||||
|
||||
{#if $tableSortable}
|
||||
{#if $tableSortable && !disableSorting}
|
||||
<th
|
||||
aria-sort="{active ? $sortHeader.sortDirection : 'none'}"
|
||||
scope="{scope}"
|
||||
|
|
|
@ -32,32 +32,33 @@
|
|||
await tick();
|
||||
ref.focus();
|
||||
}
|
||||
|
||||
$: classes = [
|
||||
expanded && "bx--toolbar-search-container-active",
|
||||
persistent
|
||||
? "bx--toolbar-search-container-persistent"
|
||||
: "bx--toolbar-search-container-expandable",
|
||||
disabled && "bx--toolbar-search-container-disabled",
|
||||
]
|
||||
.filter(Boolean)
|
||||
.join(" ");
|
||||
</script>
|
||||
|
||||
<div
|
||||
tabindex="{expanded || disabled ? '-1' : tabindex}"
|
||||
class:bx--toolbar-action="{true}"
|
||||
class:bx--toolbar-search-container-active="{expanded}"
|
||||
class:bx--toolbar-search-container-expandable="{!persistent}"
|
||||
class:bx--toolbar-search-container-persistent="{persistent}"
|
||||
class:bx--toolbar-search-container-disabled="{disabled}"
|
||||
on:click="{expandSearch}"
|
||||
<Search
|
||||
size="sm"
|
||||
tabindex="{tabindex}"
|
||||
disabled="{disabled}"
|
||||
{...$$restProps}
|
||||
searchClass="{classes} {$$restProps.class}"
|
||||
bind:ref
|
||||
bind:value
|
||||
on:clear
|
||||
on:change
|
||||
on:input
|
||||
on:focus
|
||||
on:focus="{expandSearch}"
|
||||
>
|
||||
<Search
|
||||
size="sm"
|
||||
tabindex="{expanded ? tabindex : '-1'}"
|
||||
disabled="{disabled}"
|
||||
{...$$restProps}
|
||||
bind:ref
|
||||
bind:value
|
||||
on:clear
|
||||
on:change
|
||||
on:input
|
||||
on:focus
|
||||
on:blur
|
||||
on:blur="{() => {
|
||||
expanded = !persistent && !!value.length;
|
||||
}}"
|
||||
/>
|
||||
</div>
|
||||
on:blur
|
||||
on:blur="{() => {
|
||||
expanded = !persistent && !!value.length;
|
||||
}}"
|
||||
/>
|
||||
|
|
|
@ -5,6 +5,9 @@
|
|||
/** Set to `true` to render a form requirement */
|
||||
export let message = false;
|
||||
|
||||
/** Set to `true` for to remove the bottom margin */
|
||||
export let noMargin = false;
|
||||
|
||||
/** Specify the message text */
|
||||
export let messageText = "";
|
||||
|
||||
|
@ -15,6 +18,7 @@
|
|||
<fieldset
|
||||
data-invalid="{invalid || undefined}"
|
||||
class:bx--fieldset="{true}"
|
||||
class:bx--fieldset--no-margin="{noMargin}"
|
||||
{...$$restProps}
|
||||
on:click
|
||||
on:mouseover
|
||||
|
|
|
@ -125,6 +125,9 @@
|
|||
*/
|
||||
export let name = undefined;
|
||||
|
||||
/** Obtain a reference to the input HTML element */
|
||||
export let inputRef = null;
|
||||
|
||||
import { afterUpdate, createEventDispatcher, setContext } from "svelte";
|
||||
import WarningFilled16 from "carbon-icons-svelte/lib/WarningFilled16/WarningFilled16.svelte";
|
||||
import WarningAltFilled16 from "carbon-icons-svelte/lib/WarningAltFilled16/WarningAltFilled16.svelte";
|
||||
|
@ -143,7 +146,7 @@
|
|||
let multiSelectRef = null;
|
||||
let fieldRef = null;
|
||||
let selectionRef = null;
|
||||
let inputRef = null;
|
||||
|
||||
let inputValue = "";
|
||||
let initialSorted = false;
|
||||
let highlightedIndex = -1;
|
||||
|
|
|
@ -54,11 +54,19 @@
|
|||
/** Obtain a reference to the overflow menu element */
|
||||
export let menuRef = null;
|
||||
|
||||
import { createEventDispatcher, setContext, afterUpdate } from "svelte";
|
||||
import {
|
||||
createEventDispatcher,
|
||||
getContext,
|
||||
setContext,
|
||||
afterUpdate,
|
||||
} from "svelte";
|
||||
import { writable } from "svelte/store";
|
||||
import OverflowMenuVertical16 from "carbon-icons-svelte/lib/OverflowMenuVertical16/OverflowMenuVertical16.svelte";
|
||||
import OverflowMenuHorizontal16 from "carbon-icons-svelte/lib/OverflowMenuHorizontal16/OverflowMenuHorizontal16.svelte";
|
||||
|
||||
import { formatStyle } from "./formatStyle";
|
||||
|
||||
const ctxBreadcrumbItem = getContext("BreadcrumbItem");
|
||||
const dispatch = createEventDispatcher();
|
||||
const items = writable([]);
|
||||
const currentId = writable(undefined);
|
||||
|
@ -68,6 +76,10 @@
|
|||
let buttonWidth = undefined;
|
||||
let onMountAfterUpdate = true;
|
||||
|
||||
$: if (ctxBreadcrumbItem) {
|
||||
icon = OverflowMenuHorizontal16;
|
||||
}
|
||||
|
||||
setContext("OverflowMenu", {
|
||||
focusedId,
|
||||
add: ({ id, text, primaryFocus }) => {
|
||||
|
@ -123,6 +135,11 @@
|
|||
} else if (direction === "bottom") {
|
||||
menuRef.style.top = height + "px";
|
||||
}
|
||||
|
||||
if (ctxBreadcrumbItem) {
|
||||
menuRef.style.top = height + 10 + "px";
|
||||
menuRef.style.left = -11 + "px";
|
||||
}
|
||||
}
|
||||
|
||||
if (!open) {
|
||||
|
@ -218,6 +235,7 @@
|
|||
class:bx--overflow-menu-options--light="{light}"
|
||||
class:bx--overflow-menu-options--sm="{size === 'sm'}"
|
||||
class:bx--overflow-menu-options--xl="{size === 'xl'}"
|
||||
class:bx--breadcrumb-menu-options="{!!ctxBreadcrumbItem}"
|
||||
class:menuOptionsClass
|
||||
>
|
||||
<slot />
|
||||
|
|
|
@ -12,6 +12,9 @@
|
|||
*/
|
||||
export let size = "xl";
|
||||
|
||||
/** Specify the class name passed to the outer div element */
|
||||
export let searchClass = "";
|
||||
|
||||
/**
|
||||
* Set to `true` to display the skeleton state
|
||||
* @type {boolean} [skeleton=false]
|
||||
|
@ -98,6 +101,7 @@
|
|||
class:bx--search--sm="{size === 'sm' || small}"
|
||||
class:bx--search--lg="{size === 'lg'}"
|
||||
class:bx--search--xl="{size === 'xl'}"
|
||||
class="{searchClass}"
|
||||
>
|
||||
<Search16 class="bx--search-magnifier" />
|
||||
<label id="{id}-search" for="{id}" class:bx--label="{true}"
|
||||
|
|
|
@ -5,6 +5,9 @@
|
|||
/** Set to `true` to enable the light variant */
|
||||
export let light = false;
|
||||
|
||||
/** Set to `true` to disable the tile */
|
||||
export let disabled = false;
|
||||
|
||||
/** Specify the value of the radio input */
|
||||
export let value = "";
|
||||
|
||||
|
@ -21,7 +24,7 @@
|
|||
export let name = "";
|
||||
|
||||
import { getContext } from "svelte";
|
||||
import CheckmarkFilled16 from "carbon-icons-svelte/lib/CheckmarkFilled16";
|
||||
import CheckmarkFilled16 from "carbon-icons-svelte/lib/CheckmarkFilled16/CheckmarkFilled16.svelte";
|
||||
|
||||
const { add, update, selectedValue } = getContext("TileGroup");
|
||||
|
||||
|
@ -36,14 +39,17 @@
|
|||
name="{name}"
|
||||
value="{value}"
|
||||
checked="{checked}"
|
||||
tabindex="{tabindex}"
|
||||
tabindex="{disabled ? undefined : tabindex}"
|
||||
disabled="{disabled}"
|
||||
class:bx--tile-input="{true}"
|
||||
on:change
|
||||
on:change="{() => {
|
||||
if (disabled) return;
|
||||
update(value);
|
||||
}}"
|
||||
on:keydown
|
||||
on:keydown="{(e) => {
|
||||
if (disabled) return;
|
||||
if (e.key === ' ' || e.key === 'Enter') {
|
||||
e.preventDefault();
|
||||
update(value);
|
||||
|
@ -56,6 +62,7 @@
|
|||
class:bx--tile--selectable="{true}"
|
||||
class:bx--tile--is-selected="{checked}"
|
||||
class:bx--tile--light="{light}"
|
||||
class:bx--tile--disabled="{disabled}"
|
||||
{...$$restProps}
|
||||
on:click
|
||||
on:mouseover
|
||||
|
|
|
@ -5,6 +5,9 @@
|
|||
/** Set to `true` to enable the light variant */
|
||||
export let light = false;
|
||||
|
||||
/** Set to `true` to disable the tile */
|
||||
export let disabled = false;
|
||||
|
||||
/** Specify the title of the selectable tile */
|
||||
export let title = "title";
|
||||
|
||||
|
@ -30,11 +33,11 @@
|
|||
export let ref = null;
|
||||
|
||||
import { createEventDispatcher } from "svelte";
|
||||
import CheckmarkFilled16 from "carbon-icons-svelte/lib/CheckmarkFilled16";
|
||||
import CheckmarkFilled16 from "carbon-icons-svelte/lib/CheckmarkFilled16/CheckmarkFilled16.svelte";
|
||||
|
||||
const dispatch = createEventDispatcher();
|
||||
|
||||
$: dispatch(selected ? "select" : "deselect", id);
|
||||
$: if (!disabled) dispatch(selected ? "select" : "deselect", id);
|
||||
</script>
|
||||
|
||||
<input
|
||||
|
@ -47,17 +50,20 @@
|
|||
value="{value}"
|
||||
name="{name}"
|
||||
title="{title}"
|
||||
disabled="{disabled}"
|
||||
/>
|
||||
<label
|
||||
for="{id}"
|
||||
tabindex="{tabindex}"
|
||||
tabindex="{disabled ? undefined : tabindex}"
|
||||
class:bx--tile="{true}"
|
||||
class:bx--tile--selectable="{true}"
|
||||
class:bx--tile--is-selected="{selected}"
|
||||
class:bx--tile--light="{light}"
|
||||
class:bx--tile--disabled="{disabled}"
|
||||
{...$$restProps}
|
||||
on:click
|
||||
on:click|preventDefault="{() => {
|
||||
if (disabled) return;
|
||||
selected = !selected;
|
||||
}}"
|
||||
on:mouseover
|
||||
|
@ -65,6 +71,7 @@
|
|||
on:mouseleave
|
||||
on:keydown
|
||||
on:keydown="{(e) => {
|
||||
if (disabled) return;
|
||||
if (e.key === ' ' || e.key === 'Enter') {
|
||||
e.preventDefault();
|
||||
selected = !selected;
|
||||
|
|
|
@ -67,6 +67,7 @@
|
|||
<div
|
||||
class:bx--time-picker="{true}"
|
||||
class:bx--time-picker--light="{light}"
|
||||
class:bx--time-picker--invalid="{invalid}"
|
||||
class:bx--time-picker--sm="{size === 'sm'}"
|
||||
class:bx--time-picker--xl="{size === 'xl'}"
|
||||
class:bx--select--light="{light}"
|
||||
|
|
|
@ -63,10 +63,14 @@
|
|||
/** Obtain a reference to the icon HTML element */
|
||||
export let refIcon = null;
|
||||
|
||||
import { createEventDispatcher, afterUpdate } from "svelte";
|
||||
import { createEventDispatcher, afterUpdate, setContext } from "svelte";
|
||||
import { writable } from "svelte/store";
|
||||
import Information16 from "carbon-icons-svelte/lib/Information16/Information16.svelte";
|
||||
|
||||
const dispatch = createEventDispatcher();
|
||||
const tooltipOpen = writable(open);
|
||||
|
||||
setContext("Tooltip", { tooltipOpen });
|
||||
|
||||
function onKeydown(e) {
|
||||
if (e.key === "Escape") {
|
||||
|
@ -143,6 +147,7 @@
|
|||
}
|
||||
});
|
||||
|
||||
$: tooltipOpen.set(open);
|
||||
$: dispatch(open ? "open" : "close");
|
||||
$: buttonProps = {
|
||||
role: "button",
|
||||
|
|
29
src/Tooltip/TooltipFooter.svelte
Normal file
29
src/Tooltip/TooltipFooter.svelte
Normal file
|
@ -0,0 +1,29 @@
|
|||
<script>
|
||||
/** Specify a selector to be focused inside the footer when opening the tooltip */
|
||||
export let selectorPrimaryFocus = "a[href], button:not([disabled])";
|
||||
|
||||
import { getContext, onMount } from "svelte";
|
||||
|
||||
let ref = null;
|
||||
let open = false;
|
||||
|
||||
const ctx = getContext("Tooltip");
|
||||
const unsubscribe = ctx.tooltipOpen.subscribe((tooltipOpen) => {
|
||||
open = tooltipOpen;
|
||||
});
|
||||
|
||||
onMount(() => {
|
||||
return () => {
|
||||
unsubscribe();
|
||||
};
|
||||
});
|
||||
|
||||
$: if (open && ref) {
|
||||
const node = ref.querySelector(selectorPrimaryFocus);
|
||||
if (node) node.focus();
|
||||
}
|
||||
</script>
|
||||
|
||||
<div bind:this="{ref}" class:bx--tooltip__footer="{true}">
|
||||
<slot />
|
||||
</div>
|
|
@ -1 +1,2 @@
|
|||
export { default as Tooltip } from "./Tooltip.svelte";
|
||||
export { default as TooltipFooter } from "./TooltipFooter.svelte";
|
||||
|
|
|
@ -121,7 +121,7 @@ export {
|
|||
export { TimePicker, TimePickerSelect } from "./TimePicker";
|
||||
export { Toggle, ToggleSkeleton } from "./Toggle";
|
||||
export { ToggleSmall, ToggleSmallSkeleton } from "./ToggleSmall";
|
||||
export { Tooltip } from "./Tooltip";
|
||||
export { Tooltip, TooltipFooter } from "./Tooltip";
|
||||
export { TooltipDefinition } from "./TooltipDefinition";
|
||||
export { TooltipIcon } from "./TooltipIcon";
|
||||
export { Truncate } from "./Truncate";
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue