-
-
Notifications
You must be signed in to change notification settings - Fork 41
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
New Steps and Timeline components (#395)
* Fix ButtonGroup api reference * New Timeline component (replaces Steps) (WIP) * Add compact support * Simplify grid cols/rows setup * Support `complete` status * Add timeline context and use to set vertical, compact, icon, and snapIcon within TimelineItem * Support customizing completed color * Remove old Steps component (replaced by Timeline). Add changeset * Round edges of timeline * Support providing custom point (not just icon) * Remove extra changeset * Add new Steps component * Update changesets * Update changeset
- Loading branch information
Showing
13 changed files
with
866 additions
and
97 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
--- | ||
'svelte-ux': minor | ||
--- | ||
|
||
Add new `Steps` component |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
--- | ||
'svelte-ux': minor | ||
--- | ||
|
||
Add new `Timeline` component (replaces old `Steps` component usage). See also new `Steps` component |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
<script lang="ts"> | ||
import type { ComponentProps } from 'svelte'; | ||
import Icon from './Icon.svelte'; | ||
import { getSteps } from './Steps.svelte'; | ||
import { getComponentClasses } from './theme.js'; | ||
import { cls } from '../utils/styles.js'; | ||
/** Override content (by default uses an incrementing counter)*/ | ||
export let content: string | undefined = undefined; | ||
/** Use icon instead of content */ | ||
export let icon: ComponentProps<Icon>['data'] = undefined; | ||
/** If completed, will color content and line leading up to item */ | ||
export let completed = false; | ||
export let classes: { | ||
root?: string; | ||
line?: string; | ||
content?: string; | ||
/** Apply classes to completed item point and line leading up to item */ | ||
completed?: string; | ||
} = {}; | ||
const settingsClasses = getComponentClasses('Step'); | ||
const stepsContext = getSteps(); | ||
$: vertical = stepsContext?.vertical ?? false; | ||
</script> | ||
|
||
<li | ||
class={cls( | ||
'Step', | ||
'group grid place-items-center text-center', | ||
vertical | ||
? 'grid-cols-[40px_1fr] gap-2 min-h-16 justify-items-start' | ||
: 'grid-rows-[40px_1fr] min-w-16', | ||
settingsClasses.root, | ||
classes.root, | ||
$$props.class | ||
)} | ||
> | ||
<div | ||
class={cls( | ||
'group-first:hidden col-start-1 row-start-1 bg-surface-300 text-surface-content top-0', | ||
vertical ? 'h-full w-2 -mt-[100%] justify-self-center' : 'h-2 w-full -ml-[100%]', | ||
completed && (settingsClasses.completed ?? classes.completed ?? 'bg-primary'), | ||
settingsClasses.line, | ||
classes.line | ||
)} | ||
/> | ||
|
||
<slot /> | ||
|
||
<div | ||
class={cls( | ||
'bg-surface-300 text-surface-content relative col-start-1 row-start-1 grid size-8 place-items-center place-self-center rounded-full [counter-increment:step]', | ||
content == null && !$$slots.content && icon == null && 'before:content-[counter(step)]', | ||
completed && | ||
(settingsClasses.completed ?? classes.completed ?? 'bg-primary text-primary-content'), | ||
settingsClasses.content, | ||
classes.content | ||
)} | ||
> | ||
<slot name="content"> | ||
{#if icon} | ||
<Icon data={icon} /> | ||
{:else} | ||
{content ?? ''} | ||
{/if} | ||
</slot> | ||
</div> | ||
</li> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,32 +1,65 @@ | ||
<script lang="ts" context="module"> | ||
import { type ComponentProps, setContext, getContext } from 'svelte'; | ||
type StepsContext = { | ||
vertical: boolean; | ||
}; | ||
const stepsKey = Symbol(); | ||
export function setSteps(value: StepsContext | undefined) { | ||
setContext(stepsKey, value); | ||
} | ||
export function getSteps() { | ||
return getContext<StepsContext | undefined>(stepsKey); | ||
} | ||
</script> | ||
|
||
<script lang="ts"> | ||
type T = $$Generic; | ||
import Step from './Step.svelte'; | ||
import { cls } from '../utils/styles.js'; | ||
import { getComponentClasses } from './theme.js'; | ||
import Icon from './Icon.svelte'; | ||
type StepData = { | ||
label: string; | ||
content?: string; | ||
icon?: ComponentProps<Icon>['data']; | ||
}; | ||
export let data: StepData[] = []; | ||
/** Align vertically (default: horizontal) */ | ||
export let vertical: boolean = false; | ||
export let data: T[]; | ||
export let lineGap = 4; | ||
export let classes: { | ||
root?: string; | ||
item?: ComponentProps<Step>['classes']; | ||
} = {}; | ||
const settingsClasses = getComponentClasses('Steps'); | ||
// binded | ||
let circleSize = 0; | ||
setSteps({ | ||
vertical, | ||
}); | ||
</script> | ||
|
||
<ol | ||
style:--circleSize={circleSize} | ||
style:--lineTop="{circleSize + lineGap}px" | ||
style:--lineBottom="{lineGap}px" | ||
style:--lineOffset="{circleSize / 2}px" | ||
<ul | ||
class={cls( | ||
'Steps', | ||
'inline-grid grid-flow-col overflow-hidden overflow-x-auto auto-cols-fr [counter-reset:step]', | ||
vertical ? 'grid-flow-row' : 'grid-flow-col', | ||
settingsClasses.root, | ||
classes.root, | ||
$$props.class | ||
)} | ||
> | ||
{#each data as item, index} | ||
<li class="step relative flex gap-4 pb-10"> | ||
<div bind:clientWidth={circleSize}> | ||
<slot name="marker" {item} /> | ||
</div> | ||
|
||
{#if index < data.length - 1} | ||
<div | ||
class="line absolute top-[var(--lineTop)] bottom-[var(--lineBottom)] left-0 w-[2px] translate-x-[var(--lineOffset)] bg-surface-content/20" | ||
/> | ||
{/if} | ||
|
||
<slot name="item" {item} /> | ||
</li> | ||
{/each} | ||
</ol> | ||
<slot {data}> | ||
{#each data as item} | ||
<Step classes={classes.item} {...item}> | ||
{item.label} | ||
</Step> | ||
{/each} | ||
</slot> | ||
</ul> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,79 @@ | ||
<script lang="ts" context="module"> | ||
import { type ComponentProps, setContext, getContext } from 'svelte'; | ||
type TimelineContext = { | ||
vertical: boolean; | ||
compact: boolean; | ||
icon: ComponentProps<Icon>['icon']; | ||
snapPoint: boolean; | ||
}; | ||
const timelineKey = Symbol(); | ||
export function setTimeline(value: TimelineContext | undefined) { | ||
setContext(timelineKey, value); | ||
} | ||
export function getTimeline() { | ||
return getContext<TimelineContext | undefined>(timelineKey); | ||
} | ||
</script> | ||
|
||
<script lang="ts"> | ||
import TimelineItem from './TimelineItem.svelte'; | ||
import { cls } from '../utils/styles.js'; | ||
import { getComponentClasses } from './theme.js'; | ||
import Icon from './Icon.svelte'; | ||
type TimelineItemData = { | ||
start?: string | boolean; | ||
end?: string | boolean; | ||
icon?: ComponentProps<Icon>['data']; | ||
completed?: boolean; | ||
}; | ||
export let data: TimelineItemData[] = []; | ||
/** Align vertically (default: horizontal) */ | ||
export let vertical: boolean = false; | ||
/** Place timeline on left and all start/end items on end side */ | ||
export let compact: boolean = false; | ||
/** Common icon for all items */ | ||
export let icon: ComponentProps<TimelineItem>['icon'] = undefined; | ||
/** Snap point to start */ | ||
export let snapPoint = false; | ||
export let classes: { | ||
root?: string; | ||
item?: ComponentProps<TimelineItem>['classes']; | ||
} = {}; | ||
const settingsClasses = getComponentClasses('Timeline'); | ||
setTimeline({ | ||
vertical, | ||
compact, | ||
icon, | ||
snapPoint, | ||
}); | ||
</script> | ||
|
||
<ul | ||
class={cls( | ||
'Timeline', | ||
'relative flex', | ||
vertical && 'flex-col timeline-vertical', | ||
settingsClasses.root, | ||
classes.root, | ||
$$props.class | ||
)} | ||
> | ||
<slot {data}> | ||
{#each data as item} | ||
<TimelineItem classes={classes.item} {...item} /> | ||
{/each} | ||
</slot> | ||
</ul> |
Oops, something went wrong.