@marianmeres/stuic 3.168.0 → 3.170.0

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.
Files changed (31) hide show
  1. package/AGENTS.md +2 -2
  2. package/dist/README.md +1 -1
  3. package/dist/components/Input/FieldOptions.svelte +89 -54
  4. package/dist/components/Input/FieldOptions.svelte.d.ts +13 -0
  5. package/dist/components/Input/README.md +144 -31
  6. package/dist/components/Input/_internal/FieldLikeChips.svelte +286 -0
  7. package/dist/components/Input/_internal/FieldLikeChips.svelte.d.ts +65 -0
  8. package/dist/components/Input/field-options-i18n-sk.d.ts +21 -0
  9. package/dist/components/Input/field-options-i18n-sk.js +61 -0
  10. package/dist/components/Input/field-options-i18n.d.ts +82 -0
  11. package/dist/components/Input/field-options-i18n.js +90 -0
  12. package/dist/components/Input/index.css +58 -0
  13. package/dist/components/Input/index.d.ts +2 -0
  14. package/dist/components/Input/index.js +2 -0
  15. package/dist/components/Pill/Pill.svelte +8 -2
  16. package/dist/components/Pill/Pill.svelte.d.ts +2 -0
  17. package/dist/components/Pill/README.md +35 -22
  18. package/dist/components/Pill/index.css +57 -18
  19. package/dist/components/Timeline/README.md +204 -0
  20. package/dist/components/Timeline/Timeline.svelte +246 -0
  21. package/dist/components/Timeline/Timeline.svelte.d.ts +87 -0
  22. package/dist/components/Timeline/index.css +311 -0
  23. package/dist/components/Timeline/index.d.ts +1 -0
  24. package/dist/components/Timeline/index.js +1 -0
  25. package/dist/index.css +1 -0
  26. package/dist/index.d.ts +1 -0
  27. package/dist/index.js +1 -0
  28. package/docs/domains/components.md +39 -1
  29. package/docs/maybe-todo.md +37 -13
  30. package/docs/upgrading.md +6 -0
  31. package/package.json +1 -1
@@ -0,0 +1,246 @@
1
+ <script lang="ts" module>
2
+ import type { HTMLOlAttributes } from "svelte/elements";
3
+ import type { Snippet } from "svelte";
4
+ import type { THC } from "../Thc/Thc.svelte";
5
+ import type { IntentColorKey } from "../../utils/design-tokens.js";
6
+
7
+ /** Which side of the rail the content sits on */
8
+ export type TimelineAlign = "start" | "alternate";
9
+
10
+ /** Where the time label renders */
11
+ export type TimelineTimePosition = "inline" | "opposite";
12
+
13
+ /** What the marker renders as (`data-marker` on the marker element) */
14
+ export type TimelineMarkerKind = "dot" | "icon" | "custom";
15
+
16
+ export interface TimelineItem {
17
+ /** Primary line (the event) */
18
+ title?: THC;
19
+ /** Secondary text under the title */
20
+ description?: THC;
21
+ /**
22
+ * Time label, preformatted ("2 hours ago", "Sep 1, 14:32"). When omitted and
23
+ * `datetime` is set, the component's `formatTime` (if any) produces it.
24
+ */
25
+ time?: THC;
26
+ /**
27
+ * Machine-readable timestamp — renders the label as `<time datetime="…">`
28
+ * (a `Date` is serialized to ISO 8601). Never displayed on its own.
29
+ */
30
+ datetime?: string | Date;
31
+ /**
32
+ * Marker content (typically `{ html: iconCheck() }`). Its presence switches the
33
+ * marker from the small dot to the icon bubble.
34
+ */
35
+ icon?: THC;
36
+ /** Semantic marker color (dot fill, or the bubble's soft tint) */
37
+ intent?: IntentColorKey;
38
+ /** When set, the title renders as a link */
39
+ href?: string;
40
+ }
41
+
42
+ export interface TimelineSnippetArg {
43
+ item: TimelineItem;
44
+ index: number;
45
+ }
46
+
47
+ export interface Props extends Omit<HTMLOlAttributes, "children"> {
48
+ /** The events, in the order they should appear (sort them yourself) */
49
+ items: TimelineItem[];
50
+ /**
51
+ * `"start"` (default): rail on the start side, content after it.
52
+ * `"alternate"`: centered rail, content alternating sides (history pages).
53
+ */
54
+ align?: TimelineAlign;
55
+ /**
56
+ * `"inline"` (default): the time label above the title, inside the content.
57
+ * `"opposite"`: its own column on the other side of the rail (audit-log look).
58
+ */
59
+ timePosition?: TimelineTimePosition;
60
+ /**
61
+ * Fallback formatter for items that have `datetime` but no `time`. Return
62
+ * value is THC, so a plain string is fine.
63
+ */
64
+ formatTime?: (datetime: string | Date, item: TimelineItem) => THC;
65
+ /** Override the marker content entirely (avatars, badges…) */
66
+ renderMarker?: Snippet<[TimelineSnippetArg]>;
67
+ /** Override the whole content cell (time, title, description, footer) */
68
+ renderItem?: Snippet<[TimelineSnippetArg]>;
69
+ /** Per-item footer area below the description (actions, attachments…) */
70
+ renderFooter?: Snippet<[TimelineSnippetArg]>;
71
+ /** Skip all default styling */
72
+ unstyled?: boolean;
73
+ /** Additional CSS classes */
74
+ class?: string;
75
+ /** Class for every item (`li`) */
76
+ classItem?: string;
77
+ /** Class for the marker */
78
+ classMarker?: string;
79
+ /** Class for the content cell */
80
+ classContent?: string;
81
+ /** Class for the time label (inline or opposite) */
82
+ classTime?: string;
83
+ /** Class for the title */
84
+ classTitle?: string;
85
+ /** Class for the description */
86
+ classDescription?: string;
87
+ /** Class for the footer area */
88
+ classFooter?: string;
89
+ /** Bindable element reference */
90
+ el?: HTMLOListElement;
91
+ }
92
+ </script>
93
+
94
+ <script lang="ts">
95
+ import { twMerge } from "../../utils/tw-merge.js";
96
+ import Thc from "../Thc/Thc.svelte";
97
+
98
+ let {
99
+ items,
100
+ align = "start",
101
+ timePosition = "inline",
102
+ formatTime,
103
+ renderMarker,
104
+ renderItem,
105
+ renderFooter,
106
+ unstyled = false,
107
+ class: classProp,
108
+ classItem: classItemProp,
109
+ classMarker: classMarkerProp,
110
+ classContent: classContentProp,
111
+ classTime: classTimeProp,
112
+ classTitle: classTitleProp,
113
+ classDescription: classDescriptionProp,
114
+ classFooter: classFooterProp,
115
+ el = $bindable(),
116
+ ...rest
117
+ }: Props = $props();
118
+
119
+ let _class = $derived(unstyled ? classProp : twMerge("stuic-timeline", classProp));
120
+ let _classItem = $derived(
121
+ unstyled ? classItemProp : twMerge("stuic-timeline-item", classItemProp)
122
+ );
123
+ let _classMarker = $derived(
124
+ unstyled ? classMarkerProp : twMerge("stuic-timeline-marker", classMarkerProp)
125
+ );
126
+ let _classContent = $derived(
127
+ unstyled ? classContentProp : twMerge("stuic-timeline-content", classContentProp)
128
+ );
129
+ let _classTime = $derived(
130
+ unstyled ? classTimeProp : twMerge("stuic-timeline-time", classTimeProp)
131
+ );
132
+ let _classTitle = $derived(
133
+ unstyled ? classTitleProp : twMerge("stuic-timeline-title", classTitleProp)
134
+ );
135
+ let _classDescription = $derived(
136
+ unstyled
137
+ ? classDescriptionProp
138
+ : twMerge("stuic-timeline-description", classDescriptionProp)
139
+ );
140
+ let _classFooter = $derived(
141
+ unstyled ? classFooterProp : twMerge("stuic-timeline-footer", classFooterProp)
142
+ );
143
+
144
+ function markerKind(item: TimelineItem): TimelineMarkerKind {
145
+ if (renderMarker) return "custom";
146
+ if (item.icon) return "icon";
147
+ return "dot";
148
+ }
149
+
150
+ function timeLabel(item: TimelineItem): THC | undefined {
151
+ if (item.time !== undefined && item.time !== null && item.time !== "")
152
+ return item.time;
153
+ if (item.datetime !== undefined && formatTime) return formatTime(item.datetime, item);
154
+ return undefined;
155
+ }
156
+
157
+ function datetimeAttr(item: TimelineItem): string | undefined {
158
+ if (item.datetime === undefined) return undefined;
159
+ return item.datetime instanceof Date ? item.datetime.toISOString() : item.datetime;
160
+ }
161
+ </script>
162
+
163
+ {#snippet timeEl(item: TimelineItem, label: THC)}
164
+ {@const datetime = datetimeAttr(item)}
165
+ <!-- <time> only when it can carry a machine-readable value -->
166
+ <svelte:element this={datetime ? "time" : "span"} class={_classTime} {datetime}>
167
+ <Thc thc={label} />
168
+ </svelte:element>
169
+ {/snippet}
170
+
171
+ {#if items.length}
172
+ <!-- svelte-ignore a11y_no_redundant_roles -->
173
+ <ol
174
+ bind:this={el}
175
+ class={_class}
176
+ role="list"
177
+ data-align={!unstyled ? align : undefined}
178
+ data-time-position={!unstyled ? timePosition : undefined}
179
+ {...rest}
180
+ >
181
+ {#each items as item, index (index)}
182
+ {@const label = timeLabel(item)}
183
+ {@const kind = markerKind(item)}
184
+ <li
185
+ class={_classItem}
186
+ data-intent={!unstyled && item.intent ? item.intent : undefined}
187
+ >
188
+ {#if timePosition === "opposite"}
189
+ <div class={unstyled ? undefined : "stuic-timeline-opposite"}>
190
+ {#if label !== undefined}
191
+ {@render timeEl(item, label)}
192
+ {/if}
193
+ </div>
194
+ {/if}
195
+
196
+ <div class={unstyled ? undefined : "stuic-timeline-rail"}>
197
+ <span
198
+ class={_classMarker}
199
+ data-marker={!unstyled ? kind : undefined}
200
+ aria-hidden="true"
201
+ >
202
+ {#if renderMarker}
203
+ {@render renderMarker({ item, index })}
204
+ {:else if item.icon}
205
+ <Thc thc={item.icon} />
206
+ {/if}
207
+ </span>
208
+ </div>
209
+
210
+ <div class={_classContent}>
211
+ {#if renderItem}
212
+ {@render renderItem({ item, index })}
213
+ {:else}
214
+ {#if timePosition === "inline" && label !== undefined}
215
+ {@render timeEl(item, label)}
216
+ {/if}
217
+ {#if item.title}
218
+ <div class={_classTitle}>
219
+ {#if item.href}
220
+ <a
221
+ href={item.href}
222
+ class={unstyled ? undefined : "stuic-timeline-link"}
223
+ >
224
+ <Thc thc={item.title} />
225
+ </a>
226
+ {:else}
227
+ <Thc thc={item.title} />
228
+ {/if}
229
+ </div>
230
+ {/if}
231
+ {#if item.description}
232
+ <div class={_classDescription}>
233
+ <Thc thc={item.description} />
234
+ </div>
235
+ {/if}
236
+ {#if renderFooter}
237
+ <div class={_classFooter}>
238
+ {@render renderFooter({ item, index })}
239
+ </div>
240
+ {/if}
241
+ {/if}
242
+ </div>
243
+ </li>
244
+ {/each}
245
+ </ol>
246
+ {/if}
@@ -0,0 +1,87 @@
1
+ import type { HTMLOlAttributes } from "svelte/elements";
2
+ import type { Snippet } from "svelte";
3
+ import type { THC } from "../Thc/Thc.svelte";
4
+ import type { IntentColorKey } from "../../utils/design-tokens.js";
5
+ /** Which side of the rail the content sits on */
6
+ export type TimelineAlign = "start" | "alternate";
7
+ /** Where the time label renders */
8
+ export type TimelineTimePosition = "inline" | "opposite";
9
+ /** What the marker renders as (`data-marker` on the marker element) */
10
+ export type TimelineMarkerKind = "dot" | "icon" | "custom";
11
+ export interface TimelineItem {
12
+ /** Primary line (the event) */
13
+ title?: THC;
14
+ /** Secondary text under the title */
15
+ description?: THC;
16
+ /**
17
+ * Time label, preformatted ("2 hours ago", "Sep 1, 14:32"). When omitted and
18
+ * `datetime` is set, the component's `formatTime` (if any) produces it.
19
+ */
20
+ time?: THC;
21
+ /**
22
+ * Machine-readable timestamp — renders the label as `<time datetime="…">`
23
+ * (a `Date` is serialized to ISO 8601). Never displayed on its own.
24
+ */
25
+ datetime?: string | Date;
26
+ /**
27
+ * Marker content (typically `{ html: iconCheck() }`). Its presence switches the
28
+ * marker from the small dot to the icon bubble.
29
+ */
30
+ icon?: THC;
31
+ /** Semantic marker color (dot fill, or the bubble's soft tint) */
32
+ intent?: IntentColorKey;
33
+ /** When set, the title renders as a link */
34
+ href?: string;
35
+ }
36
+ export interface TimelineSnippetArg {
37
+ item: TimelineItem;
38
+ index: number;
39
+ }
40
+ export interface Props extends Omit<HTMLOlAttributes, "children"> {
41
+ /** The events, in the order they should appear (sort them yourself) */
42
+ items: TimelineItem[];
43
+ /**
44
+ * `"start"` (default): rail on the start side, content after it.
45
+ * `"alternate"`: centered rail, content alternating sides (history pages).
46
+ */
47
+ align?: TimelineAlign;
48
+ /**
49
+ * `"inline"` (default): the time label above the title, inside the content.
50
+ * `"opposite"`: its own column on the other side of the rail (audit-log look).
51
+ */
52
+ timePosition?: TimelineTimePosition;
53
+ /**
54
+ * Fallback formatter for items that have `datetime` but no `time`. Return
55
+ * value is THC, so a plain string is fine.
56
+ */
57
+ formatTime?: (datetime: string | Date, item: TimelineItem) => THC;
58
+ /** Override the marker content entirely (avatars, badges…) */
59
+ renderMarker?: Snippet<[TimelineSnippetArg]>;
60
+ /** Override the whole content cell (time, title, description, footer) */
61
+ renderItem?: Snippet<[TimelineSnippetArg]>;
62
+ /** Per-item footer area below the description (actions, attachments…) */
63
+ renderFooter?: Snippet<[TimelineSnippetArg]>;
64
+ /** Skip all default styling */
65
+ unstyled?: boolean;
66
+ /** Additional CSS classes */
67
+ class?: string;
68
+ /** Class for every item (`li`) */
69
+ classItem?: string;
70
+ /** Class for the marker */
71
+ classMarker?: string;
72
+ /** Class for the content cell */
73
+ classContent?: string;
74
+ /** Class for the time label (inline or opposite) */
75
+ classTime?: string;
76
+ /** Class for the title */
77
+ classTitle?: string;
78
+ /** Class for the description */
79
+ classDescription?: string;
80
+ /** Class for the footer area */
81
+ classFooter?: string;
82
+ /** Bindable element reference */
83
+ el?: HTMLOListElement;
84
+ }
85
+ declare const Timeline: import("svelte").Component<Props, {}, "el">;
86
+ type Timeline = ReturnType<typeof Timeline>;
87
+ export default Timeline;
@@ -0,0 +1,311 @@
1
+ /* ============================================================================
2
+ TIMELINE COMPONENT TOKENS
3
+ Override globally: :root { --stuic-timeline-marker-size: 1rem; }
4
+ Override locally: <Timeline style="--stuic-timeline-gap-vertical: 1rem;">
5
+ ============================================================================ */
6
+
7
+ /* prettier-ignore */
8
+ :root {
9
+ /* Layout */
10
+ --stuic-timeline-gap: 1rem; /* column gap: opposite ↔ rail ↔ content */
11
+ --stuic-timeline-gap-vertical: 1.5rem; /* distance between items */
12
+ --stuic-timeline-line-height: 1.5rem; /* first-line box the marker centers on */
13
+
14
+ /* Connector (the vertical rail line) */
15
+ --stuic-timeline-connector-thickness: 2px;
16
+ --stuic-timeline-connector-bg: var(--stuic-color-border);
17
+
18
+ /* Marker: dot (no icon) */
19
+ --stuic-timeline-marker-size: 0.75rem;
20
+ --stuic-timeline-marker-bg: var(--stuic-color-muted-foreground);
21
+
22
+ /* Marker: icon bubble (item.icon) and custom (renderMarker) */
23
+ --stuic-timeline-marker-size-icon: 2rem;
24
+ --stuic-timeline-marker-bg-icon: var(--stuic-color-muted);
25
+ --stuic-timeline-marker-text-icon: var(--stuic-color-muted-foreground);
26
+ --stuic-timeline-marker-icon-size: 1rem; /* svg inside the bubble */
27
+
28
+ /* Marker ring: separates the marker from the line running behind it */
29
+ --stuic-timeline-marker-ring-width: 2px;
30
+ --stuic-timeline-marker-ring-color: var(--stuic-color-background);
31
+
32
+ /* Time */
33
+ --stuic-timeline-time-font-size: var(--text-sm);
34
+ --stuic-timeline-time-text: var(--stuic-color-muted-foreground);
35
+
36
+ /* Title */
37
+ --stuic-timeline-title-font-size: var(--text-base);
38
+ --stuic-timeline-title-font-weight: var(--font-weight-medium);
39
+ --stuic-timeline-title-text: var(--stuic-color-foreground);
40
+
41
+ /* Description */
42
+ --stuic-timeline-description-font-size: var(--text-sm);
43
+ --stuic-timeline-description-text: var(--stuic-color-muted-foreground);
44
+ --stuic-timeline-description-margin-top: 0.125rem;
45
+
46
+ /* Footer */
47
+ --stuic-timeline-footer-gap: 0.5rem;
48
+ --stuic-timeline-footer-margin-top: 0.5rem;
49
+ }
50
+
51
+ @layer components {
52
+ /* ============================================================================
53
+ BASE — the list is a grid; every item is a subgrid row, so the rail (and
54
+ the opposite time column) line up across items regardless of content.
55
+ ============================================================================ */
56
+
57
+ .stuic-timeline {
58
+ display: grid;
59
+ column-gap: var(--stuic-timeline-gap);
60
+ list-style: none;
61
+ margin: 0;
62
+ padding: 0;
63
+ }
64
+
65
+ .stuic-timeline[data-align="start"][data-time-position="inline"] {
66
+ grid-template-columns: auto minmax(0, 1fr);
67
+ }
68
+
69
+ .stuic-timeline[data-align="start"][data-time-position="opposite"] {
70
+ grid-template-columns: auto auto minmax(0, 1fr);
71
+ }
72
+
73
+ .stuic-timeline[data-align="alternate"] {
74
+ grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr);
75
+ }
76
+
77
+ .stuic-timeline-item {
78
+ display: grid;
79
+ grid-column: 1 / -1;
80
+ grid-template-columns: subgrid;
81
+ padding-bottom: var(--stuic-timeline-gap-vertical);
82
+ }
83
+
84
+ .stuic-timeline-item:last-child {
85
+ padding-bottom: 0;
86
+ }
87
+
88
+ /* every cell sits on the item's single row; columns are assigned below */
89
+ .stuic-timeline-opposite,
90
+ .stuic-timeline-rail,
91
+ .stuic-timeline-content {
92
+ grid-row: 1;
93
+ min-width: 0;
94
+ }
95
+
96
+ /* ============================================================================
97
+ COLUMN PLACEMENT
98
+ ============================================================================ */
99
+
100
+ /* start + inline: rail | content */
101
+ .stuic-timeline[data-align="start"][data-time-position="inline"] .stuic-timeline-rail {
102
+ grid-column: 1;
103
+ }
104
+ .stuic-timeline[data-align="start"][data-time-position="inline"]
105
+ .stuic-timeline-content {
106
+ grid-column: 2;
107
+ }
108
+
109
+ /* start + opposite: time | rail | content */
110
+ .stuic-timeline[data-align="start"][data-time-position="opposite"]
111
+ .stuic-timeline-opposite {
112
+ grid-column: 1;
113
+ text-align: end;
114
+ }
115
+ .stuic-timeline[data-align="start"][data-time-position="opposite"]
116
+ .stuic-timeline-rail {
117
+ grid-column: 2;
118
+ }
119
+ .stuic-timeline[data-align="start"][data-time-position="opposite"]
120
+ .stuic-timeline-content {
121
+ grid-column: 3;
122
+ }
123
+
124
+ /* alternate: centered rail; odd items → content end side, even → start side */
125
+ .stuic-timeline[data-align="alternate"] .stuic-timeline-rail {
126
+ grid-column: 2;
127
+ }
128
+ .stuic-timeline[data-align="alternate"]
129
+ .stuic-timeline-item:nth-child(odd)
130
+ .stuic-timeline-content {
131
+ grid-column: 3;
132
+ }
133
+ .stuic-timeline[data-align="alternate"]
134
+ .stuic-timeline-item:nth-child(odd)
135
+ .stuic-timeline-opposite {
136
+ grid-column: 1;
137
+ text-align: end;
138
+ }
139
+ .stuic-timeline[data-align="alternate"]
140
+ .stuic-timeline-item:nth-child(even)
141
+ .stuic-timeline-content {
142
+ grid-column: 1;
143
+ text-align: end;
144
+ }
145
+ .stuic-timeline[data-align="alternate"]
146
+ .stuic-timeline-item:nth-child(even)
147
+ .stuic-timeline-opposite {
148
+ grid-column: 3;
149
+ }
150
+ .stuic-timeline[data-align="alternate"]
151
+ .stuic-timeline-item:nth-child(even)
152
+ .stuic-timeline-footer {
153
+ justify-content: flex-end;
154
+ }
155
+
156
+ /* ============================================================================
157
+ RAIL + CONNECTOR
158
+ The line runs behind the marker in two halves (top → marker center, marker
159
+ center → bottom) so no item needs to know its neighbour's marker size. The
160
+ marker's center is always at half the first-line height.
161
+ ============================================================================ */
162
+
163
+ .stuic-timeline-rail {
164
+ position: relative;
165
+ display: flex;
166
+ flex-direction: column;
167
+ align-items: center;
168
+ }
169
+
170
+ .stuic-timeline-rail::before,
171
+ .stuic-timeline-rail::after {
172
+ content: "";
173
+ position: absolute;
174
+ left: 50%;
175
+ width: var(--stuic-timeline-connector-thickness);
176
+ transform: translateX(-50%);
177
+ background: var(--stuic-timeline-connector-bg);
178
+ }
179
+
180
+ .stuic-timeline-rail::before {
181
+ top: 0;
182
+ height: calc(var(--stuic-timeline-line-height) / 2);
183
+ }
184
+
185
+ /* the item's bottom padding (gap-vertical) lies outside the grid row, so reach
186
+ through it — the next item's ::before picks the line up at its top edge */
187
+ .stuic-timeline-rail::after {
188
+ top: calc(var(--stuic-timeline-line-height) / 2);
189
+ bottom: calc(-1 * var(--stuic-timeline-gap-vertical));
190
+ }
191
+
192
+ .stuic-timeline-item:first-child .stuic-timeline-rail::before,
193
+ .stuic-timeline-item:last-child .stuic-timeline-rail::after {
194
+ display: none;
195
+ }
196
+
197
+ /* ============================================================================
198
+ MARKER
199
+ ============================================================================ */
200
+
201
+ .stuic-timeline-marker {
202
+ position: relative;
203
+ z-index: 1;
204
+ display: inline-flex;
205
+ align-items: center;
206
+ justify-content: center;
207
+ flex-shrink: 0;
208
+ box-sizing: border-box;
209
+ width: var(--_marker-size);
210
+ height: var(--_marker-size);
211
+ /* center on the first line of the content (may go negative for big markers) */
212
+ margin-top: calc((var(--stuic-timeline-line-height) - var(--_marker-size)) / 2);
213
+ border-radius: var(--stuic-timeline-marker-radius, calc(infinity * 1px));
214
+ box-shadow: 0 0 0 var(--stuic-timeline-marker-ring-width)
215
+ var(--stuic-timeline-marker-ring-color);
216
+ }
217
+
218
+ .stuic-timeline-marker[data-marker="dot"] {
219
+ --_marker-size: var(--stuic-timeline-marker-size);
220
+ background: var(--stuic-timeline-marker-bg);
221
+ }
222
+
223
+ .stuic-timeline-marker[data-marker="icon"] {
224
+ --_marker-size: var(--stuic-timeline-marker-size-icon);
225
+ background: var(--stuic-timeline-marker-bg-icon);
226
+ color: var(--stuic-timeline-marker-text-icon);
227
+ }
228
+
229
+ .stuic-timeline-marker[data-marker="icon"] svg {
230
+ display: block;
231
+ width: var(--stuic-timeline-marker-icon-size);
232
+ height: var(--stuic-timeline-marker-icon-size);
233
+ }
234
+
235
+ /* custom (renderMarker): only the box — the snippet brings its own look */
236
+ .stuic-timeline-marker[data-marker="custom"] {
237
+ --_marker-size: var(--stuic-timeline-marker-size-icon);
238
+ }
239
+
240
+ /* ============================================================================
241
+ INTENT — dot fills with the color, the bubble takes a soft tint
242
+ ============================================================================ */
243
+
244
+ .stuic-timeline-item[data-intent="primary"] {
245
+ --_intent: var(--stuic-color-primary);
246
+ }
247
+ .stuic-timeline-item[data-intent="accent"] {
248
+ --_intent: var(--stuic-color-accent);
249
+ }
250
+ .stuic-timeline-item[data-intent="destructive"] {
251
+ --_intent: var(--stuic-color-destructive);
252
+ }
253
+ .stuic-timeline-item[data-intent="warning"] {
254
+ --_intent: var(--stuic-color-warning);
255
+ }
256
+ .stuic-timeline-item[data-intent="success"] {
257
+ --_intent: var(--stuic-color-success);
258
+ }
259
+
260
+ .stuic-timeline-item[data-intent] .stuic-timeline-marker[data-marker="dot"] {
261
+ background: var(--_intent);
262
+ }
263
+
264
+ .stuic-timeline-item[data-intent] .stuic-timeline-marker[data-marker="icon"] {
265
+ background: color-mix(in srgb, var(--_intent) 15%, var(--stuic-color-background));
266
+ color: var(--_intent);
267
+ }
268
+
269
+ /* ============================================================================
270
+ CONTENT: time, title, description, footer
271
+ ============================================================================ */
272
+
273
+ .stuic-timeline-time {
274
+ display: block;
275
+ font-size: var(--stuic-timeline-time-font-size);
276
+ line-height: var(--stuic-timeline-line-height);
277
+ color: var(--stuic-timeline-time-text);
278
+ }
279
+
280
+ .stuic-timeline-title {
281
+ font-size: var(--stuic-timeline-title-font-size);
282
+ font-weight: var(--stuic-timeline-title-font-weight);
283
+ line-height: var(--stuic-timeline-line-height);
284
+ color: var(--stuic-timeline-title-text);
285
+ overflow-wrap: anywhere;
286
+ }
287
+
288
+ .stuic-timeline-link {
289
+ color: inherit;
290
+ text-decoration: none;
291
+ }
292
+
293
+ .stuic-timeline-link:hover {
294
+ text-decoration: underline;
295
+ }
296
+
297
+ .stuic-timeline-description {
298
+ margin-top: var(--stuic-timeline-description-margin-top);
299
+ font-size: var(--stuic-timeline-description-font-size);
300
+ color: var(--stuic-timeline-description-text);
301
+ overflow-wrap: anywhere;
302
+ }
303
+
304
+ .stuic-timeline-footer {
305
+ display: flex;
306
+ flex-wrap: wrap;
307
+ align-items: center;
308
+ gap: var(--stuic-timeline-footer-gap);
309
+ margin-top: var(--stuic-timeline-footer-margin-top);
310
+ }
311
+ }
@@ -0,0 +1 @@
1
+ export { default as Timeline, type Props as TimelineProps, type TimelineItem, type TimelineAlign, type TimelineTimePosition, type TimelineMarkerKind, type TimelineSnippetArg, } from "./Timeline.svelte";
@@ -0,0 +1 @@
1
+ export { default as Timeline, } from "./Timeline.svelte";
package/dist/index.css CHANGED
@@ -112,6 +112,7 @@ In practice:
112
112
  @import "./components/Switch/index.css";
113
113
  @import "./components/TabbedMenu/index.css";
114
114
  @import "./components/ThemePreview/index.css";
115
+ @import "./components/Timeline/index.css";
115
116
  @import "./components/Tree/index.css";
116
117
  @import "./components/TwCheck/index.css";
117
118
  @import "./components/UserAvatarMenu/index.css";
package/dist/index.d.ts CHANGED
@@ -84,6 +84,7 @@ export * from "./components/Switch/index.js";
84
84
  export * from "./components/TabbedMenu/index.js";
85
85
  export * from "./components/Thc/index.js";
86
86
  export * from "./components/ThemePreview/index.js";
87
+ export * from "./components/Timeline/index.js";
87
88
  export * from "./components/Tree/index.js";
88
89
  export * from "./components/TwCheck/index.js";
89
90
  export * from "./components/TypeaheadInput/index.js";
package/dist/index.js CHANGED
@@ -90,6 +90,7 @@ export * from "./components/Switch/index.js";
90
90
  export * from "./components/TabbedMenu/index.js";
91
91
  export * from "./components/Thc/index.js";
92
92
  export * from "./components/ThemePreview/index.js";
93
+ export * from "./components/Timeline/index.js";
93
94
  // NOTE: TrendChart is deliberately NOT exported here. It statically imports the
94
95
  // optional @marianmeres/trend-chart peer, which would then be pulled into the
95
96
  // root entry graph of every consumer. It ships as the `@marianmeres/stuic/trend-chart`