feat: docker compose maybe

This commit is contained in:
2023-11-13 16:10:04 -05:00
parent 180b261e40
commit b625ccd8d6
8031 changed files with 2182966 additions and 0 deletions

View File

@ -0,0 +1,49 @@
<script context="module">import { slide } from "svelte/transition";
import { prefersReducedMotionStore } from "../../index.js";
</script>
<script generics="TransitionIn extends Transition = SlideTransition, TransitionOut extends Transition = SlideTransition">import { writable } from "svelte/store";
import { setContext } from "svelte";
export let autocollapse = false;
export let width = "w-full";
export let spacing = "space-y-1";
export let disabled = false;
export let padding = "py-2 px-4";
export let hover = "hover:bg-primary-hover-token";
export let rounded = "rounded-container-token";
export let caretOpen = "rotate-180";
export let caretClosed = "";
export let regionControl = "";
export let regionPanel = "space-y-4";
export let regionCaret = "";
export let transitions = !$prefersReducedMotionStore;
export let transitionIn = slide;
export let transitionInParams = { duration: 200 };
export let transitionOut = slide;
export let transitionOutParams = { duration: 200 };
const active = writable(null);
setContext("active", active);
setContext("autocollapse", autocollapse);
setContext("disabled", disabled);
setContext("padding", padding);
setContext("hover", hover);
setContext("rounded", rounded);
setContext("caretOpen", caretOpen);
setContext("caretClosed", caretClosed);
setContext("regionControl", regionControl);
setContext("regionPanel", regionPanel);
setContext("regionCaret", regionCaret);
setContext("transitions", transitions);
setContext("transitionIn", transitionIn);
setContext("transitionInParams", transitionInParams);
setContext("transitionOut", transitionOut);
setContext("transitionOutParams", transitionOutParams);
$:
classesBase = `${width} ${spacing} ${$$props.class ?? ""}`;
</script>
<!-- @component The Accordion parent element. -->
<div class="accordion {classesBase}" data-testid="accordion">
<slot />
</div>

View File

@ -0,0 +1,56 @@
import { SvelteComponentTyped } from "svelte";
import { slide } from 'svelte/transition';
import { type Transition, type TransitionParams } from '../../index.js';
type SlideTransition = typeof slide;
declare class __sveltets_Render<TransitionIn extends Transition = SlideTransition, TransitionOut extends Transition = SlideTransition> {
props(): {
[x: string]: any;
/** Set the auto-collapse mode.*/
autocollapse?: boolean | undefined;
/** Provide classes to set the accordion width.*/
width?: string | undefined;
/** Provide classes to set the vertical spacing between items.*/
spacing?: string | undefined;
/** Set the accordion disabled state for all items.*/
disabled?: boolean | undefined;
/** Provide classes to set the accordion item padding styles.*/
padding?: string | undefined;
/** Provide classes to set the accordion item hover styles.*/
hover?: string | undefined;
/** Provide classes to set the accordion item rounded styles.*/
rounded?: string | undefined;
/** Set the rotation of the item caret in the open state.*/
caretOpen?: string | undefined;
/** Set the rotation of the item caret in the closed state.*/
caretClosed?: string | undefined;
/** Provide arbitrary classes to the trigger button region.*/
regionControl?: string | undefined;
/** Provide arbitrary classes to the content panel region.*/
regionPanel?: string | undefined;
/** Provide arbitrary classes to the caret icon region.*/
regionCaret?: string | undefined;
/** Enable/Disable transitions*/
transitions?: boolean | undefined;
/** Provide the transition to used on entry.*/
transitionIn?: TransitionIn | undefined;
/** Transition params provided to `transitionIn`.*/
transitionInParams?: TransitionParams<TransitionIn> | undefined;
/** Provide the transition to used on exit.*/
transitionOut?: TransitionOut | undefined;
/** Transition params provided to `transitionOut`.*/
transitionOutParams?: TransitionParams<TransitionOut> | undefined;
};
events(): {} & {
[evt: string]: CustomEvent<any>;
};
slots(): {
default: {};
};
}
export type AccordionProps<TransitionIn extends Transition = SlideTransition, TransitionOut extends Transition = SlideTransition> = ReturnType<__sveltets_Render<TransitionIn, TransitionOut>['props']>;
export type AccordionEvents<TransitionIn extends Transition = SlideTransition, TransitionOut extends Transition = SlideTransition> = ReturnType<__sveltets_Render<TransitionIn, TransitionOut>['events']>;
export type AccordionSlots<TransitionIn extends Transition = SlideTransition, TransitionOut extends Transition = SlideTransition> = ReturnType<__sveltets_Render<TransitionIn, TransitionOut>['slots']>;
/** The Accordion parent element. */
export default class Accordion<TransitionIn extends Transition = SlideTransition, TransitionOut extends Transition = SlideTransition> extends SvelteComponentTyped<AccordionProps<TransitionIn, TransitionOut>, AccordionEvents<TransitionIn, TransitionOut>, AccordionSlots<TransitionIn, TransitionOut>> {
}
export {};

View File

@ -0,0 +1,109 @@
<script>import { getContext } from "svelte";
import { createEventDispatcher } from "svelte";
import { dynamicTransition } from "../../internal/transitions.js";
const dispatch = createEventDispatcher();
export let open = false;
export let id = String(Math.random());
const cBase = "";
const cControl = "text-start w-full flex items-center space-x-4";
const cControlCaret = "fill-current w-3 transition-transform duration-[200ms]";
const cPanel = "";
export let autocollapse = getContext("autocollapse");
export let active = getContext("active");
export let disabled = getContext("disabled");
export let padding = getContext("padding");
export let hover = getContext("hover");
export let rounded = getContext("rounded");
export let caretOpen = getContext("caretOpen");
export let caretClosed = getContext("caretClosed");
export let regionControl = getContext("regionControl");
export let regionPanel = getContext("regionPanel");
export let regionCaret = getContext("regionCaret");
export let transitions = getContext("transitions");
export let transitionIn = getContext("transitionIn");
export let transitionInParams = getContext("transitionInParams");
export let transitionOut = getContext("transitionOut");
export let transitionOutParams = getContext("transitionOutParams");
function setActive(event) {
if (autocollapse === true) {
active.set(id);
} else {
open = !open;
}
onToggle(event);
}
function onToggle(event) {
const currentOpenState = autocollapse ? $active === id : open;
dispatch("toggle", { event, id: `accordion-control-${id}`, open: currentOpenState, autocollapse });
}
if (autocollapse && open)
setActive();
$:
if (open && autocollapse)
setActive();
$:
openState = autocollapse ? $active === id : open;
$:
classesBase = `${cBase} ${$$props.class ?? ""}`;
$:
classesControl = `${cControl} ${padding} ${hover} ${rounded} ${regionControl}`;
$:
classesCaretState = openState ? caretOpen : caretClosed;
$:
classesControlCaret = `${cControlCaret} ${regionCaret} ${classesCaretState}`;
$:
classesPanel = `${cPanel} ${padding} ${rounded} ${regionPanel}`;
</script>
<!-- @component The Accordion child element. -->
<div class="accordion-item {classesBase}" data-testid="accordion-item">
<!-- Control -->
<button
type="button"
class="accordion-control {classesControl}"
id="accordion-control-{id}"
on:click={setActive}
on:click
on:keydown
on:keyup
on:keypress
aria-expanded={openState}
aria-controls="accordion-panel-{id}"
{disabled}
>
<!-- Lead -->
{#if $$slots.lead}
<div class="accordion-lead">
<slot name="lead" />
</div>
{/if}
<!-- Summary -->
<div class="accordion-summary flex-1">
<slot name="summary">(summary)</slot>
</div>
<!-- Caret -->
<div class="accordion-summary-caret {classesControlCaret}">
<!-- SVG Caret -->
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512">
<path
d="M201.4 374.6c12.5 12.5 32.8 12.5 45.3 0l160-160c12.5-12.5 12.5-32.8 0-45.3s-32.8-12.5-45.3 0L224 306.7 86.6 169.4c-12.5-12.5-32.8-12.5-45.3 0s-12.5 32.8 0 45.3l160 160z"
/>
</svg>
</div>
</button>
<!-- Panel -->
{#if openState}
<div
class="accordion-panel {classesPanel}"
id="accordion-panel-{id}"
in:dynamicTransition|local={{ transition: transitionIn, params: transitionInParams, enabled: transitions }}
out:dynamicTransition|local={{ transition: transitionOut, params: transitionOutParams, enabled: transitions }}
role="region"
aria-hidden={!openState}
aria-labelledby="accordion-control-{id}"
>
<slot name="content">(content)</slot>
</div>
{/if}
</div>

View File

@ -0,0 +1,70 @@
import { SvelteComponentTyped } from "svelte";
import type { Writable } from 'svelte/store';
import type { Transition, TransitionParams } from '../../index.js';
declare class __sveltets_Render<TransitionIn extends Transition, TransitionOut extends Transition> {
props(): {
[x: string]: any;
/** Set open by default on load.*/
open?: boolean | undefined;
/** Provide a unique input id. Auto-generated by default*/
id?: string | undefined;
/** Set the auto-collapse mode.*/
autocollapse?: boolean | undefined;
/** The writable store that houses the auto-collapse active item UUID.*/
active?: Writable<string | null> | undefined;
/** Set the disabled state for this item.*/
disabled?: boolean | undefined;
/** Provide classes to set the accordion item padding styles.*/
padding?: string | undefined;
/** Provide classes to set the accordion item hover styles.*/
hover?: string | undefined;
/** Provide classes to set the accordion item rounded styles.*/
rounded?: string | undefined;
/** Provide arbitrary classes to the trigger button region.*/
caretOpen?: string | undefined;
/** Provide arbitrary classes to content panel region.*/
caretClosed?: string | undefined;
/** Provide arbitrary classes to the trigger button region.*/
regionControl?: string | undefined;
/** Provide arbitrary classes to content panel region.*/
regionPanel?: string | undefined;
/** Provide arbitrary classes caret icon region.*/
regionCaret?: string | undefined;
/** Enable/Disable transitions*/
transitions?: boolean | undefined;
/** Provide the transition to used on entry.*/
transitionIn?: TransitionIn | undefined;
/** Transition params provided to `transitionIn`.*/
transitionInParams?: TransitionParams<TransitionIn> | undefined;
/** Provide the transition to used on exit.*/
transitionOut?: TransitionOut | undefined;
/** Transition params provided to `transitionOut`.*/
transitionOutParams?: TransitionParams<TransitionOut> | undefined;
};
events(): {
click: MouseEvent;
keydown: KeyboardEvent;
keyup: KeyboardEvent;
keypress: KeyboardEvent;
toggle: CustomEvent<{
event?: Event | undefined;
id: string;
open: boolean;
autocollapse: boolean;
}>;
} & {
[evt: string]: CustomEvent<any>;
};
slots(): {
lead: {};
summary: {};
content: {};
};
}
export type AccordionItemProps<TransitionIn extends Transition, TransitionOut extends Transition> = ReturnType<__sveltets_Render<TransitionIn, TransitionOut>['props']>;
export type AccordionItemEvents<TransitionIn extends Transition, TransitionOut extends Transition> = ReturnType<__sveltets_Render<TransitionIn, TransitionOut>['events']>;
export type AccordionItemSlots<TransitionIn extends Transition, TransitionOut extends Transition> = ReturnType<__sveltets_Render<TransitionIn, TransitionOut>['slots']>;
/** The Accordion child element. */
export default class AccordionItem<TransitionIn extends Transition, TransitionOut extends Transition> extends SvelteComponentTyped<AccordionItemProps<TransitionIn, TransitionOut>, AccordionItemEvents<TransitionIn, TransitionOut>, AccordionItemSlots<TransitionIn, TransitionOut>> {
}
export {};

View File

@ -0,0 +1,53 @@
<script>export let background = "bg-surface-100-800-token";
export let border = "";
export let padding = "p-4";
export let shadow = "";
export let spacing = "space-y-4";
export let gridColumns = "grid-cols-[auto_1fr_auto]";
export let gap = "gap-4";
export let regionRowMain = "";
export let regionRowHeadline = "";
export let slotLead = "";
export let slotDefault = "";
export let slotTrail = "";
export let label = "";
export let labelledby = "";
const cBase = "flex flex-col";
const cRowMain = "grid items-center";
const cRowHeadline = "";
const cSlotLead = "flex-none flex justify-between items-center";
const cSlotDefault = "flex-auto";
const cSlotTrail = "flex-none flex items-center space-x-4";
$:
classesBase = `${cBase} ${background} ${border} ${spacing} ${padding} ${shadow} ${$$props.class ?? ""}`;
$:
classesRowMain = `${cRowMain} ${gridColumns} ${gap} ${regionRowMain}`;
$:
classesRowHeadline = `${cRowHeadline} ${regionRowHeadline}`;
$:
classesSlotLead = `${cSlotLead} ${slotLead}`;
$:
classesSlotDefault = `${cSlotDefault} ${slotDefault}`;
$:
classesSlotTrail = `${cSlotTrail} ${slotTrail}`;
</script>
<div class="app-bar {classesBase}" data-testid="app-bar" role="toolbar" aria-label={label} aria-labelledby={labelledby}>
<!-- Row: Main -->
<div class="app-bar-row-main {classesRowMain}">
<!-- Slot: lead -->
{#if $$slots.lead}
<div class="app-bar-slot-lead {classesSlotLead}"><slot name="lead" /></div>
{/if}
<!-- Slot: default -->
<div class="app-bar-slot-default {classesSlotDefault}"><slot /></div>
<!-- Slot: trail -->
{#if $$slots.trail}
<div class="app-bar-slot-trail {classesSlotTrail}"><slot name="trail" /></div>
{/if}
</div>
<!-- Row: Headline -->
{#if $$slots.headline}
<div class="app-bar-row-headline {classesRowHeadline}"><slot name="headline" /></div>
{/if}
</div>

View File

@ -0,0 +1,49 @@
import { SvelteComponentTyped } from "svelte";
declare const __propDef: {
props: {
[x: string]: any;
/** Provide classes to set background color.*/
background?: string | undefined;
/** Provide classes to set border styles.*/
border?: string | undefined;
/** Provide classes to set padding.*/
padding?: string | undefined;
/** Provide classes to define a box shadow.*/
shadow?: string | undefined;
/** Provide classes to set the vertical spacing between rows.*/
spacing?: string | undefined;
/** Provide classes to set grid columns for the main row.*/
gridColumns?: string | undefined;
/** Provide classes to set gap spacing for the main row.*/
gap?: string | undefined;
/** Provide arbitrary classes to style the top (main) row.*/
regionRowMain?: string | undefined;
/** Provide arbitrary classes to style the bottom (headline) row.*/
regionRowHeadline?: string | undefined;
/** Classes to apply to the lead slot container element*/
slotLead?: string | undefined;
/** Classes to apply to the default slot container element*/
slotDefault?: string | undefined;
/** Classes to apply to the trail slot container element*/
slotTrail?: string | undefined;
/** Provide a semantic ID for the ARIA label.*/
label?: string | undefined;
/** Provide the ID of the element that labels the toolbar.*/
labelledby?: string | undefined;
};
events: {
[evt: string]: CustomEvent<any>;
};
slots: {
lead: {};
default: {};
trail: {};
headline: {};
};
};
export type AppBarProps = typeof __propDef.props;
export type AppBarEvents = typeof __propDef.events;
export type AppBarSlots = typeof __propDef.slots;
export default class AppBar extends SvelteComponentTyped<AppBarProps, AppBarEvents, AppBarSlots> {
}
export {};

View File

@ -0,0 +1,41 @@
<script>import { setContext } from "svelte";
export let background = "bg-surface-100-800-token";
export let border = "";
export let width = "w-20";
export let height = "h-full";
export let gap = "gap-0";
export let regionLead = "";
export let regionDefault = "";
export let regionTrail = "";
export let hover = "bg-primary-hover-token";
export let active = "bg-primary-active-token";
export let spacing = "space-y-1";
export let aspectRatio = "aspect-square";
setContext("active", active);
setContext("hover", hover);
setContext("spacing", spacing);
setContext("aspectRatio", aspectRatio);
const cBase = "grid grid-rows-[auto_1fr_auto] overflow-y-auto";
const cRegionLead = "box-border";
const cRegionDefault = "box-border";
const cRegionTrail = "box-border";
$:
classesBase = `${cBase} ${background} ${border} ${width} ${height} ${gap} ${$$props.class || ""}`;
$:
classesRegionLead = `${cRegionLead} ${regionLead}`;
$:
classesRegionDefault = `${cRegionDefault} ${regionDefault}`;
$:
classesRegionTrail = `${cRegionTrail} ${regionTrail}`;
</script>
<!-- @component A vertical navigation rail component. -->
<div class="app-rail {classesBase}" data-testid="app-rail">
<!-- Slot: lead -->
<div class="app-bar-lead {classesRegionLead}"><slot name="lead" /></div>
<!-- Slot: Default -->
<div class="app-bar-default {classesRegionDefault}"><slot /></div>
<!-- Slot: lead -->
<div class="app-bar-trail {classesRegionTrail}"><slot name="trail" /></div>
</div>

View File

@ -0,0 +1,45 @@
import { SvelteComponentTyped } from "svelte";
declare const __propDef: {
props: {
[x: string]: any;
/** Rail: Provide classes to set the background color.*/
background?: string | undefined;
/** Rail: Provide classes to set the background color.*/
border?: string | undefined;
/** Rail: Provide classes to set the width.*/
width?: string | undefined;
/** Rail: Provide classes to set the height.*/
height?: string | undefined;
/** Rail: Provide a class to set the grid gap.*/
gap?: string | undefined;
/** Rail: Provide arbitrary classes to the lead region.*/
regionLead?: string | undefined;
/** Rail: Provide arbitrary classes to the default region.*/
regionDefault?: string | undefined;
/** Rail: Provide arbitrary classes to the trail region.*/
regionTrail?: string | undefined;
/** Provide classes to set the tile/anchor hover background color.*/
hover?: string | undefined;
/** Provide classes to set the tile/anchor active tile background.*/
active?: string | undefined;
/** Provide classes to set the tile/anchor vertical spacing.*/
spacing?: string | undefined;
/** Provide classes to set the tile/anchor aspect ratio.*/
aspectRatio?: string | undefined;
};
events: {
[evt: string]: CustomEvent<any>;
};
slots: {
lead: {};
default: {};
trail: {};
};
};
export type AppRailProps = typeof __propDef.props;
export type AppRailEvents = typeof __propDef.events;
export type AppRailSlots = typeof __propDef.slots;
/** A vertical navigation rail component. */
export default class AppRail extends SvelteComponentTyped<AppRailProps, AppRailEvents, AppRailSlots> {
}
export {};

View File

@ -0,0 +1,46 @@
<script>import { getContext } from "svelte";
export let selected = false;
export let regionLead = "flex justify-center items-center";
export let regionLabel = "";
export let hover = getContext("hover");
export let active = getContext("active");
export let spacing = getContext("spacing");
export let aspectRatio = getContext("aspectRatio");
const cBase = "unstyled";
const cWrapper = "w-full flex flex-col justify-center items-stretch text-center space-y-1";
const cLabel = "font-bold text-xs";
$:
classActive = selected ? active : "";
$:
classesBase = `${cBase} ${$$props.class || ""}`;
$:
classesWrapper = `${cWrapper} ${aspectRatio} ${hover} ${spacing} ${classActive}`;
$:
classesLead = `${regionLead}`;
$:
classesLabel = `${cLabel} ${regionLabel}`;
function prunedRestProps() {
delete $$restProps.class;
return $$restProps;
}
</script>
<a
class="app-rail-anchor {classesBase}"
href={$$props.href}
{...prunedRestProps()}
on:click
on:keydown
on:keyup
on:keypress
on:mouseover
on:mouseleave
on:focus
on:blur
data-testid="app-rail-anchor"
>
<div class="app-rail-wrapper {classesWrapper}">
{#if $$slots.lead}<div class="app-rail-lead {classesLead}"><slot name="lead" /></div>{/if}
<div class="app-rail-label {classesLabel}"><slot /></div>
</div>
</a>

View File

@ -0,0 +1,38 @@
import { SvelteComponentTyped } from "svelte";
declare const __propDef: {
props: {
[x: string]: any;
/** Enables the active state styles when set true.*/
selected?: boolean | undefined;
/** Provide arbitrary classes to style the lead region.*/
regionLead?: string | undefined;
/** Provide arbitrary classes to style the label region.*/
regionLabel?: string | undefined;
hover?: string | undefined;
active?: string | undefined;
spacing?: string | undefined;
aspectRatio?: string | undefined;
};
events: {
click: MouseEvent;
keydown: KeyboardEvent;
keyup: KeyboardEvent;
keypress: KeyboardEvent;
mouseover: MouseEvent;
mouseleave: MouseEvent;
focus: FocusEvent;
blur: FocusEvent;
} & {
[evt: string]: CustomEvent<any>;
};
slots: {
lead: {};
default: {};
};
};
export type AppRailAnchorProps = typeof __propDef.props;
export type AppRailAnchorEvents = typeof __propDef.events;
export type AppRailAnchorSlots = typeof __propDef.slots;
export default class AppRailAnchor extends SvelteComponentTyped<AppRailAnchorProps, AppRailAnchorEvents, AppRailAnchorSlots> {
}
export {};

View File

@ -0,0 +1,51 @@
<script>import { getContext } from "svelte";
export let group;
export let name;
export let value;
export let title = "";
export let regionLead = "";
export let regionLabel = "";
export let hover = getContext("hover");
export let active = getContext("active");
export let spacing = getContext("spacing");
export let width = getContext("width");
export let aspectRatio = getContext("aspectRatio");
const cBase = "cursor-pointer";
const cWrapper = "flex flex-col justify-center items-stretch";
const cInterface = "text-center";
const cLabel = "font-bold text-xs";
let elemInput;
$:
classActive = group === value ? active : "";
$:
classesBase = `${cBase} ${$$props.class || ""}`;
$:
classesWrapper = `${cWrapper} ${aspectRatio} ${width} ${hover} ${classActive}`;
$:
classesInterface = `${cInterface} ${spacing}`;
$:
classesLead = `${regionLead}`;
$:
classesLabel = `${cLabel} ${regionLabel}`;
function prunedRestProps() {
delete $$restProps.class;
return $$restProps;
}
</script>
<label class="app-rail-tile {classesBase}" data-testid="app-rail-tile" {title} on:mouseover on:mouseleave on:focus on:blur>
<!-- A11y attributes are not allowed on <label> -->
<!-- FIXME: resolve a11y warnings -->
<!-- svelte-ignore a11y-no-static-element-interactions -->
<div class="app-rail-wrapper {classesWrapper}" on:keydown on:keyup on:keypress>
<!-- NOTE: Don't use `hidden` as it prevents `required` from operating -->
<div class="h-0 w-0 overflow-hidden">
<input bind:this={elemInput} type="radio" bind:group {name} {value} {...prunedRestProps()} tabindex="-1" on:click on:change />
</div>
<!-- Interface -->
<div class="app-rail-interface {classesInterface}">
{#if $$slots.lead}<div class="app-rail-lead {classesLead}"><slot name="lead" /></div>{/if}
<div class="app-rail-label {classesLabel}"><slot /></div>
</div>
</div>
</label>

View File

@ -0,0 +1,46 @@
import { SvelteComponentTyped } from "svelte";
declare const __propDef: {
props: {
[x: string]: any;
/** Set the radio group binding value.*/
group: any;
/** Set a unique name value for the input.*/
name: string;
/** Set the input's value.*/
value: any;
/** Provide a hoverable title attribute for the tile.*/
title?: string | undefined;
/** Provide arbitrary classes to style the lead region.*/
regionLead?: string | undefined;
/** Provide arbitrary classes to style the label region.*/
regionLabel?: string | undefined;
hover?: string | undefined;
active?: string | undefined;
spacing?: string | undefined;
width?: string | undefined;
aspectRatio?: string | undefined;
};
events: {
mouseover: MouseEvent;
mouseleave: MouseEvent;
focus: FocusEvent;
blur: FocusEvent;
keydown: KeyboardEvent;
keyup: KeyboardEvent;
keypress: KeyboardEvent;
click: MouseEvent;
change: Event;
} & {
[evt: string]: CustomEvent<any>;
};
slots: {
lead: {};
default: {};
};
};
export type AppRailTileProps = typeof __propDef.props;
export type AppRailTileEvents = typeof __propDef.events;
export type AppRailTileSlots = typeof __propDef.slots;
export default class AppRailTile extends SvelteComponentTyped<AppRailTileProps, AppRailTileEvents, AppRailTileSlots> {
}
export {};

View File

@ -0,0 +1,72 @@
<script>export let scrollbarGutter = "auto";
export let regionPage = "";
export let slotHeader = "z-10";
export let slotSidebarLeft = "w-auto";
export let slotSidebarRight = "w-auto";
export let slotPageHeader = "";
export let slotPageContent = "";
export let slotPageFooter = "";
export let slotFooter = "";
const cBaseAppShell = "w-full h-full flex flex-col overflow-hidden";
const cContentArea = "w-full h-full flex overflow-hidden";
const cPage = "flex-1 overflow-x-hidden flex flex-col";
const cSidebarLeft = "flex-none overflow-x-hidden overflow-y-auto";
const cSidebarRight = "flex-none overflow-x-hidden overflow-y-auto";
$:
classesBase = `${cBaseAppShell} ${$$props.class ?? ""}`;
$:
classesHeader = `${slotHeader}`;
$:
classesSidebarLeft = `${cSidebarLeft} ${slotSidebarLeft}`;
$:
classesSidebarRight = `${cSidebarRight} ${slotSidebarRight}`;
$:
classesPageHeader = `${slotPageHeader}`;
$:
classesPageContent = `${slotPageContent}`;
$:
classesPageFooter = `${slotPageFooter}`;
$:
classesFooter = `${slotFooter}`;
</script>
<div id="appShell" class={classesBase} data-testid="app-shell">
<!-- Slot: Header -->
{#if $$slots.header}
<header id="shell-header" class="flex-none {classesHeader}"><slot name="header" /></header>
{/if}
<!-- Content Area -->
<div class="flex-auto {cContentArea}">
<!-- Slot: Sidebar (left) -->
{#if $$slots.sidebarLeft}
<aside id="sidebar-left" class={classesSidebarLeft}><slot name="sidebarLeft" /></aside>
{/if}
<!-- Page -->
<div id="page" class="{regionPage} {cPage}" style:scrollbar-gutter={scrollbarGutter} on:scroll>
<!-- Slot: Page Header -->
{#if $$slots.pageHeader}
<header id="page-header" class="flex-none {classesPageHeader}"><slot name="pageHeader">(slot:header)</slot></header>
{/if}
<!-- Slot: Page Content (default) -->
<main id="page-content" class="flex-auto {classesPageContent}"><slot /></main>
<!-- Slot: Page Footer -->
{#if $$slots.pageFooter}
<footer id="page-footer" class="flex-none {classesPageFooter}"><slot name="pageFooter">(slot:footer)</slot></footer>
{/if}
</div>
<!-- Slot: Sidebar (right) -->
{#if $$slots.sidebarRight}
<aside id="sidebar-right" class={classesSidebarRight}><slot name="sidebarRight" /></aside>
{/if}
</div>
<!-- Slot: footer -->
{#if $$slots.footer}
<footer id="shell-footer" class="flex-none {classesFooter}"><slot name="footer" /></footer>
{/if}
</div>

View File

@ -0,0 +1,50 @@
import { SvelteComponentTyped } from "svelte";
/** @slot header - Insert fixed header content, such as Skeleton's App Bar component.
* @slot sidebarLeft - Hidden when empty. Allows you to set fixed left sidebar content.
* @slot sidebarRight - Hidden when empty. Allows you to set fixed right sidebar content.
* @slot pageHeader - Insert content that resides above your page content. Great for global alerts.
* @slot pageFooter - Insert content that resides below your page content. Recommended for most layouts.
* @slot footer - Insert fixed footer content. Not recommended for most layouts.
*/
import type { SvelteEvent } from '../../index.js';
declare const __propDef: {
props: {
[x: string]: any;
/** Set `scrollbar-gutter` style.*/
scrollbarGutter?: string | undefined;
/** Apply arbitrary classes to the entire `#page` region.*/
regionPage?: string | undefined;
/** Apply arbitrary classes to the `header` slot container element*/
slotHeader?: string | undefined;
/** Apply arbitrary classes to the `sidebarLeft` slot container element*/
slotSidebarLeft?: string | undefined;
/** Apply arbitrary classes to the `sidebarRight` slot container element*/
slotSidebarRight?: string | undefined;
/** Apply arbitrary classes to the `pageHeader` slot container element*/
slotPageHeader?: string | undefined;
/** Apply arbitrary classes to the `pageContent` slot container element*/
slotPageContent?: string | undefined;
/** Apply arbitrary classes to the `pageFooter` slot container element*/
slotPageFooter?: string | undefined;
/** Apply arbitrary classes to the `footer` slot container element*/
slotFooter?: string | undefined;
};
events: {
scroll: SvelteEvent<UIEvent, HTMLDivElement>;
};
slots: {
header: {};
sidebarLeft: {};
pageHeader: {};
default: {};
pageFooter: {};
sidebarRight: {};
footer: {};
};
};
export type AppShellProps = typeof __propDef.props;
export type AppShellEvents = typeof __propDef.events;
export type AppShellSlots = typeof __propDef.slots;
export default class AppShell extends SvelteComponentTyped<AppShellProps, AppShellEvents, AppShellSlots> {
}
export {};

View File

@ -0,0 +1,97 @@
<script context="module">import { slide } from "svelte/transition";
import { prefersReducedMotionStore } from "../../index.js";
import { dynamicTransition } from "../../internal/transitions.js";
</script>
<script
generics="Value = unknown, Meta = unknown,
TransitionIn extends Transition = SlideTransition, TransitionOut extends Transition = SlideTransition"
>import { createEventDispatcher } from "svelte";
const dispatch = createEventDispatcher();
export let input = void 0;
export let options = [];
export let limit = void 0;
export let allowlist = [];
export let denylist = [];
export let emptyState = "No Results Found.";
export let regionNav = "";
export let regionList = "list-nav";
export let regionItem = "";
export let regionButton = "w-full";
export let regionEmpty = "text-center";
export let transitions = !$prefersReducedMotionStore;
export let transitionIn = slide;
export let transitionInParams = { duration: 200 };
export let transitionOut = slide;
export let transitionOutParams = { duration: 200 };
$:
listedOptions = options;
function filterByAllowDeny(allowlist2, denylist2) {
let _options = [...options];
if (allowlist2.length) {
_options = _options.filter((option) => allowlist2.includes(option.value));
}
if (denylist2.length) {
_options = _options.filter((option) => !denylist2.includes(option.value));
}
if (!allowlist2.length && !denylist2.length) {
_options = options;
}
listedOptions = _options;
}
function filterOptions() {
let _options = [...listedOptions];
_options = _options.filter((option) => {
const inputFormatted = String(input).toLowerCase().trim();
let optionFormatted = JSON.stringify([option.label, option.value, option.keywords]).toLowerCase();
if (optionFormatted.includes(inputFormatted))
return option;
});
return _options;
}
function onSelection(option) {
dispatch("selection", option);
}
$:
filterByAllowDeny(allowlist, denylist);
$:
optionsFiltered = input ? filterOptions() : listedOptions;
$:
sliceLimit = limit ?? optionsFiltered.length;
$:
classesBase = `${$$props.class ?? ""}`;
$:
classesNav = `${regionNav}`;
$:
classesList = `${regionList}`;
$:
classesItem = `${regionItem}`;
$:
classesButton = `${regionButton}`;
$:
classesEmpty = `${regionEmpty}`;
</script>
<!-- animate:flip={{ duration }} -->
<div class="autocomplete {classesBase}" data-testid="autocomplete">
{#if optionsFiltered.length > 0}
<nav class="autocomplete-nav {classesNav}">
<ul class="autocomplete-list {classesList}">
{#each optionsFiltered.slice(0, sliceLimit) as option (option)}
<li
class="autocomplete-item {classesItem}"
in:dynamicTransition|local={{ transition: transitionIn, params: transitionInParams, enabled: transitions }}
out:dynamicTransition|local={{ transition: transitionOut, params: transitionOutParams, enabled: transitions }}
>
<button class="autocomplete-button {classesButton}" type="button" on:click={() => onSelection(option)} on:click on:keypress>
{@html option.label}
</button>
</li>
{/each}
</ul>
</nav>
{:else}
<div class="autocomplete-empty {classesEmpty}">{emptyState}</div>
{/if}
</div>

View File

@ -0,0 +1,56 @@
import { SvelteComponentTyped } from "svelte";
import { slide } from 'svelte/transition';
import { type Transition, type TransitionParams } from '../../index.js';
type SlideTransition = typeof slide;
import type { AutocompleteOption } from './types.js';
declare class __sveltets_Render<Value = unknown, Meta = unknown, TransitionIn extends Transition = SlideTransition, TransitionOut extends Transition = SlideTransition> {
props(): {
[x: string]: any;
/** Bind the input value.*/
input?: Value | undefined;
/** Define values for the list.*/
options?: AutocompleteOption<Value, Meta>[] | undefined;
/** Limit the total number of suggestions.*/
limit?: number | undefined;
/** Provide allowlist values.*/
allowlist?: Value[] | undefined;
/** Provide denylist values.*/
denylist?: Value[] | undefined;
/** Provide a HTML markup to display when no match is found.*/
emptyState?: string | undefined;
/** Provide arbitrary classes to nav element.*/
regionNav?: string | undefined;
/** Provide arbitrary classes to each list.*/
regionList?: string | undefined;
/** Provide arbitrary classes to each list item.*/
regionItem?: string | undefined;
/** Provide arbitrary classes to each button.*/
regionButton?: string | undefined;
/** Provide arbitrary classes to empty message.*/
regionEmpty?: string | undefined;
/** Enable/Disable transitions*/
transitions?: boolean | undefined;
/** Provide the transition used on entry.*/
transitionIn?: TransitionIn | undefined;
/** Transition params provided to `transitionIn`.*/
transitionInParams?: TransitionParams<TransitionIn> | undefined;
/** Provide the transition used on exit.*/
transitionOut?: TransitionOut | undefined;
/** Transition params provided to `transitionOut`.*/
transitionOutParams?: TransitionParams<TransitionOut> | undefined;
};
events(): {
click: MouseEvent;
keypress: KeyboardEvent;
selection: CustomEvent<AutocompleteOption<Value, Meta>>;
} & {
[evt: string]: CustomEvent<any>;
};
slots(): {};
}
export type AutocompleteProps<Value = unknown, Meta = unknown, TransitionIn extends Transition = SlideTransition, TransitionOut extends Transition = SlideTransition> = ReturnType<__sveltets_Render<Value, Meta, TransitionIn, TransitionOut>['props']>;
export type AutocompleteEvents<Value = unknown, Meta = unknown, TransitionIn extends Transition = SlideTransition, TransitionOut extends Transition = SlideTransition> = ReturnType<__sveltets_Render<Value, Meta, TransitionIn, TransitionOut>['events']>;
export type AutocompleteSlots<Value = unknown, Meta = unknown, TransitionIn extends Transition = SlideTransition, TransitionOut extends Transition = SlideTransition> = ReturnType<__sveltets_Render<Value, Meta, TransitionIn, TransitionOut>['slots']>;
export default class Autocomplete<Value = unknown, Meta = unknown, TransitionIn extends Transition = SlideTransition, TransitionOut extends Transition = SlideTransition> extends SvelteComponentTyped<AutocompleteProps<Value, Meta, TransitionIn, TransitionOut>, AutocompleteEvents<Value, Meta, TransitionIn, TransitionOut>, AutocompleteSlots<Value, Meta, TransitionIn, TransitionOut>> {
}
export {};

View File

@ -0,0 +1,10 @@
export interface AutocompleteOption<Value = unknown, Meta = unknown> {
/** Provide a unique display label per option. Supports HTML. */
label: string;
/** Provide a unique option value. */
value: Value;
/** Provide a comma separated list of keywords. */
keywords?: string;
/** Pass arbitrary data per option. */
meta?: Meta;
}

View File

@ -0,0 +1,2 @@
// Autocomplete Types
export {};

View File

@ -0,0 +1,44 @@
<script>export let initials = "AB";
export let fill = "fill-token";
export let src = "";
export let fallback = "";
export let action = () => {
};
export let actionParams = "";
export let background = "bg-surface-400-500-token";
export let width = "w-16";
export let border = "";
export let rounded = "rounded-full";
export let shadow = "";
export let cursor = "";
let cBase = "flex aspect-square text-surface-50 font-semibold justify-center items-center overflow-hidden isolate";
let cImage = "w-full h-full object-cover";
$:
classesBase = `${cBase} ${background} ${width} ${border} ${rounded} ${shadow} ${cursor} ${$$props.class ?? ""}`;
function prunedRestProps() {
delete $$restProps.class;
return $$restProps;
}
</script>
<!-- FIXME: resolve a11y warnings -->
<!-- svelte-ignore a11y-no-noninteractive-element-interactions -->
<figure class="avatar {classesBase}" data-testid="avatar" on:click on:keydown on:keyup on:keypress>
{#if src}
<img
class="avatar-image {cImage}"
style={$$props.style ?? ''}
{src}
alt={$$props.alt || ''}
use:action={actionParams}
on:error={() => (src = fallback)}
{...prunedRestProps()}
/>
{:else}
<svg class="avatar-initials w-full h-full" viewBox="0 0 512 512">
<text x="50%" y="50%" dominant-baseline="central" text-anchor="middle" font-weight="bold" font-size={150} class="avatar-text {fill}">
{String(initials).substring(0, 2).toUpperCase()}
</text>
</svg>
{/if}
</figure>

View File

@ -0,0 +1,46 @@
import { SvelteComponentTyped } from "svelte";
import type { Action } from 'svelte/action';
declare const __propDef: {
props: {
[x: string]: any;
/** Initials only - Provide up to two text characters.*/
initials?: string | undefined;
/** Initials only - Provide classes to set the SVG text fill color.*/
fill?: string | undefined;
/** Provide the avatar image element source.*/
src?: string | undefined;
/** Provide the fallback image element source.*/
fallback?: string | undefined;
/** Image only. Provide a Svelte action reference, such as `filter`.*/
action?: Action<HTMLElement, string, Record<never, any>> | undefined;
/** Image only. Provide Svelte action params, such as Apollo.*/
actionParams?: string | undefined;
/** Provide classes to set background styles.*/
background?: string | undefined;
/** Provide classes to set avatar width.*/
width?: string | undefined;
/** Provide classes to set border styles.*/
border?: string | undefined;
/** Provide classes to set rounded style.*/
rounded?: string | undefined;
/** Provide classes to set shadow styles.*/
shadow?: string | undefined;
/** Provide classes to set cursor styles.*/
cursor?: string | undefined;
};
events: {
click: MouseEvent;
keydown: KeyboardEvent;
keyup: KeyboardEvent;
keypress: KeyboardEvent;
} & {
[evt: string]: CustomEvent<any>;
};
slots: {};
};
export type AvatarProps = typeof __propDef.props;
export type AvatarEvents = typeof __propDef.events;
export type AvatarSlots = typeof __propDef.slots;
export default class Avatar extends SvelteComponentTyped<AvatarProps, AvatarEvents, AvatarSlots> {
}
export {};

View File

@ -0,0 +1,77 @@
<script>import { afterUpdate } from "svelte";
import { tailwindDefaultColors } from "./settings.js";
export let stops = [{ color: ["neutral", 500], start: 0, end: 100 }];
export let legend = false;
export let spin = false;
export let width = "w-24";
export let hover = "bg-primary-hover-token";
export let digits = 0;
export let regionCaption = "";
export let regionCone = "";
export let regionLegend = "";
let cone;
let generatedLegendList;
const cBase = "flex flex-col items-center space-y-4 w-";
const cCaption = "text-center";
const cCone = "block aspect-square rounded-full";
const cLegend = "text-sm w-full";
const cSwatch = "block aspect-square bg-black w-5 rounded-full mr-2";
function setColorValue(color) {
if (typeof color === "string")
return color;
const colorSet = tailwindDefaultColors.find((c) => c.label === color[0]);
return colorSet?.shades[color[1]].hex;
}
function genConicGradient() {
let d = stops.map((v) => `${setColorValue(v.color)} ${v.start}% ${v.end}%`);
cone = `conic-gradient(${d.join(", ")})`;
}
function genLegend() {
if (!legend)
return;
generatedLegendList = stops.map((v) => {
return {
label: v.label,
color: setColorValue(v.color),
value: (v.end - v.start).toFixed(digits)
};
});
}
afterUpdate(() => {
genConicGradient();
genLegend();
});
$:
classesBase = `${cBase} ${$$props.class ?? ""}`;
$:
classesCaption = `${cCaption} ${regionCaption}`;
$:
classesCone = `${cCone} ${width} ${regionCone}`;
$:
classesLegend = `${cLegend} ${regionLegend}`;
</script>
<figure class="conic-gradient {classesBase}" data-testid="conic-gradient">
<!-- Label -->
{#if $$slots.default}
<figcaption class="conic-caption {classesCaption}"><slot /></figcaption>
{/if}
<!-- Conic Gradient -->
{#if cone}
<div class="conic-cone {classesCone}" class:animate-spin={spin} style:background={cone} />
{/if}
<!-- Legend -->
{#if legend && generatedLegendList}
<ul class="conic-list list {classesLegend}">
{#each generatedLegendList as { color, label, value }}
<!-- FIXME: resolve a11y warnings -->
<!-- svelte-ignore a11y-no-noninteractive-element-interactions -->
<li class="conic-item {hover}" on:click on:keydown on:keyup on:keypress>
<span class="conic-swatch {cSwatch}" style:background={color} />
<span class="conic-label flex-auto">{label}</span>
<strong class="conic-value">{value}%</strong>
</li>
{/each}
</ul>
{/if}
</figure>

View File

@ -0,0 +1,42 @@
import { SvelteComponentTyped } from "svelte";
import type { ConicStop } from './types.js';
declare const __propDef: {
props: {
[x: string]: any;
/** Provide a data set of color stops and labels.*/
stops?: ConicStop[] | undefined;
/** Enable a contextual legend.*/
legend?: boolean | undefined;
/** When enabled, the conic gradient will spin.*/
spin?: boolean | undefined;
/** Style the conic gradient width.*/
width?: string | undefined;
/** Style the legend hover effect.*/
hover?: string | undefined;
/** Set the number of digits on the legend values.*/
digits?: number | undefined;
/** Style the caption region above the gradient.*/
regionCaption?: string | undefined;
/** Style the conic gradient region.*/
regionCone?: string | undefined;
/** Style the legend region below the gradient.*/
regionLegend?: string | undefined;
};
events: {
click: MouseEvent;
keydown: KeyboardEvent;
keyup: KeyboardEvent;
keypress: KeyboardEvent;
} & {
[evt: string]: CustomEvent<any>;
};
slots: {
default: {};
};
};
export type ConicGradientProps = typeof __propDef.props;
export type ConicGradientEvents = typeof __propDef.events;
export type ConicGradientSlots = typeof __propDef.slots;
export default class ConicGradient extends SvelteComponentTyped<ConicGradientProps, ConicGradientEvents, ConicGradientSlots> {
}
export {};

View File

@ -0,0 +1,9 @@
export type HexRgb = {
hex: string;
rgb: string;
};
export type TailwindColorObject = {
label: string;
shades: Record<string, HexRgb>;
};
export declare const tailwindDefaultColors: TailwindColorObject[];

View File

@ -0,0 +1,334 @@
// Provides the full set of Tailwind colors via Javascript
// https://tailwindcss.com/docs/customizing-colors#default-color-palette
export const tailwindDefaultColors = [
{
label: 'slate',
shades: {
'50': { hex: '#f8fafc', rgb: '248 250 252' },
'100': { hex: '#f1f5f9', rgb: '241 245 249' },
'200': { hex: '#e2e8f0', rgb: '226 232 240' },
'300': { hex: '#cbd5e1', rgb: '203 213 225' },
'400': { hex: '#94a3b8', rgb: '148 163 184' },
'500': { hex: '#64748b', rgb: '100 116 139' },
'600': { hex: '#475569', rgb: '71 85 105' },
'700': { hex: '#334155', rgb: '51 65 85' },
'800': { hex: '#1e293b', rgb: '30 41 59' },
'900': { hex: '#0f172a', rgb: '15 23 42' }
}
},
{
label: 'gray',
shades: {
'50': { hex: '#f9fafb', rgb: '249 250 251' },
'100': { hex: '#f3f4f6', rgb: '243 244 246' },
'200': { hex: '#e5e7eb', rgb: '229 231 235' },
'300': { hex: '#d1d5db', rgb: '209 213 219' },
'400': { hex: '#9ca3af', rgb: '156 163 175' },
'500': { hex: '#6b7280', rgb: '107 114 128' },
'600': { hex: '#4b5563', rgb: '75 85 99' },
'700': { hex: '#374151', rgb: '55 65 81' },
'800': { hex: '#1f2937', rgb: '31 41 55' },
'900': { hex: '#111827', rgb: '17 24 39' }
}
},
{
label: 'zinc',
shades: {
'50': { hex: '#fafafa', rgb: '250 250 250' },
'100': { hex: '#f4f4f5', rgb: '244 244 245' },
'200': { hex: '#e4e4e7', rgb: '228 228 231' },
'300': { hex: '#d4d4d8', rgb: '212 212 216' },
'400': { hex: '#a1a1aa', rgb: '161 161 170' },
'500': { hex: '#71717a', rgb: '113 113 122' },
'600': { hex: '#52525b', rgb: '82 82 91' },
'700': { hex: '#3f3f46', rgb: '63 63 70' },
'800': { hex: '#27272a', rgb: '39 39 42' },
'900': { hex: '#18181b', rgb: '24 24 27' }
}
},
{
label: 'neutral',
shades: {
'50': { hex: '#fafafa', rgb: '250 250 250' },
'100': { hex: '#f5f5f5', rgb: '245 245 245' },
'200': { hex: '#e5e5e5', rgb: '229 229 229' },
'300': { hex: '#d4d4d4', rgb: '212 212 212' },
'400': { hex: '#a3a3a3', rgb: '163 163 163' },
'500': { hex: '#737373', rgb: '115 115 115' },
'600': { hex: '#525252', rgb: '82 82 82' },
'700': { hex: '#404040', rgb: '64 64 64' },
'800': { hex: '#262626', rgb: '38 38 38' },
'900': { hex: '#171717', rgb: '23 23 23' }
}
},
{
label: 'stone',
shades: {
'50': { hex: '#fafaf9', rgb: '250 250 249' },
'100': { hex: '#f5f5f4', rgb: '245 245 244' },
'200': { hex: '#e7e5e4', rgb: '231 229 228' },
'300': { hex: '#d6d3d1', rgb: '214 211 209' },
'400': { hex: '#a8a29e', rgb: '168 162 158' },
'500': { hex: '#78716c', rgb: '120 113 108' },
'600': { hex: '#57534e', rgb: '87 83 78' },
'700': { hex: '#44403c', rgb: '68 64 60' },
'800': { hex: '#292524', rgb: '41 37 36' },
'900': { hex: '#1c1917', rgb: '28 25 23' }
}
},
{
label: 'red',
shades: {
'50': { hex: '#fef2f2', rgb: '254 242 242' },
'100': { hex: '#fee2e2', rgb: '254 226 226' },
'200': { hex: '#fecaca', rgb: '254 202 202' },
'300': { hex: '#fca5a5', rgb: '252 165 165' },
'400': { hex: '#f87171', rgb: '248 113 113' },
'500': { hex: '#ef4444', rgb: '239 68 68' },
'600': { hex: '#dc2626', rgb: '220 38 38' },
'700': { hex: '#b91c1c', rgb: '185 28 28' },
'800': { hex: '#991b1b', rgb: '153 27 27' },
'900': { hex: '#7f1d1d', rgb: '127 29 29' }
}
},
{
label: 'orange',
shades: {
'50': { hex: '#fff7ed', rgb: '255 247 237' },
'100': { hex: '#ffedd5', rgb: '255 237 213' },
'200': { hex: '#fed7aa', rgb: '254 215 170' },
'300': { hex: '#fdba74', rgb: '253 186 116' },
'400': { hex: '#fb923c', rgb: '251 146 60' },
'500': { hex: '#f97316', rgb: '249 115 22' },
'600': { hex: '#ea580c', rgb: '234 88 12' },
'700': { hex: '#c2410c', rgb: '194 65 12' },
'800': { hex: '#9a3412', rgb: '154 52 18' },
'900': { hex: '#7c2d12', rgb: '124 45 18' }
}
},
{
label: 'amber',
shades: {
'50': { hex: '#fffbeb', rgb: '255 251 235' },
'100': { hex: '#fef3c7', rgb: '254 243 199' },
'200': { hex: '#fde68a', rgb: '253 230 138' },
'300': { hex: '#fcd34d', rgb: '252 211 77' },
'400': { hex: '#fbbf24', rgb: '251 191 36' },
'500': { hex: '#f59e0b', rgb: '245 158 11' },
'600': { hex: '#d97706', rgb: '217 119 6' },
'700': { hex: '#b45309', rgb: '180 83 9' },
'800': { hex: '#92400e', rgb: '146 64 14' },
'900': { hex: '#78350f', rgb: '120 53 15' }
}
},
{
label: 'yellow',
shades: {
'50': { hex: '#fefce8', rgb: '254 252 232' },
'100': { hex: '#fef9c3', rgb: '254 249 195' },
'200': { hex: '#fef08a', rgb: '254 240 138' },
'300': { hex: '#fde047', rgb: '253 224 71' },
'400': { hex: '#facc15', rgb: '250 204 21' },
'500': { hex: '#eab308', rgb: '234 179 8' },
'600': { hex: '#ca8a04', rgb: '202 138 4' },
'700': { hex: '#a16207', rgb: '161 98 7' },
'800': { hex: '#854d0e', rgb: '133 77 14' },
'900': { hex: '#713f12', rgb: '113 63 18' }
}
},
{
label: 'lime',
shades: {
'50': { hex: '#f7fee7', rgb: '247 254 231' },
'100': { hex: '#ecfccb', rgb: '236 252 203' },
'200': { hex: '#d9f99d', rgb: '217 249 157' },
'300': { hex: '#bef264', rgb: '190 242 100' },
'400': { hex: '#a3e635', rgb: '163 230 53' },
'500': { hex: '#84cc16', rgb: '132 204 22' },
'600': { hex: '#65a30d', rgb: '101 163 13' },
'700': { hex: '#4d7c0f', rgb: '77 124 15' },
'800': { hex: '#3f6212', rgb: '63 98 18' },
'900': { hex: '#365314', rgb: '54 83 20' }
}
},
{
label: 'green',
shades: {
'50': { hex: '#f0fdf4', rgb: '240 253 244' },
'100': { hex: '#dcfce7', rgb: '220 252 231' },
'200': { hex: '#bbf7d0', rgb: '187 247 208' },
'300': { hex: '#86efac', rgb: '134 239 172' },
'400': { hex: '#4ade80', rgb: '74 222 128' },
'500': { hex: '#22c55e', rgb: '34 197 94' },
'600': { hex: '#16a34a', rgb: '22 163 74' },
'700': { hex: '#15803d', rgb: '21 128 61' },
'800': { hex: '#166534', rgb: '22 101 52' },
'900': { hex: '#14532d', rgb: '20 83 45' }
}
},
{
label: 'emerald',
shades: {
'50': { hex: '#ecfdf5', rgb: '236 253 245' },
'100': { hex: '#d1fae5', rgb: '209 250 229' },
'200': { hex: '#a7f3d0', rgb: '167 243 208' },
'300': { hex: '#6ee7b7', rgb: '110 231 183' },
'400': { hex: '#34d399', rgb: '52 211 153' },
'500': { hex: '#10b981', rgb: '16 185 129' },
'600': { hex: '#059669', rgb: '5 150 105' },
'700': { hex: '#047857', rgb: '4 120 87' },
'800': { hex: '#065f46', rgb: '6 95 70' },
'900': { hex: '#064e3b', rgb: '6 78 59' }
}
},
{
label: 'teal',
shades: {
'50': { hex: '#f0fdfa', rgb: '240 253 250' },
'100': { hex: '#ccfbf1', rgb: '204 251 241' },
'200': { hex: '#99f6e4', rgb: '153 246 228' },
'300': { hex: '#5eead4', rgb: '94 234 212' },
'400': { hex: '#2dd4bf', rgb: '45 212 191' },
'500': { hex: '#14b8a6', rgb: '20 184 166' },
'600': { hex: '#0d9488', rgb: '13 148 136' },
'700': { hex: '#0f766e', rgb: '15 118 110' },
'800': { hex: '#115e59', rgb: '17 94 89' },
'900': { hex: '#134e4a', rgb: '19 78 74' }
}
},
{
label: 'cyan',
shades: {
'50': { hex: '#ecfeff', rgb: '236 254 255' },
'100': { hex: '#cffafe', rgb: '207 250 254' },
'200': { hex: '#a5f3fc', rgb: '165 243 252' },
'300': { hex: '#67e8f9', rgb: '103 232 249' },
'400': { hex: '#22d3ee', rgb: '34 211 238' },
'500': { hex: '#06b6d4', rgb: '6 182 212' },
'600': { hex: '#0891b2', rgb: '8 145 178' },
'700': { hex: '#0e7490', rgb: '14 116 144' },
'800': { hex: '#155e75', rgb: '21 94 117' },
'900': { hex: '#164e63', rgb: '22 78 99' }
}
},
{
label: 'sky',
shades: {
'50': { hex: '#f0f9ff', rgb: '240 249 255' },
'100': { hex: '#e0f2fe', rgb: '224 242 254' },
'200': { hex: '#bae6fd', rgb: '186 230 253' },
'300': { hex: '#7dd3fc', rgb: '125 211 252' },
'400': { hex: '#38bdf8', rgb: '56 189 248' },
'500': { hex: '#0ea5e9', rgb: '14 165 233' },
'600': { hex: '#0284c7', rgb: '2 132 199' },
'700': { hex: '#0369a1', rgb: '3 105 161' },
'800': { hex: '#075985', rgb: '7 89 133' },
'900': { hex: '#0c4a6e', rgb: '12 74 110' }
}
},
{
label: 'blue',
shades: {
'50': { hex: '#eff6ff', rgb: '239 246 255' },
'100': { hex: '#dbeafe', rgb: '219 234 254' },
'200': { hex: '#bfdbfe', rgb: '191 219 254' },
'300': { hex: '#93c5fd', rgb: '147 197 253' },
'400': { hex: '#60a5fa', rgb: '96 165 250' },
'500': { hex: '#3b82f6', rgb: '59 130 246' },
'600': { hex: '#2563eb', rgb: '37 99 235' },
'700': { hex: '#1d4ed8', rgb: '29 78 216' },
'800': { hex: '#1e40af', rgb: '30 64 175' },
'900': { hex: '#1e3a8a', rgb: '30 58 138' }
}
},
{
label: 'indigo',
shades: {
'50': { hex: '#eef2ff', rgb: '238 242 255' },
'100': { hex: '#e0e7ff', rgb: '224 231 255' },
'200': { hex: '#c7d2fe', rgb: '199 210 254' },
'300': { hex: '#a5b4fc', rgb: '165 180 252' },
'400': { hex: '#818cf8', rgb: '129 140 248' },
'500': { hex: '#6366f1', rgb: '99 102 241' },
'600': { hex: '#4f46e5', rgb: '79 70 229' },
'700': { hex: '#4338ca', rgb: '67 56 202' },
'800': { hex: '#3730a3', rgb: '55 48 163' },
'900': { hex: '#312e81', rgb: '49 46 129' }
}
},
{
label: 'violet',
shades: {
'50': { hex: '#f5f3ff', rgb: '245 243 255' },
'100': { hex: '#ede9fe', rgb: '237 233 254' },
'200': { hex: '#ddd6fe', rgb: '221 214 254' },
'300': { hex: '#c4b5fd', rgb: '196 181 253' },
'400': { hex: '#a78bfa', rgb: '167 139 250' },
'500': { hex: '#8b5cf6', rgb: '139 92 246' },
'600': { hex: '#7c3aed', rgb: '124 58 237' },
'700': { hex: '#6d28d9', rgb: '109 40 217' },
'800': { hex: '#5b21b6', rgb: '91 33 182' },
'900': { hex: '#4c1d95', rgb: '76 29 149' }
}
},
{
label: 'purple',
shades: {
'50': { hex: '#faf5ff', rgb: '250 245 255' },
'100': { hex: '#f3e8ff', rgb: '243 232 255' },
'200': { hex: '#e9d5ff', rgb: '233 213 255' },
'300': { hex: '#d8b4fe', rgb: '216 180 254' },
'400': { hex: '#c084fc', rgb: '192 132 252' },
'500': { hex: '#a855f7', rgb: '168 85 247' },
'600': { hex: '#9333ea', rgb: '147 51 234' },
'700': { hex: '#7e22ce', rgb: '126 34 206' },
'800': { hex: '#6b21a8', rgb: '107 33 168' },
'900': { hex: '#581c87', rgb: '88 28 135' }
}
},
{
label: 'fuchsia',
shades: {
'50': { hex: '#fdf4ff', rgb: '253 244 255' },
'100': { hex: '#fae8ff', rgb: '250 232 255' },
'200': { hex: '#f5d0fe', rgb: '245 208 254' },
'300': { hex: '#f0abfc', rgb: '240 171 252' },
'400': { hex: '#e879f9', rgb: '232 121 249' },
'500': { hex: '#d946ef', rgb: '217 70 239' },
'600': { hex: '#c026d3', rgb: '192 38 211' },
'700': { hex: '#a21caf', rgb: '162 28 175' },
'800': { hex: '#86198f', rgb: '134 25 143' },
'900': { hex: '#701a75', rgb: '112 26 117' }
}
},
{
label: 'pink',
shades: {
'50': { hex: '#fdf2f8', rgb: '253 242 248' },
'100': { hex: '#fce7f3', rgb: '252 231 243' },
'200': { hex: '#fbcfe8', rgb: '251 207 232' },
'300': { hex: '#f9a8d4', rgb: '249 168 212' },
'400': { hex: '#f472b6', rgb: '244 114 182' },
'500': { hex: '#ec4899', rgb: '236 72 153' },
'600': { hex: '#db2777', rgb: '219 39 119' },
'700': { hex: '#be185d', rgb: '190 24 93' },
'800': { hex: '#9d174d', rgb: '157 23 77' },
'900': { hex: '#831843', rgb: '131 24 67' }
}
},
{
label: 'rose',
shades: {
'50': { hex: '#fff1f2', rgb: '255 241 242' },
'100': { hex: '#ffe4e6', rgb: '255 228 230' },
'200': { hex: '#fecdd3', rgb: '254 205 211' },
'300': { hex: '#fda4af', rgb: '253 164 175' },
'400': { hex: '#fb7185', rgb: '251 113 133' },
'500': { hex: '#f43f5e', rgb: '244 63 94' },
'600': { hex: '#e11d48', rgb: '225 29 72' },
'700': { hex: '#be123c', rgb: '190 18 60' },
'800': { hex: '#9f1239', rgb: '159 18 57' },
'900': { hex: '#881337', rgb: '136 19 55' }
}
}
];

View File

@ -0,0 +1,10 @@
export interface ConicStop {
/** The legend label value. */
label?: string;
/** The desired color value. */
color: string | object;
/** Starting stop value (0-100) */
start: number;
/** Ending stop value (0-100) */
end: number;
}

View File

@ -0,0 +1,2 @@
// Conic Gradient Types
export {};

View File

@ -0,0 +1,37 @@
<script>export let files = void 0;
export let fileInput = void 0;
export let name;
export let width = "";
export let button = "btn variant-filled";
function onButtonClick() {
if (fileInput)
fileInput.click();
}
function prunedRestProps() {
delete $$restProps.class;
return $$restProps;
}
$:
classesBase = `${$$props.class ?? ""}`;
$:
classesButton = `${button} ${width}`;
</script>
<div class="file-button {classesBase}" data-testid="file-button">
<!-- NOTE: Don't use `hidden` as it prevents `required` from operating -->
<div class="w-0 h-0 overflow-hidden">
<input type="file" bind:this={fileInput} bind:files {name} {...prunedRestProps()} on:change />
</div>
<!-- Button -->
<button
type="button"
class="file-button-btn {classesButton}"
disabled={$$restProps.disabled}
on:click={onButtonClick}
on:keydown
on:keyup
on:keypress
>
<slot>Select a File</slot>
</button>
</div>

View File

@ -0,0 +1,33 @@
import { SvelteComponentTyped } from "svelte";
declare const __propDef: {
props: {
[x: string]: any;
/** Bind FileList to the file input.*/
files?: FileList | undefined;
/** File input reference.*/
fileInput?: HTMLInputElement | undefined;
/** Required. Set a unique name for the file input.*/
name: string;
/** Provide classes to set the width.*/
width?: string | undefined;
/** Provide a button variant or other class styles.*/
button?: string | undefined;
};
events: {
change: Event;
keydown: KeyboardEvent;
keyup: KeyboardEvent;
keypress: KeyboardEvent;
} & {
[evt: string]: CustomEvent<any>;
};
slots: {
default: {};
};
};
export type FileButtonProps = typeof __propDef.props;
export type FileButtonEvents = typeof __propDef.events;
export type FileButtonSlots = typeof __propDef.slots;
export default class FileButton extends SvelteComponentTyped<FileButtonProps, FileButtonEvents, FileButtonSlots> {
}
export {};

View File

@ -0,0 +1,63 @@
<script>export let files = void 0;
export let fileInput = void 0;
export let name;
export let border = "border-2 border-dashed";
export let padding = "p-4 py-8";
export let rounded = "rounded-container-token";
export let regionInterface = "";
export let regionInterfaceText = "";
export let slotLead = "mb-4";
export let slotMessage = "";
export let slotMeta = "opacity-75";
const cBase = "textarea relative flex justify-center items-center";
const cInput = "w-full absolute top-0 left-0 right-0 bottom-0 z-[1] opacity-0 disabled:!opacity-0 cursor-pointer";
const cInterface = "flex justify-center items-center text-center";
$:
classesBase = `${cBase} ${border} ${padding} ${rounded} ${$$props.class ?? ""}`;
$:
classesInput = `${cInput}`;
$:
classesInterface = `${cInterface}`;
function prunedRestProps() {
delete $$restProps.class;
return $$restProps;
}
</script>
<div class="dropzone {classesBase}" class:opacity-50={$$restProps.disabled} data-testid="file-dropzone">
<!-- Input: File (hidden) -->
<!-- NOTE: keep `bind:files` here, unlike FileButton -->
<input
bind:files
bind:this={fileInput}
type="file"
{name}
class="dropzone-input {classesInput}"
{...prunedRestProps()}
on:change
on:dragenter
on:dragover
on:dragleave
on:drop
on:click
on:keydown
on:keyup
on:keypress
on:focus
on:focusin
on:focusout
/>
<!-- Interface -->
<div class="dropzone-interface {classesInterface} {regionInterface}">
<div class="dropzone-interface-text {regionInterfaceText}">
<!-- Lead -->
{#if $$slots.lead}<div class="dropzone-lead {slotLead}"><slot name="lead" /></div>{/if}
<!-- Message -->
<div class="dropzone-message {slotMessage}">
<slot name="message"><strong>Upload a file</strong> or drag and drop</slot>
</div>
<!-- Meta Text -->
{#if $$slots.meta}<small class="dropzone-meta {slotMeta}"><slot name="meta" /></small>{/if}
</div>
</div>
</div>

View File

@ -0,0 +1,55 @@
import { SvelteComponentTyped } from "svelte";
declare const __propDef: {
props: {
[x: string]: any;
/** Bind FileList to the file input.*/
files?: FileList | undefined;
/** File input reference.*/
fileInput?: HTMLInputElement | undefined;
/** Required. Set a unique name for the file input.*/
name: string;
/** Provide classes to set the border styles.*/
border?: string | undefined;
/** Provide classes to set the padding styles.*/
padding?: string | undefined;
/** Provide classes to set the box radius styles.*/
rounded?: string | undefined;
/** Provide arbitrary styles for the UI region.*/
regionInterface?: string | undefined;
/** Provide arbitrary styles for the UI text region.*/
regionInterfaceText?: string | undefined;
/** Provide arbitrary styles for lead slot container.*/
slotLead?: string | undefined;
/** Provide arbitrary styles for message slot container.*/
slotMessage?: string | undefined;
/** Provide arbitrary styles for meta text slot container.*/
slotMeta?: string | undefined;
};
events: {
change: Event;
dragenter: DragEvent;
dragover: DragEvent;
dragleave: DragEvent;
drop: DragEvent;
click: MouseEvent;
keydown: KeyboardEvent;
keyup: KeyboardEvent;
keypress: KeyboardEvent;
focus: FocusEvent;
focusin: FocusEvent;
focusout: FocusEvent;
} & {
[evt: string]: CustomEvent<any>;
};
slots: {
lead: {};
message: {};
meta: {};
};
};
export type FileDropzoneProps = typeof __propDef.props;
export type FileDropzoneEvents = typeof __propDef.events;
export type FileDropzoneSlots = typeof __propDef.slots;
export default class FileDropzone extends SvelteComponentTyped<FileDropzoneProps, FileDropzoneEvents, FileDropzoneSlots> {
}
export {};

View File

@ -0,0 +1,179 @@
<script context="module">import { fly, scale } from "svelte/transition";
import { prefersReducedMotionStore } from "../../index.js";
import { dynamicTransition } from "../../internal/transitions.js";
</script>
<script
generics="ListTransitionIn extends Transition = FlyTransition, ListTransitionOut extends Transition = FlyTransition, ChipTransitionIn extends Transition = ScaleTransition, ChipTransitionOut extends Transition = ScaleTransition"
>import { createEventDispatcher, onMount } from "svelte";
import { flip } from "svelte/animate";
const dispatch = createEventDispatcher();
export let input = "";
export let name;
export let value = [];
export let whitelist = [];
export let max = -1;
export let minlength = -1;
export let maxlength = -1;
export let allowUpperCase = false;
export let allowDuplicates = false;
export let validation = () => true;
export let duration = 150;
export let required = false;
export let chips = "variant-filled";
export let invalid = "input-error";
export let padding = "p-2";
export let rounded = "rounded-container-token";
export let regionChipWrapper = "";
export let regionChipList = "";
export let regionInput = "";
export let transitions = !$prefersReducedMotionStore;
export let listTransitionIn = fly;
export let listTransitionInParams = { duration: 150, opacity: 0, y: -20 };
export let listTransitionOut = fly;
export let listTransitionOutParams = { duration: 150, opacity: 0, y: -20 };
export let chipTransitionIn = scale;
export let chipTransitionInParams = { duration: 150, opacity: 0 };
export let chipTransitionOut = scale;
export let chipTransitionOutParams = { duration: 150, opacity: 0 };
const cBase = "textarea cursor-pointer";
const cChipWrapper = "space-y-4";
const cChipList = "flex flex-wrap gap-2";
const cInputField = "unstyled bg-transparent border-0 !ring-0 p-0 w-full";
let inputValid = true;
let chipValues = value?.map((val) => {
return { val, id: Math.random() };
}) || [];
function resetFormHandler() {
value = [];
}
let selectElement;
onMount(() => {
if (!selectElement.form)
return;
const externalForm = selectElement.form;
externalForm.addEventListener("reset", resetFormHandler);
return () => {
externalForm.removeEventListener("reset", resetFormHandler);
};
});
function onInputHandler() {
inputValid = true;
}
function validate() {
if (!input)
return false;
input = input.trim();
if (validation !== void 0 && !validation(input))
return false;
if (max !== -1 && value.length >= max)
return false;
if (minlength !== -1 && input.length < minlength)
return false;
if (maxlength !== -1 && input.length > maxlength)
return false;
if (whitelist.length > 0 && !whitelist.includes(input))
return false;
if (allowDuplicates === false && value.includes(input))
return false;
return true;
}
function addChip(event) {
event.preventDefault();
inputValid = validate();
if (inputValid === false) {
dispatch("invalid", { event, input });
return;
}
input = allowUpperCase ? input : input.toLowerCase();
value.push(input);
value = value;
chipValues.push({ val: input, id: Math.random() });
chipValues = chipValues;
dispatch("add", { event, chipIndex: value.length - 1, chipValue: input });
input = "";
}
function removeChip(event, chipIndex, chipValue) {
if ($$restProps.disabled)
return;
value.splice(chipIndex, 1);
value = value;
chipValues.splice(chipIndex, 1);
chipValues = chipValues;
dispatch("remove", { event, chipIndex, chipValue });
}
$:
classesInvalid = inputValid === false ? invalid : "";
$:
classesBase = `${cBase} ${padding} ${rounded} ${$$props.class ?? ""} ${classesInvalid}`;
$:
classesChipWrapper = `${cChipWrapper} ${regionChipWrapper}`;
$:
classesChipList = `${cChipList} ${regionChipList}`;
$:
classesInput = `${cInputField} ${regionInput}`;
$:
chipValues = value?.map((val, i) => {
if (chipValues[i]?.val === val)
return chipValues[i];
return { id: Math.random(), val };
}) || [];
</script>
<div class="input-chip {classesBase}" class:opacity-50={$$restProps.disabled}>
<!-- NOTE: Don't use `hidden` as it prevents `required` from operating -->
<div class="h-0 overflow-hidden">
<select bind:this={selectElement} bind:value {name} multiple {required} tabindex="-1">
<!-- NOTE: options are required! -->
{#each value as option}<option value={option}>{option}</option>{/each}
</select>
</div>
<!-- Chip Wrapper -->
<div class="input-chip-wrapper {classesChipWrapper}">
<!-- Input Field -->
<form on:submit={addChip}>
<input
type="text"
bind:value={input}
placeholder={$$restProps.placeholder ?? 'Enter values...'}
class="input-chip-field {classesInput}"
on:input={onInputHandler}
on:input
on:focus
on:blur
disabled={$$restProps.disabled}
/>
</form>
<!-- Chip List -->
{#if chipValues.length}
<div
class="input-chip-list {classesChipList}"
in:dynamicTransition|local={{ transition: listTransitionIn, params: listTransitionInParams, enabled: transitions }}
out:dynamicTransition|local={{ transition: listTransitionOut, params: listTransitionOutParams, enabled: transitions }}
>
{#each chipValues as { id, val }, i (id)}
<!-- Wrapping div required for FLIP animation -->
<div animate:flip={{ duration }}>
<button
type="button"
class="chip {chips}"
on:click={(e) => {
removeChip(e, i, val);
}}
on:click
on:keypress
on:keydown
on:keyup
in:dynamicTransition|local={{ transition: chipTransitionIn, params: chipTransitionInParams, enabled: transitions }}
out:dynamicTransition|local={{ transition: chipTransitionOut, params: chipTransitionOutParams, enabled: transitions }}
>
<span>{val}</span>
<span></span>
</button>
</div>
{/each}
</div>
{/if}
</div>
</div>

View File

@ -0,0 +1,98 @@
import { SvelteComponentTyped } from "svelte";
import { fly, scale } from 'svelte/transition';
import { type Transition, type TransitionParams } from '../../index.js';
type FlyTransition = typeof fly;
type ScaleTransition = typeof scale;
declare class __sveltets_Render<ListTransitionIn extends Transition = FlyTransition, ListTransitionOut extends Transition = FlyTransition, ChipTransitionIn extends Transition = ScaleTransition, ChipTransitionOut extends Transition = ScaleTransition> {
props(): {
[x: string]: any;
/** Bind the input value.*/
input?: string | undefined;
/** Set a unique select input name.*/
name: string;
/** An array of values.*/
value?: any[] | undefined;
/** Provide a whitelist of accepted values.*/
whitelist?: string[] | undefined;
/** Maximum number of chips. Set -1 to disable.*/
max?: number | undefined;
/** Set the minimum character length.*/
minlength?: number | undefined;
/** Set the maximum character length.*/
maxlength?: number | undefined;
/** When enabled, allows for uppercase values.*/
allowUpperCase?: boolean | undefined;
/** When enabled, allows for duplicate values.*/
allowDuplicates?: boolean | undefined;
/** Provide a custom validator function.*/
validation?: ((...args: any[]) => boolean) | undefined;
/** The duration of the flip (first, last, invert, play) animation.*/
duration?: number | undefined;
/** Set the required state for this input field.*/
required?: boolean | undefined;
/** Provide classes or a variant to style the chips.*/
chips?: string | undefined;
/** {{ event: Event, input: any }} invalid - Fires when the input value is invalid.*/
invalid?: string | undefined;
/** Provide classes to set padding styles.*/
padding?: string | undefined;
/** Provide classes to set border radius styles.*/
rounded?: string | undefined;
/** Provide arbitrary classes to style the chip wrapper region.*/
regionChipWrapper?: string | undefined;
/** Provide arbitrary classes to style the chip list region.*/
regionChipList?: string | undefined;
/** Provide arbitrary classes to style the input field region.*/
regionInput?: string | undefined;
/** Enable/Disable transitions*/
transitions?: boolean | undefined;
/** Provide the transition used in list on entry.*/
listTransitionIn?: ListTransitionIn | undefined;
/** Transition params provided to `ListTransitionIn`.*/
listTransitionInParams?: TransitionParams<ListTransitionIn> | undefined;
/** Provide the transition used in list on exit.*/
listTransitionOut?: ListTransitionOut | undefined;
/** Transition params provided to `ListTransitionOut`.*/
listTransitionOutParams?: TransitionParams<ListTransitionOut> | undefined;
/** Provide the transition used in chip on entry.*/
chipTransitionIn?: ChipTransitionIn | undefined;
/** Transition params provided to `ChipTransitionIn`.*/
chipTransitionInParams?: TransitionParams<ChipTransitionIn> | undefined;
/** Provide the transition used in chip on exit.*/
chipTransitionOut?: ChipTransitionOut | undefined;
/** Transition params provided to `ChipTransitionOut`.*/
chipTransitionOutParams?: TransitionParams<ChipTransitionOut> | undefined;
};
events(): {
input: Event;
focus: FocusEvent;
blur: FocusEvent;
click: MouseEvent;
keypress: KeyboardEvent;
keydown: KeyboardEvent;
keyup: KeyboardEvent;
add: CustomEvent<{
event: SubmitEvent;
chipIndex: number;
chipValue: string;
}>;
remove: CustomEvent<{
event: MouseEvent;
chipIndex: number;
chipValue: string;
}>;
invalid: CustomEvent<{
event: SubmitEvent;
input: string;
}>;
} & {
[evt: string]: CustomEvent<any>;
};
slots(): {};
}
export type InputChipProps<ListTransitionIn extends Transition = FlyTransition, ListTransitionOut extends Transition = FlyTransition, ChipTransitionIn extends Transition = ScaleTransition, ChipTransitionOut extends Transition = ScaleTransition> = ReturnType<__sveltets_Render<ListTransitionIn, ListTransitionOut, ChipTransitionIn, ChipTransitionOut>['props']>;
export type InputChipEvents<ListTransitionIn extends Transition = FlyTransition, ListTransitionOut extends Transition = FlyTransition, ChipTransitionIn extends Transition = ScaleTransition, ChipTransitionOut extends Transition = ScaleTransition> = ReturnType<__sveltets_Render<ListTransitionIn, ListTransitionOut, ChipTransitionIn, ChipTransitionOut>['events']>;
export type InputChipSlots<ListTransitionIn extends Transition = FlyTransition, ListTransitionOut extends Transition = FlyTransition, ChipTransitionIn extends Transition = ScaleTransition, ChipTransitionOut extends Transition = ScaleTransition> = ReturnType<__sveltets_Render<ListTransitionIn, ListTransitionOut, ChipTransitionIn, ChipTransitionOut>['slots']>;
export default class InputChip<ListTransitionIn extends Transition = FlyTransition, ListTransitionOut extends Transition = FlyTransition, ChipTransitionIn extends Transition = ScaleTransition, ChipTransitionOut extends Transition = ScaleTransition> extends SvelteComponentTyped<InputChipProps<ListTransitionIn, ListTransitionOut, ChipTransitionIn, ChipTransitionOut>, InputChipEvents<ListTransitionIn, ListTransitionOut, ChipTransitionIn, ChipTransitionOut>, InputChipSlots<ListTransitionIn, ListTransitionOut, ChipTransitionIn, ChipTransitionOut>> {
}
export {};

View File

@ -0,0 +1,27 @@
<script>import { setContext } from "svelte";
export let multiple = false;
export let spacing = "space-y-1";
export let rounded = "rounded-token";
export let active = "variant-filled";
export let hover = "hover:variant-soft";
export let padding = "px-4 py-2";
export let regionLead = "";
export let regionDefault = "";
export let regionTrail = "";
export let labelledby = "";
setContext("multiple", multiple);
setContext("rounded", rounded);
setContext("active", active);
setContext("hover", hover);
setContext("padding", padding);
setContext("regionLead", regionLead);
setContext("regionDefault", regionDefault);
setContext("regionTrail", regionTrail);
const cBase = "";
$:
classesBase = `${cBase} ${spacing} ${rounded} ${$$props.class ?? ""}`;
</script>
<div class="listbox {classesBase}" role="listbox" aria-labelledby={labelledby} data-testid="listbox">
<slot />
</div>

View File

@ -0,0 +1,38 @@
import { SvelteComponentTyped } from "svelte";
declare const __propDef: {
props: {
[x: string]: any;
/** Enable selection of multiple items.*/
multiple?: boolean | undefined;
/** Provide class to set the vertical spacing style.*/
spacing?: string | undefined;
/** Provide classes to set the listbox box radius styles.*/
rounded?: string | undefined;
/** Provide classes to set the listbox item active background styles.*/
active?: string | undefined;
/** Provide classes to set the listbox item hover background styles.*/
hover?: string | undefined;
/** Provide classes to set the listbox item padding styles.*/
padding?: string | undefined;
/** Provide arbitrary classes to style the lead region.*/
regionLead?: string | undefined;
/** Provide arbitrary classes to the default region.*/
regionDefault?: string | undefined;
/** Provide arbitrary classes to the trail region.*/
regionTrail?: string | undefined;
/** Provide the ARIA labelledby value.*/
labelledby?: string | undefined;
};
events: {
[evt: string]: CustomEvent<any>;
};
slots: {
default: {};
};
};
export type ListBoxProps = typeof __propDef.props;
export type ListBoxEvents = typeof __propDef.events;
export type ListBoxSlots = typeof __propDef.slots;
export default class ListBox extends SvelteComponentTyped<ListBoxProps, ListBoxEvents, ListBoxSlots> {
}
export {};

View File

@ -0,0 +1,113 @@
<script>import { getContext } from "svelte";
export let group;
export let name;
export let value;
export let multiple = getContext("multiple");
export let rounded = getContext("rounded");
export let active = getContext("active");
export let hover = getContext("hover");
export let padding = getContext("padding");
export let regionLead = getContext("regionLead");
export let regionDefault = getContext("regionDefault");
export let regionTrail = getContext("regionTrail");
const cBase = "cursor-pointer -outline-offset-[3px]";
const cLabel = "flex items-center space-x-4";
let checked;
let elemInput;
function areDeeplyEqual(param1, param2) {
if (param1 === param2)
return true;
if (!(param1 instanceof Object) || !(param2 instanceof Object))
return false;
const keys1 = Object.keys(param1);
const keys2 = Object.keys(param2);
if (keys1.length !== keys2.length)
return false;
for (const key of keys1) {
const value1 = param1[key];
const value2 = param2[key];
if (!areDeeplyEqual(value1, value2))
return false;
}
return true;
}
$:
if (multiple)
updateCheckbox(group);
$:
if (multiple)
updateGroup(checked);
function updateCheckbox(group2) {
checked = group2.indexOf(value) >= 0;
}
function updateGroup(checked2) {
const index = group.indexOf(value);
if (checked2) {
if (index < 0) {
group.push(value);
group = group;
}
} else {
if (index >= 0) {
group.splice(index, 1);
group = group;
}
}
}
function onKeyDown(event) {
if (["Enter", "Space"].includes(event.code)) {
event.preventDefault();
elemInput.click();
}
}
const cRegionLead = "";
const cRegionDefault = "flex-1";
const cRegionTrail = "";
$:
selected = multiple ? group.some((groupVal) => areDeeplyEqual(value, groupVal)) : areDeeplyEqual(group, value);
$:
classesActive = selected ? active : hover;
$:
classesBase = `${cBase} ${rounded} ${padding} ${classesActive} ${$$props.class ?? ""}`;
$:
classesLabel = `${cLabel}`;
$:
classesRegionLead = `${cRegionLead} ${regionLead}`;
$:
classesRegionDefault = `${cRegionDefault} ${regionDefault}`;
$:
classesRegionTrail = `${cRegionTrail} ${regionTrail}`;
</script>
<label>
<!-- A11y attributes are not allowed on <label> -->
<div
class="listbox-item {classesBase}"
data-testid="listbox-item"
role="option"
aria-selected={selected}
tabindex="0"
on:keydown={onKeyDown}
on:keydown
on:keyup
on:keypress
>
<!-- NOTE: Don't use `hidden` as it prevents `required` from operating -->
<div class="h-0 w-0 overflow-hidden">
{#if multiple}
<input bind:this={elemInput} type="checkbox" {name} {value} bind:checked tabindex="-1" on:click on:change />
{:else}
<input bind:this={elemInput} type="radio" bind:group {name} {value} tabindex="-1" on:click on:change />
{/if}
</div>
<!-- <slot /> -->
<div class="listbox-label {classesLabel}">
<!-- Slot: Lead -->
{#if $$slots.lead}<div class="listbox-label-lead {classesRegionLead}"><slot name="lead" /></div>{/if}
<!-- Slot: Default -->
<div class="listbox-label-content {classesRegionDefault}"><slot /></div>
<!-- Slot: Trail -->
{#if $$slots.trail}<div class="listbox-label-trail {classesRegionTrail}"><slot name="trail" /></div>{/if}
</div>
</div>
</label>

View File

@ -0,0 +1,40 @@
import { SvelteComponentTyped } from "svelte";
declare const __propDef: {
props: {
[x: string]: any;
/** Set the radio group binding value.*/
group: any;
/** Set a unique name value for the input.*/
name: string;
/** Set the input's value.*/
value: any;
multiple?: string | undefined;
rounded?: string | undefined;
active?: string | undefined;
hover?: string | undefined;
padding?: string | undefined;
regionLead?: string | undefined;
regionDefault?: string | undefined;
regionTrail?: string | undefined;
};
events: {
keydown: KeyboardEvent;
keyup: KeyboardEvent;
keypress: KeyboardEvent;
click: MouseEvent;
change: Event;
} & {
[evt: string]: CustomEvent<any>;
};
slots: {
lead: {};
default: {};
trail: {};
};
};
export type ListBoxItemProps = typeof __propDef.props;
export type ListBoxItemEvents = typeof __propDef.events;
export type ListBoxItemSlots = typeof __propDef.slots;
export default class ListBoxItem extends SvelteComponentTyped<ListBoxItemProps, ListBoxItemEvents, ListBoxItemSlots> {
}
export {};

View File

@ -0,0 +1,190 @@
<script>import { createEventDispatcher } from "svelte";
import { leftAngles, leftArrow, rightAngles, rightArrow } from "./icons.js";
const dispatch = createEventDispatcher();
export let settings = { page: 0, limit: 5, size: 0, amounts: [1, 2, 5, 10] };
export let disabled = false;
export let showPreviousNextButtons = true;
export let showFirstLastButtons = false;
export let showNumerals = false;
export let maxNumerals = 1;
export let justify = "justify-between";
export let select = "select min-w-[150px]";
export let amountText = "Items";
export let regionControl = "btn-group";
export let controlVariant = "variant-filled";
export let controlSeparator = "";
export let active = "variant-filled-primary";
export let buttonClasses = "!px-3 !py-1.5 fill-current";
export let buttonTextPrevious = leftArrow;
export let buttonTextNext = rightArrow;
export let buttonTextFirst = leftAngles;
export let buttonTextLast = rightAngles;
export let separatorText = "of";
export let labelFirst = "First page";
export let labelPrevious = "Previous page";
export let labelNext = "Next page";
export let labelLast = "Last page";
const cBase = "flex flex-col md:flex-row items-center space-y-4 md:space-y-0 md:space-x-4";
const cLabel = "w-full md:w-auto";
let lastPage = Math.max(0, Math.ceil(settings.size / settings.limit - 1));
let controlPages = getNumerals();
function onChangeLength() {
dispatch("amount", settings.limit);
lastPage = Math.max(0, Math.ceil(settings.size / settings.limit - 1));
if (settings.page > lastPage) {
settings.page = lastPage;
}
controlPages = getNumerals();
}
function gotoPage(page) {
if (page < 0)
return;
settings.page = page;
dispatch("page", settings.page);
controlPages = getNumerals();
}
function getFullNumerals() {
const pages = [];
for (let index = 0; index <= lastPage; index++) {
pages.push(index);
}
return pages;
}
function getNumerals() {
const pages = [];
const isWithinLeftSection = settings.page < maxNumerals + 2;
const isWithinRightSection = settings.page > lastPage - (maxNumerals + 2);
if (lastPage <= maxNumerals * 2 + 1)
return getFullNumerals();
pages.push(0);
if (!isWithinLeftSection)
pages.push(-1);
if (isWithinLeftSection || isWithinRightSection) {
const sectionStart = isWithinLeftSection ? 1 : lastPage - (maxNumerals + 2);
const sectionEnd = isWithinRightSection ? lastPage - 1 : maxNumerals + 2;
for (let i = sectionStart; i <= sectionEnd; i++) {
pages.push(i);
}
} else {
for (let i = settings.page - maxNumerals; i <= settings.page + maxNumerals; i++) {
pages.push(i);
}
}
if (!isWithinRightSection)
pages.push(-1);
pages.push(lastPage);
return pages;
}
function updateSize(size) {
lastPage = Math.max(0, Math.ceil(size / settings.limit - 1));
controlPages = getNumerals();
}
$:
classesButtonActive = (page) => {
return page === settings.page ? `${active} pointer-events-none` : "";
};
$:
maxNumerals, onChangeLength();
$:
updateSize(settings.size);
$:
classesBase = `${cBase} ${justify} ${$$props.class ?? ""}`;
$:
classesLabel = `${cLabel}`;
$:
classesSelect = `${select}`;
$:
classesControls = `${regionControl} ${controlVariant} ${controlSeparator}`;
</script>
<div class="paginator {classesBase}" data-testid="paginator">
<!-- Select Amount -->
{#if settings.amounts.length}
<label class="paginator-label {classesLabel}">
<select
bind:value={settings.limit}
on:change={onChangeLength}
class="paginator-select {classesSelect}"
{disabled}
aria-label="Select Amount"
>
{#each settings.amounts as amount}<option value={amount}>{amount} {amountText}</option>{/each}
</select>
</label>
{/if}
<!-- Controls -->
<div class="paginator-controls {classesControls}">
<!-- Button: First -->
{#if showFirstLastButtons}
<button
type="button"
aria-label={labelFirst}
class={buttonClasses}
on:click={() => {
gotoPage(0);
}}
disabled={disabled || settings.page === 0}
>
{@html buttonTextFirst}
</button>
{/if}
<!-- Button: Back -->
{#if showPreviousNextButtons}
<button
type="button"
aria-label={labelPrevious}
class={buttonClasses}
on:click={() => {
gotoPage(settings.page - 1);
}}
disabled={disabled || settings.page === 0}
>
{@html buttonTextPrevious}
</button>
{/if}
<!-- Center -->
{#if showNumerals === false}
<!-- Details -->
<button type="button" class="{buttonClasses} pointer-events-none !text-sm">
{settings.page * settings.limit + 1}-{Math.min(settings.page * settings.limit + settings.limit, settings.size)}&nbsp;<span
class="opacity-50">{separatorText} {settings.size}</span
>
</button>
{:else}
<!-- Numeric Row -->
{#each controlPages as page}
<button type="button" class="{buttonClasses} {classesButtonActive(page)}" on:click={() => gotoPage(page)}>
{page >= 0 ? page + 1 : '...'}
</button>
{/each}
{/if}
<!-- Button: Next -->
{#if showPreviousNextButtons}
<button
type="button"
aria-label={labelNext}
class={buttonClasses}
on:click={() => {
gotoPage(settings.page + 1);
}}
disabled={disabled || (settings.page + 1) * settings.limit >= settings.size}
>
{@html buttonTextNext}
</button>
{/if}
<!-- Button: last -->
{#if showFirstLastButtons}
<button
type="button"
aria-label={labelLast}
class={buttonClasses}
on:click={() => {
gotoPage(lastPage);
}}
disabled={disabled || (settings.page + 1) * settings.limit >= settings.size}
>
{@html buttonTextLast}
</button>
{/if}
</div>
</div>

View File

@ -0,0 +1,68 @@
import { SvelteComponentTyped } from "svelte";
import type { PaginationSettings } from './types.js';
declare const __propDef: {
props: {
[x: string]: any;
/** Pass the page setting object.*/
settings?: PaginationSettings | undefined;
/** Sets selection and buttons to disabled state on-demand.*/
disabled?: boolean | undefined;
/** Show Previous and Next buttons.*/
showPreviousNextButtons?: boolean | undefined;
/** Show First and Last buttons.*/
showFirstLastButtons?: boolean | undefined;
/** Displays a numeric row of page buttons.*/
showNumerals?: boolean | undefined;
/** Maximum number of active page siblings in the numeric row.*/
maxNumerals?: number | undefined;
/** Provide classes to set flexbox justification.*/
justify?: string | undefined;
/** Provide classes to style the select input.*/
select?: string | undefined;
/** Set the text for the amount selection input.*/
amountText?: string | undefined;
/** Set the base classes for the control element.*/
regionControl?: string | undefined;
/** Provide variant style for the control button group.*/
controlVariant?: string | undefined;
/** Provide separator style for the control button group.*/
controlSeparator?: string | undefined;
/** Provide arbitrary classes to the active page buttons.*/
active?: string | undefined;
/** * Set the base button classes.*/
buttonClasses?: string | undefined;
/** Set the label for the Previous button.*/
buttonTextPrevious?: string | undefined;
/** Set the label for the Next button.*/
buttonTextNext?: string | undefined;
/** Set the label for the First button.*/
buttonTextFirst?: string | undefined;
/** Set the label for the Last button.*/
buttonTextLast?: string | undefined;
/** Set the label for the pages separator.*/
separatorText?: string | undefined;
/** Provide the ARIA label for the First page button.*/
labelFirst?: string | undefined;
/** Provide the ARIA label for the Previous page button.*/
labelPrevious?: string | undefined;
/** Provide the ARIA label for the Next page button.*/
labelNext?: string | undefined;
/** Provide the ARIA label for the Last page button.*/
labelLast?: string | undefined;
};
events: {
/** {{ length: number }} amount - Fires when the amount selection input changes.*/
amount: CustomEvent<number>;
/** {{ page: number }} page Fires when the next/back buttons are pressed.*/
page: CustomEvent<number>;
} & {
[evt: string]: CustomEvent<any>;
};
slots: {};
};
export type PaginatorProps = typeof __propDef.props;
export type PaginatorEvents = typeof __propDef.events;
export type PaginatorSlots = typeof __propDef.slots;
export default class Paginator extends SvelteComponentTyped<PaginatorProps, PaginatorEvents, PaginatorSlots> {
}
export {};

View File

@ -0,0 +1,4 @@
export declare const leftArrow = "<svg xmlns=\"http://www.w3.org/2000/svg\" height=\"1em\" viewBox=\"0 0 448 512\"><!--! Font Awesome Free 6.4.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2023 Fonticons, Inc. --><path d=\"M9.4 233.4c-12.5 12.5-12.5 32.8 0 45.3l160 160c12.5 12.5 32.8 12.5 45.3 0s12.5-32.8 0-45.3L109.2 288 416 288c17.7 0 32-14.3 32-32s-14.3-32-32-32l-306.7 0L214.6 118.6c12.5-12.5 12.5-32.8 0-45.3s-32.8-12.5-45.3 0l-160 160z\"/></svg>";
export declare const rightArrow = "<svg xmlns=\"http://www.w3.org/2000/svg\" height=\"1em\" viewBox=\"0 0 448 512\"><!--! Font Awesome Free 6.4.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2023 Fonticons, Inc. --><path d=\"M438.6 278.6c12.5-12.5 12.5-32.8 0-45.3l-160-160c-12.5-12.5-32.8-12.5-45.3 0s-12.5 32.8 0 45.3L338.8 224 32 224c-17.7 0-32 14.3-32 32s14.3 32 32 32l306.7 0L233.4 393.4c-12.5 12.5-12.5 32.8 0 45.3s32.8 12.5 45.3 0l160-160z\"/></svg>";
export declare const leftAngles = "<svg xmlns=\"http://www.w3.org/2000/svg\" height=\"1em\" viewBox=\"0 0 512 512\"><!--! Font Awesome Free 6.4.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2023 Fonticons, Inc. --><path d=\"M41.4 233.4c-12.5 12.5-12.5 32.8 0 45.3l160 160c12.5 12.5 32.8 12.5 45.3 0s12.5-32.8 0-45.3L109.3 256 246.6 118.6c12.5-12.5 12.5-32.8 0-45.3s-32.8-12.5-45.3 0l-160 160zm352-160l-160 160c-12.5 12.5-12.5 32.8 0 45.3l160 160c12.5 12.5 32.8 12.5 45.3 0s12.5-32.8 0-45.3L301.3 256 438.6 118.6c12.5-12.5 12.5-32.8 0-45.3s-32.8-12.5-45.3 0z\"/></svg>";
export declare const rightAngles = "<svg xmlns=\"http://www.w3.org/2000/svg\" height=\"1em\" viewBox=\"0 0 512 512\"><!--! Font Awesome Free 6.4.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2023 Fonticons, Inc. --><path d=\"M470.6 278.6c12.5-12.5 12.5-32.8 0-45.3l-160-160c-12.5-12.5-32.8-12.5-45.3 0s-12.5 32.8 0 45.3L402.7 256 265.4 393.4c-12.5 12.5-12.5 32.8 0 45.3s32.8 12.5 45.3 0l160-160zm-352 160l160-160c12.5-12.5 12.5-32.8 0-45.3l-160-160c-12.5-12.5-32.8-12.5-45.3 0s-12.5 32.8 0 45.3L210.7 256 73.4 393.4c-12.5 12.5-12.5 32.8 0 45.3s32.8 12.5 45.3 0z\"/></svg>";

View File

@ -0,0 +1,4 @@
export const leftArrow = `<svg xmlns="http://www.w3.org/2000/svg" height="1em" viewBox="0 0 448 512"><!--! Font Awesome Free 6.4.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2023 Fonticons, Inc. --><path d="M9.4 233.4c-12.5 12.5-12.5 32.8 0 45.3l160 160c12.5 12.5 32.8 12.5 45.3 0s12.5-32.8 0-45.3L109.2 288 416 288c17.7 0 32-14.3 32-32s-14.3-32-32-32l-306.7 0L214.6 118.6c12.5-12.5 12.5-32.8 0-45.3s-32.8-12.5-45.3 0l-160 160z"/></svg>`;
export const rightArrow = `<svg xmlns="http://www.w3.org/2000/svg" height="1em" viewBox="0 0 448 512"><!--! Font Awesome Free 6.4.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2023 Fonticons, Inc. --><path d="M438.6 278.6c12.5-12.5 12.5-32.8 0-45.3l-160-160c-12.5-12.5-32.8-12.5-45.3 0s-12.5 32.8 0 45.3L338.8 224 32 224c-17.7 0-32 14.3-32 32s14.3 32 32 32l306.7 0L233.4 393.4c-12.5 12.5-12.5 32.8 0 45.3s32.8 12.5 45.3 0l160-160z"/></svg>`;
export const leftAngles = `<svg xmlns="http://www.w3.org/2000/svg" height="1em" viewBox="0 0 512 512"><!--! Font Awesome Free 6.4.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2023 Fonticons, Inc. --><path d="M41.4 233.4c-12.5 12.5-12.5 32.8 0 45.3l160 160c12.5 12.5 32.8 12.5 45.3 0s12.5-32.8 0-45.3L109.3 256 246.6 118.6c12.5-12.5 12.5-32.8 0-45.3s-32.8-12.5-45.3 0l-160 160zm352-160l-160 160c-12.5 12.5-12.5 32.8 0 45.3l160 160c12.5 12.5 32.8 12.5 45.3 0s12.5-32.8 0-45.3L301.3 256 438.6 118.6c12.5-12.5 12.5-32.8 0-45.3s-32.8-12.5-45.3 0z"/></svg>`;
export const rightAngles = `<svg xmlns="http://www.w3.org/2000/svg" height="1em" viewBox="0 0 512 512"><!--! Font Awesome Free 6.4.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2023 Fonticons, Inc. --><path d="M470.6 278.6c12.5-12.5 12.5-32.8 0-45.3l-160-160c-12.5-12.5-32.8-12.5-45.3 0s-12.5 32.8 0 45.3L402.7 256 265.4 393.4c-12.5 12.5-12.5 32.8 0 45.3s32.8 12.5 45.3 0l160-160zm-352 160l160-160c12.5-12.5 12.5-32.8 0-45.3l-160-160c-12.5-12.5-32.8-12.5-45.3 0s-12.5 32.8 0 45.3L210.7 256 73.4 393.4c-12.5 12.5-12.5 32.8 0 45.3s32.8 12.5 45.3 0z"/></svg>`;

View File

@ -0,0 +1,10 @@
export interface PaginationSettings {
/** Index of the current page to display. */
page: number;
/** Current number of items to display. */
limit: number;
/** The total size (length) of your source content. */
size: number;
/** List of amounts available to the select input */
amounts: number[];
}

View File

@ -0,0 +1,2 @@
// Pagination Types
export {};

View File

@ -0,0 +1,48 @@
<script>export let value = void 0;
export let min = 0;
export let max = 100;
export let height = "h-2";
export let rounded = "rounded-token";
export let meter = "bg-surface-900-50-token";
export let track = "bg-surface-200-700-token";
export let labelledby = "";
const cTrack = "w-full overflow-hidden";
const cMeter = "h-full";
$:
fillPercent = value ? 100 * (value - min) / (max - min) : 0;
$:
indeterminate = value === void 0 || value < 0;
$:
classesIndeterminate = indeterminate ? "animIndeterminate" : "";
$:
classesTrack = `${cTrack} ${height} ${rounded} ${track} ${$$props.class ?? ""}`;
$:
classesMeter = `${cMeter} ${rounded} ${classesIndeterminate} ${meter}`;
</script>
<!-- Track -->
<div
class="progress-bar {classesTrack}"
data-testid="progress-bar"
role="progressbar"
aria-labelledby={labelledby}
aria-valuenow={value}
aria-valuemin={min}
aria-valuemax={max - min}
>
<!-- Meter -->
<div class="progress-bar-meter {classesMeter} {classesMeter}" style:width="{indeterminate ? 100 : fillPercent}%" />
</div>
<style>
.animIndeterminate {
transform-origin: 0% 50%;
animation: animIndeterminate 2s infinite linear;
}
/* prettier-ignore */
@keyframes animIndeterminate {
0% { transform: translateX(0) scaleX(0); }
40% { transform: translateX(0) scaleX(0.4); }
100% { transform: translateX(100%) scaleX(0.5); }
}
</style>

View File

@ -0,0 +1,32 @@
import { SvelteComponentTyped } from "svelte";
declare const __propDef: {
props: {
[x: string]: any;
/** Specifies the amount completed. Indeterminate when `undefined`.*/
value?: number | undefined;
/** Minimum amount the bar represents.*/
min?: number | undefined;
/** Maximum amount the bar represents.*/
max?: number | undefined;
/** Provide classes to set track height.*/
height?: string | undefined;
/** Provide classes to set rounded styles.*/
rounded?: string | undefined;
/** Provide arbitrary classes to style the meter element.*/
meter?: string | undefined;
/** Provide arbitrary classes to style the track element.*/
track?: string | undefined;
/** Provide the ARIA labelledby value.*/
labelledby?: string | undefined;
};
events: {
[evt: string]: CustomEvent<any>;
};
slots: {};
};
export type ProgressBarProps = typeof __propDef.props;
export type ProgressBarEvents = typeof __propDef.events;
export type ProgressBarSlots = typeof __propDef.slots;
export default class ProgressBar extends SvelteComponentTyped<ProgressBarProps, ProgressBarEvents, ProgressBarSlots> {
}
export {};

View File

@ -0,0 +1,72 @@
<!-- Reference: https://css-tricks.com/building-progress-ring-quickly/ -->
<script>import { afterUpdate } from "svelte";
export let value = void 0;
export let stroke = 40;
export let font = 56;
export let strokeLinecap = "butt";
export let width = "w-36";
export let meter = "stroke-surface-900 dark:stroke-surface-50";
export let track = "stroke-surface-500/30";
export let fill = "fill-token";
export let labelledby = "";
const cBase = "progress-radial relative overflow-hidden";
const cBaseTrack = "fill-transparent";
const cBaseMeter = "fill-transparent transition-[stroke-dashoffset] duration-200 -rotate-90 origin-[50%_50%]";
const baseSize = 512;
const radius = baseSize / 2 - stroke / 2;
let circumference = radius;
let dashoffset;
function setProgress(percent) {
circumference = radius * 2 * Math.PI;
dashoffset = circumference - percent / 100 * circumference;
}
setProgress(0);
afterUpdate(() => {
setProgress(value === void 0 ? 25 : value);
});
$:
classesBase = `${cBase} ${width} ${$$props.class ?? ""}`;
</script>
<figure
class="progress-radial {classesBase}"
data-testid="progress-radial"
role="meter"
aria-labelledby={labelledby}
aria-valuenow={value || 0}
aria-valuetext={value ? `${value}%` : 'Indeterminate Spinner'}
aria-valuemin={0}
aria-valuemax={100}
>
<!-- Draw SVG -->
<svg viewBox="0 0 {baseSize} {baseSize}" class="rounded-full" class:animate-spin={value === undefined}>
<!-- Track -->
<circle class="progress-radial-track {cBaseTrack} {track}" stroke-width={stroke} r={radius} cx="50%" cy="50%" />
<!-- Meter -->
<circle
class="progress-radial-meter {cBaseMeter} {meter}"
stroke-width={stroke}
r={radius}
cx="50%"
cy="50%"
style:stroke-dasharray="{circumference}
{circumference}"
style:stroke-dashoffset={dashoffset}
stroke-linecap={strokeLinecap}
/>
<!-- Center Text -->
{#if value != undefined && value >= 0 && $$slots.default}
<text
x="50%"
y="50%"
text-anchor="middle"
dominant-baseline="middle"
font-weight="bold"
font-size={font}
class="progress-radial-text {fill}"><slot /></text
>
{/if}
</svg>
</figure>

View File

@ -0,0 +1,36 @@
import { SvelteComponentTyped } from "svelte";
declare const __propDef: {
props: {
[x: string]: any;
/** Set the meter fill amount. Shows as indeterminate when set `undefined`.*/
value?: number | undefined;
/** Sets the base stroke width. Scales responsively.*/
stroke?: number | undefined;
/** Sets the base font size. Scales responsively.*/
font?: number | undefined;
/** Sets the stoke-linecap value*/
strokeLinecap?: "butt" | "round" | "square" | undefined;
/** Provide classes to set the width.*/
width?: string | undefined;
/** Provide classes to set meter color.*/
meter?: string | undefined;
/** Provide classes to set track color.*/
track?: string | undefined;
/** Provide classes to set the SVG text fill color.*/
fill?: string | undefined;
/** Provide the ARIA labelledby value.*/
labelledby?: string | undefined;
};
events: {
[evt: string]: CustomEvent<any>;
};
slots: {
default: {};
};
};
export type ProgressRadialProps = typeof __propDef.props;
export type ProgressRadialEvents = typeof __propDef.events;
export type ProgressRadialSlots = typeof __propDef.slots;
export default class ProgressRadial extends SvelteComponentTyped<ProgressRadialProps, ProgressRadialEvents, ProgressRadialSlots> {
}
export {};

View File

@ -0,0 +1,30 @@
<script>import { setContext } from "svelte";
export let display = "inline-flex";
export let background = "bg-surface-200-700-token";
export let border = "border-token border-surface-400-500-token";
export let spacing = "";
export let rounded = "rounded-token";
export let padding = "px-4 py-1";
export let active = "variant-filled";
export let hover = "hover:variant-soft";
export let color = "";
export let fill = "";
export let regionLabel = "";
export let labelledby = "";
setContext("rounded", rounded);
setContext("padding", padding);
setContext("active", active);
setContext("hover", hover);
setContext("color", color);
setContext("fill", fill);
setContext("regionLabel", regionLabel);
const cBase = "p-1";
$:
spacing = `${display.includes("flex-col") ? "" : "space-x-1"}`;
$:
classesBase = `${cBase} ${display} ${background} ${border} ${spacing} ${rounded} ${$$props.class ?? ""}`;
</script>
<div class="radio-group {classesBase}" data-testid="radio-group" role="radiogroup" aria-labelledby={labelledby}>
<slot />
</div>

View File

@ -0,0 +1,42 @@
import { SvelteComponentTyped } from "svelte";
declare const __propDef: {
props: {
[x: string]: any;
/** Provide display classes. Set `flex` to stretch full width.*/
display?: string | undefined;
/** Provide classes to set the base background color.*/
background?: string | undefined;
/** Provide classes to set the border styles.*/
border?: string | undefined;
/** Provide classes horizontal spacing between items.*/
spacing?: string | undefined;
/** Provide classes to set the border radius.*/
rounded?: string | undefined;
/** Provide classes to set the RadioItem padding.*/
padding?: string | undefined;
/** Provide classes to set the active item color.*/
active?: string | undefined;
/** Provide classes to set the hover style.*/
hover?: string | undefined;
/** Provide classes to set the highlighted text color.*/
color?: string | undefined;
/** Provide classes to set the highlighted SVG fill color.*/
fill?: string | undefined;
/** Provide classes for the label region.*/
regionLabel?: string | undefined;
/** Provide the ARIA labelledby value.*/
labelledby?: string | undefined;
};
events: {
[evt: string]: CustomEvent<any>;
};
slots: {
default: {};
};
};
export type RadioGroupProps = typeof __propDef.props;
export type RadioGroupEvents = typeof __propDef.events;
export type RadioGroupSlots = typeof __propDef.slots;
export default class RadioGroup extends SvelteComponentTyped<RadioGroupProps, RadioGroupEvents, RadioGroupSlots> {
}
export {};

View File

@ -0,0 +1,61 @@
<script>import { getContext } from "svelte";
export let group;
export let name;
export let value;
export let title = "";
export let label = "";
export let rounded = getContext("rounded");
export let padding = getContext("padding");
export let active = getContext("active");
export let hover = getContext("hover");
export let color = getContext("color");
export let fill = getContext("fill");
export let regionLabel = getContext("regionLabel");
const cBase = "flex-auto";
const cWrapper = "text-base text-center cursor-pointer";
const cDisabled = "opacity-50 cursor-not-allowed";
let elemInput;
function onKeyDown(event) {
if (["Enter", "Space"].includes(event.code)) {
event.preventDefault();
elemInput.click();
}
}
$:
checked = value === group;
$:
classesActive = checked ? `${active} ${color} ${fill}` : hover;
$:
classesDisabled = $$props.disabled ? cDisabled : "";
$:
classsBase = `${cBase}`;
$:
classesWrapper = `${cWrapper} ${padding} ${rounded} ${classesActive} ${classesDisabled} ${$$props.class ?? ""}`;
function prunedRestProps() {
delete $$restProps.class;
return $$restProps;
}
</script>
<label class="radio-label {classsBase} {regionLabel}">
<!-- A11y attributes are not allowed on <label> -->
<div
class="radio-item {classesWrapper}"
data-testid="radio-item"
role="radio"
aria-checked={checked}
aria-label={label}
tabindex="0"
{title}
on:keydown={onKeyDown}
on:keydown
on:keyup
on:keypress
>
<!-- NOTE: Don't use `hidden` as it prevents `required` from operating -->
<div class="h-0 w-0 overflow-hidden">
<input bind:this={elemInput} type="radio" bind:group {name} {value} {...prunedRestProps()} tabindex="-1" on:click on:change />
</div>
<slot />
</div>
</label>

View File

@ -0,0 +1,41 @@
import { SvelteComponentTyped } from "svelte";
declare const __propDef: {
props: {
[x: string]: any;
/** Set the radio group binding value.*/
group: any;
/** Set a unique name value for the input.*/
name: string;
/** Set the input's value.*/
value: any;
/** Set the hover title.*/
title?: string | undefined;
/** Defines a semantic ARIA label.*/
label?: string | undefined;
rounded?: string | undefined;
padding?: string | undefined;
active?: string | undefined;
hover?: string | undefined;
color?: string | undefined;
fill?: string | undefined;
regionLabel?: string | undefined;
};
events: {
keydown: KeyboardEvent;
keyup: KeyboardEvent;
keypress: KeyboardEvent;
click: MouseEvent;
change: Event;
} & {
[evt: string]: CustomEvent<any>;
};
slots: {
default: {};
};
};
export type RadioItemProps = typeof __propDef.props;
export type RadioItemEvents = typeof __propDef.events;
export type RadioItemSlots = typeof __propDef.slots;
export default class RadioItem extends SvelteComponentTyped<RadioItemProps, RadioItemEvents, RadioItemSlots> {
}
export {};

View File

@ -0,0 +1,72 @@
<script>import { afterUpdate } from "svelte";
export let name;
export let id = String(Math.random());
export let value = 0;
export let min = 0;
export let max = 100;
export let step = 1;
export let ticked = false;
export let accent = "accent-surface-900 dark:accent-surface-50";
export let label = "";
const cBase = "space-y-2";
const cBaseLabel = "";
const cBaseContent = "flex justify-center py-2";
const cBaseInput = "w-full h-2";
let tickmarks;
function setTicks() {
if (ticked == false)
return;
tickmarks = Array.from({ length: max - min + 1 }, (_, i) => i + min);
}
if (ticked)
setTicks();
afterUpdate(() => {
setTicks();
});
$:
classesBase = `${cBase} ${$$props.class ?? ""}`;
$:
classesInput = `${cBaseInput} ${accent}`;
function prunedRestProps() {
delete $$restProps.class;
return $$restProps;
}
</script>
<div class="range-slider {classesBase}" data-testid="range-slider">
<!-- Slot: Default -->
{#if $$slots.default}<label class="range-slider-label {cBaseLabel}" for={id}><slot /></label>{/if}
<!-- Content -->
<div class="range-content {cBaseContent}">
<!-- Input -->
<input
type="range"
{id}
{name}
class="range-slider-input {classesInput}"
list="tickmarks-{id}"
aria-label={label}
{min}
{max}
{step}
bind:value
on:click
on:change
on:blur
{...prunedRestProps()}
/>
<!-- Tickmarks -->
{#if ticked && tickmarks && tickmarks.length}
<datalist id="tickmarks-{id}" class="range-slider-ticks">
{#each tickmarks as tm}
<option value={tm} label={tm} />
{/each}
</datalist>
{/if}
</div>
<!-- Slot: Trail -->
{#if $$slots.trail}<div class="range-slider-trail"><slot name="trail" /></div>{/if}
</div>

View File

@ -0,0 +1,41 @@
import { SvelteComponentTyped } from "svelte";
declare const __propDef: {
props: {
[x: string]: any;
/** Required. Set a unique name for the input.*/
name: string;
/** Provide a unique input id. Auto-generated by default*/
id?: string | undefined;
/** Set the input value.*/
value?: number | undefined;
/** Set the input minimum range.*/
min?: number | undefined;
/** Set the input maximum range.*/
max?: number | undefined;
/** Set the input step offset.*/
step?: number | undefined;
/** Enables tick marks. See browser support below.*/
ticked?: boolean | undefined;
/** Provide classes to set the input accent color.*/
accent?: string | undefined;
/** A semantic ARIA label.*/
label?: string | undefined;
};
events: {
click: MouseEvent;
change: Event;
blur: FocusEvent;
} & {
[evt: string]: CustomEvent<any>;
};
slots: {
default: {};
trail: {};
};
};
export type RangeSliderProps = typeof __propDef.props;
export type RangeSliderEvents = typeof __propDef.events;
export type RangeSliderSlots = typeof __propDef.slots;
export default class RangeSlider extends SvelteComponentTyped<RangeSliderProps, RangeSliderEvents, RangeSliderSlots> {
}
export {};

View File

@ -0,0 +1,52 @@
<script>import { createEventDispatcher } from "svelte";
export let value = 0;
export let max = 5;
export let interactive = false;
export let text = "text-token";
export let fill = "fill-token";
export let justify = "justify-center";
export let spacing = "space-x-2";
export let regionIcon = "";
const dispatch = createEventDispatcher();
function iconClick(index) {
dispatch("icon", {
index: index + 1
});
}
function isFull(value2, index) {
return Math.floor(value2) >= index + 1;
}
function isHalf(value2, index) {
return value2 === index + 0.5;
}
const cBase = "w-full flex";
$:
classesBase = `${cBase} ${text} ${fill} ${justify} ${spacing} ${$$props.class ?? ""}`;
</script>
<div class="ratings {classesBase}" data-testid="rating-bar">
<!-- eslint-disable-next-line @typescript-eslint/no-unused-vars -->
{#each { length: max } as _, i}
{#if interactive}
<button class="rating-icon {regionIcon}" type="button" on:click={() => iconClick(i)}>
{#if isFull(value, i)}
<slot name="full" />
{:else if isHalf(value, i)}
<slot name="half" />
{:else}
<slot name="empty" />
{/if}
</button>
{:else}
<span class="rating-icon {regionIcon}">
{#if isFull(value, i)}
<slot name="full" />
{:else if isHalf(value, i)}
<slot name="half" />
{:else}
<slot name="empty" />
{/if}
</span>
{/if}
{/each}
</div>

View File

@ -0,0 +1,41 @@
import { SvelteComponentTyped } from "svelte";
declare const __propDef: {
props: {
[x: string]: any;
/** Current rating value.*/
value?: number | undefined;
/** Maximum rating value.*/
max?: number | undefined;
/** Enables interactive mode for each rating icon.*/
interactive?: boolean | undefined;
/** Provide classes to set the text color.*/
text?: string | undefined;
/** Provide classes to set the SVG fill color.*/
fill?: string | undefined;
/** Provide classes to set the flexbox justification.*/
justify?: string | undefined;
/** Provide classes to set the horizontal spacing style.*/
spacing?: string | undefined;
/** Provide arbitrary classes to the icon region.*/
regionIcon?: string | undefined;
};
events: {
/** {{ index: number }} icon - Fires when an icons is clicked*/
icon: CustomEvent<{
index: number;
}>;
} & {
[evt: string]: CustomEvent<any>;
};
slots: {
full: {};
half: {};
empty: {};
};
};
export type RatingsProps = typeof __propDef.props;
export type RatingsEvents = typeof __propDef.events;
export type RatingsSlots = typeof __propDef.slots;
export default class Ratings extends SvelteComponentTyped<RatingsProps, RatingsEvents, RatingsSlots> {
}
export {};

View File

@ -0,0 +1,91 @@
<script>import { createEventDispatcher } from "svelte";
const dispatch = createEventDispatcher();
export let name;
export let checked = false;
export let size = "md";
export let background = "bg-surface-400 dark:bg-surface-700";
export let active = "bg-surface-900 dark:bg-surface-300";
export let border = "";
export let rounded = "rounded-full";
export let label = "";
const cBase = "inline-block";
const cLabel = "unstyled flex items-center";
const cTrack = "flex transition-all duration-[200ms] cursor-pointer";
const cThumb = "w-[50%] h-full scale-[0.8] transition-all duration-[200ms] shadow";
let trackSize;
switch (size) {
case "sm":
trackSize = "w-12 h-6";
break;
case "lg":
trackSize = "w-20 h-10";
break;
default:
trackSize = "w-16 h-8";
}
function onKeyDown(event) {
if (["Enter", "Space"].includes(event.code)) {
event.preventDefault();
dispatch("keyup", event);
const inputElem = event.currentTarget.firstChild;
inputElem.click();
}
}
$:
cTrackActive = checked ? active : `${background} cursor-pointer`;
$:
cThumbBackground = checked ? "bg-white/75" : "bg-white";
$:
cThumbPos = checked ? "translate-x-full" : "";
$:
classesDisabled = $$props.disabled === true ? "opacity-50" : "hover:brightness-[105%] dark:hover:brightness-110 cursor-pointer";
$:
classesBase = `${cBase} ${rounded} ${classesDisabled} ${$$props.class ?? ""}`;
$:
classesLabel = `${cLabel}`;
$:
classesTrack = `${cTrack} ${border} ${rounded} ${trackSize} ${cTrackActive}`;
$:
classesThumb = `${cThumb} ${rounded} ${cThumbBackground} ${cThumbPos}`;
function prunedRestProps() {
delete $$restProps.class;
return $$restProps;
}
</script>
<div
id={label}
class="slide-toggle {classesBase}"
data-testid="slide-toggle"
on:keydown={onKeyDown}
role="switch"
aria-label={label}
aria-checked={checked}
tabindex="0"
>
<label class="slide-toggle-label {classesLabel}">
<!-- Hidden Input -->
<input
type="checkbox"
class="slide-toggle-input hidden"
bind:checked
{name}
on:click
on:keydown
on:keyup
on:keypress
on:mouseover
on:change
on:focus
on:blur
{...prunedRestProps()}
disabled={$$props.disabled}
/>
<!-- Slider Track/Thumb -->
<div class="slide-toggle-track {classesTrack}" class:cursor-not-allowed={$$props.disabled}>
<div class="slide-toggle-thumb {classesThumb}" class:cursor-not-allowed={$$props.disabled} />
</div>
<!-- Label -->
{#if $$slots.default}<div class="slide-toggle-text ml-3"><slot /></div>{/if}
</label>
</div>

View File

@ -0,0 +1,44 @@
import { SvelteComponentTyped } from "svelte";
declare const __propDef: {
props: {
[x: string]: any;
/** Required. Set a unique name for the input.*/
name: string;
/** The checked state of the input element.*/
checked?: boolean | undefined;
/** Sets the size of the component.*/
size?: string | undefined;
/** Provide classes to set the inactive state background color.*/
background?: string | undefined;
/** Provide classes to set the active state background color.*/
active?: string | undefined;
/** Provide classes to set the border styles.*/
border?: string | undefined;
/** Provide classes to set border radius styles.*/
rounded?: string | undefined;
/** Provide a semantic label.*/
label?: string | undefined;
};
events: {
click: MouseEvent;
keydown: KeyboardEvent;
/** {{ event }} keyup Fires when the component is focused and key is pressed.*/
keyup: KeyboardEvent;
keypress: KeyboardEvent;
mouseover: MouseEvent;
change: Event;
focus: FocusEvent;
blur: FocusEvent;
} & {
[evt: string]: CustomEvent<any>;
};
slots: {
default: {};
};
};
export type SlideToggleProps = typeof __propDef.props;
export type SlideToggleEvents = typeof __propDef.events;
export type SlideToggleSlots = typeof __propDef.slots;
export default class SlideToggle extends SvelteComponentTyped<SlideToggleProps, SlideToggleEvents, SlideToggleSlots> {
}
export {};

View File

@ -0,0 +1,111 @@
<!-- Reference: https://dribbble.com/shots/16221169-Figma-Material-Ui-components-Steppers-and-sliders -->
<script>import { getContext, onDestroy } from "svelte";
import { dynamicTransition } from "../../internal/transitions.js";
export let locked = false;
export let regionHeader = "";
export let regionContent = "";
export let regionNavigation = "";
export let state = getContext("state");
export let dispatchParent = getContext("dispatchParent");
export let stepTerm = getContext("stepTerm");
export let gap = getContext("gap");
export let justify = getContext("justify");
export let buttonBack = getContext("buttonBack");
export let buttonBackType = getContext("buttonBackType");
export let buttonBackLabel = getContext("buttonBackLabel");
export let buttonNext = getContext("buttonNext");
export let buttonNextType = getContext("buttonNextType");
export let buttonNextLabel = getContext("buttonNextLabel");
export let buttonComplete = getContext("buttonComplete");
export let buttonCompleteType = getContext("buttonCompleteType");
export let buttonCompleteLabel = getContext("buttonCompleteLabel");
export let transitions = getContext("transitions");
export let transitionIn = getContext("transitionIn");
export let transitionInParams = getContext("transitionInParams");
export let transitionOut = getContext("transitionOut");
export let transitionOutParams = getContext("transitionOutParams");
const stepIndex = $state.total;
$state.total++;
const cBase = "space-y-4";
const cHeader = "text-2xl font-bold";
const cContent = "space-y-4";
const cNavigation = "flex";
async function onNext() {
await new Promise((resolve) => setTimeout(resolve));
if (locked)
return;
$state.current++;
dispatchParent("next", { step: stepIndex, state: $state });
dispatchParent("step", { step: stepIndex, state: $state });
}
function onBack() {
$state.current--;
dispatchParent("back", { step: stepIndex, state: $state });
dispatchParent("step", { step: stepIndex, state: $state });
}
function onComplete() {
dispatchParent("complete", { step: stepIndex, state: $state });
}
$:
classesBase = `${cBase} ${$$props.class ?? ""}`;
$:
classesHeader = `${cHeader} ${regionHeader}`;
$:
classesContent = `${cContent} ${regionContent}`;
$:
classesNavigation = `${cNavigation} ${justify} ${gap} ${regionNavigation}`;
onDestroy(() => {
$state.total--;
});
</script>
{#if stepIndex === $state.current}
<div class="step {classesBase}" data-testid="step">
<!-- Slot: Header -->
<header class="step-header {classesHeader}">
<slot name="header">{stepTerm} {stepIndex + 1}</slot>
</header>
<!-- Slot: Default -->
<div class="step-content {classesContent}">
<slot>({stepTerm} {stepIndex + 1} Content)</slot>
</div>
<!-- Navigation -->
{#if $state.total > 1}
<div
class="step-navigation {classesNavigation}"
in:dynamicTransition|local={{ transition: transitionIn, params: transitionInParams, enabled: transitions }}
out:dynamicTransition|local={{ transition: transitionOut, params: transitionOutParams, enabled: transitions }}
>
{#if stepIndex === 0 && $$slots.navigation}
<!-- Slot: Navigation -->
<div class="step-navigation-slot">
<slot name="navigation" />
</div>
{:else}
<!-- Button: Back -->
<button type={buttonBackType} class="btn {buttonBack}" on:click={onBack} disabled={$state.current === 0}>
{@html buttonBackLabel}
</button>
{/if}
{#if stepIndex < $state.total - 1}
<!-- Button: Next -->
<button type={buttonNextType} class="btn {buttonNext}" on:click={onNext} disabled={locked}>
{#if locked}
<svg class="w-3 aspect-square fill-current" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512">
<path
d="M144 144v48H304V144c0-44.2-35.8-80-80-80s-80 35.8-80 80zM80 192V144C80 64.5 144.5 0 224 0s144 64.5 144 144v48h16c35.3 0 64 28.7 64 64V448c0 35.3-28.7 64-64 64H64c-35.3 0-64-28.7-64-64V256c0-35.3 28.7-64 64-64H80z"
/>
</svg>
{/if}
<span>{@html buttonNextLabel}</span>
</button>
{:else}
<!-- Button: Complete -->
<button type={buttonCompleteType} class="btn {buttonComplete}" on:click={onComplete} disabled={locked}>
{@html buttonCompleteLabel}
</button>
{/if}
</div>
{/if}
</div>
{/if}

View File

@ -0,0 +1,54 @@
import { SvelteComponentTyped } from "svelte";
import type { Writable } from 'svelte/store';
import type { StepperEventDispatcher, StepperState } from './types.js';
import type { Transition, TransitionParams } from '../../index.js';
declare class __sveltets_Render<TransitionIn extends Transition, TransitionOut extends Transition> {
props(): {
[x: string]: any;
locked?: boolean | undefined;
/** Provide arbitrary classes to the step header region.*/
regionHeader?: string | undefined;
/** Provide arbitrary classes to the step content region.*/
regionContent?: string | undefined;
/** Provide arbitrary classes to the step navigation region.*/
regionNavigation?: string | undefined;
state?: Writable<StepperState> | undefined;
dispatchParent?: StepperEventDispatcher | undefined;
stepTerm?: string | undefined;
gap?: string | undefined;
justify?: string | undefined;
buttonBack?: string | undefined;
buttonBackType?: "button" | "reset" | "submit" | undefined;
buttonBackLabel?: string | undefined;
buttonNext?: string | undefined;
buttonNextType?: "button" | "reset" | "submit" | undefined;
buttonNextLabel?: string | undefined;
buttonComplete?: string | undefined;
buttonCompleteType?: "button" | "reset" | "submit" | undefined;
buttonCompleteLabel?: string | undefined;
/** Enable/Disable transitions*/
transitions?: boolean | undefined;
/** Provide the transition to used on entry.*/
transitionIn?: TransitionIn | undefined;
/** Transition params provided to `transitionIn`.*/
transitionInParams?: TransitionParams<TransitionIn> | undefined;
/** Provide the transition to used on exit.*/
transitionOut?: TransitionOut | undefined;
/** Transition params provided to `transitionOut`.*/
transitionOutParams?: TransitionParams<TransitionOut> | undefined;
};
events(): {} & {
[evt: string]: CustomEvent<any>;
};
slots(): {
header: {};
default: {};
navigation: {};
};
}
export type StepProps<TransitionIn extends Transition, TransitionOut extends Transition> = ReturnType<__sveltets_Render<TransitionIn, TransitionOut>['props']>;
export type StepEvents<TransitionIn extends Transition, TransitionOut extends Transition> = ReturnType<__sveltets_Render<TransitionIn, TransitionOut>['events']>;
export type StepSlots<TransitionIn extends Transition, TransitionOut extends Transition> = ReturnType<__sveltets_Render<TransitionIn, TransitionOut>['slots']>;
export default class Step<TransitionIn extends Transition, TransitionOut extends Transition> extends SvelteComponentTyped<StepProps<TransitionIn, TransitionOut>, StepEvents<TransitionIn, TransitionOut>, StepSlots<TransitionIn, TransitionOut>> {
}
export {};

View File

@ -0,0 +1,89 @@
<script context="module">import { fade } from "svelte/transition";
import { prefersReducedMotionStore } from "../../index.js";
</script>
<script generics="TransitionIn extends Transition = FadeTransition, TransitionOut extends Transition = FadeTransition">import { createEventDispatcher, setContext } from "svelte";
import { writable } from "svelte/store";
import { dynamicTransition } from "../../internal/transitions.js";
const dispatch = createEventDispatcher();
export let gap = "gap-4";
export let stepTerm = "Step";
export let badge = "variant-filled-surface";
export let active = "variant-filled";
export let border = "border-surface-400-500-token";
export let start = 0;
export let justify = "justify-between";
export let buttonBack = "variant-ghost";
export let buttonBackType = "button";
export let buttonBackLabel = "&larr; Back";
export let buttonNext = "variant-filled";
export let buttonNextType = "button";
export let buttonNextLabel = "Next &rarr;";
export let buttonComplete = "variant-filled-primary";
export let buttonCompleteType = "button";
export let buttonCompleteLabel = "Complete";
export let regionHeader = "";
export let regionContent = "";
export let transitions = !$prefersReducedMotionStore;
export let transitionIn = fade;
export let transitionInParams = { duration: 100 };
export let transitionOut = fade;
export let transitionOutParams = { duration: 100 };
let state = writable({ current: start, total: 0 });
setContext("state", state);
setContext("dispatchParent", dispatch);
setContext("stepTerm", stepTerm);
setContext("gap", gap);
setContext("justify", justify);
setContext("buttonBack", buttonBack);
setContext("buttonBackType", buttonBackType);
setContext("buttonBackLabel", buttonBackLabel);
setContext("buttonNext", buttonNext);
setContext("buttonNextType", buttonNextType);
setContext("buttonNextLabel", buttonNextLabel);
setContext("buttonComplete", buttonComplete);
setContext("buttonCompleteType", buttonCompleteType);
setContext("buttonCompleteLabel", buttonCompleteLabel);
setContext("transitions", transitions);
setContext("transitionIn", transitionIn);
setContext("transitionInParams", transitionInParams);
setContext("transitionOut", transitionOut);
setContext("transitionOutParams", transitionOutParams);
const cBase = "space-y-4";
const cHeader = "flex items-center border-t mt-[15px]";
const cHeaderStep = "-mt-[15px] transition-all duration-300";
const cContent = "";
$:
isActive = (step) => step === $state.current;
$:
classesBase = `${cBase} ${$$props.class ?? ""}`;
$:
classesHeader = `${cHeader} ${border} ${gap} ${regionHeader}`;
$:
classesHeaderStep = `${cHeaderStep}`;
$:
classesBadge = (step) => isActive(step) ? active : badge;
$:
classesContent = `${cContent} ${regionContent}`;
</script>
<div class="stepper {classesBase}" data-testid="stepper">
<!-- Header -->
{#if $state.total}
<header
class="stepper-header {classesHeader}"
in:dynamicTransition|local={{ transition: transitionIn, params: transitionInParams, enabled: transitions }}
out:dynamicTransition|local={{ transition: transitionOut, params: transitionOutParams, enabled: transitions }}
>
{#each Array.from(Array($state.total).keys()) as step}
<div class="stepper-header-step {classesHeaderStep}" class:flex-1={isActive(step)}>
<span class="badge {classesBadge(step)}">{isActive(step) ? `${stepTerm} ${step + 1}` : step + 1}</span>
</div>
{/each}
</header>
{/if}
<!-- Content -->
<div class="stepper-content {classesContent}">
<slot />
</div>
</div>

View File

@ -0,0 +1,85 @@
import { SvelteComponentTyped } from "svelte";
import { fade } from 'svelte/transition';
import { type Transition, type TransitionParams } from '../../index.js';
type FadeTransition = typeof fade;
import type { StepperButton, StepperState } from './types.js';
declare class __sveltets_Render<TransitionIn extends Transition = FadeTransition, TransitionOut extends Transition = FadeTransition> {
props(): {
[x: string]: any;
/** Provide classes to style the stepper header gap.*/
gap?: string | undefined;
/** Provide the verbiage that represents "Step".*/
stepTerm?: string | undefined;
/** Provide classes to style the stepper header badges.*/
badge?: string | undefined;
/** Provide classes to style the stepper header active step badge.*/
active?: string | undefined;
/** Provide classes to style the stepper header border.*/
border?: string | undefined;
/** Provide the initially selected step*/
start?: number | undefined;
/** Set the justification for the step navigation buttons.*/
justify?: string | undefined;
/** Provide arbitrary classes to style the back button.*/
buttonBack?: string | undefined;
/** Set the type of the back button.*/
buttonBackType?: StepperButton | undefined;
/** Provide the HTML label content for the back button.*/
buttonBackLabel?: string | undefined;
/** Provide arbitrary classes to style the next button.*/
buttonNext?: string | undefined;
/** Set the type of the next button.*/
buttonNextType?: StepperButton | undefined;
/** Provide the HTML label content for the next button.*/
buttonNextLabel?: string | undefined;
/** Provide arbitrary classes to style the complete button.*/
buttonComplete?: string | undefined;
/** Set the type of the complete button.*/
buttonCompleteType?: StepperButton | undefined;
/** Provide the HTML label content for the complete button.*/
buttonCompleteLabel?: string | undefined;
/** Provide arbitrary classes to the stepper header region.*/
regionHeader?: string | undefined;
/** Provide arbitrary classes to the stepper content region.*/
regionContent?: string | undefined;
/** Enable/Disable transitions*/
transitions?: boolean | undefined;
/** Provide the transition to used on entry.*/
transitionIn?: TransitionIn | undefined;
/** Transition params provided to `transitionIn`.*/
transitionInParams?: TransitionParams<TransitionIn> | undefined;
/** Provide the transition to used on exit.*/
transitionOut?: TransitionOut | undefined;
/** Transition params provided to `transitionOut`.*/
transitionOutParams?: TransitionParams<TransitionOut> | undefined;
};
events(): {
next: CustomEvent<{
step: number;
state: StepperState;
}>;
step: CustomEvent<{
step: number;
state: StepperState;
}>;
back: CustomEvent<{
step: number;
state: StepperState;
}>;
complete: CustomEvent<{
step: number;
state: StepperState;
}>;
} & {
[evt: string]: CustomEvent<any>;
};
slots(): {
default: {};
};
}
export type StepperProps<TransitionIn extends Transition = FadeTransition, TransitionOut extends Transition = FadeTransition> = ReturnType<__sveltets_Render<TransitionIn, TransitionOut>['props']>;
export type StepperEvents<TransitionIn extends Transition = FadeTransition, TransitionOut extends Transition = FadeTransition> = ReturnType<__sveltets_Render<TransitionIn, TransitionOut>['events']>;
export type StepperSlots<TransitionIn extends Transition = FadeTransition, TransitionOut extends Transition = FadeTransition> = ReturnType<__sveltets_Render<TransitionIn, TransitionOut>['slots']>;
export default class Stepper<TransitionIn extends Transition = FadeTransition, TransitionOut extends Transition = FadeTransition> extends SvelteComponentTyped<StepperProps<TransitionIn, TransitionOut>, StepperEvents<TransitionIn, TransitionOut>, StepperSlots<TransitionIn, TransitionOut>> {
}
export {};

View File

@ -0,0 +1,25 @@
import type { EventDispatcher } from 'svelte';
export interface StepperState {
current: number;
total: number;
}
export type StepperButton = 'submit' | 'reset' | 'button';
export type StepperEvent = {
next: {
step: number;
state: StepperState;
};
step: {
step: number;
state: StepperState;
};
back: {
step: number;
state: StepperState;
};
complete: {
step: number;
state: StepperState;
};
};
export type StepperEventDispatcher = EventDispatcher<StepperEvent>;

View File

@ -0,0 +1 @@
export {};

View File

@ -0,0 +1,95 @@
<script>import { getContext } from "svelte";
export let group;
export let name;
export let value;
export let title = "";
export let controls = "";
export let regionTab = "";
export let active = getContext("active");
export let hover = getContext("hover");
export let flex = getContext("flex");
export let padding = getContext("padding");
export let rounded = getContext("rounded");
export let spacing = getContext("spacing");
const cBase = "text-center cursor-pointer transition-colors duration-100";
const cInterface = "";
let elemInput;
function onKeyDown(event) {
if (["Enter", "Space"].includes(event.code)) {
event.preventDefault();
elemInput.click();
} else if (event.code === "ArrowRight") {
const tabList = elemInput.closest(".tab-list");
if (!tabList)
return;
const tabs = Array.from(tabList.querySelectorAll(".tab"));
const currTab = elemInput.closest(".tab");
if (!currTab)
return;
const currIndex = tabs.indexOf(currTab);
const nextIndex = currIndex + 1 >= tabs.length ? 0 : currIndex + 1;
const nextTab = tabs[nextIndex];
const nextTabInput = nextTab?.querySelector("input");
if (nextTab && nextTabInput) {
nextTabInput.click();
nextTab.focus();
}
} else if (event.code === "ArrowLeft") {
const tabList = elemInput.closest(".tab-list");
if (!tabList)
return;
const tabs = Array.from(tabList.querySelectorAll(".tab"));
const currTab = elemInput.closest(".tab");
if (!currTab)
return;
const currIndex = tabs.indexOf(currTab);
const nextIndex = currIndex - 1 < 0 ? tabs.length - 1 : currIndex - 1;
const nextTab = tabs[nextIndex];
const nextTabInput = nextTab?.querySelector("input");
if (nextTab && nextTabInput) {
nextTabInput.click();
nextTab.focus();
}
}
}
$:
selected = value === group;
$:
classesActive = selected ? active : hover;
$:
classesBase = `${cBase} ${flex} ${padding} ${rounded} ${classesActive} ${$$props.class ?? ""}`;
$:
classesInterface = `${cInterface} ${spacing}`;
$:
classesTab = `${regionTab}`;
function prunedRestProps() {
delete $$restProps.class;
return $$restProps;
}
</script>
<label class={classesBase} {title}>
<!-- A11y attributes are not allowed on <label> -->
<div
class="tab {classesTab}"
data-testid="tab"
role="tab"
aria-controls={controls}
aria-selected={selected}
tabindex={selected ? 0 : -1}
on:keydown={onKeyDown}
on:keydown
on:keyup
on:keypress
>
<!-- NOTE: Don't use `hidden` as it prevents `required` from operating -->
<div class="h-0 w-0 overflow-hidden">
<input bind:this={elemInput} type="radio" bind:group {name} {value} {...prunedRestProps()} tabindex="-1" on:click on:change />
</div>
<!-- Interface -->
<div class="tab-interface {classesInterface}">
{#if $$slots.lead}<div class="tab-lead"><slot name="lead" /></div>{/if}
<div class="tab-label"><slot /></div>
</div>
</div>
</label>

View File

@ -0,0 +1,49 @@
import { SvelteComponentTyped } from "svelte";
declare const __propDef: {
props: {
[x: string]: any;
/** Set the radio group binding value.*/
group: any;
/** Set a unique name value for the input.*/
name: string;
/** Set the input's value.*/
value: any;
/** Provide a hoverable title attribute for the tab.*/
title?: string | undefined;
/** Set the ARIA controls value to define which panel this tab controls.*/
controls?: string | undefined;
/** Provide arbitrary classes to style the tab region.*/
regionTab?: string | undefined;
/** Provide classes to style each tab's active styles.*/
active?: string | undefined;
/** Provide classes to style each tab's hover styles.*/
hover?: string | undefined;
/** Provide classes to style each tab's flex styles.*/
flex?: string | undefined;
/** Provide classes to style each tab's padding styles.*/
padding?: string | undefined;
/** Provide classes to style each tab's box radius styles.*/
rounded?: string | undefined;
/** Provide classes to set the vertical spacing between items.*/
spacing?: string | undefined;
};
events: {
keydown: KeyboardEvent;
keyup: KeyboardEvent;
keypress: KeyboardEvent;
click: MouseEvent;
change: Event;
} & {
[evt: string]: CustomEvent<any>;
};
slots: {
lead: {};
default: {};
};
};
export type TabProps = typeof __propDef.props;
export type TabEvents = typeof __propDef.events;
export type TabSlots = typeof __propDef.slots;
export default class Tab extends SvelteComponentTyped<TabProps, TabEvents, TabSlots> {
}
export {};

View File

@ -0,0 +1,44 @@
<script>import { getContext } from "svelte";
export let selected = false;
export let controls = "";
export let active = getContext("active");
export let hover = getContext("hover");
export let flex = getContext("flex");
export let padding = getContext("padding");
export let rounded = getContext("rounded");
export let spacing = getContext("spacing");
const cBase = "text-center cursor-pointer transition-colors duration-100";
const cInterface = "";
$:
classesActive = selected ? active : hover;
$:
classesBase = `${cBase} ${flex} ${padding} ${rounded} ${classesActive} ${$$props.class ?? ""}`;
$:
classesInterface = `${cInterface} ${spacing}`;
function prunedRestProps() {
delete $$restProps.class;
return $$restProps;
}
</script>
<a
class="tab-anchor {classesBase}"
href={$$props.href}
{...prunedRestProps()}
aria-controls={controls}
on:click
on:keydown
on:keyup
on:keypress
on:mouseover
on:mouseleave
on:focus
on:blur
data-testid="tab-anchor"
>
<!-- Interface -->
<div class="tab-interface {classesInterface}">
{#if $$slots.lead}<div class="tab-lead"><slot name="lead" /></div>{/if}
<div class="tab-label"><slot /></div>
</div>
</a>

View File

@ -0,0 +1,44 @@
import { SvelteComponentTyped } from "svelte";
declare const __propDef: {
props: {
[x: string]: any;
/** Enables the active state styles when set true.*/
selected?: boolean | undefined;
/** Set the ARIA controls value to define which panel this tab controls.*/
controls?: string | undefined;
/** Provide classes to style each tab's active styles.*/
active?: string | undefined;
/** Provide classes to style each tab's hover styles.*/
hover?: string | undefined;
/** Provide classes to style each tab's flex styles.*/
flex?: string | undefined;
/** Provide classes to style each tab's padding styles.*/
padding?: string | undefined;
/** Provide classes to style each tab's box radius styles.*/
rounded?: string | undefined;
/** Provide classes to set the vertical spacing between items.*/
spacing?: string | undefined;
};
events: {
click: MouseEvent;
keydown: KeyboardEvent;
keyup: KeyboardEvent;
keypress: KeyboardEvent;
mouseover: MouseEvent;
mouseleave: MouseEvent;
focus: FocusEvent;
blur: FocusEvent;
} & {
[evt: string]: CustomEvent<any>;
};
slots: {
lead: {};
default: {};
};
};
export type TabAnchorProps = typeof __propDef.props;
export type TabAnchorEvents = typeof __propDef.events;
export type TabAnchorSlots = typeof __propDef.slots;
export default class TabAnchor extends SvelteComponentTyped<TabAnchorProps, TabAnchorEvents, TabAnchorSlots> {
}
export {};

View File

@ -0,0 +1,44 @@
<script>import { setContext } from "svelte";
export let justify = "justify-start";
export let border = "border-b border-surface-400-500-token";
export let active = "border-b-2 border-surface-900-50-token";
export let hover = "hover:variant-soft";
export let flex = "flex-none";
export let padding = "px-4 py-2";
export let rounded = "rounded-tl-container-token rounded-tr-container-token";
export let spacing = "space-y-1";
export let regionList = "";
export let regionPanel = "";
export let labelledby = "";
export let panel = "";
setContext("active", active);
setContext("hover", hover);
setContext("flex", flex);
setContext("padding", padding);
setContext("rounded", rounded);
setContext("spacing", spacing);
const cBase = "space-y-4";
const cList = "flex overflow-x-auto hide-scrollbar";
const cPanel = "";
$:
classesBase = `${cBase} ${$$props.class ?? ""}`;
$:
classesList = `${cList} ${justify} ${border} ${regionList}`;
$:
classesPanel = `${cPanel} ${regionPanel}`;
</script>
<!-- FIXME: resolve a11y warnings -->
<!-- svelte-ignore a11y-no-static-element-interactions -->
<div class="tab-group {classesBase}" data-testid="tab-group" on:click on:keypress on:keydown on:keyup>
<!-- Tab List -->
<div class="tab-list {classesList}" role="tablist" aria-labelledby={labelledby}>
<slot />
</div>
<!-- Tab Panel -->
{#if $$slots.panel}
<div class="tab-panel {classesPanel}" role="tabpanel" aria-labelledby={panel} tabindex="0">
<slot name="panel" />
</div>
{/if}
</div>

View File

@ -0,0 +1,48 @@
import { SvelteComponentTyped } from "svelte";
declare const __propDef: {
props: {
[x: string]: any;
/** Provide classes to set the tab list flex justification.*/
justify?: string | undefined;
/** Provide classes to set the tab group border styles.*/
border?: string | undefined;
/** Provide classes to style each tab's active styles.*/
active?: string | undefined;
/** Provide classes to style each tab's hover styles.*/
hover?: string | undefined;
/** Provide classes to style each tab's flex styles.*/
flex?: string | undefined;
/** Provide classes to style each tab's padding styles.*/
padding?: string | undefined;
/** Provide classes to style each tab's box radius styles.*/
rounded?: string | undefined;
/** Provide classes to set the vertical spacing between items.*/
spacing?: string | undefined;
/** Provide arbitrary classes to style the tab list region.*/
regionList?: string | undefined;
/** Provide arbitrary classes to style the tab panel region.*/
regionPanel?: string | undefined;
/** Provide the ID of the element that labels the tab list.*/
labelledby?: string | undefined;
/** Matches the tab aria-control value, pairs with the panel.*/
panel?: string | undefined;
};
events: {
click: MouseEvent;
keypress: KeyboardEvent;
keydown: KeyboardEvent;
keyup: KeyboardEvent;
} & {
[evt: string]: CustomEvent<any>;
};
slots: {
default: {};
panel: {};
};
};
export type TabGroupProps = typeof __propDef.props;
export type TabGroupEvents = typeof __propDef.events;
export type TabGroupSlots = typeof __propDef.slots;
export default class TabGroup extends SvelteComponentTyped<TabGroupProps, TabGroupEvents, TabGroupSlots> {
}
export {};

View File

@ -0,0 +1,87 @@
<script>import { createEventDispatcher } from "svelte";
import { tableA11y } from "./actions.js";
const dispatch = createEventDispatcher();
export let source;
export let interactive = false;
export let element = "table";
export let text = "";
export let color = "";
export let regionHead = "";
export let regionHeadCell = "";
export let regionBody = "";
export let regionCell = "";
export let regionFoot = "";
export let regionFootCell = "";
function onRowClick(event, rowIndex) {
if (!interactive)
return;
event.preventDefault();
event.stopPropagation();
const rowMetaData = source.meta ? source.meta[rowIndex] : source.body[rowIndex];
dispatch("selected", rowMetaData);
}
function onRowKeydown(event, rowIndex) {
if (["Enter", "Space"].includes(event.code))
onRowClick(event, rowIndex);
}
$:
classesBase = `${$$props.class || ""}`;
$:
classesTable = `${element} ${text} ${color}`;
</script>
<div class="table-container {classesBase}">
<!-- Table -->
<!-- prettier-ignore -->
<table
class="{classesTable}"
class:table-interactive={interactive}
role="grid"
use:tableA11y
>
<!-- on:keydown={(e) => onTableKeydown(elemTable, e)} -->
<!-- Head -->
<thead class="table-head {regionHead}">
<tr>
{#each source.head as heading }
<th class="{regionHeadCell}">{@html heading}</th>
{/each}
</tr>
</thead>
<!-- Body -->
<tbody class="table-body {regionBody}">
{#each source.body as row, rowIndex}
<!-- Row -->
<!-- prettier-ignore -->
<tr
on:click={(e) => { onRowClick(e, rowIndex); }}
on:keydown={(e) => { onRowKeydown(e, rowIndex); }}
aria-rowindex={rowIndex + 1}
>
{#each row as cell, cellIndex}
<!-- Cell -->
<!-- prettier-ignore -->
<td
class="{regionCell}"
role="gridcell"
aria-colindex={cellIndex + 1}
tabindex={cellIndex === 0 ? 0 : -1}
>
{@html Number(cell) === 0 ? cell : (cell ? cell : '-')}
</td>
{/each}
</tr>
{/each}
</tbody>
<!-- Foot -->
{#if source.foot}
<tfoot class="table-foot {regionFoot}">
<tr>
{#each source.foot as cell }
<td class="{regionFootCell}">{@html cell}</td>
{/each}
</tr>
</tfoot>
{/if}
</table>
</div>

View File

@ -0,0 +1,42 @@
import { SvelteComponentTyped } from "svelte";
import type { TableSource } from '../../index.js';
declare const __propDef: {
props: {
[x: string]: any;
/** Provide the full set of table source data.*/
source: TableSource;
/** Enables row hover style and `on:selected` event when rows are clicked.*/
interactive?: boolean | undefined;
/** Override the Tailwind Element class. Replace this for a headless UI.*/
element?: string | undefined;
/** Provide classes to set the table text size.*/
text?: string | undefined;
/** Provide classes to set the table text color.*/
color?: string | undefined;
/** Provide arbitrary classes for the table head.*/
regionHead?: string | undefined;
/** Provide arbitrary classes for the table head cells.*/
regionHeadCell?: string | undefined;
/** Provide arbitrary classes for the table body.*/
regionBody?: string | undefined;
/** Provide arbitrary classes for the table cells.*/
regionCell?: string | undefined;
/** Provide arbitrary classes for the table foot.*/
regionFoot?: string | undefined;
/** Provide arbitrary classes for the table foot cells.*/
regionFootCell?: string | undefined;
};
events: {
/** {rowMetaData} selected - Fires when a table row is clicked.*/
selected: CustomEvent<string[]>;
} & {
[evt: string]: CustomEvent<any>;
};
slots: {};
};
export type TableProps = typeof __propDef.props;
export type TableEvents = typeof __propDef.events;
export type TableSlots = typeof __propDef.slots;
export default class Table extends SvelteComponentTyped<TableProps, TableEvents, TableSlots> {
}
export {};

View File

@ -0,0 +1,8 @@
/** Svelte Action for applying sort asc/dsc classes. */
export declare function tableInteraction(node: HTMLElement): {
destroy(): void;
};
/** Svelte Action for handling table a11y keyboard interactions. */
export declare function tableA11y(node: HTMLElement): {
destroy(): void;
};

View File

@ -0,0 +1,114 @@
// Shared Data/Table Actions
// Data Table (only) ---
/** Svelte Action for applying sort asc/dsc classes. */
export function tableInteraction(node) {
const classAsc = 'table-sort-asc';
const classDsc = 'table-sort-dsc';
// Click Handler
const onClick = (e) => {
if (!(e.target instanceof Element))
return;
const sortTarget = e.target;
// Get target state before modification
const targetAscSorted = sortTarget.classList.contains(classAsc);
const sortTargetKey = sortTarget.getAttribute('data-sort');
// Clear asc class
const elemAsc = node.querySelector(`.${classAsc}`);
if (elemAsc)
elemAsc.classList.remove(classAsc);
// Clear dsc class
const elemDsc = node.querySelector(`.${classDsc}`);
if (elemDsc)
elemDsc.classList.remove(classDsc);
// Set new sort class
if (sortTargetKey) {
const classToApply = targetAscSorted ? classDsc : classAsc;
e.target.classList.add(classToApply);
}
};
// Events
node.addEventListener('click', onClick);
// Lifecycle
return {
destroy() {
node.removeEventListener('click', onClick);
}
};
}
// Shared ---
/** Svelte Action for handling table a11y keyboard interactions. */
export function tableA11y(node) {
const keyWhitelist = ['ArrowRight', 'ArrowUp', 'ArrowLeft', 'ArrowDown', 'Home', 'End'];
// on:keydown
const onKeyDown = (event) => {
// console.log('keydown triggered');
if (keyWhitelist.includes(event.code)) {
event.preventDefault();
// prettier-ignore
switch (event.code) {
case 'ArrowUp':
a11ySetActiveCell(node, 0, -1);
break;
case 'ArrowDown':
a11ySetActiveCell(node, 0, 1);
break;
case 'ArrowLeft':
a11ySetActiveCell(node, -1, 0);
break;
case 'ArrowRight':
a11ySetActiveCell(node, 1, 0);
break;
case 'Home':
a11yJumpToOuterColumn(node, 'first');
break;
case 'End':
a11yJumpToOuterColumn(node, 'last');
break;
default: break;
}
}
};
// Event Listener
node.addEventListener('keydown', onKeyDown);
// Lifecycle
return {
destroy() {
node.removeEventListener('keydown', onKeyDown);
}
};
}
function a11ySetActiveCell(node, x, y) {
// Focused Element
const focusedElem = document.activeElement;
if (!focusedElem || !focusedElem.parentElement || !focusedElem.parentElement.ariaRowIndex || !focusedElem.ariaColIndex)
return;
const focusedElemRowIndex = parseInt(focusedElem.parentElement.ariaRowIndex);
const focusedElemColIndex = parseInt(focusedElem.ariaColIndex);
// Target Element
const targetRowElement = node.querySelector(`[aria-rowindex="${focusedElemRowIndex + y}"]`);
if (targetRowElement !== null) {
const targetColElement = targetRowElement.querySelector(`[aria-colindex="${focusedElemColIndex + x}"]`);
if (targetColElement !== null)
targetColElement.focus();
}
}
function a11yGetTargetElem(node) {
// Focused Element
const focusedElem = document.activeElement;
if (!focusedElem || !focusedElem.parentElement || !focusedElem.parentElement.ariaRowIndex)
return null;
const focusedElemRowIndex = parseInt(focusedElem.parentElement.ariaRowIndex);
// Return Target Element
return node.querySelector(`[aria-rowindex="${focusedElemRowIndex}"]`);
}
function a11yJumpToOuterColumn(node, type = 'first') {
const targetRowElement = a11yGetTargetElem(node);
if (targetRowElement === null)
return;
const lastIndex = targetRowElement.children.length;
const selected = type === 'first' ? 1 : lastIndex;
const targetColElement = targetRowElement.querySelector(`[aria-colindex="${selected}"]`);
if (targetColElement === null)
return;
targetColElement.focus();
}

View File

@ -0,0 +1,10 @@
export interface TableSource {
/** The formatted table heading values. */
head: string[];
/** The formatted table body values. */
body: string[][];
/** The data returned when an interactive row is clicked. */
meta?: string[][];
/** The formatted table footer values. */
foot?: string[];
}

View File

@ -0,0 +1 @@
export {};

View File

@ -0,0 +1,7 @@
/** Wrap object key value with an HTML tag. */
/** Map an object to a defined order. */
export declare function tableSourceMapper(source: any[], keys: string[]): any[];
/** Map an array of objects to an array of values. */
export declare function tableSourceValues(source: any[]): any[];
/** Sets object order and returns values. */
export declare function tableMapperValues(source: any[], keys: string[]): any[];

View File

@ -0,0 +1,33 @@
// Table Component Utilities
// Cell Formatters ---
// NOTE: this would require `onMount`, which is too slow, so may just nix this.
// REMINDER: if re-enabled, update `index.ts`!
/** Wrap object key value with an HTML tag. */
// export function tableCellFormatter(source: any[], key: string, tagName: string, classes?: string) {
// return source.map((row) => {
// if (row[key]) {
// const newElem: HTMLElement = document.createElement(tagName);
// newElem.innerHTML = row[key];
// if (classes) newElem.setAttribute('class', classes);
// row[key] = newElem.outerHTML;
// }
// return row;
// });
// }
// Source Formatters ---
/** Map an object to a defined order. */
export function tableSourceMapper(source, keys) {
return source.map((row) => {
const mappedRow = {};
keys.forEach((key) => (mappedRow[key] = row[key]));
return mappedRow;
});
}
/** Map an array of objects to an array of values. */
export function tableSourceValues(source) {
return source.map((row) => Object.values(row));
}
/** Sets object order and returns values. */
export function tableMapperValues(source, keys) {
return tableSourceValues(tableSourceMapper(source, keys));
}

View File

@ -0,0 +1,75 @@
<script>import { createEventDispatcher, setContext } from "svelte";
import RecursiveTreeViewItem from "./RecursiveTreeViewItem.svelte";
export let selection = false;
export let multiple = false;
export let relational = false;
export let nodes = [];
export let expandedNodes = [];
export let disabledNodes = [];
export let checkedNodes = [];
export let indeterminateNodes = [];
export let width = "w-full";
export let spacing = "space-y-1";
export let open = false;
export let disabled = false;
export let padding = "py-4 px-4";
export let indent = "ml-4";
export let hover = "hover:variant-soft";
export let rounded = "rounded-container-token";
export let caretOpen = "rotate-180";
export let caretClosed = "";
export let hyphenOpacity = "opacity-10";
export let regionSummary = "";
export let regionSymbol = "";
export let regionChildren = "";
export let labelledby = "";
setContext("open", open);
setContext("selection", selection);
setContext("multiple", multiple);
setContext("relational", relational);
setContext("disabled", disabled);
setContext("padding", padding);
setContext("indent", indent);
setContext("hover", hover);
setContext("rounded", rounded);
setContext("caretOpen", caretOpen);
setContext("caretClosed", caretClosed);
setContext("hyphenOpacity", hyphenOpacity);
setContext("regionSummary", regionSummary);
setContext("regionSymbol", regionSymbol);
setContext("regionChildren", regionChildren);
const dispatch = createEventDispatcher();
function onClick(event) {
dispatch("click", {
id: event.detail.id
});
}
function onToggle(event) {
dispatch("toggle", {
id: event.detail.id
});
}
$:
classesBase = `${width} ${spacing} ${$$props.class ?? ""}`;
</script>
<div
class="tree {classesBase}"
data-testid="tree"
role="tree"
aria-multiselectable={multiple}
aria-label={labelledby}
aria-disabled={disabled}
>
{#if nodes && nodes.length > 0}
<RecursiveTreeViewItem
{nodes}
bind:expandedNodes
bind:disabledNodes
bind:checkedNodes
bind:indeterminateNodes
on:click={onClick}
on:toggle={onToggle}
/>
{/if}
</div>

View File

@ -0,0 +1,67 @@
import { SvelteComponentTyped } from "svelte";
import type { TreeViewNode } from '../../index.js';
declare const __propDef: {
props: {
[x: string]: any;
/** Enable tree-view selection.*/
selection?: boolean | undefined;
/** Enable selection of multiple items.*/
multiple?: boolean | undefined;
/** Enable relational checking.*/
relational?: boolean | undefined;
/** Provide data-driven nodes.*/
nodes?: TreeViewNode[] | undefined;
/** provides id's of expanded nodes*/
expandedNodes?: string[] | undefined;
/** provides id's of disabled nodes*/
disabledNodes?: string[] | undefined;
/** provides id's of checked nodes*/
checkedNodes?: string[] | undefined;
/** provides id's of indeterminate nodes*/
indeterminateNodes?: string[] | undefined;
/** Provide classes to set the tree width.*/
width?: string | undefined;
/** Provide classes to set the vertical spacing between items.*/
spacing?: string | undefined;
/** Set open by default on load.*/
open?: boolean | undefined;
/** Set the tree disabled state*/
disabled?: boolean | undefined;
/** Provide classes to set the tree item padding styles.*/
padding?: string | undefined;
/** Provide classes to set the tree children indentation*/
indent?: string | undefined;
/** Provide classes to set the tree item hover styles.*/
hover?: string | undefined;
/** Provide classes to set the tree item rounded styles.*/
rounded?: string | undefined;
/** Set the rotation of the item caret in the open state.*/
caretOpen?: string | undefined;
/** Set the rotation of the item caret in the closed state.*/
caretClosed?: string | undefined;
hyphenOpacity?: string | undefined;
/** Provide arbitrary classes to the tree item summary region.*/
regionSummary?: string | undefined;
/** Provide arbitrary classes to the symbol icon region.*/
regionSymbol?: string | undefined;
/** Provide arbitrary classes to the children region.*/
regionChildren?: string | undefined;
/** Provide the ARIA labelledby value.*/
labelledby?: string | undefined;
};
events: {
/** {{id:string}} click - Fires on tree item click*/
click: CustomEvent<any>;
/** {{id:string}} toggle - Fires on tree item toggle*/
toggle: CustomEvent<any>;
} & {
[evt: string]: CustomEvent<any>;
};
slots: {};
};
export type RecursiveTreeViewProps = typeof __propDef.props;
export type RecursiveTreeViewEvents = typeof __propDef.events;
export type RecursiveTreeViewSlots = typeof __propDef.slots;
export default class RecursiveTreeView extends SvelteComponentTyped<RecursiveTreeViewProps, RecursiveTreeViewEvents, RecursiveTreeViewSlots> {
}
export {};

View File

@ -0,0 +1,140 @@
<script>import TreeViewItem from "./TreeViewItem.svelte";
import RecursiveTreeViewItem from "./RecursiveTreeViewItem.svelte";
import { createEventDispatcher, getContext, onMount, tick } from "svelte";
export let nodes = [];
export let expandedNodes = [];
export let disabledNodes = [];
export let checkedNodes = [];
export let indeterminateNodes = [];
let selection = getContext("selection");
let multiple = getContext("multiple");
let relational = getContext("relational");
let tempCheckedNodes = [];
let group;
let name = "";
const dispatch = createEventDispatcher();
function toggleNode(node, open) {
if (!node.children?.length)
return;
if (open) {
if (!expandedNodes.includes(node.id)) {
expandedNodes.push(node.id);
expandedNodes = expandedNodes;
}
} else {
if (expandedNodes.includes(node.id)) {
expandedNodes.splice(expandedNodes.indexOf(node.id), 1);
expandedNodes = expandedNodes;
}
}
}
function checkNode(node, checked, indeterminate) {
if (checked) {
if (!checkedNodes.includes(node.id)) {
checkedNodes.push(node.id);
checkedNodes = checkedNodes;
}
if (!indeterminate && indeterminateNodes.includes(node.id)) {
indeterminateNodes.splice(indeterminateNodes.indexOf(node.id), 1);
indeterminateNodes = indeterminateNodes;
}
} else {
if (checkedNodes.includes(node.id)) {
checkedNodes.splice(checkedNodes.indexOf(node.id), 1);
checkedNodes = checkedNodes;
}
if (indeterminate && !indeterminateNodes.includes(node.id)) {
indeterminateNodes.push(node.id);
indeterminateNodes = indeterminateNodes;
} else if (!indeterminate && indeterminateNodes.includes(node.id)) {
indeterminateNodes.splice(indeterminateNodes.indexOf(node.id), 1);
indeterminateNodes = indeterminateNodes;
}
}
}
tempCheckedNodes = [...checkedNodes];
onMount(async () => {
if (selection) {
name = String(Math.random());
if (group === void 0) {
if (multiple) {
group = [];
nodes.forEach((node) => {
if (checkedNodes.includes(node.id) && Array.isArray(group))
group.push(node.id);
});
group = group;
} else if (!nodes.some((node) => checkedNodes.includes(node.id))) {
group = "";
}
}
if (!relational)
treeItems = [];
checkedNodes = [];
await tick();
checkedNodes = [...tempCheckedNodes];
}
});
export let treeItems = [];
let children = [];
</script>
{#if nodes && nodes.length > 0}
{#each nodes as node, i}
<TreeViewItem
bind:this={treeItems[i]}
bind:children={children[i]}
bind:group
bind:name
bind:value={node.id}
hideLead={!node.lead}
hideChildren={!node.children || node.children.length === 0}
open={expandedNodes.includes(node.id)}
disabled={disabledNodes.includes(node.id)}
checked={checkedNodes.includes(node.id)}
indeterminate={indeterminateNodes.includes(node.id)}
on:toggle={(e) => toggleNode(node, e.detail.open)}
on:groupChange={(e) => checkNode(node, e.detail.checked, e.detail.indeterminate)}
on:click={() =>
dispatch('click', {
id: node.id
})}
on:toggle={() => {
dispatch('toggle', {
id: node.id
});
}}
>
{#if typeof node.content === 'string'}
{@html node.content}
{:else}
<svelte:component this={node.content} {...node.contentProps} />
{/if}
<svelte:fragment slot="lead">
{#if typeof node.lead === 'string'}
{@html node.lead}
{:else}
<svelte:component this={node.lead} {...node.leadProps} />
{/if}
</svelte:fragment>
<svelte:fragment slot="children">
<RecursiveTreeViewItem
nodes={node.children}
bind:expandedNodes
bind:disabledNodes
bind:checkedNodes
bind:indeterminateNodes
bind:treeItems={children[i]}
on:click={(e) =>
dispatch('click', {
id: e.detail.id
})}
on:toggle={(e) =>
dispatch('toggle', {
id: e.detail.id
})}
/>
</svelte:fragment>
</TreeViewItem>
{/each}
{/if}

View File

@ -0,0 +1,38 @@
import { SvelteComponentTyped } from "svelte";
import TreeViewItem from './TreeViewItem.svelte';
import type { TreeViewNode } from './types.js';
declare const __propDef: {
props: {
/** Provide data-driven nodes. */ nodes?: TreeViewNode[] | undefined;
/**
* provides id's of expanded nodes
* @type {string[]}
*/ expandedNodes?: string[] | undefined;
/**
* provides id's of disabled nodes
* @type {string[]}
*/ disabledNodes?: string[] | undefined;
/**
* provides id's of checked nodes
* @type {string[]}
*/ checkedNodes?: string[] | undefined;
/**
* provides id's of indeterminate nodes
* @type {string[]}
*/ indeterminateNodes?: string[] | undefined;
treeItems?: TreeViewItem[] | undefined;
};
events: {
click: CustomEvent<any>;
toggle: CustomEvent<any>;
} & {
[evt: string]: CustomEvent<any>;
};
slots: {};
};
export type RecursiveTreeViewItemProps = typeof __propDef.props;
export type RecursiveTreeViewItemEvents = typeof __propDef.events;
export type RecursiveTreeViewItemSlots = typeof __propDef.slots;
export default class RecursiveTreeViewItem extends SvelteComponentTyped<RecursiveTreeViewItemProps, RecursiveTreeViewItemEvents, RecursiveTreeViewItemSlots> {
}
export {};

View File

@ -0,0 +1,68 @@
<script>import { setContext } from "svelte";
export let selection = false;
export let multiple = false;
export let width = "w-full";
export let spacing = "space-y-1";
export let open = false;
export let disabled = false;
export let padding = "py-4 px-4";
export let indent = "ml-4";
export let hover = "hover:variant-soft";
export let rounded = "rounded-container-token";
export let caretOpen = "rotate-180";
export let caretClosed = "";
export let hyphenOpacity = "opacity-10";
export let regionSummary = "";
export let regionSymbol = "";
export let regionChildren = "";
export let labelledby = "";
export function expandAll() {
const detailsElements = tree.querySelectorAll("details.tree-item");
detailsElements.forEach((details) => {
if (!details.open) {
const summary = details.querySelector("summary.tree-item-summary");
if (summary)
summary.click();
}
});
}
export function collapseAll() {
const detailsElements = tree.querySelectorAll("details.tree-item");
detailsElements.forEach((details) => {
if (details.open) {
const summary = details.querySelector("summary.tree-item-summary");
if (summary)
summary.click();
}
});
}
setContext("open", open);
setContext("selection", selection);
setContext("multiple", multiple);
setContext("disabled", disabled);
setContext("padding", padding);
setContext("indent", indent);
setContext("hover", hover);
setContext("rounded", rounded);
setContext("caretOpen", caretOpen);
setContext("caretClosed", caretClosed);
setContext("hyphenOpacity", hyphenOpacity);
setContext("regionSummary", regionSummary);
setContext("regionSymbol", regionSymbol);
setContext("regionChildren", regionChildren);
$:
classesBase = `${width} ${spacing} ${$$props.class ?? ""}`;
let tree;
</script>
<div
bind:this={tree}
class="tree {classesBase}"
data-testid="tree"
role="tree"
aria-multiselectable={multiple}
aria-label={labelledby}
aria-disabled={disabled}
>
<slot />
</div>

View File

@ -0,0 +1,55 @@
import { SvelteComponentTyped } from "svelte";
declare const __propDef: {
props: {
[x: string]: any;
/** Enable tree-view selection.*/
selection?: boolean | undefined;
/** Enable selection of multiple items.*/
multiple?: boolean | undefined;
/** Provide classes to set the tree width.*/
width?: string | undefined;
/** Provide classes to set the vertical spacing between items.*/
spacing?: string | undefined;
/** Set open by default on load.*/
open?: boolean | undefined;
/** Set the tree disabled state*/
disabled?: boolean | undefined;
/** Provide classes to set the tree item padding styles.*/
padding?: string | undefined;
/** Provide classes to set the tree children indentation*/
indent?: string | undefined;
/** Provide classes to set the tree item hover styles.*/
hover?: string | undefined;
/** Provide classes to set the tree item rounded styles.*/
rounded?: string | undefined;
/** Set the rotation of the item caret in the open state.*/
caretOpen?: string | undefined;
/** Set the rotation of the item caret in the closed state.*/
caretClosed?: string | undefined;
hyphenOpacity?: string | undefined;
/** Provide arbitrary classes to the tree item summary region.*/
regionSummary?: string | undefined;
/** Provide arbitrary classes to the symbol icon region.*/
regionSymbol?: string | undefined;
/** Provide arbitrary classes to the children region.*/
regionChildren?: string | undefined;
/** Provide the ARIA labelledby value.*/
labelledby?: string | undefined;
expandAll?: (() => void) | undefined;
collapseAll?: (() => void) | undefined;
};
events: {
[evt: string]: CustomEvent<any>;
};
slots: {
default: {};
};
};
export type TreeViewProps = typeof __propDef.props;
export type TreeViewEvents = typeof __propDef.events;
export type TreeViewSlots = typeof __propDef.slots;
export default class TreeView extends SvelteComponentTyped<TreeViewProps, TreeViewEvents, TreeViewSlots> {
get expandAll(): () => void;
get collapseAll(): () => void;
}
export {};

View File

@ -0,0 +1,323 @@
<!-- To access props and events using reference -->
<svelte:options accessors />
<script>import { getContext, createEventDispatcher, onMount } from "svelte";
export let group = void 0;
export let name = void 0;
export let value = void 0;
export let checked = false;
export let children = [];
export let spacing = "space-x-4";
export let open = getContext("open");
export let selection = getContext("selection");
export let multiple = getContext("multiple");
export let disabled = getContext("disabled");
export let indeterminate = false;
export let padding = getContext("padding");
export let indent = getContext("indent");
export let hover = getContext("hover");
export let rounded = getContext("rounded");
export let caretOpen = getContext("caretOpen");
export let caretClosed = getContext("caretClosed");
export let hyphenOpacity = getContext("hyphenOpacity");
export let regionSummary = getContext("regionSummary");
export let regionSymbol = getContext("regionSymbol");
export let regionChildren = getContext("regionChildren");
export let hideLead = false;
export let hideChildren = false;
let treeItem;
let childrenDiv;
function onSummaryClick(event) {
if (disabled)
event.preventDefault();
}
$:
if (multiple)
updateCheckbox(group, indeterminate);
$:
if (multiple)
updateGroup(checked, indeterminate);
$:
if (!multiple)
updateRadio(group);
$:
if (!multiple)
updateRadioGroup(checked);
let initUpdate = true;
function updateCheckbox(group2, indeterminate2) {
if (!Array.isArray(group2))
return;
checked = group2.indexOf(value) >= 0;
dispatch("groupChange", { checked, indeterminate: indeterminate2 });
dispatch("childChange");
if (initUpdate) {
onParentChange();
initUpdate = false;
}
}
function updateGroup(checked2, indeterminate2) {
if (!Array.isArray(group))
return;
const index = group.indexOf(value);
if (checked2) {
if (index < 0) {
group.push(value);
group = group;
onParentChange();
}
} else {
if (index >= 0) {
group.splice(index, 1);
group = group;
onParentChange();
}
}
}
function updateRadio(group2) {
checked = group2 === value;
dispatch("groupChange", { checked, indeterminate: false });
if (group2)
dispatch("childChange");
}
function updateRadioGroup(checked2) {
if (checked2 && group !== value)
group = value;
else if (!checked2 && group === value)
group = "";
}
function onChildValueChange() {
if (multiple) {
if (!Array.isArray(group))
return;
const childrenValues = children.map((c) => c.value);
const childrenGroup = children[0].group;
const index = group.indexOf(value);
if (children.some((c) => c.indeterminate)) {
indeterminate = true;
if (index >= 0) {
group.splice(index, 1);
group = group;
}
} else if (childrenValues.every((c) => Array.isArray(childrenGroup) && childrenGroup.includes(c))) {
indeterminate = false;
if (index < 0) {
group.push(value);
group = group;
}
} else if (childrenValues.some((c) => Array.isArray(childrenGroup) && childrenGroup.includes(c))) {
indeterminate = true;
if (index >= 0) {
group.splice(index, 1);
group = group;
}
} else {
indeterminate = false;
if (index >= 0) {
group.splice(index, 1);
group = group;
}
}
} else {
if (group !== value && children.some((c) => c.checked)) {
group = value;
} else if (group === value && !children.some((c) => c.checked)) {
group = "";
}
}
dispatch("childChange");
}
export function onParentChange() {
if (!multiple || !children || children.length === 0)
return;
if (!Array.isArray(group))
return;
const index = group.indexOf(value);
const checkChild = (child) => {
if (!child || !Array.isArray(child.group))
return;
child.indeterminate = false;
if (child.group.indexOf(child.value) < 0) {
child.group.push(child.value);
child.group = child.group;
}
};
const uncheckChild = (child) => {
if (!child || !Array.isArray(child.group))
return;
child.indeterminate = false;
const childIndex = child.group.indexOf(child.value);
if (childIndex >= 0) {
child.group.splice(childIndex, 1);
child.group = child.group;
}
};
children.forEach((child) => {
if (!child)
return;
index >= 0 ? checkChild(child) : uncheckChild(child);
child.onParentChange();
});
}
$:
if (!multiple && group !== void 0) {
if (group !== value) {
children.forEach((child) => {
if (child)
child.group = "";
});
}
}
const dispatch = createEventDispatcher();
$:
dispatch("toggle", { open });
$:
children.forEach((child) => {
if (child)
child.$on("childChange", onChildValueChange);
});
function onKeyDown(event) {
function getRootTree() {
let currentElement = treeItem;
while (currentElement !== null) {
if (currentElement.classList.contains("tree"))
return currentElement;
currentElement = currentElement.parentElement;
}
return void 0;
}
let rootTree = void 0;
let lastVisibleElement = null;
switch (event.code) {
case "ArrowRight":
if (!open)
open = true;
else if ($$slots.children && !hideChildren) {
const child = childrenDiv.querySelector("details>summary");
if (child)
child.focus();
}
break;
case "ArrowLeft":
if (open)
open = false;
else {
const parent = treeItem.parentElement?.parentElement;
if (parent && parent.tagName === "DETAILS")
parent.querySelector("summary")?.focus();
}
break;
case "Home":
event.preventDefault();
rootTree = getRootTree();
if (rootTree)
rootTree?.querySelector("summary")?.focus();
break;
case "End":
event.preventDefault();
rootTree = getRootTree();
if (rootTree) {
const detailsElements = rootTree?.querySelectorAll("details");
if (!detailsElements)
return;
for (let i = detailsElements.length - 1; i >= 0; i--) {
const details = detailsElements[i];
if (details.parentElement?.classList?.contains("tree") || details.parentElement?.parentElement?.getAttribute("open") !== null) {
lastVisibleElement = details;
break;
} else if (details.parentElement?.parentElement?.tagName !== "details") {
lastVisibleElement = details.parentElement.parentElement;
break;
}
}
if (lastVisibleElement) {
const summary = lastVisibleElement.querySelector("summary");
if (summary)
summary.focus();
}
}
break;
}
}
const cBase = "";
const cSummary = "list-none [&::-webkit-details-marker]:hidden flex items-center cursor-pointer";
const cSymbol = "fill-current w-3 text-center transition-transform duration-[200ms]";
const cChildren = "";
const cDisabled = "opacity-50 !cursor-not-allowed";
$:
classesCaretState = open && $$slots.children && !hideChildren ? caretOpen : caretClosed;
$:
classesDisabled = disabled ? cDisabled : "";
$:
classesBase = `${cBase} ${$$props.class ?? ""}`;
$:
classesSummary = `${cSummary} ${classesDisabled} ${spacing} ${rounded} ${padding} ${hover} ${regionSummary}`;
$:
classesSymbol = `${cSymbol} ${classesCaret} ${regionSymbol}`;
$:
classesCaret = `${classesCaretState}`;
$:
classesHyphen = `${hyphenOpacity}`;
$:
classesChildren = `${cChildren} ${indent} ${regionChildren}`;
</script>
<details bind:this={treeItem} bind:open class="tree-item {classesBase}" data-testid="tree-item" aria-disabled={disabled}>
<summary
class="tree-item-summary {classesSummary}"
role="treeitem"
aria-selected={selection ? checked : undefined}
aria-expanded={$$slots.children ? open : undefined}
on:click={onSummaryClick}
on:click
on:keydown={onKeyDown}
on:keydown
on:keyup
>
<!-- Symbol -->
<div class="tree-summary-symbol {classesSymbol}">
{#if $$slots.children && !hideChildren}
<!-- SVG Caret -->
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512">
<path
d="M201.4 374.6c12.5 12.5 32.8 12.5 45.3 0l160-160c12.5-12.5 12.5-32.8 0-45.3s-32.8-12.5-45.3 0L224 306.7 86.6 169.4c-12.5-12.5-32.8-12.5-45.3 0s-12.5 32.8 0 45.3l160 160z"
/>
</svg>
{:else}
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512" class="w-3 {classesHyphen}">
<path d="M432 256c0 17.7-14.3 32-32 32L48 288c-17.7 0-32-14.3-32-32s14.3-32 32-32l352 0c17.7 0 32 14.3 32 32z" />
</svg>
{/if}
</div>
<!-- Selection -->
{#if selection && name && group !== undefined}
{#if multiple}
<input
class="checkbox tree-item-checkbox"
type="checkbox"
{name}
{value}
bind:checked
bind:indeterminate
on:change={onParentChange}
/>
{:else}
<input class="radio tree-item-radio" type="radio" bind:group {name} {value} />
{/if}
{/if}
<!-- Slot: Lead -->
{#if $$slots.lead && !hideLead}
<div class="tree-item-lead">
<slot name="lead" />
</div>
{/if}
<!-- Slot: Content -->
<div class="tree-item-content">
<slot />
</div>
</summary>
<div bind:this={childrenDiv} class="tree-item-children {classesChildren}" role="group">
<slot name="children" />
</div>
</details>

View File

@ -0,0 +1,145 @@
import { SvelteComponentTyped } from "svelte";
import type { TreeViewItem } from '../../index.js';
declare const __propDef: {
props: {
[x: string]: any;
/** Set the radio group binding value.*/
group?: unknown;
/** Set a unique name value for the input.*/
name?: string | undefined;
/** Set the input's value.*/
value?: unknown;
/** Set the input's check state*/
checked?: boolean | undefined;
/** Provide children references to support relational checking.*/
children?: TreeViewItem[] | undefined;
/** Provide classes to set the horizontal spacing.*/
spacing?: string | undefined;
/** Set open by default on load.*/
open?: boolean | undefined;
/** Enable tree-view selection*/
selection?: boolean | undefined;
/** Enable selection of multiple items.*/
multiple?: boolean | undefined;
/** Set the tree item disabled state*/
disabled?: boolean | undefined;
/** Set the check state to indeterminate(-).*/
indeterminate?: boolean | undefined;
/** Provide classes to set the tree item padding styles.*/
padding?: string | undefined;
/** Provide classes to set the tree children indentation*/
indent?: string | undefined;
/** Provide classes to set the tree item hover styles.*/
hover?: string | undefined;
/** Provide classes to set the tree item rounded styles.*/
rounded?: string | undefined;
/** Set the rotation of the item caret in the open state.*/
caretOpen?: string | undefined;
/** Set the rotation of the item caret in the closed state.*/
caretClosed?: string | undefined;
hyphenOpacity?: string | undefined;
/** Provide arbitrary classes to the tree item summary region.*/
regionSummary?: string | undefined;
/** Provide arbitrary classes to the symbol icon region.*/
regionSymbol?: string | undefined;
/** Provide arbitrary classes to the children region.*/
regionChildren?: string | undefined;
/** Don't use this prop, workaround until svelte implements conditional slots*/
hideLead?: boolean | undefined;
/** Don't use this prop, workaround until svelte implements conditional slots*/
hideChildren?: boolean | undefined;
onParentChange?: (() => void) | undefined;
};
events: {
click: MouseEvent;
keydown: KeyboardEvent;
keyup: KeyboardEvent;
toggle: CustomEvent<any>;
} & {
[evt: string]: CustomEvent<any>;
};
slots: {
lead: {};
default: {};
children: {};
};
};
export type TreeViewItemProps = typeof __propDef.props;
export type TreeViewItemEvents = typeof __propDef.events;
export type TreeViewItemSlots = typeof __propDef.slots;
export default class TreeViewItem extends SvelteComponentTyped<TreeViewItemProps, TreeViewItemEvents, TreeViewItemSlots> {
get onParentChange(): () => void;
get group(): unknown;
/**accessor*/
set group(_: unknown);
get name(): string | undefined;
/**accessor*/
set name(_: string | undefined);
get value(): unknown;
/**accessor*/
set value(_: unknown);
get checked(): boolean | undefined;
/**accessor*/
set checked(_: boolean | undefined);
get children(): TreeViewItem[] | undefined;
/**accessor*/
set children(_: TreeViewItem[] | undefined);
get spacing(): string | undefined;
/**accessor*/
set spacing(_: string | undefined);
get open(): boolean | undefined;
/**accessor*/
set open(_: boolean | undefined);
get selection(): boolean | undefined;
/**accessor*/
set selection(_: boolean | undefined);
get multiple(): boolean | undefined;
/**accessor*/
set multiple(_: boolean | undefined);
get disabled(): boolean | undefined;
/**accessor*/
set disabled(_: boolean | undefined);
get indeterminate(): boolean | undefined;
/**accessor*/
set indeterminate(_: boolean | undefined);
get padding(): string | undefined;
/**accessor*/
set padding(_: string | undefined);
get indent(): string | undefined;
/**accessor*/
set indent(_: string | undefined);
get hover(): string | undefined;
/**accessor*/
set hover(_: string | undefined);
get rounded(): string | undefined;
/**accessor*/
set rounded(_: string | undefined);
get caretOpen(): string | undefined;
/**accessor*/
set caretOpen(_: string | undefined);
get caretClosed(): string | undefined;
/**accessor*/
set caretClosed(_: string | undefined);
get hyphenOpacity(): string | undefined;
/**accessor*/
set hyphenOpacity(_: string | undefined);
get regionSummary(): string | undefined;
/**accessor*/
set regionSummary(_: string | undefined);
get regionSymbol(): string | undefined;
/**accessor*/
set regionSymbol(_: string | undefined);
get regionChildren(): string | undefined;
/**accessor*/
set regionChildren(_: string | undefined);
get hideLead(): boolean | undefined;
/**accessor*/
set hideLead(_: boolean | undefined);
get hideChildren(): boolean | undefined;
/**accessor*/
set hideChildren(_: boolean | undefined);
get undefined(): any;
/**accessor*/
set undefined(_: any);
}
export {};

View File

@ -0,0 +1,17 @@
import type { ComponentType } from 'svelte';
export interface TreeViewNode {
/** Nodes Unique ID */
id: string;
/** Main content. accepts HTML or svelte component. */
content: string | ComponentType;
/** Main content props. only used when the Content is a svelte component. */
contentProps?: object;
/** Lead content. accepts HTML or svelte component. */
lead?: string | ComponentType;
/** lead props. only used when the Lead is a svelte component. */
leadProps?: object;
/** children nodes. */
children?: TreeViewNode[];
/** Set the input's value. */
value?: unknown;
}

View File

@ -0,0 +1 @@
export {};