@marianmeres/stuic 3.167.0 → 3.168.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.
- package/AGENTS.md +6 -6
- package/dist/attachments/index.d.ts +1 -0
- package/dist/attachments/index.js +1 -0
- package/dist/attachments/long-press.d.ts +43 -0
- package/dist/attachments/long-press.js +107 -0
- package/dist/components/Breadcrumbs/Breadcrumbs.svelte +198 -0
- package/dist/components/Breadcrumbs/Breadcrumbs.svelte.d.ts +60 -0
- package/dist/components/Breadcrumbs/README.md +174 -0
- package/dist/components/Breadcrumbs/i18n-sk.d.ts +17 -0
- package/dist/components/Breadcrumbs/i18n-sk.js +19 -0
- package/dist/components/Breadcrumbs/i18n.d.ts +31 -0
- package/dist/components/Breadcrumbs/i18n.js +40 -0
- package/dist/components/Breadcrumbs/index.css +84 -0
- package/dist/components/Breadcrumbs/index.d.ts +4 -0
- package/dist/components/Breadcrumbs/index.js +4 -0
- package/dist/components/Breadcrumbs/json-ld.d.ts +58 -0
- package/dist/components/Breadcrumbs/json-ld.js +56 -0
- package/dist/components/Collapsible/Collapsible.svelte +84 -15
- package/dist/components/Collapsible/Collapsible.svelte.d.ts +29 -2
- package/dist/components/Collapsible/README.md +82 -23
- package/dist/components/Collapsible/index.css +38 -0
- package/dist/components/Collapsible/index.d.ts +1 -1
- package/dist/components/ContextMenu/ContextMenu.svelte +302 -0
- package/dist/components/ContextMenu/ContextMenu.svelte.d.ts +94 -0
- package/dist/components/ContextMenu/README.md +159 -0
- package/dist/components/ContextMenu/i18n-sk.d.ts +17 -0
- package/dist/components/ContextMenu/i18n-sk.js +18 -0
- package/dist/components/ContextMenu/i18n.d.ts +30 -0
- package/dist/components/ContextMenu/i18n.js +38 -0
- package/dist/components/ContextMenu/index.css +26 -0
- package/dist/components/ContextMenu/index.d.ts +3 -0
- package/dist/components/ContextMenu/index.js +3 -0
- package/dist/components/CopyButton/CopyButton.svelte +278 -0
- package/dist/components/CopyButton/CopyButton.svelte.d.ts +76 -0
- package/dist/components/CopyButton/README.md +241 -0
- package/dist/components/CopyButton/i18n-sk.d.ts +17 -0
- package/dist/components/CopyButton/i18n-sk.js +20 -0
- package/dist/components/CopyButton/i18n.d.ts +35 -0
- package/dist/components/CopyButton/i18n.js +43 -0
- package/dist/components/CopyButton/index.css +67 -0
- package/dist/components/CopyButton/index.d.ts +3 -0
- package/dist/components/CopyButton/index.js +3 -0
- package/dist/components/DataTable/DataTable.svelte +41 -34
- package/dist/components/DataTable/README.md +45 -0
- package/dist/components/DataTable/i18n-sk.js +1 -0
- package/dist/components/DataTable/i18n.d.ts +1 -0
- package/dist/components/DataTable/i18n.js +3 -0
- package/dist/components/DataTable/index.css +41 -3
- package/dist/components/EmptyState/EmptyState.svelte +121 -0
- package/dist/components/EmptyState/EmptyState.svelte.d.ts +40 -0
- package/dist/components/EmptyState/README.md +188 -0
- package/dist/components/EmptyState/index.css +154 -0
- package/dist/components/EmptyState/index.d.ts +1 -0
- package/dist/components/EmptyState/index.js +1 -0
- package/dist/components/Pagination/Pagination.svelte +250 -0
- package/dist/components/Pagination/Pagination.svelte.d.ts +69 -0
- package/dist/components/Pagination/README.md +152 -0
- package/dist/components/Pagination/i18n-sk.d.ts +17 -0
- package/dist/components/Pagination/i18n-sk.js +24 -0
- package/dist/components/Pagination/i18n.d.ts +41 -0
- package/dist/components/Pagination/i18n.js +49 -0
- package/dist/components/Pagination/index.css +50 -0
- package/dist/components/Pagination/index.d.ts +4 -0
- package/dist/components/Pagination/index.js +4 -0
- package/dist/components/Pagination/pagination-range.d.ts +21 -0
- package/dist/components/Pagination/pagination-range.js +41 -0
- package/dist/components/Stat/README.md +157 -0
- package/dist/components/Stat/Stat.svelte +226 -0
- package/dist/components/Stat/Stat.svelte.d.ts +54 -0
- package/dist/components/Stat/index.css +217 -0
- package/dist/components/Stat/index.d.ts +1 -0
- package/dist/components/Stat/index.js +1 -0
- package/dist/components/Stepper/README.md +181 -0
- package/dist/components/Stepper/Stepper.svelte +240 -0
- package/dist/components/Stepper/Stepper.svelte.d.ts +86 -0
- package/dist/components/Stepper/i18n-sk.d.ts +17 -0
- package/dist/components/Stepper/i18n-sk.js +21 -0
- package/dist/components/Stepper/i18n.d.ts +35 -0
- package/dist/components/Stepper/i18n.js +43 -0
- package/dist/components/Stepper/index.css +302 -0
- package/dist/components/Stepper/index.d.ts +3 -0
- package/dist/components/Stepper/index.js +3 -0
- package/dist/components/TrendChart/README.md +123 -0
- package/dist/components/TrendChart/TrendChart.svelte +114 -0
- package/dist/components/TrendChart/TrendChart.svelte.d.ts +36 -0
- package/dist/components/TrendChart/index.css +51 -0
- package/dist/components/TrendChart/index.d.ts +1 -0
- package/dist/components/TrendChart/index.js +1 -0
- package/dist/icons/index.d.ts +4 -0
- package/dist/icons/index.js +4 -0
- package/dist/index.css +7 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.js +12 -0
- package/dist/utils/copy-to-clipboard.d.ts +43 -0
- package/dist/utils/copy-to-clipboard.js +102 -0
- package/dist/utils/index.d.ts +1 -0
- package/dist/utils/index.js +1 -0
- package/docs/architecture.md +1 -1
- package/docs/domains/attachments.md +41 -4
- package/docs/domains/components.md +280 -13
- package/docs/domains/utils.md +8 -6
- package/docs/maybe-todo.md +111 -0
- package/package.json +11 -1
|
@@ -0,0 +1,302 @@
|
|
|
1
|
+
/* ============================================================================
|
|
2
|
+
STEPPER COMPONENT TOKENS
|
|
3
|
+
Override globally: :root { --stuic-stepper-indicator-size: 2.5rem; }
|
|
4
|
+
Override locally: <Stepper style="--stuic-stepper-connector-thickness: 4px;">
|
|
5
|
+
============================================================================ */
|
|
6
|
+
|
|
7
|
+
/* prettier-ignore */
|
|
8
|
+
:root {
|
|
9
|
+
/* Layout */
|
|
10
|
+
--stuic-stepper-gap: 0.75rem; /* indicator↔label + step↔connector */
|
|
11
|
+
--stuic-stepper-gap-vertical: 1.75rem; /* vertical: distance between steps */
|
|
12
|
+
--stuic-stepper-connector-min-length: 1.5rem; /* horizontal: shortest connector */
|
|
13
|
+
|
|
14
|
+
/* Indicator bubble */
|
|
15
|
+
--stuic-stepper-indicator-size: 2rem;
|
|
16
|
+
--stuic-stepper-indicator-border-width: 2px;
|
|
17
|
+
--stuic-stepper-indicator-font-size: var(--text-sm);
|
|
18
|
+
--stuic-stepper-indicator-font-weight: var(--font-weight-medium);
|
|
19
|
+
--stuic-stepper-indicator-bg: transparent;
|
|
20
|
+
--stuic-stepper-indicator-text: var(--stuic-color-muted-foreground);
|
|
21
|
+
--stuic-stepper-indicator-border: var(--stuic-color-border);
|
|
22
|
+
--stuic-stepper-indicator-bg-current: transparent;
|
|
23
|
+
--stuic-stepper-indicator-text-current: var(--stuic-color-primary);
|
|
24
|
+
--stuic-stepper-indicator-border-current: var(--stuic-color-primary);
|
|
25
|
+
--stuic-stepper-indicator-bg-completed: var(--stuic-color-primary);
|
|
26
|
+
--stuic-stepper-indicator-text-completed: var(--stuic-color-primary-foreground);
|
|
27
|
+
--stuic-stepper-indicator-border-completed: var(--stuic-color-primary);
|
|
28
|
+
--stuic-stepper-indicator-bg-error: var(--stuic-color-destructive);
|
|
29
|
+
--stuic-stepper-indicator-text-error: var(--stuic-color-destructive-foreground);
|
|
30
|
+
--stuic-stepper-indicator-border-error: var(--stuic-color-destructive);
|
|
31
|
+
|
|
32
|
+
/* Label */
|
|
33
|
+
--stuic-stepper-label-font-size: var(--text-base);
|
|
34
|
+
--stuic-stepper-label-font-weight: var(--font-weight-medium);
|
|
35
|
+
--stuic-stepper-label-text: var(--stuic-color-muted-foreground);
|
|
36
|
+
--stuic-stepper-label-text-current: var(--stuic-color-foreground);
|
|
37
|
+
--stuic-stepper-label-text-completed: var(--stuic-color-foreground);
|
|
38
|
+
--stuic-stepper-label-text-error: var(--stuic-color-destructive);
|
|
39
|
+
|
|
40
|
+
/* Description */
|
|
41
|
+
--stuic-stepper-description-font-size: var(--text-sm);
|
|
42
|
+
--stuic-stepper-description-text: var(--stuic-color-muted-foreground);
|
|
43
|
+
|
|
44
|
+
/* Connector line */
|
|
45
|
+
--stuic-stepper-connector-thickness: 2px;
|
|
46
|
+
--stuic-stepper-connector-bg: var(--stuic-color-border);
|
|
47
|
+
--stuic-stepper-connector-bg-completed: var(--stuic-color-primary);
|
|
48
|
+
|
|
49
|
+
/* Focus ring */
|
|
50
|
+
--stuic-stepper-ring-width: 3px;
|
|
51
|
+
--stuic-stepper-ring-color: var(--stuic-color-ring);
|
|
52
|
+
|
|
53
|
+
/* Disabled */
|
|
54
|
+
--stuic-stepper-opacity-disabled: 0.5;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
@layer components {
|
|
58
|
+
/* ============================================================================
|
|
59
|
+
BASE
|
|
60
|
+
============================================================================ */
|
|
61
|
+
|
|
62
|
+
.stuic-stepper[data-disabled] {
|
|
63
|
+
opacity: var(--stuic-stepper-opacity-disabled);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
.stuic-stepper-list {
|
|
67
|
+
display: flex;
|
|
68
|
+
list-style: none;
|
|
69
|
+
margin: 0;
|
|
70
|
+
padding: 0;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
.stuic-stepper-item[data-disabled] {
|
|
74
|
+
opacity: var(--stuic-stepper-opacity-disabled);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/* ============================================================================
|
|
78
|
+
TRIGGER (the step content — <button> when interactive, <div> otherwise)
|
|
79
|
+
============================================================================ */
|
|
80
|
+
|
|
81
|
+
.stuic-stepper-trigger {
|
|
82
|
+
display: flex;
|
|
83
|
+
align-items: center;
|
|
84
|
+
gap: var(--stuic-stepper-gap);
|
|
85
|
+
text-align: start;
|
|
86
|
+
min-width: 0;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
button.stuic-stepper-trigger {
|
|
90
|
+
font: inherit;
|
|
91
|
+
color: inherit;
|
|
92
|
+
background: none;
|
|
93
|
+
border: 0;
|
|
94
|
+
padding: 0;
|
|
95
|
+
cursor: pointer;
|
|
96
|
+
-webkit-tap-highlight-color: transparent;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
button.stuic-stepper-trigger:disabled {
|
|
100
|
+
cursor: default;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
button.stuic-stepper-trigger:focus-visible {
|
|
104
|
+
outline: var(--stuic-stepper-ring-width) solid var(--stuic-stepper-ring-color);
|
|
105
|
+
outline-offset: 2px;
|
|
106
|
+
border-radius: var(--stuic-stepper-radius, var(--stuic-radius));
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/* clickable affordance: label picks up the emphasized color */
|
|
110
|
+
button.stuic-stepper-trigger:not(:disabled):hover .stuic-stepper-label {
|
|
111
|
+
color: var(--stuic-stepper-label-text-current);
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/* ============================================================================
|
|
115
|
+
INDICATOR
|
|
116
|
+
============================================================================ */
|
|
117
|
+
|
|
118
|
+
.stuic-stepper-indicator {
|
|
119
|
+
display: inline-flex;
|
|
120
|
+
align-items: center;
|
|
121
|
+
justify-content: center;
|
|
122
|
+
flex-shrink: 0;
|
|
123
|
+
width: var(--stuic-stepper-indicator-size);
|
|
124
|
+
height: var(--stuic-stepper-indicator-size);
|
|
125
|
+
border-radius: var(--stuic-stepper-indicator-radius, calc(infinity * 1px));
|
|
126
|
+
border: var(--stuic-stepper-indicator-border-width) solid
|
|
127
|
+
var(--stuic-stepper-indicator-border);
|
|
128
|
+
background: var(--stuic-stepper-indicator-bg);
|
|
129
|
+
color: var(--stuic-stepper-indicator-text);
|
|
130
|
+
font-size: var(--stuic-stepper-indicator-font-size);
|
|
131
|
+
font-weight: var(--stuic-stepper-indicator-font-weight);
|
|
132
|
+
transition:
|
|
133
|
+
background var(--stuic-stepper-transition, var(--stuic-transition)),
|
|
134
|
+
border-color var(--stuic-stepper-transition, var(--stuic-transition)),
|
|
135
|
+
color var(--stuic-stepper-transition, var(--stuic-transition));
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
.stuic-stepper-indicator svg {
|
|
139
|
+
display: block;
|
|
140
|
+
width: 1.25em;
|
|
141
|
+
height: 1.25em;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
.stuic-stepper-item[data-state="current"] .stuic-stepper-indicator {
|
|
145
|
+
background: var(--stuic-stepper-indicator-bg-current);
|
|
146
|
+
border-color: var(--stuic-stepper-indicator-border-current);
|
|
147
|
+
color: var(--stuic-stepper-indicator-text-current);
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
.stuic-stepper-item[data-state="completed"] .stuic-stepper-indicator {
|
|
151
|
+
background: var(--stuic-stepper-indicator-bg-completed);
|
|
152
|
+
border-color: var(--stuic-stepper-indicator-border-completed);
|
|
153
|
+
color: var(--stuic-stepper-indicator-text-completed);
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
/* error wins over any state */
|
|
157
|
+
.stuic-stepper-item[data-error] .stuic-stepper-indicator {
|
|
158
|
+
background: var(--stuic-stepper-indicator-bg-error);
|
|
159
|
+
border-color: var(--stuic-stepper-indicator-border-error);
|
|
160
|
+
color: var(--stuic-stepper-indicator-text-error);
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
/* ============================================================================
|
|
164
|
+
TEXT (label + description)
|
|
165
|
+
============================================================================ */
|
|
166
|
+
|
|
167
|
+
.stuic-stepper-text {
|
|
168
|
+
display: flex;
|
|
169
|
+
flex-direction: column;
|
|
170
|
+
gap: 0.125rem;
|
|
171
|
+
min-width: 0;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
.stuic-stepper-label {
|
|
175
|
+
font-size: var(--stuic-stepper-label-font-size);
|
|
176
|
+
font-weight: var(--stuic-stepper-label-font-weight);
|
|
177
|
+
color: var(--stuic-stepper-label-text);
|
|
178
|
+
transition: color var(--stuic-stepper-transition, var(--stuic-transition));
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
.stuic-stepper-item[data-state="current"] .stuic-stepper-label {
|
|
182
|
+
color: var(--stuic-stepper-label-text-current);
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
.stuic-stepper-item[data-state="completed"] .stuic-stepper-label {
|
|
186
|
+
color: var(--stuic-stepper-label-text-completed);
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
.stuic-stepper-item[data-error] .stuic-stepper-label {
|
|
190
|
+
color: var(--stuic-stepper-label-text-error);
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
.stuic-stepper-description {
|
|
194
|
+
font-size: var(--stuic-stepper-description-font-size);
|
|
195
|
+
color: var(--stuic-stepper-description-text);
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
/* ============================================================================
|
|
199
|
+
CONNECTOR
|
|
200
|
+
============================================================================ */
|
|
201
|
+
|
|
202
|
+
.stuic-stepper-connector {
|
|
203
|
+
background: var(--stuic-stepper-connector-bg);
|
|
204
|
+
transition: background var(--stuic-stepper-transition, var(--stuic-transition));
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
.stuic-stepper-connector[data-state="completed"] {
|
|
208
|
+
background: var(--stuic-stepper-connector-bg-completed);
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
/* ============================================================================
|
|
212
|
+
HORIZONTAL (labels at the end — default)
|
|
213
|
+
============================================================================ */
|
|
214
|
+
|
|
215
|
+
.stuic-stepper[data-orientation="horizontal"] .stuic-stepper-list {
|
|
216
|
+
flex-direction: row;
|
|
217
|
+
align-items: center;
|
|
218
|
+
gap: var(--stuic-stepper-gap);
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
.stuic-stepper[data-orientation="horizontal"] .stuic-stepper-item {
|
|
222
|
+
display: flex;
|
|
223
|
+
align-items: center;
|
|
224
|
+
gap: var(--stuic-stepper-gap);
|
|
225
|
+
flex: 1;
|
|
226
|
+
min-width: 0;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
/* the last step carries no connector — don't stretch it */
|
|
230
|
+
.stuic-stepper[data-orientation="horizontal"] .stuic-stepper-item:last-child {
|
|
231
|
+
flex: none;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
.stuic-stepper[data-orientation="horizontal"] .stuic-stepper-connector {
|
|
235
|
+
flex: 1;
|
|
236
|
+
min-width: var(--stuic-stepper-connector-min-length);
|
|
237
|
+
height: var(--stuic-stepper-connector-thickness);
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
/* ============================================================================
|
|
241
|
+
HORIZONTAL, LABELS BELOW (classic checkout header)
|
|
242
|
+
============================================================================ */
|
|
243
|
+
|
|
244
|
+
.stuic-stepper[data-label-position="below"] .stuic-stepper-item {
|
|
245
|
+
align-items: flex-start;
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
.stuic-stepper[data-label-position="below"] .stuic-stepper-trigger {
|
|
249
|
+
flex-direction: column;
|
|
250
|
+
align-items: center;
|
|
251
|
+
text-align: center;
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
.stuic-stepper[data-label-position="below"] .stuic-stepper-text {
|
|
255
|
+
align-items: center;
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
/* keep the connector on the indicator's horizontal axis */
|
|
259
|
+
.stuic-stepper[data-label-position="below"] .stuic-stepper-connector {
|
|
260
|
+
margin-top: calc(
|
|
261
|
+
(var(--stuic-stepper-indicator-size) - var(--stuic-stepper-connector-thickness)) / 2
|
|
262
|
+
);
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
/* ============================================================================
|
|
266
|
+
VERTICAL
|
|
267
|
+
============================================================================ */
|
|
268
|
+
|
|
269
|
+
.stuic-stepper[data-orientation="vertical"] .stuic-stepper-list {
|
|
270
|
+
flex-direction: column;
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
.stuic-stepper[data-orientation="vertical"] .stuic-stepper-item {
|
|
274
|
+
position: relative;
|
|
275
|
+
padding-bottom: var(--stuic-stepper-gap-vertical);
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
.stuic-stepper[data-orientation="vertical"] .stuic-stepper-item:last-child {
|
|
279
|
+
padding-bottom: 0;
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
/* top-align so a multi-line description grows downward, not around the bubble */
|
|
283
|
+
.stuic-stepper[data-orientation="vertical"] .stuic-stepper-trigger {
|
|
284
|
+
align-items: flex-start;
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
/* ...while a single-line label still centers against the bubble */
|
|
288
|
+
.stuic-stepper[data-orientation="vertical"] .stuic-stepper-text {
|
|
289
|
+
min-height: var(--stuic-stepper-indicator-size);
|
|
290
|
+
justify-content: center;
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
.stuic-stepper[data-orientation="vertical"] .stuic-stepper-connector {
|
|
294
|
+
position: absolute;
|
|
295
|
+
inset-inline-start: calc(
|
|
296
|
+
(var(--stuic-stepper-indicator-size) - var(--stuic-stepper-connector-thickness)) / 2
|
|
297
|
+
);
|
|
298
|
+
top: calc(var(--stuic-stepper-indicator-size) + 0.25rem);
|
|
299
|
+
bottom: 0.25rem;
|
|
300
|
+
width: var(--stuic-stepper-connector-thickness);
|
|
301
|
+
}
|
|
302
|
+
}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
export { default as Stepper, type Props as StepperProps, type StepperStep, type StepperStepState, type StepperOrientation, type StepperLabelPosition, type StepperClickable, } from "./Stepper.svelte";
|
|
2
|
+
export { createStepperT, STEPPER_MESSAGES_EN, type StepperMessageKey, type StepperMessages, } from "./i18n.js";
|
|
3
|
+
export { STEPPER_MESSAGES_SK } from "./i18n-sk.js";
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
# TrendChart
|
|
2
|
+
|
|
3
|
+
A thin Svelte wrapper around [`@marianmeres/trend-chart`](https://github.com/marianmeres/trend-chart)
|
|
4
|
+
(framework-agnostic, zero-dependency single-series SVG trend chart): reactive `data`
|
|
5
|
+
and `options` props, lifecycle management (create/update/destroy), a `sparkline`
|
|
6
|
+
preset, and automatic STUIC theming (dark mode included) by mapping the chart's
|
|
7
|
+
`--trend-chart-*` CSS hooks to STUIC tokens.
|
|
8
|
+
|
|
9
|
+
## Installation
|
|
10
|
+
|
|
11
|
+
This component ships as an **optional subpath export** — the
|
|
12
|
+
`@marianmeres/trend-chart` peer dependency is NOT bundled with stuic and is only
|
|
13
|
+
required if you actually use this component:
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
npm install @marianmeres/trend-chart
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
```svelte
|
|
20
|
+
<script>
|
|
21
|
+
import { TrendChart } from "@marianmeres/stuic/trend-chart";
|
|
22
|
+
</script>
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
It is deliberately not exported from the main `@marianmeres/stuic` barrel, so
|
|
26
|
+
consumers who don't use it never pull the dependency into their module graph.
|
|
27
|
+
|
|
28
|
+
## Usage
|
|
29
|
+
|
|
30
|
+
```svelte
|
|
31
|
+
<script>
|
|
32
|
+
import { TrendChart } from "@marianmeres/stuic/trend-chart";
|
|
33
|
+
|
|
34
|
+
let data = $state([3, 5, 4, 8, 6, 9, 7]);
|
|
35
|
+
</script>
|
|
36
|
+
|
|
37
|
+
<!-- Full chart (axes, gridlines, pan/zoom) — themed via stuic tokens -->
|
|
38
|
+
<TrendChart {data} />
|
|
39
|
+
|
|
40
|
+
<!-- Sparkline (no axes/grid/interaction, compact height) -->
|
|
41
|
+
<TrendChart {data} sparkline />
|
|
42
|
+
|
|
43
|
+
<!-- Any @marianmeres/trend-chart option passes through -->
|
|
44
|
+
<TrendChart
|
|
45
|
+
{data}
|
|
46
|
+
options={{
|
|
47
|
+
smooth: true,
|
|
48
|
+
endDot: true,
|
|
49
|
+
formatX: (x) => new Date(x).toLocaleDateString(),
|
|
50
|
+
onPointClick: (e) => console.log(e.point),
|
|
51
|
+
}}
|
|
52
|
+
/>
|
|
53
|
+
|
|
54
|
+
<!-- Imperative API via the bindable chart instance -->
|
|
55
|
+
<TrendChart {data} bind:chart />
|
|
56
|
+
<button onclick={() => chart?.resetDomain()}>Reset zoom</button>
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
Updating `data` (reassignment or deep `$state` mutation) patches the chart in
|
|
60
|
+
place — pan/zoom state is preserved. Changing `options` merges them into the
|
|
61
|
+
running instance.
|
|
62
|
+
|
|
63
|
+
### With `Stat` (KPI card)
|
|
64
|
+
|
|
65
|
+
The first-class pairing — a sparkline in a `Stat` footer:
|
|
66
|
+
|
|
67
|
+
```svelte
|
|
68
|
+
<script>
|
|
69
|
+
import { Stat } from "@marianmeres/stuic";
|
|
70
|
+
import { TrendChart } from "@marianmeres/stuic/trend-chart";
|
|
71
|
+
</script>
|
|
72
|
+
|
|
73
|
+
<Stat label="Requests" value="1.2M" delta="+8.4%" trend="up" hint="last 7 days">
|
|
74
|
+
{#snippet renderFooter()}
|
|
75
|
+
<TrendChart data={[42, 51, 48, 63, 58, 71, 84]} sparkline />
|
|
76
|
+
{/snippet}
|
|
77
|
+
</Stat>
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
## Props
|
|
81
|
+
|
|
82
|
+
| Prop | Type | Default | Description |
|
|
83
|
+
| ----------- | ------------------- | ------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
84
|
+
| `data` | `TrendData` | — | The series: `DataPoint[]` or plain `number[]` shorthand (index becomes x). Reactive. |
|
|
85
|
+
| `options` | `TrendChartOptions` | — | [`@marianmeres/trend-chart` options](https://github.com/marianmeres/trend-chart/blob/master/API.md), passed through. Reactive. Merged OVER the sparkline preset. |
|
|
86
|
+
| `sparkline` | `boolean` | `false` | Preset: no axes/grid/pan/zoom/points + compact default height |
|
|
87
|
+
| `chart` | `TrendChart` | — | Bindable underlying instance (`setDomainX`, `resetDomain`, ...). `undefined` during SSR/before mount. |
|
|
88
|
+
| `unstyled` | `boolean` | `false` | Skip all default styling — including the default height; size the container yourself |
|
|
89
|
+
| `class` | `string` | - | Additional CSS classes for the container |
|
|
90
|
+
| `el` | `HTMLElement` | - | Bindable element reference (the chart's container) |
|
|
91
|
+
|
|
92
|
+
## CSS Variables
|
|
93
|
+
|
|
94
|
+
| Variable | Default | Description |
|
|
95
|
+
| -------------------------------------- | ------------------------------------- | --------------------------------- |
|
|
96
|
+
| `--stuic-trend-chart-height` | `8rem` | Container height |
|
|
97
|
+
| `--stuic-trend-chart-height-sparkline` | `2.5rem` | Container height with `sparkline` |
|
|
98
|
+
| `--stuic-trend-chart-line` | `var(--stuic-color-primary)` | Line stroke |
|
|
99
|
+
| `--stuic-trend-chart-fill` | `var(--stuic-color-primary)` | Area fill base color |
|
|
100
|
+
| `--stuic-trend-chart-grid` | `var(--stuic-color-border)` | Gridline stroke |
|
|
101
|
+
| `--stuic-trend-chart-label` | `var(--stuic-color-muted-foreground)` | Axis label color |
|
|
102
|
+
| `--stuic-trend-chart-font` | `var(--font-sans)` | Label font family |
|
|
103
|
+
| `--stuic-trend-chart-end-dot-ring` | `var(--stuic-color-background)` | End-dot/hover-dot ring color |
|
|
104
|
+
| `--stuic-trend-chart-annotation` | `var(--stuic-color-warning)` | Annotation rule + label color |
|
|
105
|
+
| `--stuic-trend-chart-annotation-halo` | `var(--stuic-color-background)` | Halo behind annotation labels |
|
|
106
|
+
|
|
107
|
+
These map onto the chart's own `--trend-chart-*` hooks (active because the DOM
|
|
108
|
+
renderer's `cssVars` option defaults to `true`). Any `lineColor`/`fill`/... option
|
|
109
|
+
you pass still acts as the fallback inside the `var()` wrapper.
|
|
110
|
+
|
|
111
|
+
## Notes
|
|
112
|
+
|
|
113
|
+
- **Sizing**: the chart measures its container (via `ResizeObserver`), so the
|
|
114
|
+
container needs a real size. The default styles provide the height
|
|
115
|
+
(`--stuic-trend-chart-height`); with `unstyled` you must size it yourself, or
|
|
116
|
+
pass explicit `width`/`height` in `options`.
|
|
117
|
+
- **SSR**: the chart is created in an effect, so the server renders an empty
|
|
118
|
+
container. For static server-rendered charts use the library's
|
|
119
|
+
`renderToString` directly.
|
|
120
|
+
- Single-series by design (the underlying library's scope): one line/area — no
|
|
121
|
+
bars, pies, or multi-series.
|
|
122
|
+
- The chart instance is created once per container; `data`/`options` changes
|
|
123
|
+
patch it in place, so pan/zoom state survives updates.
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
<script lang="ts" module>
|
|
2
|
+
import type { HTMLAttributes } from "svelte/elements";
|
|
3
|
+
import type {
|
|
4
|
+
TrendChart as TrendChartInstance,
|
|
5
|
+
TrendChartOptions,
|
|
6
|
+
TrendData,
|
|
7
|
+
} from "@marianmeres/trend-chart";
|
|
8
|
+
|
|
9
|
+
export interface Props extends Omit<HTMLAttributes<HTMLDivElement>, "children"> {
|
|
10
|
+
/**
|
|
11
|
+
* The series: `DataPoint[]` or plain `number[]` shorthand (index becomes x).
|
|
12
|
+
* Reactive — the chart updates in place (keeping pan/zoom state) when it changes.
|
|
13
|
+
*/
|
|
14
|
+
data: TrendData;
|
|
15
|
+
/**
|
|
16
|
+
* `@marianmeres/trend-chart` options, passed through. Reactive. When `sparkline`
|
|
17
|
+
* is set, these are merged OVER the sparkline preset (so any preset key can be
|
|
18
|
+
* overridden back).
|
|
19
|
+
*/
|
|
20
|
+
options?: TrendChartOptions;
|
|
21
|
+
/**
|
|
22
|
+
* Preset for the axis-less, non-interactive mini chart look:
|
|
23
|
+
* no axes/grid/pan/zoom/points. Also switches the default height.
|
|
24
|
+
*/
|
|
25
|
+
sparkline?: boolean;
|
|
26
|
+
/**
|
|
27
|
+
* Bindable underlying `TrendChart` instance for the imperative API
|
|
28
|
+
* (`setDomainX`, `resetDomain`, `getDomainX`, ...). `undefined` during SSR
|
|
29
|
+
* and before mount.
|
|
30
|
+
*/
|
|
31
|
+
chart?: TrendChartInstance;
|
|
32
|
+
/** Skip all default styling (incl. the default height — size it yourself) */
|
|
33
|
+
unstyled?: boolean;
|
|
34
|
+
/** Additional CSS classes */
|
|
35
|
+
class?: string;
|
|
36
|
+
/** Bindable element reference (the chart's container) */
|
|
37
|
+
el?: HTMLElement;
|
|
38
|
+
}
|
|
39
|
+
</script>
|
|
40
|
+
|
|
41
|
+
<script lang="ts">
|
|
42
|
+
import { untrack } from "svelte";
|
|
43
|
+
import { TrendChart as TrendChartClass } from "@marianmeres/trend-chart";
|
|
44
|
+
import { twMerge } from "../../utils/tw-merge.js";
|
|
45
|
+
import "./index.css";
|
|
46
|
+
|
|
47
|
+
const SPARKLINE_PRESET: Partial<TrendChartOptions> = {
|
|
48
|
+
xAxis: false,
|
|
49
|
+
yAxis: false,
|
|
50
|
+
grid: false,
|
|
51
|
+
pan: false,
|
|
52
|
+
zoom: false,
|
|
53
|
+
points: "none",
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
let {
|
|
57
|
+
data,
|
|
58
|
+
options,
|
|
59
|
+
sparkline = false,
|
|
60
|
+
chart = $bindable(),
|
|
61
|
+
unstyled = false,
|
|
62
|
+
class: classProp,
|
|
63
|
+
el = $bindable(),
|
|
64
|
+
...rest
|
|
65
|
+
}: Props = $props();
|
|
66
|
+
|
|
67
|
+
let _class = $derived(unstyled ? classProp : twMerge("stuic-trend-chart", classProp));
|
|
68
|
+
|
|
69
|
+
let _options: TrendChartOptions = $derived({
|
|
70
|
+
...(sparkline ? SPARKLINE_PRESET : {}),
|
|
71
|
+
...options,
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
// Hand the library plain (non-proxied) data; reading the snapshot also makes
|
|
75
|
+
// deep mutations of a $state-backed series reactive, not just reassignments.
|
|
76
|
+
let _data = $derived($state.snapshot(data) as TrendData);
|
|
77
|
+
|
|
78
|
+
// The internal wiring must not run through `el`/`chart`: those are write-out
|
|
79
|
+
// mirrors a parent (or test harness) may overwrite as plain props at any time.
|
|
80
|
+
let _container = $state<HTMLElement>();
|
|
81
|
+
let _chart = $state<TrendChartInstance>();
|
|
82
|
+
|
|
83
|
+
// Create once per container element; option/data changes below patch the
|
|
84
|
+
// existing instance in place (preserving pan/zoom state) instead of rebuilding.
|
|
85
|
+
$effect(() => {
|
|
86
|
+
if (!_container) return;
|
|
87
|
+
const instance = untrack(() => new TrendChartClass(_container!, _data, _options));
|
|
88
|
+
_chart = instance;
|
|
89
|
+
el = _container;
|
|
90
|
+
chart = instance;
|
|
91
|
+
return () => {
|
|
92
|
+
instance.destroy();
|
|
93
|
+
_chart = undefined;
|
|
94
|
+
chart = undefined;
|
|
95
|
+
};
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
$effect(() => {
|
|
99
|
+
const d = _data;
|
|
100
|
+
untrack(() => _chart)?.update(d);
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
$effect(() => {
|
|
104
|
+
const o = _options;
|
|
105
|
+
untrack(() => _chart)?.setOptions(o);
|
|
106
|
+
});
|
|
107
|
+
</script>
|
|
108
|
+
|
|
109
|
+
<div
|
|
110
|
+
bind:this={_container}
|
|
111
|
+
class={_class}
|
|
112
|
+
data-sparkline={!unstyled && sparkline ? "" : undefined}
|
|
113
|
+
{...rest}
|
|
114
|
+
></div>
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import type { HTMLAttributes } from "svelte/elements";
|
|
2
|
+
import type { TrendChart as TrendChartInstance, TrendChartOptions, TrendData } from "@marianmeres/trend-chart";
|
|
3
|
+
export interface Props extends Omit<HTMLAttributes<HTMLDivElement>, "children"> {
|
|
4
|
+
/**
|
|
5
|
+
* The series: `DataPoint[]` or plain `number[]` shorthand (index becomes x).
|
|
6
|
+
* Reactive — the chart updates in place (keeping pan/zoom state) when it changes.
|
|
7
|
+
*/
|
|
8
|
+
data: TrendData;
|
|
9
|
+
/**
|
|
10
|
+
* `@marianmeres/trend-chart` options, passed through. Reactive. When `sparkline`
|
|
11
|
+
* is set, these are merged OVER the sparkline preset (so any preset key can be
|
|
12
|
+
* overridden back).
|
|
13
|
+
*/
|
|
14
|
+
options?: TrendChartOptions;
|
|
15
|
+
/**
|
|
16
|
+
* Preset for the axis-less, non-interactive mini chart look:
|
|
17
|
+
* no axes/grid/pan/zoom/points. Also switches the default height.
|
|
18
|
+
*/
|
|
19
|
+
sparkline?: boolean;
|
|
20
|
+
/**
|
|
21
|
+
* Bindable underlying `TrendChart` instance for the imperative API
|
|
22
|
+
* (`setDomainX`, `resetDomain`, `getDomainX`, ...). `undefined` during SSR
|
|
23
|
+
* and before mount.
|
|
24
|
+
*/
|
|
25
|
+
chart?: TrendChartInstance;
|
|
26
|
+
/** Skip all default styling (incl. the default height — size it yourself) */
|
|
27
|
+
unstyled?: boolean;
|
|
28
|
+
/** Additional CSS classes */
|
|
29
|
+
class?: string;
|
|
30
|
+
/** Bindable element reference (the chart's container) */
|
|
31
|
+
el?: HTMLElement;
|
|
32
|
+
}
|
|
33
|
+
import "./index.css";
|
|
34
|
+
declare const TrendChart: import("svelte").Component<Props, {}, "el" | "chart">;
|
|
35
|
+
type TrendChart = ReturnType<typeof TrendChart>;
|
|
36
|
+
export default TrendChart;
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/******************************************************************************
|
|
2
|
+
TrendChart
|
|
3
|
+
|
|
4
|
+
NOTE — intentional deviation from the usual STUIC CSS convention.
|
|
5
|
+
Every other component's `index.css` is `@import`-ed into the central
|
|
6
|
+
`src/lib/index.css`. This component is NOT: it is an OPTIONAL subpath export
|
|
7
|
+
(`@marianmeres/stuic/trend-chart`) kept off the main barrel so its
|
|
8
|
+
`@marianmeres/trend-chart` peer dependency stays opt-in. Centralizing its
|
|
9
|
+
CSS would ship these styles to every consumer, defeating that. Instead
|
|
10
|
+
`TrendChart.svelte` imports THIS file locally; the package's `sideEffects`
|
|
11
|
+
glob (all css files) keeps the import for real users.
|
|
12
|
+
|
|
13
|
+
Theming: the underlying chart renders its colors wrapped in
|
|
14
|
+
`var(--trend-chart-*, fallback)` (its `cssVars` option, on by default in the
|
|
15
|
+
DOM renderer). Mapping those vars to STUIC theme tokens here is what makes
|
|
16
|
+
the chart follow the active theme — dark mode included — with zero options.
|
|
17
|
+
******************************************************************************/
|
|
18
|
+
|
|
19
|
+
@layer components {
|
|
20
|
+
.stuic-trend-chart {
|
|
21
|
+
/* The chart measures its container — it must have a real size. */
|
|
22
|
+
width: 100%;
|
|
23
|
+
height: var(--stuic-trend-chart-height, 8rem);
|
|
24
|
+
|
|
25
|
+
/* Map the chart's own CSS hooks to STUIC theme tokens. */
|
|
26
|
+
--trend-chart-line: var(--stuic-trend-chart-line, var(--stuic-color-primary));
|
|
27
|
+
--trend-chart-fill: var(--stuic-trend-chart-fill, var(--stuic-color-primary));
|
|
28
|
+
--trend-chart-grid: var(--stuic-trend-chart-grid, var(--stuic-color-border));
|
|
29
|
+
--trend-chart-label: var(
|
|
30
|
+
--stuic-trend-chart-label,
|
|
31
|
+
var(--stuic-color-muted-foreground)
|
|
32
|
+
);
|
|
33
|
+
--trend-chart-font: var(--stuic-trend-chart-font, var(--font-sans));
|
|
34
|
+
--trend-chart-end-dot-ring: var(
|
|
35
|
+
--stuic-trend-chart-end-dot-ring,
|
|
36
|
+
var(--stuic-color-background)
|
|
37
|
+
);
|
|
38
|
+
--trend-chart-annotation: var(
|
|
39
|
+
--stuic-trend-chart-annotation,
|
|
40
|
+
var(--stuic-color-warning)
|
|
41
|
+
);
|
|
42
|
+
--trend-chart-annotation-halo: var(
|
|
43
|
+
--stuic-trend-chart-annotation-halo,
|
|
44
|
+
var(--stuic-color-background)
|
|
45
|
+
);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
.stuic-trend-chart[data-sparkline] {
|
|
49
|
+
height: var(--stuic-trend-chart-height-sparkline, 2.5rem);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default as TrendChart, type Props as TrendChartProps, } from "./TrendChart.svelte";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default as TrendChart, } from "./TrendChart.svelte";
|
package/dist/icons/index.d.ts
CHANGED
|
@@ -22,10 +22,13 @@ export { iconLucideArrowLeft as iconArrowLeft } from "@marianmeres/icons-fns/luc
|
|
|
22
22
|
export { iconLucideArrowRight as iconArrowRight } from "@marianmeres/icons-fns/lucide/iconLucideArrowRight.js";
|
|
23
23
|
export { iconLucideArrowUp as iconArrowUp } from "@marianmeres/icons-fns/lucide/iconLucideArrowUp.js";
|
|
24
24
|
export { iconLucideArrowUpToLine as iconArrowUpToLine } from "@marianmeres/icons-fns/lucide/iconLucideArrowUpToLine.js";
|
|
25
|
+
export { iconLucideCopy as iconCopy } from "@marianmeres/icons-fns/lucide/iconLucideCopy.js";
|
|
25
26
|
export { iconLucideDownload as iconDownload } from "@marianmeres/icons-fns/lucide/iconLucideDownload.js";
|
|
26
27
|
export { iconLucideMinus as iconMinus } from "@marianmeres/icons-fns/lucide/iconLucideMinus.js";
|
|
27
28
|
export { iconLucidePlus as iconPlus } from "@marianmeres/icons-fns/lucide/iconLucidePlus.js";
|
|
28
29
|
export { iconLucideTrash2 as iconTrash } from "@marianmeres/icons-fns/lucide/iconLucideTrash2.js";
|
|
30
|
+
export { iconLucideTrendingDown as iconTrendingDown } from "@marianmeres/icons-fns/lucide/iconLucideTrendingDown.js";
|
|
31
|
+
export { iconLucideTrendingUp as iconTrendingUp } from "@marianmeres/icons-fns/lucide/iconLucideTrendingUp.js";
|
|
29
32
|
export { iconLucideZoomIn as iconZoomIn } from "@marianmeres/icons-fns/lucide/iconLucideZoomIn.js";
|
|
30
33
|
export { iconLucideZoomOut as iconZoomOut } from "@marianmeres/icons-fns/lucide/iconLucideZoomOut.js";
|
|
31
34
|
export { iconLucideCheck as iconCheck } from "@marianmeres/icons-fns/lucide/iconLucideCheck.js";
|
|
@@ -40,6 +43,7 @@ export { iconLucideEllipsisVertical as iconEllipsisVertical } from "@marianmeres
|
|
|
40
43
|
export { iconLucideGrip as iconGrip } from "@marianmeres/icons-fns/lucide/iconLucideGrip.js";
|
|
41
44
|
export { iconLucideGripHorizontal as iconGripHorizontal } from "@marianmeres/icons-fns/lucide/iconLucideGripHorizontal.js";
|
|
42
45
|
export { iconLucideGripVertical as iconGripVertical } from "@marianmeres/icons-fns/lucide/iconLucideGripVertical.js";
|
|
46
|
+
export { iconLucideInbox as iconInbox } from "@marianmeres/icons-fns/lucide/iconLucideInbox.js";
|
|
43
47
|
export { iconLucideLanguages as iconLanguages } from "@marianmeres/icons-fns/lucide/iconLucideLanguages.js";
|
|
44
48
|
export { iconLucideList as iconList } from "@marianmeres/icons-fns/lucide/iconLucideList.js";
|
|
45
49
|
export { iconLucideLogOut as iconLogOut } from "@marianmeres/icons-fns/lucide/iconLucideLogOut.js";
|