Skip to content

Commit

Permalink
Merge branch 'main' of https://github.com/techniq/svelte-ux
Browse files Browse the repository at this point in the history
  • Loading branch information
techniq committed Jun 18, 2024
2 parents 7e4eeb4 + a1483e7 commit 9081c0a
Show file tree
Hide file tree
Showing 14 changed files with 869 additions and 103 deletions.
5 changes: 0 additions & 5 deletions .changeset/early-elephants-marry.md

This file was deleted.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,5 +19,5 @@
"@svitejs/changesets-changelog-github-compact": "^1.1.0",
"rimraf": "5.0.7"
},
"packageManager": "pnpm@9.3.0"
"packageManager": "pnpm@9.4.0"
}
12 changes: 12 additions & 0 deletions packages/svelte-ux/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,17 @@
# svelte-ux

## 0.67.0

### Minor Changes

- Add new `Steps` component ([#395](https://github.com/techniq/svelte-ux/pull/395))

- Add new `Timeline` component (replaces old `Steps` component usage). See also new `Steps` component ([#395](https://github.com/techniq/svelte-ux/pull/395))

### Patch Changes

- Add `popover` action to top-level exports ([#393](https://github.com/techniq/svelte-ux/pull/393))

## 0.66.8

### Patch Changes
Expand Down
2 changes: 1 addition & 1 deletion packages/svelte-ux/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
"author": "Sean Lynch <[email protected]>",
"license": "MIT",
"repository": "techniq/svelte-ux",
"version": "0.66.8",
"version": "0.67.0",
"scripts": {
"dev": "vite dev",
"build": "vite build",
Expand Down
73 changes: 73 additions & 0 deletions packages/svelte-ux/src/lib/components/Step.svelte
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>
85 changes: 59 additions & 26 deletions packages/svelte-ux/src/lib/components/Steps.svelte
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>
79 changes: 79 additions & 0 deletions packages/svelte-ux/src/lib/components/Timeline.svelte
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>
Loading

0 comments on commit 9081c0a

Please sign in to comment.