entasis 0.13.4 → 0.13.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/Code/Code.svelte +7 -2
- package/dist/components/Code/CodeTheme.svelte +12 -1
- package/dist/components/Code/code.highlighter.js +2 -2
- package/dist/components/Code/code.mcp.d.ts +1 -1
- package/dist/components/Code/code.mcp.js +3 -1
- package/dist/components/Code/code.theme.js +6 -5
- package/dist/components/Sidebar/sidebar-layout.js +3 -1
- package/dist/components/Timeline/Timeline.svelte +1 -1
- package/dist/components/Timeline/TimelineEntry.svelte +16 -2
- package/dist/components/Timeline/index.d.ts +1 -1
- package/dist/components/Timeline/timeline.items.d.ts +1 -1
- package/dist/components/Timeline/timeline.items.js +7 -2
- package/dist/components/Timeline/timeline.mcp.d.ts +1 -1
- package/dist/components/Timeline/timeline.mcp.js +35 -3
- package/dist/components/Timeline/timeline.props.d.ts +17 -1
- package/dist/components/Timeline/timeline.theme.d.ts +36 -0
- package/dist/components/Timeline/timeline.theme.js +27 -4
- package/dist/generated/componentContract.d.ts +1 -1
- package/dist/generated/componentContract.js +1 -0
- package/package.json +1 -1
|
@@ -108,8 +108,13 @@
|
|
|
108
108
|
{/if}
|
|
109
109
|
|
|
110
110
|
<!-- ScrollArea owns both axes: horizontal (long lines) natively, vertical when maxHeight caps
|
|
111
|
-
the height
|
|
112
|
-
|
|
111
|
+
the height or a height-bound flex column (a Dialog body) shrinks the block: `min-h-0` lets
|
|
112
|
+
it shrink below its content, so it scrolls under the kept header instead of the root
|
|
113
|
+
clipping its last lines. Its viewport is the focusable native scroll region. -->
|
|
114
|
+
<ScrollArea
|
|
115
|
+
type="hover"
|
|
116
|
+
class="flex max-h-[var(--code-max-height)] min-h-0 flex-col rounded-b-lg"
|
|
117
|
+
>
|
|
113
118
|
{@render codeBody()}
|
|
114
119
|
</ScrollArea>
|
|
115
120
|
|
|
@@ -52,11 +52,22 @@
|
|
|
52
52
|
--code-token-property: color-mix(in oklab, var(--color-info) 70%, var(--color-neutral));
|
|
53
53
|
}
|
|
54
54
|
|
|
55
|
-
/* The pre stays transparent so the container background shows through.
|
|
55
|
+
/* The pre stays transparent so the container background shows through. Code owns its layout
|
|
56
|
+
too: an app stylesheet may style every `pre.th-code` (edytor's `code.css` sets `white-space:
|
|
57
|
+
pre`, `tab-size` and `overflow-x`, unlayered, so it beats utilities), and these selectors
|
|
58
|
+
are scoped under the Code root so they win. The ScrollArea scrolls, never the pre. */
|
|
56
59
|
:global([data-slot='code'] pre.th-code) {
|
|
57
60
|
margin: 0;
|
|
61
|
+
overflow: visible;
|
|
58
62
|
background-color: transparent;
|
|
59
63
|
color: var(--code-token-plain);
|
|
64
|
+
white-space: pre;
|
|
65
|
+
word-break: normal;
|
|
66
|
+
tab-size: var(--code-tab-size, 2);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
:global([data-slot='code'] pre.th-code[data-wrap]) {
|
|
70
|
+
white-space: pre-wrap;
|
|
60
71
|
}
|
|
61
72
|
|
|
62
73
|
/* Token classes emitted by TanStack Highlight (`th-token th-<role>`), mapped to our roles. */
|
|
@@ -16,11 +16,11 @@ function getHighlighter() {
|
|
|
16
16
|
// Applied to the highlighter's `<pre>`. Scrolling is owned by the wrapping ScrollArea (see
|
|
17
17
|
// Code.svelte), so the pre itself does not scroll: when not wrapping it takes its natural
|
|
18
18
|
// (max-content) width so the ScrollArea sees the horizontal overflow; when wrapping it fills
|
|
19
|
-
// and soft-wraps. `has-[.th-line]:px-0` lets the gutter sit flush against the edge. A narrow
|
|
19
|
+
// and soft-wraps (its white-space is set in CodeTheme.svelte). `has-[.th-line]:px-0` lets the gutter sit flush against the edge. A narrow
|
|
20
20
|
// block (under 28rem) tightens its padding, as its text steps down (see `code.theme.ts`).
|
|
21
21
|
const preClass = (wrap) => [
|
|
22
22
|
'px-4 py-3.5 @max-md:px-3 @max-md:py-2.5 outline-none has-[.th-line]:px-0',
|
|
23
|
-
wrap ? 'w-full
|
|
23
|
+
wrap ? 'w-full break-words' : 'w-max'
|
|
24
24
|
].join(' ');
|
|
25
25
|
/**
|
|
26
26
|
* Highlights `code` to a `<pre class="th-code"><code>…</code></pre>` HTML string
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const codeDescription = "\n# Code Component\n\nDisplays a syntax-highlighted code block with an optional header (language label\n+ copy button), line numbers, and header/footer slots. Highlighting is powered by\nTanStack Highlight with every language bundled (synchronous, SSR-safe) and a CSS-variable token palette, so colors\nadapt to light and dark automatically from the design tokens.\n\n## Basic Usage\n\n```svelte\n<Code language=\"typescript\" code={`const hello: string = 'world';`} />\n```\n\n## Props\n\n### Core Props\n- **code**: string (required) - Source code to highlight. Also what the copy button writes to the clipboard.\n- **language**: string (default: 'text') - Language id (`ts`, `svelte`, `css`, `shell`, `json`, `python`, \u2026). Aliases like `typescript`, `js`, `bash` resolve automatically; every language TanStack Highlight ships is bundled, and unknown ids fall back to plain text.\n- **title**: string - Header label. Defaults to the language's display name (e.g. \"TypeScript\").\n\n### Display Props\n- **showLineNumbers**: boolean (default: false) - Renders a line-number gutter.\n- **showHeader**: boolean (default: true) - Renders the default header row (title + copy button). Set to false to show only the code block. Ignored when a custom `header` snippet is provided.\n- **copyable**: boolean (default: true) - Shows the copy-to-clipboard button. In the header when one is shown, otherwise a floating button in the top-right corner that appears on hover.\n- **wrap**: boolean (default: false) - Soft-wraps long lines instead of scrolling horizontally.\n- **maxHeight**: number | string (default: none) - Caps the block height and makes it vertically scrollable (via ScrollArea). A number is pixels; a string is used as-is (e.g. `'20rem'`).\n- **tabSize**: number (default: 2) - Tab width in spaces.\n\n### Styling Props\n- **class**: string - Additional CSS classes on the root element.\n- **theme**: CodeThemeProps - Theme overrides for the `code`, `header`, `title`, `container`, and `footer` parts.\n\n### Slots\n- **header**: Snippet<[CodeHeaderPayload]> - Replaces the default header row. Receives `{ language, label, copied, copy }`.\n- **footer**: Snippet - Optional footer row (e.g. a token count or a run button).\n\n## Examples\n\n### With a title and line numbers\n```svelte\n<Code\n language=\"svelte\"\n title=\"Counter.svelte\"\n showLineNumbers\n code={svelteSource}\n/>\n```\n\n### Custom header\n```svelte\n<Code language=\"json\" code={json}>\n {#snippet header({ label, copied, copy })}\n <div class=\"flex items-center justify-between px-3 py-1.5\">\n <span>{label}</span>\n <button onclick={copy}>{copied ? 'Copied!' : 'Copy'}</button>\n </div>\n {/snippet}\n</Code>\n```\n\n### With a footer\n```svelte\n<Code language=\"bash\" code={installCmd}>\n {#snippet footer()}\n <span>Run in your project root</span>\n {/snippet}\n</Code>\n```\n\n## Theming\n\nThe block chrome (border, header, footer, container) is styled with cva parts and\nuses `bg-neutral-muted` / `text-neutral/70` for the header and footer.\nThe syntax colors are NOT part of cva \u2014 they come from the highlighter's `th-*` token classes plus the\ncolocated `CodeTheme.svelte`, which maps each `--code-token-*` variable onto our\n`--color-*` design tokens (keyword \u2192 primary, string \u2192 success, number \u2192 warning,\nfunction \u2192 info, tag \u2192 danger, \u2026) and re-tunes a few roles under the dark selector.\n\n### Theme Structure\n- **root**: Root container (border, radius, background).\n- **header**: Header row (language label + copy button).\n- **title**: The language/title label text.\n- **container**: The scrollable code area wrapping the highlighted `<pre>`.\n- **footer**: Optional footer row.\n\n### Theme Type Definition\n\n```typescript\nimport type { CodeThemeProps } from 'entasis/code';\n\nconst customTheme: CodeThemeProps = {\n root: { base: 'rounded-xl raised-4' },\n header: { base: 'bg-primary text-primary-contrast px-4 py-2' }\n};\n```\n\n## Accessibility\n- The copy button carries an `aria-label` that reflects its state (\"Copy\" / \"Copied\").\n- Clipboard access is guarded (`navigator.clipboard`) and only runs client-side.\n\n## Notes\n- The highlighter is a singleton constructed at module load \u2014 SSR-safe, no top-level await.\n- Copied state resets automatically after 2 seconds and whenever `code` or `language` changes.\n";
|
|
1
|
+
export declare const codeDescription = "\n# Code Component\n\nDisplays a syntax-highlighted code block with an optional header (language label\n+ copy button), line numbers, and header/footer slots. Highlighting is powered by\nTanStack Highlight with every language bundled (synchronous, SSR-safe) and a CSS-variable token palette, so colors\nadapt to light and dark automatically from the design tokens.\n\n## Basic Usage\n\n```svelte\n<Code language=\"typescript\" code={`const hello: string = 'world';`} />\n```\n\n## Props\n\n### Core Props\n- **code**: string (required) - Source code to highlight. Also what the copy button writes to the clipboard.\n- **language**: string (default: 'text') - Language id (`ts`, `svelte`, `css`, `shell`, `json`, `python`, \u2026). Aliases like `typescript`, `js`, `bash` resolve automatically; every language TanStack Highlight ships is bundled, and unknown ids fall back to plain text.\n- **title**: string - Header label. Defaults to the language's display name (e.g. \"TypeScript\").\n\n### Display Props\n- **showLineNumbers**: boolean (default: false) - Renders a line-number gutter.\n- **showHeader**: boolean (default: true) - Renders the default header row (title + copy button). Set to false to show only the code block. Ignored when a custom `header` snippet is provided.\n- **copyable**: boolean (default: true) - Shows the copy-to-clipboard button. In the header when one is shown, otherwise a floating button in the top-right corner that appears on hover.\n- **wrap**: boolean (default: false) - Soft-wraps long lines instead of scrolling horizontally. Code sets its `<pre>`'s `white-space` and `tab-size` itself, scoped under its root, so an app stylesheet that styles every `pre.th-code` (edytor's `code.css` does) changes neither.\n- **maxHeight**: number | string (default: none) - Caps the block height and makes it vertically scrollable (via ScrollArea). A number is pixels; a string is used as-is (e.g. `'20rem'`).\n- **tabSize**: number (default: 2) - Tab width in spaces.\n\nIn a height-bound flex column (a Dialog or Drawer body, `flex min-h-0 flex-1 flex-col`), a Code taller than the room left shrinks to it and scrolls inside: the header and footer stay put and every line stays reachable. To keep its full height and let the column scroll instead, pass `class=\"shrink-0\"`.\n\n### Styling Props\n- **class**: string - Additional CSS classes on the root element.\n- **theme**: CodeThemeProps - Theme overrides for the `code`, `header`, `title`, `container`, and `footer` parts.\n\n### Slots\n- **header**: Snippet<[CodeHeaderPayload]> - Replaces the default header row. Receives `{ language, label, copied, copy }`.\n- **footer**: Snippet - Optional footer row (e.g. a token count or a run button).\n\n## Examples\n\n### With a title and line numbers\n```svelte\n<Code\n language=\"svelte\"\n title=\"Counter.svelte\"\n showLineNumbers\n code={svelteSource}\n/>\n```\n\n### Custom header\n```svelte\n<Code language=\"json\" code={json}>\n {#snippet header({ label, copied, copy })}\n <div class=\"flex items-center justify-between px-3 py-1.5\">\n <span>{label}</span>\n <button onclick={copy}>{copied ? 'Copied!' : 'Copy'}</button>\n </div>\n {/snippet}\n</Code>\n```\n\n### With a footer\n```svelte\n<Code language=\"bash\" code={installCmd}>\n {#snippet footer()}\n <span>Run in your project root</span>\n {/snippet}\n</Code>\n```\n\n## Theming\n\nThe block chrome (border, header, footer, container) is styled with cva parts and\nuses `bg-neutral-muted` / `text-neutral/70` for the header and footer.\nThe syntax colors are NOT part of cva \u2014 they come from the highlighter's `th-*` token classes plus the\ncolocated `CodeTheme.svelte`, which maps each `--code-token-*` variable onto our\n`--color-*` design tokens (keyword \u2192 primary, string \u2192 success, number \u2192 warning,\nfunction \u2192 info, tag \u2192 danger, \u2026) and re-tunes a few roles under the dark selector.\n\n### Theme Structure\n- **root**: Root container (border, radius, background).\n- **header**: Header row (language label + copy button).\n- **title**: The language/title label text.\n- **container**: The scrollable code area wrapping the highlighted `<pre>`.\n- **footer**: Optional footer row.\n\n### Theme Type Definition\n\n```typescript\nimport type { CodeThemeProps } from 'entasis/code';\n\nconst customTheme: CodeThemeProps = {\n root: { base: 'rounded-xl raised-4' },\n header: { base: 'bg-primary text-primary-contrast px-4 py-2' }\n};\n```\n\n## Accessibility\n- The copy button carries an `aria-label` that reflects its state (\"Copy\" / \"Copied\").\n- Clipboard access is guarded (`navigator.clipboard`) and only runs client-side.\n\n## Notes\n- The highlighter is a singleton constructed at module load \u2014 SSR-safe, no top-level await.\n- Copied state resets automatically after 2 seconds and whenever `code` or `language` changes.\n";
|
|
@@ -23,10 +23,12 @@ adapt to light and dark automatically from the design tokens.
|
|
|
23
23
|
- **showLineNumbers**: boolean (default: false) - Renders a line-number gutter.
|
|
24
24
|
- **showHeader**: boolean (default: true) - Renders the default header row (title + copy button). Set to false to show only the code block. Ignored when a custom \`header\` snippet is provided.
|
|
25
25
|
- **copyable**: boolean (default: true) - Shows the copy-to-clipboard button. In the header when one is shown, otherwise a floating button in the top-right corner that appears on hover.
|
|
26
|
-
- **wrap**: boolean (default: false) - Soft-wraps long lines instead of scrolling horizontally.
|
|
26
|
+
- **wrap**: boolean (default: false) - Soft-wraps long lines instead of scrolling horizontally. Code sets its \`<pre>\`'s \`white-space\` and \`tab-size\` itself, scoped under its root, so an app stylesheet that styles every \`pre.th-code\` (edytor's \`code.css\` does) changes neither.
|
|
27
27
|
- **maxHeight**: number | string (default: none) - Caps the block height and makes it vertically scrollable (via ScrollArea). A number is pixels; a string is used as-is (e.g. \`'20rem'\`).
|
|
28
28
|
- **tabSize**: number (default: 2) - Tab width in spaces.
|
|
29
29
|
|
|
30
|
+
In a height-bound flex column (a Dialog or Drawer body, \`flex min-h-0 flex-1 flex-col\`), a Code taller than the room left shrinks to it and scrolls inside: the header and footer stay put and every line stays reachable. To keep its full height and let the column scroll instead, pass \`class="shrink-0"\`.
|
|
31
|
+
|
|
30
32
|
### Styling Props
|
|
31
33
|
- **class**: string - Additional CSS classes on the root element.
|
|
32
34
|
- **theme**: CodeThemeProps - Theme overrides for the \`code\`, \`header\`, \`title\`, \`container\`, and \`footer\` parts.
|
|
@@ -9,20 +9,21 @@ const defaultCode = cva({
|
|
|
9
9
|
const defaultCodeFloatingCopy = cva({
|
|
10
10
|
base: 'absolute top-2 right-2 z-10 opacity-0 transition-opacity focus-within:opacity-100 group-hover:opacity-100'
|
|
11
11
|
});
|
|
12
|
+
// Header and footer never shrink: in a height-bound column the code scrolls between them.
|
|
12
13
|
const defaultCodeHeader = cva({
|
|
13
|
-
base: 'flex items-center justify-between gap-md border-b border-neutral-muted bg-surface-raised px-lg py-sm text-xs text-neutral/70'
|
|
14
|
+
base: 'flex shrink-0 items-center justify-between gap-md border-b border-neutral-muted bg-surface-raised px-lg py-sm text-xs text-neutral/70'
|
|
14
15
|
});
|
|
15
16
|
const defaultCodeTitle = cva({
|
|
16
17
|
base: 'font-mono'
|
|
17
18
|
});
|
|
18
19
|
const defaultCodeContainer = cva({
|
|
19
20
|
// The scroll + padding live on the inner highlighter <pre> (classes added by codeToHtml)
|
|
20
|
-
// so the focusable node is the scroller; the container is just the surface.
|
|
21
|
-
//
|
|
22
|
-
base: 'min-w-0 bg-surface text-sm @max-md:text-xs [&_pre]:!bg-transparent [&
|
|
21
|
+
// so the focusable node is the scroller; the container is just the surface. The pre's
|
|
22
|
+
// white-space and `tab-size` (from `--code-tab-size` on the root) live in CodeTheme.svelte.
|
|
23
|
+
base: 'min-w-0 bg-surface text-sm @max-md:text-xs [&_pre]:!bg-transparent [&_code]:font-mono'
|
|
23
24
|
});
|
|
24
25
|
const defaultCodeFooter = cva({
|
|
25
|
-
base: 'flex items-center justify-between gap-md border-t border-neutral-muted bg-surface-raised px-lg py-sm text-xs text-neutral/70'
|
|
26
|
+
base: 'flex shrink-0 items-center justify-between gap-md border-t border-neutral-muted bg-surface-raised px-lg py-sm text-xs text-neutral/70'
|
|
26
27
|
});
|
|
27
28
|
export const codeTheme = {
|
|
28
29
|
root: defaultCode,
|
|
@@ -59,6 +59,8 @@ export function getSidebarPanelPeekClass(variant) {
|
|
|
59
59
|
* ones for floating and split (the panel's own gutter spaces the pair).
|
|
60
60
|
*/
|
|
61
61
|
export function getSidebarActivityBarContainerClass(side, frame, variant) {
|
|
62
|
-
|
|
62
|
+
// Above the panel in every state, a peek (`z-40`) included: an edge-revealed panel slides in
|
|
63
|
+
// from past the screen edge and must come out from under the rail, never across it.
|
|
64
|
+
return cx('inset-y-0 z-[45] hidden w-[var(--sidebar-activity-offset,3rem)] md:flex', frame === 'viewport' ? 'fixed h-window' : 'absolute h-full', side === 'left' ? 'left-0' : 'right-0', variant === 'inset' && 'py-md', (variant === 'floating' || variant === 'split') &&
|
|
63
65
|
(side === 'left' ? 'py-md pl-md' : 'py-md pr-md'));
|
|
64
66
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
<script lang="ts" generics="Item extends TimelineItem = TimelineItem">
|
|
2
|
+
import { checkIcon } from '../Icons/check.js';
|
|
2
3
|
import Slot from '../Slot/Slot.svelte';
|
|
3
4
|
import Spinner from '../Spinner/Spinner.svelte';
|
|
4
5
|
import type { Density, Sizes } from '../../types/theme.js';
|
|
@@ -64,6 +65,8 @@
|
|
|
64
65
|
data-density={density}
|
|
65
66
|
data-first={entry.isFirst ? 'true' : undefined}
|
|
66
67
|
data-last={entry.isLast ? 'true' : undefined}
|
|
68
|
+
data-progress={entry.item.progress}
|
|
69
|
+
aria-current={entry.item.progress === 'current' ? 'step' : undefined}
|
|
67
70
|
class={classes.item({
|
|
68
71
|
orientation: entry.orientation,
|
|
69
72
|
placement,
|
|
@@ -107,9 +110,11 @@
|
|
|
107
110
|
<span
|
|
108
111
|
data-slot="timeline-connector"
|
|
109
112
|
data-color={entry.connectorColor}
|
|
113
|
+
data-progress={entry.item.progress}
|
|
110
114
|
class={classes.connector({
|
|
111
115
|
orientation: entry.orientation,
|
|
112
|
-
color: entry.connectorColor
|
|
116
|
+
color: entry.connectorColor,
|
|
117
|
+
progress: entry.item.progress ?? 'none'
|
|
113
118
|
})}
|
|
114
119
|
></span>
|
|
115
120
|
{/if}
|
|
@@ -182,7 +187,12 @@
|
|
|
182
187
|
<span
|
|
183
188
|
data-slot="timeline-marker"
|
|
184
189
|
data-color={entry.color}
|
|
185
|
-
|
|
190
|
+
data-progress={entry.item.loading ? undefined : entry.item.progress}
|
|
191
|
+
class={classes.marker({
|
|
192
|
+
size,
|
|
193
|
+
color: entry.color,
|
|
194
|
+
progress: entry.item.loading ? 'none' : (entry.item.progress ?? 'none')
|
|
195
|
+
})}
|
|
186
196
|
>
|
|
187
197
|
{#if entry.item.loading}
|
|
188
198
|
<span data-slot="timeline-loading" class={classes.loading({ size })}>
|
|
@@ -190,6 +200,10 @@
|
|
|
190
200
|
</span>
|
|
191
201
|
{:else if entry.item.icon}
|
|
192
202
|
<Slot render={entry.item.icon} />
|
|
203
|
+
{:else if entry.item.progress === 'done'}
|
|
204
|
+
{@render checkIcon()}
|
|
205
|
+
{:else if entry.item.progress === 'upcoming'}
|
|
206
|
+
<span data-slot="timeline-step-number">{entry.index + 1}</span>
|
|
193
207
|
{:else}
|
|
194
208
|
<span data-slot="timeline-dot"></span>
|
|
195
209
|
{/if}
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
export { default as Timeline } from './Timeline.svelte';
|
|
2
|
-
export type { TimelineItem, TimelineItemPayload, TimelineOrientation, TimelinePlacement, TimelineProps, TimelineSide, TimelineVariant } from './timeline.props.js';
|
|
2
|
+
export type { TimelineItem, TimelineItemPayload, TimelineOrientation, TimelinePlacement, TimelineProgress, TimelineProps, TimelineSide, TimelineVariant } from './timeline.props.js';
|
|
3
3
|
export { timelineTheme, setTimelineTheme, useTimelineTheme, type TimelineTheme, type TimelineThemeProps } from './timeline.theme.js';
|
|
@@ -11,4 +11,4 @@ export type ResolvedTimelineItem<Item extends TimelineItem> = Readonly<{
|
|
|
11
11
|
isFirst: boolean;
|
|
12
12
|
isLast: boolean;
|
|
13
13
|
}>;
|
|
14
|
-
export declare function resolveTimelineItems<Item extends TimelineItem>(items: readonly Item[], orientation: TimelineOrientation, placement: TimelinePlacement, color: Colors, connectorColor: Colors): readonly ResolvedTimelineItem<Item>[];
|
|
14
|
+
export declare function resolveTimelineItems<Item extends TimelineItem>(items: readonly Item[], orientation: TimelineOrientation, placement: TimelinePlacement, color: Colors, connectorColor: Colors | undefined): readonly ResolvedTimelineItem<Item>[];
|
|
@@ -17,6 +17,7 @@ export function resolveTimelineItems(items, orientation, placement, color, conne
|
|
|
17
17
|
const side = placement === 'alternate'
|
|
18
18
|
? (timelineItem.side ?? (index % 2 === 0 ? 'end' : 'start'))
|
|
19
19
|
: placement;
|
|
20
|
+
const itemColor = timelineItem.color ?? color;
|
|
20
21
|
let key = `index:${index}`;
|
|
21
22
|
if (explicitId !== undefined) {
|
|
22
23
|
key = `id:${typeof explicitId}:${explicitId}`;
|
|
@@ -27,8 +28,12 @@ export function resolveTimelineItems(items, orientation, placement, color, conne
|
|
|
27
28
|
index,
|
|
28
29
|
side,
|
|
29
30
|
orientation,
|
|
30
|
-
color:
|
|
31
|
-
|
|
31
|
+
color: itemColor,
|
|
32
|
+
// A progress band reads as one stroke: its connectors follow the step's own color
|
|
33
|
+
// unless a connector color is set on the item or the root.
|
|
34
|
+
connectorColor: timelineItem.connectorColor ??
|
|
35
|
+
connectorColor ??
|
|
36
|
+
(timelineItem.progress ? itemColor : 'neutral'),
|
|
32
37
|
isFirst: index === 0,
|
|
33
38
|
isLast: index === items.length - 1
|
|
34
39
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const timelineDescription = "\n# Timeline\n\nRender an ordered sequence of dated or descriptive events on a vertical or horizontal axis. Timeline owns the semantic list, item surfaces, axis anchors, markers, connectors, responsive alternate collapse, and horizontal overflow behavior. Input order is always render order.\n\n## Basic usage\n\n```svelte\n<script lang=\"ts\">\n import { Timeline, type TimelineItem } from './index.ts';\n\n const items: TimelineItem[] = [\n {\n id: 'placed',\n date: 'Mar 15, 2024',\n datetime: '2024-03-15',\n title: 'Order placed',\n description: 'Your order has been received.'\n },\n {\n id: 'payment',\n date: 'Mar 16, 2024',\n datetime: '2024-03-16',\n title: 'Payment confirmed',\n color: 'success'\n }\n ];\n</script>\n\n<Timeline {items} />\n```\n\nThe default configuration is a vertical timeline with all content on the logical end side of the axis.\n\n## Props\n\n### Data and layout\n\n- **items**: `readonly Item[]` (required) \u2014 entries in display order. `Item` must extend `TimelineItem`.\n- **orientation**: `'vertical' | 'horizontal'` (default: `'vertical'`) \u2014 direction of the sequence axis.\n- **placement**: `'start' | 'end' | 'alternate'` (default: `'end'`) \u2014 logical side used for item surfaces. Alternate placement starts on `end`, then alternates by array index.\n- **variant**: `'ghost' | 'card' | 'outline' | 'soft'` (default: `'ghost'`) \u2014 global surface treatment for all entries.\n- **size**: `'small' | 'normal' | 'large'` (default: `'normal'`) \u2014 title and description typography, marker and icon scale, and loading Spinner scale.\n- **density**: `'compact' | 'normal' | 'comfortable'` (default: `'normal'`) \u2014 item gaps, surface padding, connector spacing, and horizontal item minimum width.\n- **color**: Entasis semantic color (default: `'neutral'`) \u2014 default marker and outline or soft surface accent.\n- **connectorColor**: Entasis semantic color (default: `'neutral'`) \u2014 default outgoing connector color.\n- **showConnectors**: `boolean` (default: `true`) \u2014 shows connector segments between markers.\n- **scrollFade**: `boolean` (default: `true`) \u2014 applies the shared logical horizontal scroll fade only while a horizontal timeline actually overflows.\n- **i18n**: `Partial<Messages>` \u2014 per-instance translations merged over the global i18n catalog.\n\n### Custom rendering\n\n- **item**: `Snippet<[TimelineItemPayload<Item>]>` \u2014 replaces the content inside each Timeline-owned variant surface.\n- **marker**: `Snippet<[TimelineItemPayload<Item>]>` \u2014 replaces the marker visual inside the Timeline-owned axis anchor.\n- **opposite**: `Snippet<[TimelineItemPayload<Item>]>` \u2014 replaces the opposite track in alternate placement. Its default renderer is the item date. TypeScript rejects this prop with fixed `start` or `end` placement.\n\n### Root element\n\n- **ref**: `HTMLOListElement | null` (bindable) \u2014 reference to the root `<ol>`.\n- **class**: `string` \u2014 additional root classes.\n- **theme**: `TimelineThemeProps` \u2014 per-instance overrides for Timeline theme parts.\n- Native ordered-list attributes and Svelte attachments are forwarded to the root.\n\n## Item shape\n\n```ts\ntype TimelineItem = {\n id?: string | number;\n title: Slot;\n date?: Slot;\n datetime?: string;\n description?: Slot;\n icon?: Slot;\n loading?: boolean;\n color?: Colors;\n connectorColor?: Colors;\n side?: 'start' | 'end';\n};\n```\n\n- `title` is required. `title`, `date`, `description`, and `icon` accept a string or snippet.\n- `id` is optional. Use a stable explicit ID when entries can reorder; otherwise Timeline uses the array index as identity.\n- `datetime` adds the machine-readable value to a default `<time>` element when `date` is present.\n- `icon` replaces the default dot inside the default marker.\n- `loading` replaces the default marker visual with a color- and size-aware Spinner.\n- `color` overrides the root color for this marker and its outline or soft surface.\n- `connectorColor` overrides the root color for this item's outgoing connector. It has no effect on the final item.\n- `side` overrides alternate parity for one item. It is not valid with fixed placement.\n\n## Placement and dates\n\nFixed `start` and `end` placement keeps every surface on one logical side. The default content renders the date before the title inside each surface.\n\n`placement=\"alternate\"` creates an opposite track and starts the first item on `end`. Its default opposite renderer displays the date. Set `item.side` to place a specific alternate item on `start` or `end` without changing the array order.\n\n```svelte\n<Timeline items={milestones} placement=\"alternate\" variant=\"card\" />\n```\n\nTimeline treats dates as display content. It does not parse, format, compare, or sort them. It also has no completed, current, or pending status model. Put status meaning in the title or description and use semantic color or a custom marker only as supporting presentation.\n\n## Generic snippets and defaults\n\nApplication item types can extend `TimelineItem`. The extended type remains available as `payload.item` in all three renderer snippets.\n\n```svelte\n<script lang=\"ts\">\n import { Timeline, type TimelineItem } from './index.ts';\n\n type Release = TimelineItem & {\n version: string;\n href: string;\n };\n\n const releases: Release[] = [\n { id: 'v2', title: 'Version 2 released', version: '2.0.0', href: '/releases/v2' }\n ];\n</script>\n\n<Timeline items={releases}>\n {#snippet item({ item, defaultContent })}\n <a href={item.href} class=\"block\">\n {@render defaultContent()}\n <span class=\"text-neutral/70 text-xs\">{item.version}</span>\n </a>\n {/snippet}\n</Timeline>\n```\n\nEvery snippet receives:\n\n```ts\ntype TimelineItemPayload<Item extends TimelineItem> = Readonly<{\n item: Item;\n index: number;\n side: 'start' | 'end';\n orientation: 'vertical' | 'horizontal';\n color: Colors;\n connectorColor: Colors;\n isFirst: boolean;\n isLast: boolean;\n defaultContent: Snippet;\n defaultMarker: Snippet;\n defaultOpposite: Snippet;\n}>;\n```\n\nCall `defaultContent()`, `defaultMarker()`, or `defaultOpposite()` to wrap or extend the matching default renderer. A custom `marker` snippet that does not call `defaultMarker()` owns its complete marker visual, including loading presentation. Timeline still owns the `<ol>`, each `<li>`, axis and connector geometry, marker anchor, opposite track, and variant surface.\n\n## Responsive alternate layout\n\nA vertical alternate timeline uses its own inline-size container. Below `40rem`, it moves the axis to the logical start edge, places every main surface on the end side, and places opposite content before the main surface. DOM and input order do not change. Per-item `side` values remain in the payload, but their visual side effect is suspended while the layout is collapsed.\n\n## Horizontal overflow\n\nHorizontal entries stay on one axis and use density-controlled minimum widths. They do not wrap or compress; the root uses native horizontal scrolling. Timeline measures real overflow with `ResizeObserver`, applies `scroll-fade-x` only when needed, and makes the ordered list keyboard-focusable only while it overflows. The fade and native scrolling use logical inline direction and work in LTR and RTL layouts.\n\n## Variants\n\n- `ghost`: no surface chrome.\n- `card`: neutral raised surface with a quiet ring and shadow.\n- `outline`: transparent surface with a ring in the resolved item color.\n- `soft`: muted surface in the resolved item color.\n\nThe variant is global. Timeline does not support per-item variant overrides.\n\n## Runtime validation\n\nTimeline throws a descriptive `TypeError` when:\n\n- two items have the same explicit `id`;\n- an item supplies `side` while placement is fixed to `start` or `end`.\n\nThe ID check preserves number and string identity, so `1` and `'1'` are different IDs. TypeScript separately rejects `opposite` with fixed placement.\n\n## Accessibility\n\n- The root is an ordered list and every event is a list item.\n- Axis anchors, markers, and connectors are decorative and hidden from assistive technology. Do not use marker color or shape as the only status signal.\n- A default loading marker has a localized polite status announcement outside the decorative axis.\n- A default date with `datetime` renders as a semantic `<time>` element.\n- An overflowing horizontal timeline becomes a native keyboard scroll region; a non-overflowing timeline adds no tab stop.\n\n## Theme parts\n\n`root`, `item`, `opposite`, `axis`, `connector`, `marker`, `content`, `date`, `titleRow`, `title`, `description`, and `loading`.\n\nTimeline is display-only. It has no selection, navigation, event callbacks, animation state, bindable controller, date processing, or built-in progress status.\n";
|
|
1
|
+
export declare const timelineDescription = "\n# Timeline\n\nRender an ordered sequence of dated or descriptive events on a vertical or horizontal axis. Timeline owns the semantic list, item surfaces, axis anchors, markers, connectors, responsive alternate collapse, and horizontal overflow behavior. Input order is always render order.\n\n## Basic usage\n\n```svelte\n<script lang=\"ts\">\n import { Timeline, type TimelineItem } from './index.ts';\n\n const items: TimelineItem[] = [\n {\n id: 'placed',\n date: 'Mar 15, 2024',\n datetime: '2024-03-15',\n title: 'Order placed',\n description: 'Your order has been received.'\n },\n {\n id: 'payment',\n date: 'Mar 16, 2024',\n datetime: '2024-03-16',\n title: 'Payment confirmed',\n color: 'success'\n }\n ];\n</script>\n\n<Timeline {items} />\n```\n\nThe default configuration is a vertical timeline with all content on the logical end side of the axis.\n\n## Props\n\n### Data and layout\n\n- **items**: `readonly Item[]` (required) \u2014 entries in display order. `Item` must extend `TimelineItem`.\n- **orientation**: `'vertical' | 'horizontal'` (default: `'vertical'`) \u2014 direction of the sequence axis.\n- **placement**: `'start' | 'end' | 'alternate'` (default: `'end'`) \u2014 logical side used for item surfaces. Alternate placement starts on `end`, then alternates by array index.\n- **variant**: `'ghost' | 'card' | 'outline' | 'soft'` (default: `'ghost'`) \u2014 global surface treatment for all entries.\n- **size**: `'small' | 'normal' | 'large'` (default: `'normal'`) \u2014 title and description typography, marker and icon scale, and loading Spinner scale.\n- **density**: `'compact' | 'normal' | 'comfortable'` (default: `'normal'`) \u2014 item gaps, surface padding, connector spacing, and horizontal item minimum width.\n- **color**: Entasis semantic color (default: `'neutral'`) \u2014 default marker and outline or soft surface accent.\n- **connectorColor**: Entasis semantic color \u2014 default outgoing connector color. When omitted, an item with `progress` uses its own resolved color for its connector, and every other item uses `'neutral'`.\n- **showConnectors**: `boolean` (default: `true`) \u2014 shows connector segments between markers.\n- **scrollFade**: `boolean` (default: `true`) \u2014 applies the shared logical horizontal scroll fade only while a horizontal timeline actually overflows.\n- **i18n**: `Partial<Messages>` \u2014 per-instance translations merged over the global i18n catalog.\n\n### Custom rendering\n\n- **item**: `Snippet<[TimelineItemPayload<Item>]>` \u2014 replaces the content inside each Timeline-owned variant surface.\n- **marker**: `Snippet<[TimelineItemPayload<Item>]>` \u2014 replaces the marker visual inside the Timeline-owned axis anchor.\n- **opposite**: `Snippet<[TimelineItemPayload<Item>]>` \u2014 replaces the opposite track in alternate placement. Its default renderer is the item date. TypeScript rejects this prop with fixed `start` or `end` placement.\n\n### Root element\n\n- **ref**: `HTMLOListElement | null` (bindable) \u2014 reference to the root `<ol>`.\n- **class**: `string` \u2014 additional root classes.\n- **theme**: `TimelineThemeProps` \u2014 per-instance overrides for Timeline theme parts.\n- Native ordered-list attributes and Svelte attachments are forwarded to the root.\n\n## Item shape\n\n```ts\ntype TimelineItem = {\n id?: string | number;\n title: Slot;\n date?: Slot;\n datetime?: string;\n description?: Slot;\n icon?: Slot;\n loading?: boolean;\n color?: Colors;\n connectorColor?: Colors;\n progress?: 'done' | 'current' | 'upcoming';\n side?: 'start' | 'end';\n};\n```\n\n- `title` is required. `title`, `date`, `description`, and `icon` accept a string or snippet.\n- `id` is optional. Use a stable explicit ID when entries can reorder; otherwise Timeline uses the array index as identity.\n- `datetime` adds the machine-readable value to a default `<time>` element when `date` is present.\n- `icon` replaces the default dot inside the default marker.\n- `loading` replaces the default marker visual with a color- and size-aware Spinner.\n- `color` overrides the root color for this marker and its outline or soft surface.\n- `connectorColor` overrides the root color for this item's outgoing connector. It has no effect on the final item.\n- `side` overrides alternate parity for one item. It is not valid with fixed placement.\n- `progress` marks a step of a process (`TimelineProgress`). See Step progress below.\n\n## Placement and dates\n\nFixed `start` and `end` placement keeps every surface on one logical side. The default content renders the date before the title inside each surface.\n\n`placement=\"alternate\"` creates an opposite track and starts the first item on `end`. Its default opposite renderer displays the date. Set `item.side` to place a specific alternate item on `start` or `end` without changing the array order.\n\n```svelte\n<Timeline items={milestones} placement=\"alternate\" variant=\"card\" />\n```\n\nTimeline treats dates as display content. It does not parse, format, compare, or sort them.\n\n## Step progress\n\nGive each item a `progress` to draw a process's progress band, such as a file's six stages, so a reader sees at a glance what is done, what is under way, and what is to come:\n\n```svelte\n<script lang=\"ts\">\n import { Timeline, type TimelineItem } from './index.ts';\n\n const steps: TimelineItem[] = [\n { id: 'opened', title: 'Opened', progress: 'done' },\n { id: 'documents', title: 'Documents', progress: 'done' },\n { id: 'appraisal', title: 'Appraisal', progress: 'current' },\n { id: 'report', title: 'Report', progress: 'upcoming' }\n ];\n</script>\n\n<Timeline items={steps} orientation=\"horizontal\" color=\"primary\" />\n```\n\n- `done`: the marker is filled with the item color and carries a check. Its outgoing connector is solid.\n- `current`: the marker is a ring in the item color around a point. The `<li>` gets `aria-current=\"step\"`. Its outgoing connector is faint.\n- `upcoming`: the marker is a quiet neutral ring carrying the step number (the item's position, from 1). Its outgoing connector is faint.\n- Markers keep the size's marker scale. Progress connectors are 2px thick instead of the hairline, so the done part of the band stands out.\n- An item `icon` replaces the check, the point, or the number, and keeps the progress ring and fill. `loading` replaces the whole marker with the Spinner.\n- `progress` is per item: Timeline does not derive it from an index, so a host may mark any combination.\n- The step's state is not announced by the markers, which stay decorative. Put it in the item's own text (for example \"Step 3 of 6, done\") or an `item` snippet. `aria-current=\"step\"` on the current item is the only state Timeline adds.\n- The `marker` snippet still replaces every marker: read `payload.item.progress` and call `defaultMarker()` for the steps it leaves alone. Theme overrides reach the `progress` variant of the `marker` and `connector` parts, for example `theme={{ connector: { progress: { done: 'bg-success' } } }}`.\n- Styling hooks: `data-progress` on the item, its marker and its outgoing connector.\n\n## Generic snippets and defaults\n\nApplication item types can extend `TimelineItem`. The extended type remains available as `payload.item` in all three renderer snippets.\n\n```svelte\n<script lang=\"ts\">\n import { Timeline, type TimelineItem } from './index.ts';\n\n type Release = TimelineItem & {\n version: string;\n href: string;\n };\n\n const releases: Release[] = [\n { id: 'v2', title: 'Version 2 released', version: '2.0.0', href: '/releases/v2' }\n ];\n</script>\n\n<Timeline items={releases}>\n {#snippet item({ item, defaultContent })}\n <a href={item.href} class=\"block\">\n {@render defaultContent()}\n <span class=\"text-neutral/70 text-xs\">{item.version}</span>\n </a>\n {/snippet}\n</Timeline>\n```\n\nEvery snippet receives:\n\n```ts\ntype TimelineItemPayload<Item extends TimelineItem> = Readonly<{\n item: Item;\n index: number;\n side: 'start' | 'end';\n orientation: 'vertical' | 'horizontal';\n color: Colors;\n connectorColor: Colors;\n isFirst: boolean;\n isLast: boolean;\n defaultContent: Snippet;\n defaultMarker: Snippet;\n defaultOpposite: Snippet;\n}>;\n```\n\nCall `defaultContent()`, `defaultMarker()`, or `defaultOpposite()` to wrap or extend the matching default renderer. A custom `marker` snippet that does not call `defaultMarker()` owns its complete marker visual, including loading presentation. Timeline still owns the `<ol>`, each `<li>`, axis and connector geometry, marker anchor, opposite track, and variant surface.\n\n## Responsive alternate layout\n\nA vertical alternate timeline uses its own inline-size container. Below `40rem`, it moves the axis to the logical start edge, places every main surface on the end side, and places opposite content before the main surface. DOM and input order do not change. Per-item `side` values remain in the payload, but their visual side effect is suspended while the layout is collapsed.\n\n## Horizontal overflow\n\nHorizontal entries stay on one axis and use density-controlled minimum widths. They do not wrap or compress; the root uses native horizontal scrolling. Timeline measures real overflow with `ResizeObserver`, applies `scroll-fade-x` only when needed, and makes the ordered list keyboard-focusable only while it overflows. The fade and native scrolling use logical inline direction and work in LTR and RTL layouts.\n\n## Variants\n\n- `ghost`: no surface chrome.\n- `card`: neutral raised surface with a quiet ring and shadow.\n- `outline`: transparent surface with a ring in the resolved item color.\n- `soft`: muted surface in the resolved item color.\n\nThe variant is global. Timeline does not support per-item variant overrides.\n\n## Runtime validation\n\nTimeline throws a descriptive `TypeError` when:\n\n- two items have the same explicit `id`;\n- an item supplies `side` while placement is fixed to `start` or `end`.\n\nThe ID check preserves number and string identity, so `1` and `'1'` are different IDs. TypeScript separately rejects `opposite` with fixed placement.\n\n## Accessibility\n\n- The root is an ordered list and every event is a list item.\n- Axis anchors, markers, and connectors are decorative and hidden from assistive technology. Do not use marker color or shape as the only status signal.\n- An item with `progress: 'current'` carries `aria-current=\"step\"`.\n- A default loading marker has a localized polite status announcement outside the decorative axis.\n- A default date with `datetime` renders as a semantic `<time>` element.\n- An overflowing horizontal timeline becomes a native keyboard scroll region; a non-overflowing timeline adds no tab stop.\n\n## Theme parts\n\n`root`, `item`, `opposite`, `axis`, `connector`, `marker`, `content`, `date`, `titleRow`, `title`, `description`, and `loading`.\n\nTimeline is display-only. It has no selection, navigation, event callbacks, animation state, bindable controller, or date processing. Step `progress` is presentation the host sets per item, not a state Timeline advances.\n";
|
|
@@ -43,7 +43,7 @@ The default configuration is a vertical timeline with all content on the logical
|
|
|
43
43
|
- **size**: \`'small' | 'normal' | 'large'\` (default: \`'normal'\`) — title and description typography, marker and icon scale, and loading Spinner scale.
|
|
44
44
|
- **density**: \`'compact' | 'normal' | 'comfortable'\` (default: \`'normal'\`) — item gaps, surface padding, connector spacing, and horizontal item minimum width.
|
|
45
45
|
- **color**: Entasis semantic color (default: \`'neutral'\`) — default marker and outline or soft surface accent.
|
|
46
|
-
- **connectorColor**: Entasis semantic color
|
|
46
|
+
- **connectorColor**: Entasis semantic color — default outgoing connector color. When omitted, an item with \`progress\` uses its own resolved color for its connector, and every other item uses \`'neutral'\`.
|
|
47
47
|
- **showConnectors**: \`boolean\` (default: \`true\`) — shows connector segments between markers.
|
|
48
48
|
- **scrollFade**: \`boolean\` (default: \`true\`) — applies the shared logical horizontal scroll fade only while a horizontal timeline actually overflows.
|
|
49
49
|
- **i18n**: \`Partial<Messages>\` — per-instance translations merged over the global i18n catalog.
|
|
@@ -74,6 +74,7 @@ type TimelineItem = {
|
|
|
74
74
|
loading?: boolean;
|
|
75
75
|
color?: Colors;
|
|
76
76
|
connectorColor?: Colors;
|
|
77
|
+
progress?: 'done' | 'current' | 'upcoming';
|
|
77
78
|
side?: 'start' | 'end';
|
|
78
79
|
};
|
|
79
80
|
\`\`\`
|
|
@@ -86,6 +87,7 @@ type TimelineItem = {
|
|
|
86
87
|
- \`color\` overrides the root color for this marker and its outline or soft surface.
|
|
87
88
|
- \`connectorColor\` overrides the root color for this item's outgoing connector. It has no effect on the final item.
|
|
88
89
|
- \`side\` overrides alternate parity for one item. It is not valid with fixed placement.
|
|
90
|
+
- \`progress\` marks a step of a process (\`TimelineProgress\`). See Step progress below.
|
|
89
91
|
|
|
90
92
|
## Placement and dates
|
|
91
93
|
|
|
@@ -97,7 +99,36 @@ Fixed \`start\` and \`end\` placement keeps every surface on one logical side. T
|
|
|
97
99
|
<Timeline items={milestones} placement="alternate" variant="card" />
|
|
98
100
|
\`\`\`
|
|
99
101
|
|
|
100
|
-
Timeline treats dates as display content. It does not parse, format, compare, or sort them.
|
|
102
|
+
Timeline treats dates as display content. It does not parse, format, compare, or sort them.
|
|
103
|
+
|
|
104
|
+
## Step progress
|
|
105
|
+
|
|
106
|
+
Give each item a \`progress\` to draw a process's progress band, such as a file's six stages, so a reader sees at a glance what is done, what is under way, and what is to come:
|
|
107
|
+
|
|
108
|
+
\`\`\`svelte
|
|
109
|
+
<script lang="ts">
|
|
110
|
+
import { Timeline, type TimelineItem } from './index.ts';
|
|
111
|
+
|
|
112
|
+
const steps: TimelineItem[] = [
|
|
113
|
+
{ id: 'opened', title: 'Opened', progress: 'done' },
|
|
114
|
+
{ id: 'documents', title: 'Documents', progress: 'done' },
|
|
115
|
+
{ id: 'appraisal', title: 'Appraisal', progress: 'current' },
|
|
116
|
+
{ id: 'report', title: 'Report', progress: 'upcoming' }
|
|
117
|
+
];
|
|
118
|
+
</script>
|
|
119
|
+
|
|
120
|
+
<Timeline items={steps} orientation="horizontal" color="primary" />
|
|
121
|
+
\`\`\`
|
|
122
|
+
|
|
123
|
+
- \`done\`: the marker is filled with the item color and carries a check. Its outgoing connector is solid.
|
|
124
|
+
- \`current\`: the marker is a ring in the item color around a point. The \`<li>\` gets \`aria-current="step"\`. Its outgoing connector is faint.
|
|
125
|
+
- \`upcoming\`: the marker is a quiet neutral ring carrying the step number (the item's position, from 1). Its outgoing connector is faint.
|
|
126
|
+
- Markers keep the size's marker scale. Progress connectors are 2px thick instead of the hairline, so the done part of the band stands out.
|
|
127
|
+
- An item \`icon\` replaces the check, the point, or the number, and keeps the progress ring and fill. \`loading\` replaces the whole marker with the Spinner.
|
|
128
|
+
- \`progress\` is per item: Timeline does not derive it from an index, so a host may mark any combination.
|
|
129
|
+
- The step's state is not announced by the markers, which stay decorative. Put it in the item's own text (for example "Step 3 of 6, done") or an \`item\` snippet. \`aria-current="step"\` on the current item is the only state Timeline adds.
|
|
130
|
+
- The \`marker\` snippet still replaces every marker: read \`payload.item.progress\` and call \`defaultMarker()\` for the steps it leaves alone. Theme overrides reach the \`progress\` variant of the \`marker\` and \`connector\` parts, for example \`theme={{ connector: { progress: { done: 'bg-success' } } }}\`.
|
|
131
|
+
- Styling hooks: \`data-progress\` on the item, its marker and its outgoing connector.
|
|
101
132
|
|
|
102
133
|
## Generic snippets and defaults
|
|
103
134
|
|
|
@@ -177,6 +208,7 @@ The ID check preserves number and string identity, so \`1\` and \`'1'\` are diff
|
|
|
177
208
|
|
|
178
209
|
- The root is an ordered list and every event is a list item.
|
|
179
210
|
- Axis anchors, markers, and connectors are decorative and hidden from assistive technology. Do not use marker color or shape as the only status signal.
|
|
211
|
+
- An item with \`progress: 'current'\` carries \`aria-current="step"\`.
|
|
180
212
|
- A default loading marker has a localized polite status announcement outside the decorative axis.
|
|
181
213
|
- A default date with \`datetime\` renders as a semantic \`<time>\` element.
|
|
182
214
|
- An overflowing horizontal timeline becomes a native keyboard scroll region; a non-overflowing timeline adds no tab stop.
|
|
@@ -185,5 +217,5 @@ The ID check preserves number and string identity, so \`1\` and \`'1'\` are diff
|
|
|
185
217
|
|
|
186
218
|
\`root\`, \`item\`, \`opposite\`, \`axis\`, \`connector\`, \`marker\`, \`content\`, \`date\`, \`titleRow\`, \`title\`, \`description\`, and \`loading\`.
|
|
187
219
|
|
|
188
|
-
Timeline is display-only. It has no selection, navigation, event callbacks, animation state, bindable controller, date processing,
|
|
220
|
+
Timeline is display-only. It has no selection, navigation, event callbacks, animation state, bindable controller, or date processing. Step \`progress\` is presentation the host sets per item, not a state Timeline advances.
|
|
189
221
|
`;
|
|
@@ -9,6 +9,12 @@ export type TimelineOrientation = 'vertical' | 'horizontal';
|
|
|
9
9
|
export type TimelinePlacement = 'start' | 'end' | 'alternate';
|
|
10
10
|
export type TimelineSide = 'start' | 'end';
|
|
11
11
|
export type TimelineVariant = 'ghost' | 'card' | 'outline' | 'soft';
|
|
12
|
+
/**
|
|
13
|
+
* Where a step stands in a process: finished, under way, or still to come. Drives the default
|
|
14
|
+
* marker (a filled check, a ring with a point, a quiet numbered ring) and the outgoing connector
|
|
15
|
+
* (solid after a finished step, faint after the others).
|
|
16
|
+
*/
|
|
17
|
+
export type TimelineProgress = 'done' | 'current' | 'upcoming';
|
|
12
18
|
export type TimelineItem = {
|
|
13
19
|
/** Stable identity. Use an explicit ID when the array can reorder. */
|
|
14
20
|
id?: string | number;
|
|
@@ -28,6 +34,13 @@ export type TimelineItem = {
|
|
|
28
34
|
color?: Colors;
|
|
29
35
|
/** Outgoing connector color. Ignored on the final item. */
|
|
30
36
|
connectorColor?: Colors;
|
|
37
|
+
/**
|
|
38
|
+
* Step progress. A `done` step draws a filled check and a solid outgoing connector, the
|
|
39
|
+
* `current` step a ring with a point and `aria-current="step"`, an `upcoming` step a quiet ring
|
|
40
|
+
* with its step number; the connectors after `current` and `upcoming` steps stay faint. An
|
|
41
|
+
* `icon` replaces the check, the point or the number; `loading` replaces the whole marker.
|
|
42
|
+
*/
|
|
43
|
+
progress?: TimelineProgress;
|
|
31
44
|
/** Logical side override. Valid only when placement is alternate. */
|
|
32
45
|
side?: TimelineSide;
|
|
33
46
|
};
|
|
@@ -69,7 +82,10 @@ export type TimelineProps<Item extends TimelineItem = TimelineItem> = WithAttach
|
|
|
69
82
|
density?: Density;
|
|
70
83
|
/** Default semantic item accent. */
|
|
71
84
|
color?: Colors;
|
|
72
|
-
/**
|
|
85
|
+
/**
|
|
86
|
+
* Default outgoing connector accent. When omitted, an item with `progress` takes its own
|
|
87
|
+
* color for its connector, and every other item takes `neutral`.
|
|
88
|
+
*/
|
|
73
89
|
connectorColor?: Colors;
|
|
74
90
|
/** Shows connector segments between markers. */
|
|
75
91
|
showConnectors?: boolean;
|
|
@@ -109,6 +109,12 @@ export declare const timelineTheme: {
|
|
|
109
109
|
readonly info: "";
|
|
110
110
|
readonly neutral: "";
|
|
111
111
|
};
|
|
112
|
+
progress: {
|
|
113
|
+
none: string;
|
|
114
|
+
done: string;
|
|
115
|
+
current: string;
|
|
116
|
+
upcoming: string;
|
|
117
|
+
};
|
|
112
118
|
}> & import("../../utils/cva/types.ts").CVAClassProp) | undefined) => string;
|
|
113
119
|
marker: (props?: (import("../../utils/cva/types.ts").CVAVariantSchema<{
|
|
114
120
|
size: {
|
|
@@ -125,6 +131,12 @@ export declare const timelineTheme: {
|
|
|
125
131
|
readonly info: "";
|
|
126
132
|
readonly neutral: "";
|
|
127
133
|
};
|
|
134
|
+
progress: {
|
|
135
|
+
none: string;
|
|
136
|
+
done: string;
|
|
137
|
+
current: string;
|
|
138
|
+
upcoming: string;
|
|
139
|
+
};
|
|
128
140
|
}> & import("../../utils/cva/types.ts").CVAClassProp) | undefined) => string;
|
|
129
141
|
content: (props?: (import("../../utils/cva/types.ts").CVAVariantSchema<{
|
|
130
142
|
orientation: {
|
|
@@ -336,6 +348,12 @@ export declare const setTimelineTheme: (theme: InferComponentTheme<{
|
|
|
336
348
|
readonly info: "";
|
|
337
349
|
readonly neutral: "";
|
|
338
350
|
};
|
|
351
|
+
progress: {
|
|
352
|
+
none: string;
|
|
353
|
+
done: string;
|
|
354
|
+
current: string;
|
|
355
|
+
upcoming: string;
|
|
356
|
+
};
|
|
339
357
|
}> & import("../../utils/cva/types.ts").CVAClassProp) | undefined) => string;
|
|
340
358
|
marker: (props?: (import("../../utils/cva/types.ts").CVAVariantSchema<{
|
|
341
359
|
size: {
|
|
@@ -352,6 +370,12 @@ export declare const setTimelineTheme: (theme: InferComponentTheme<{
|
|
|
352
370
|
readonly info: "";
|
|
353
371
|
readonly neutral: "";
|
|
354
372
|
};
|
|
373
|
+
progress: {
|
|
374
|
+
none: string;
|
|
375
|
+
done: string;
|
|
376
|
+
current: string;
|
|
377
|
+
upcoming: string;
|
|
378
|
+
};
|
|
355
379
|
}> & import("../../utils/cva/types.ts").CVAClassProp) | undefined) => string;
|
|
356
380
|
content: (props?: (import("../../utils/cva/types.ts").CVAVariantSchema<{
|
|
357
381
|
orientation: {
|
|
@@ -561,6 +585,12 @@ export declare const useTimelineTheme: import("../../utils/cva/theme.ts").UseCom
|
|
|
561
585
|
readonly info: "";
|
|
562
586
|
readonly neutral: "";
|
|
563
587
|
};
|
|
588
|
+
progress: {
|
|
589
|
+
none: string;
|
|
590
|
+
done: string;
|
|
591
|
+
current: string;
|
|
592
|
+
upcoming: string;
|
|
593
|
+
};
|
|
564
594
|
}> & import("../../utils/cva/types.ts").CVAClassProp) | undefined) => string;
|
|
565
595
|
marker: (props?: (import("../../utils/cva/types.ts").CVAVariantSchema<{
|
|
566
596
|
size: {
|
|
@@ -577,6 +607,12 @@ export declare const useTimelineTheme: import("../../utils/cva/theme.ts").UseCom
|
|
|
577
607
|
readonly info: "";
|
|
578
608
|
readonly neutral: "";
|
|
579
609
|
};
|
|
610
|
+
progress: {
|
|
611
|
+
none: string;
|
|
612
|
+
done: string;
|
|
613
|
+
current: string;
|
|
614
|
+
upcoming: string;
|
|
615
|
+
};
|
|
580
616
|
}> & import("../../utils/cva/types.ts").CVAClassProp) | undefined) => string;
|
|
581
617
|
content: (props?: (import("../../utils/cva/types.ts").CVAVariantSchema<{
|
|
582
618
|
orientation: {
|
|
@@ -248,6 +248,8 @@ const defaultAxis = cva({
|
|
|
248
248
|
isLast: false
|
|
249
249
|
}
|
|
250
250
|
});
|
|
251
|
+
// `progress` is the step the connector leaves: solid after a done step, faint after the
|
|
252
|
+
// current and upcoming ones, so the band reads as finished up to the current step.
|
|
251
253
|
const defaultConnector = cva({
|
|
252
254
|
base: 'pointer-events-none absolute z-0 bg-color/35',
|
|
253
255
|
variants: {
|
|
@@ -255,11 +257,22 @@ const defaultConnector = cva({
|
|
|
255
257
|
vertical: 'left-1/2 top-[calc(var(--timeline-marker-size)/2)] h-full w-px -translate-x-1/2',
|
|
256
258
|
horizontal: 'start-[calc(var(--timeline-marker-size)/2)] top-1/2 h-px w-full -translate-y-1/2'
|
|
257
259
|
},
|
|
258
|
-
color: colorVariants
|
|
260
|
+
color: colorVariants,
|
|
261
|
+
progress: {
|
|
262
|
+
none: '',
|
|
263
|
+
done: 'bg-color',
|
|
264
|
+
current: 'bg-color/20',
|
|
265
|
+
upcoming: 'bg-color/20'
|
|
266
|
+
}
|
|
259
267
|
},
|
|
268
|
+
compoundVariants: [
|
|
269
|
+
{ orientation: 'vertical', progress: ['done', 'current', 'upcoming'], class: 'w-0.5' },
|
|
270
|
+
{ orientation: 'horizontal', progress: ['done', 'current', 'upcoming'], class: 'h-0.5' }
|
|
271
|
+
],
|
|
260
272
|
defaultVariants: {
|
|
261
273
|
orientation: 'vertical',
|
|
262
|
-
color: 'neutral'
|
|
274
|
+
color: 'neutral',
|
|
275
|
+
progress: 'none'
|
|
263
276
|
}
|
|
264
277
|
});
|
|
265
278
|
const defaultMarker = cva({
|
|
@@ -270,11 +283,21 @@ const defaultMarker = cva({
|
|
|
270
283
|
normal: 'size-[1.125rem]',
|
|
271
284
|
large: 'size-[1.375rem]'
|
|
272
285
|
},
|
|
273
|
-
color: colorVariants
|
|
286
|
+
color: colorVariants,
|
|
287
|
+
// A done step is filled with its check, the current one ringed around its point, an
|
|
288
|
+
// upcoming one a quiet ring around its step number. The number is a glyph drawn to the
|
|
289
|
+
// marker, like the check, so it scales with the marker size rather than the type ramp.
|
|
290
|
+
progress: {
|
|
291
|
+
none: '',
|
|
292
|
+
done: 'bg-color text-color-contrast ring-color',
|
|
293
|
+
current: 'ring-2 ring-color',
|
|
294
|
+
upcoming: 'text-neutral/70 ring-neutral-muted font-medium leading-none tabular-nums text-[length:calc(var(--timeline-marker-size)*0.55)]'
|
|
295
|
+
}
|
|
274
296
|
},
|
|
275
297
|
defaultVariants: {
|
|
276
298
|
size: 'normal',
|
|
277
|
-
color: 'neutral'
|
|
299
|
+
color: 'neutral',
|
|
300
|
+
progress: 'none'
|
|
278
301
|
}
|
|
279
302
|
});
|
|
280
303
|
const defaultContent = cva({
|
|
@@ -1098,7 +1098,7 @@ export declare const componentInventory: readonly [{
|
|
|
1098
1098
|
readonly id: "timeline";
|
|
1099
1099
|
readonly subpath: "entasis/timeline";
|
|
1100
1100
|
readonly sourceIndex: "src/lib/components/Timeline/index.ts";
|
|
1101
|
-
readonly exportedSymbols: readonly ["Timeline", "TimelineItem", "TimelineItemPayload", "TimelineOrientation", "TimelinePlacement", "TimelineProps", "TimelineSide", "TimelineTheme", "TimelineThemeProps", "TimelineVariant", "setTimelineTheme", "timelineTheme", "useTimelineTheme"];
|
|
1101
|
+
readonly exportedSymbols: readonly ["Timeline", "TimelineItem", "TimelineItemPayload", "TimelineOrientation", "TimelinePlacement", "TimelineProgress", "TimelineProps", "TimelineSide", "TimelineTheme", "TimelineThemeProps", "TimelineVariant", "setTimelineTheme", "timelineTheme", "useTimelineTheme"];
|
|
1102
1102
|
readonly docs: readonly [{
|
|
1103
1103
|
readonly id: "timeline";
|
|
1104
1104
|
readonly route: "/components/timeline";
|