@marianmeres/stuic 3.115.0 → 3.116.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/API.md +297 -304
- package/dist/actions/dim-behind/index.css +4 -1
- package/dist/actions/focus-trap.js +3 -1
- package/dist/components/Accordion/README.md +17 -17
- package/dist/components/Accordion/index.css +4 -2
- package/dist/components/AssetsPreview/README.md +7 -7
- package/dist/components/AssetsPreview/_internal/assets-preview-types.d.ts +1 -2
- package/dist/components/AssetsPreview/_internal/assets-preview-utils.d.ts +1 -1
- package/dist/components/AssetsPreview/_internal/assets-preview-utils.js +9 -3
- package/dist/components/Avatar/Avatar.svelte +1 -3
- package/dist/components/Avatar/README.md +33 -27
- package/dist/components/Book/Book.svelte +6 -1
- package/dist/components/Book/README.md +22 -20
- package/dist/components/Book/index.css +4 -2
- package/dist/components/Button/README.md +17 -17
- package/dist/components/Card/Card.svelte +25 -8
- package/dist/components/Card/README.md +52 -56
- package/dist/components/Card/index.css +2 -1
- package/dist/components/Carousel/Carousel.svelte +1 -3
- package/dist/components/Carousel/README.md +28 -28
- package/dist/components/Cart/Cart.svelte +2 -1
- package/dist/components/Cart/README.md +25 -25
- package/dist/components/Checkout/CheckoutGuestOrLoginForm.svelte +8 -3
- package/dist/components/Checkout/CheckoutShippingStep.svelte +1 -2
- package/dist/components/Checkout/README.md +143 -130
- package/dist/components/CronInput/CronInput.svelte +64 -60
- package/dist/components/CronInput/README.md +46 -46
- package/dist/components/DataTable/DataTable.svelte +5 -1
- package/dist/components/DataTable/README.md +78 -63
- package/dist/components/DropdownMenu/DropdownMenu.svelte +6 -2
- package/dist/components/DropdownMenu/README.md +33 -27
- package/dist/components/EmailVerifyForm/EmailVerifyForm.svelte +2 -9
- package/dist/components/EmailVerifyForm/README.md +30 -30
- package/dist/components/Header/Header.svelte +161 -165
- package/dist/components/Header/README.md +7 -7
- package/dist/components/IconSwap/README.md +20 -15
- package/dist/components/IconSwap/index.css +2 -1
- package/dist/components/ImageCycler/ImageCycler.svelte +19 -5
- package/dist/components/ImageCycler/ImageCycler.svelte.d.ts +14 -10
- package/dist/components/ImageCycler/README.md +15 -15
- package/dist/components/ImageCycler/index.css +26 -20
- package/dist/components/Input/FieldFile.svelte +1 -3
- package/dist/components/Input/FieldInput.svelte +1 -3
- package/dist/components/Input/FieldKeyValues.svelte +2 -6
- package/dist/components/Input/FieldObject.svelte +2 -1
- package/dist/components/Input/README.md +11 -11
- package/dist/components/KbdShortcut/index.css +2 -1
- package/dist/components/LoginForm/LoginForm.svelte +1 -7
- package/dist/components/LoginForm/README.md +46 -46
- package/dist/components/ModalDialog/index.css +2 -1
- package/dist/components/Notifications/index.css +24 -6
- package/dist/components/OtpInput/OtpInput.svelte +0 -0
- package/dist/components/OtpInput/README.md +15 -19
- package/dist/components/OtpInput/index.css +1 -4
- package/dist/components/OtpInput/index.d.ts +1 -1
- package/dist/components/OtpInput/index.js +1 -1
- package/dist/components/Pill/README.md +41 -40
- package/dist/components/Pill/index.css +3 -6
- package/dist/components/PricingTable/README.md +86 -86
- package/dist/components/PricingTable/index.css +20 -35
- package/dist/components/RegisterForm/README.md +60 -60
- package/dist/components/RegisterForm/RegisterForm.svelte +1 -7
- package/dist/components/Separator/README.md +7 -7
- package/dist/components/TabbedMenu/index.css +6 -3
- package/dist/components/Tree/README.md +67 -67
- package/dist/components/UserAvatarMenu/UserAvatarMenu.svelte +1 -5
- package/dist/components/WithSidePanel/index.css +4 -4
- package/dist/index.css +12 -8
- package/dist/utils/design-tokens.d.ts +1 -1
- package/dist/utils/design-tokens.js +1 -1
- package/docs/architecture.md +7 -7
- package/docs/component-testing/00-overview-and-roadmap.md +19 -19
- package/docs/component-testing/01-framework-setup.md +6 -6
- package/docs/component-testing/02-test-conventions.md +6 -5
- package/docs/component-testing/03-component-coverage-roadmap.md +27 -27
- package/docs/component-testing/04-hard-cases-and-e2e.md +8 -8
- package/docs/component-testing/05-ci.md +3 -3
- package/docs/component-testing/PROGRESS.md +30 -26
- package/docs/component-testing/README.md +8 -8
- package/docs/conventions.md +25 -25
- package/docs/domains/components.md +386 -385
- package/docs/domains/theming.md +24 -24
- package/docs/domains/utils.md +22 -25
- package/docs/testing.md +2 -2
- package/docs/upgrading.md +32 -28
- package/package.json +2 -1
|
@@ -90,8 +90,19 @@
|
|
|
90
90
|
] as const;
|
|
91
91
|
|
|
92
92
|
const MONTH_NAMES = [
|
|
93
|
-
"",
|
|
94
|
-
"
|
|
93
|
+
"",
|
|
94
|
+
"Jan",
|
|
95
|
+
"Feb",
|
|
96
|
+
"Mar",
|
|
97
|
+
"Apr",
|
|
98
|
+
"May",
|
|
99
|
+
"Jun",
|
|
100
|
+
"Jul",
|
|
101
|
+
"Aug",
|
|
102
|
+
"Sep",
|
|
103
|
+
"Oct",
|
|
104
|
+
"Nov",
|
|
105
|
+
"Dec",
|
|
95
106
|
];
|
|
96
107
|
|
|
97
108
|
const DAY_NAMES = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];
|
|
@@ -120,7 +131,9 @@
|
|
|
120
131
|
} else if (hour.startsWith("*/")) {
|
|
121
132
|
segments.push(`every ${hour.slice(2)} hours`);
|
|
122
133
|
} else {
|
|
123
|
-
segments.push(
|
|
134
|
+
segments.push(
|
|
135
|
+
`at ${hour.padStart(2, "0")}:${minute === "*" ? "00" : minute.padStart(2, "0")}`
|
|
136
|
+
);
|
|
124
137
|
// remove the minute segment if we have a specific hour
|
|
125
138
|
if (minute !== "*" && !minute.includes("/")) {
|
|
126
139
|
segments.length = 0;
|
|
@@ -167,7 +180,9 @@
|
|
|
167
180
|
}
|
|
168
181
|
}
|
|
169
182
|
|
|
170
|
-
return segments.length
|
|
183
|
+
return segments.length
|
|
184
|
+
? segments[0].charAt(0).toUpperCase() + segments.join(", ").slice(1)
|
|
185
|
+
: "";
|
|
171
186
|
}
|
|
172
187
|
</script>
|
|
173
188
|
|
|
@@ -240,21 +255,11 @@
|
|
|
240
255
|
}
|
|
241
256
|
|
|
242
257
|
// Effective show flags — mode overrides explicit props when defined
|
|
243
|
-
let _showPresets = $derived(
|
|
244
|
-
|
|
245
|
-
);
|
|
246
|
-
let
|
|
247
|
-
|
|
248
|
-
);
|
|
249
|
-
let _showRawInput = $derived(
|
|
250
|
-
hasModeToggle ? false : showRawInput
|
|
251
|
-
);
|
|
252
|
-
let _showDescription = $derived(
|
|
253
|
-
hasModeToggle ? mode === "manual" : showDescription
|
|
254
|
-
);
|
|
255
|
-
let _showNextRun = $derived(
|
|
256
|
-
hasModeToggle ? mode === "manual" : showNextRun
|
|
257
|
-
);
|
|
258
|
+
let _showPresets = $derived(hasModeToggle ? mode === "predefined" : showPresets);
|
|
259
|
+
let _showFields = $derived(hasModeToggle ? mode === "manual" : showFields);
|
|
260
|
+
let _showRawInput = $derived(hasModeToggle ? false : showRawInput);
|
|
261
|
+
let _showDescription = $derived(hasModeToggle ? mode === "manual" : showDescription);
|
|
262
|
+
let _showNextRun = $derived(hasModeToggle ? mode === "manual" : showNextRun);
|
|
258
263
|
|
|
259
264
|
const BTN_CLS = [
|
|
260
265
|
"toggle-btn",
|
|
@@ -378,7 +383,9 @@
|
|
|
378
383
|
}
|
|
379
384
|
|
|
380
385
|
// When only presets are visible, render as a plain select (no extra padding/border)
|
|
381
|
-
let presetsOnly = $derived(
|
|
386
|
+
let presetsOnly = $derived(
|
|
387
|
+
_showPresets && !_showFields && !_showRawInput && !_showDescription && !_showNextRun
|
|
388
|
+
);
|
|
382
389
|
|
|
383
390
|
// Minute tick — triggers re-evaluation of "Next: ..." every 60s
|
|
384
391
|
let _tick = $state(0);
|
|
@@ -463,48 +470,46 @@
|
|
|
463
470
|
{/if}
|
|
464
471
|
|
|
465
472
|
{#if _showFields}
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
class={unstyled
|
|
474
|
-
? classField
|
|
475
|
-
: twMerge("stuic-cron-input-field", classField)}
|
|
476
|
-
>
|
|
477
|
-
<span
|
|
473
|
+
<div
|
|
474
|
+
class={unstyled
|
|
475
|
+
? classFields
|
|
476
|
+
: twMerge("stuic-cron-input-fields", classFields)}
|
|
477
|
+
>
|
|
478
|
+
{#each FIELD_DEFS as def}
|
|
479
|
+
<div
|
|
478
480
|
class={unstyled
|
|
479
|
-
?
|
|
480
|
-
: twMerge("stuic-cron-input-field
|
|
481
|
+
? classField
|
|
482
|
+
: twMerge("stuic-cron-input-field", classField)}
|
|
481
483
|
>
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
484
|
+
<span
|
|
485
|
+
class={unstyled
|
|
486
|
+
? classFieldLabel
|
|
487
|
+
: twMerge("stuic-cron-input-field-label", classFieldLabel)}
|
|
488
|
+
>
|
|
489
|
+
{def.label}
|
|
490
|
+
</span>
|
|
491
|
+
<input
|
|
492
|
+
type="text"
|
|
493
|
+
class={unstyled
|
|
494
|
+
? classFieldInput
|
|
495
|
+
: twMerge("stuic-cron-input-field-input", classFieldInput)}
|
|
496
|
+
bind:value={fields[def.key]}
|
|
497
|
+
oninput={onFieldInput}
|
|
498
|
+
placeholder={def.placeholder}
|
|
499
|
+
aria-label={`${def.label} (${def.placeholder})`}
|
|
500
|
+
{disabled}
|
|
501
|
+
autocomplete="off"
|
|
502
|
+
spellcheck={false}
|
|
503
|
+
/>
|
|
504
|
+
</div>
|
|
505
|
+
{/each}
|
|
506
|
+
</div>
|
|
500
507
|
{/if}
|
|
501
508
|
|
|
502
509
|
{#if _showRawInput}
|
|
503
510
|
<input
|
|
504
511
|
type="text"
|
|
505
|
-
class={unstyled
|
|
506
|
-
? classRaw
|
|
507
|
-
: twMerge("stuic-cron-input-raw", classRaw)}
|
|
512
|
+
class={unstyled ? classRaw : twMerge("stuic-cron-input-raw", classRaw)}
|
|
508
513
|
bind:value={rawValue}
|
|
509
514
|
oninput={onRawInput}
|
|
510
515
|
placeholder="* * * * *"
|
|
@@ -524,16 +529,15 @@
|
|
|
524
529
|
{humanDescription}
|
|
525
530
|
</div>
|
|
526
531
|
{/if}
|
|
527
|
-
|
|
528
532
|
</div>
|
|
529
533
|
{#if hasModeToggle}
|
|
530
534
|
<button
|
|
531
535
|
type="button"
|
|
532
|
-
class={unstyled
|
|
533
|
-
? classToggleButton
|
|
534
|
-
: twMerge(BTN_CLS, classToggleButton)}
|
|
536
|
+
class={unstyled ? classToggleButton : twMerge(BTN_CLS, classToggleButton)}
|
|
535
537
|
onclick={toggleMode}
|
|
536
|
-
aria-label={mode === "predefined"
|
|
538
|
+
aria-label={mode === "predefined"
|
|
539
|
+
? "Switch to manual input"
|
|
540
|
+
: "Switch to presets"}
|
|
537
541
|
{disabled}
|
|
538
542
|
use:tooltip={() => ({
|
|
539
543
|
enabled: true,
|
|
@@ -10,9 +10,9 @@ The cron expression string is the single source of truth; field / preset / raw s
|
|
|
10
10
|
|
|
11
11
|
```svelte
|
|
12
12
|
<script lang="ts">
|
|
13
|
-
|
|
13
|
+
import { CronInput } from "@marianmeres/stuic";
|
|
14
14
|
|
|
15
|
-
|
|
15
|
+
let expression = $state("0 9 * * 1-5");
|
|
16
16
|
</script>
|
|
17
17
|
|
|
18
18
|
<CronInput bind:value={expression} label="Schedule" />
|
|
@@ -24,13 +24,13 @@ Default `mode` is `"predefined"` — users see the preset picker with a toggle b
|
|
|
24
24
|
|
|
25
25
|
```svelte
|
|
26
26
|
<CronInput
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
27
|
+
bind:value={expression}
|
|
28
|
+
mode={undefined}
|
|
29
|
+
showPresets
|
|
30
|
+
showFields
|
|
31
|
+
showRawInput
|
|
32
|
+
showDescription
|
|
33
|
+
showNextRun
|
|
34
34
|
/>
|
|
35
35
|
```
|
|
36
36
|
|
|
@@ -38,13 +38,13 @@ Default `mode` is `"predefined"` — users see the preset picker with a toggle b
|
|
|
38
38
|
|
|
39
39
|
```svelte
|
|
40
40
|
<script lang="ts">
|
|
41
|
-
|
|
41
|
+
import { CronInput, type CronPreset } from "@marianmeres/stuic";
|
|
42
42
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
43
|
+
const presets: CronPreset[] = [
|
|
44
|
+
{ label: "Top of every hour", value: "0 * * * *" },
|
|
45
|
+
{ label: "Daily at 09:00", value: "0 9 * * *" },
|
|
46
|
+
{ label: "Every 5 minutes", value: "*/5 * * * *" },
|
|
47
|
+
];
|
|
48
48
|
</script>
|
|
49
49
|
|
|
50
50
|
<CronInput bind:value={expression} {presets} />
|
|
@@ -56,11 +56,11 @@ For places outside the CronInput that need the next-fire time (e.g. a dashboard
|
|
|
56
56
|
|
|
57
57
|
```svelte
|
|
58
58
|
<script lang="ts">
|
|
59
|
-
|
|
60
|
-
|
|
59
|
+
import { CronNextRun } from "@marianmeres/stuic";
|
|
60
|
+
import { onDestroy } from "svelte";
|
|
61
61
|
|
|
62
|
-
|
|
63
|
-
|
|
62
|
+
const nr = new CronNextRun("0 9 * * 1-5");
|
|
63
|
+
onDestroy(() => nr.destroy());
|
|
64
64
|
</script>
|
|
65
65
|
|
|
66
66
|
<p>Next run: {nr.nextRunFormatted}</p>
|
|
@@ -72,11 +72,11 @@ For places outside the CronInput that need the next-fire time (e.g. a dashboard
|
|
|
72
72
|
|
|
73
73
|
The `mode` prop controls which surfaces are visible and whether the toggle button is shown:
|
|
74
74
|
|
|
75
|
-
| `mode`
|
|
76
|
-
|
|
|
77
|
-
| `"predefined"`
|
|
78
|
-
| `"manual"`
|
|
79
|
-
| `undefined`
|
|
75
|
+
| `mode` | Toggle shown | Visible surfaces |
|
|
76
|
+
| -------------- | ------------ | ------------------------------------------------ |
|
|
77
|
+
| `"predefined"` | yes | preset picker |
|
|
78
|
+
| `"manual"` | yes | fields + raw + description + next-run |
|
|
79
|
+
| `undefined` | no | whatever the `show*` flags enable (full control) |
|
|
80
80
|
|
|
81
81
|
When `mode` is defined, it **overrides** the individual `show*` flags. Set `mode={undefined}` if you want to pick surfaces yourself.
|
|
82
82
|
|
|
@@ -91,13 +91,13 @@ The `value` string is canonical. Internally:
|
|
|
91
91
|
|
|
92
92
|
Off-by-one conventions match standard cron:
|
|
93
93
|
|
|
94
|
-
| Field | Range
|
|
95
|
-
| ------------ |
|
|
96
|
-
| minute | 0-59
|
|
97
|
-
| hour | 0-23
|
|
98
|
-
| day of month | 1-31
|
|
99
|
-
| month | 1-12
|
|
100
|
-
| day of week | 0-6
|
|
94
|
+
| Field | Range | Notes |
|
|
95
|
+
| ------------ | ----- | ----------- |
|
|
96
|
+
| minute | 0-59 | |
|
|
97
|
+
| hour | 0-23 | |
|
|
98
|
+
| day of month | 1-31 | |
|
|
99
|
+
| month | 1-12 | 1 = January |
|
|
100
|
+
| day of week | 0-6 | 0 = Sunday |
|
|
101
101
|
|
|
102
102
|
## Validation
|
|
103
103
|
|
|
@@ -113,21 +113,21 @@ All next-run calculations use the **host's local timezone**. There is no `timezo
|
|
|
113
113
|
|
|
114
114
|
## Props
|
|
115
115
|
|
|
116
|
-
| Prop
|
|
117
|
-
|
|
|
118
|
-
| `value`
|
|
119
|
-
| `mode`
|
|
120
|
-
| `presets`
|
|
121
|
-
| `showPresets`
|
|
122
|
-
| `showFields`
|
|
123
|
-
| `showRawInput`
|
|
124
|
-
| `showDescription`
|
|
125
|
-
| `showNextRun`
|
|
126
|
-
| `onchange`
|
|
127
|
-
| `unstyled`
|
|
128
|
-
| `class`
|
|
129
|
-
| `el`
|
|
130
|
-
| `classFields`/`classField`/`classFieldLabel`/`classFieldInput`/`classPreset`/`classRaw`/`classSummary`/`classToggleButton` | `string`
|
|
116
|
+
| Prop | Type | Default | Description |
|
|
117
|
+
| -------------------------------------------------------------------------------------------------------------------------- | --------------------------------------- | ----------------- | --------------------------------------------------- |
|
|
118
|
+
| `value` | `string` | `"* * * * *"` | Cron expression (bindable) |
|
|
119
|
+
| `mode` | `"predefined" \| "manual" \| undefined` | `"predefined"` | Editor mode; `undefined` hides the toggle |
|
|
120
|
+
| `presets` | `CronPreset[]` | `DEFAULT_PRESETS` | Preset options |
|
|
121
|
+
| `showPresets` | `boolean` | `true` | (Ignored when `mode` is defined) |
|
|
122
|
+
| `showFields` | `boolean` | `true` | (Ignored when `mode` is defined) |
|
|
123
|
+
| `showRawInput` | `boolean` | `true` | (Ignored when `mode` is defined) |
|
|
124
|
+
| `showDescription` | `boolean` | `true` | (Ignored when `mode` is defined) |
|
|
125
|
+
| `showNextRun` | `boolean` | `true` | (Ignored when `mode` is defined) |
|
|
126
|
+
| `onchange` | `(expr, valid) => void` | - | Fires on every valid or invalid change |
|
|
127
|
+
| `unstyled` | `boolean` | `false` | Skip stuic base classes (user provides all styling) |
|
|
128
|
+
| `class` | `string` | - | Wrapper class |
|
|
129
|
+
| `el` | `HTMLElement` | - | Bindable wrapper element |
|
|
130
|
+
| `classFields`/`classField`/`classFieldLabel`/`classFieldInput`/`classPreset`/`classRaw`/`classSummary`/`classToggleButton` | `string` | - | Per-element class overrides |
|
|
131
131
|
|
|
132
132
|
Plus all standard `InputWrap` wrapper class props (`classLabel`, `classLabelBox`, `classInputBox`, `classInputBoxWrap`, `classInputBoxWrapInvalid`, `classDescBox`, `classBelowBox`) — same pattern as every other `Field*` component.
|
|
133
133
|
|
|
@@ -563,7 +563,11 @@
|
|
|
563
563
|
}}
|
|
564
564
|
>
|
|
565
565
|
{#if selectable}
|
|
566
|
-
<div
|
|
566
|
+
<div
|
|
567
|
+
class={!unstyled
|
|
568
|
+
? "stuic-checkbox stuic-data-table-card-checkbox"
|
|
569
|
+
: undefined}
|
|
570
|
+
>
|
|
567
571
|
<input
|
|
568
572
|
type="checkbox"
|
|
569
573
|
checked={isSelected}
|
|
@@ -87,7 +87,13 @@ When your data is paged, DataTable can offer a "select all results" affordance t
|
|
|
87
87
|
bind:excluded
|
|
88
88
|
getRowId={(row) => row.id}
|
|
89
89
|
>
|
|
90
|
-
{#snippet batchActions({
|
|
90
|
+
{#snippet batchActions({
|
|
91
|
+
selectedAll,
|
|
92
|
+
excluded,
|
|
93
|
+
effectiveCount,
|
|
94
|
+
totalCount,
|
|
95
|
+
clearSelection,
|
|
96
|
+
})}
|
|
91
97
|
<span>{effectiveCount} selected{selectedAll ? ` of ${totalCount}` : ""}</span>
|
|
92
98
|
<Button onclick={() => deleteSelection({ selectedAll, excluded })}>Delete</Button>
|
|
93
99
|
<Button variant="ghost" onclick={clearSelection}>Clear</Button>
|
|
@@ -112,7 +118,16 @@ New records inserted while all-pages mode is active are implicitly selected (the
|
|
|
112
118
|
**Customising the banner:** the default banner uses the built-in `t()` keys `select_all_on_page_x`, `select_all_results`, `all_results_selected`, and `clear_selection`. Override markup entirely with the `selectAllBanner` snippet:
|
|
113
119
|
|
|
114
120
|
```svelte
|
|
115
|
-
<DataTable
|
|
121
|
+
<DataTable
|
|
122
|
+
{columns}
|
|
123
|
+
{data}
|
|
124
|
+
{paging}
|
|
125
|
+
selectable
|
|
126
|
+
allowSelectAllPages
|
|
127
|
+
bind:selected
|
|
128
|
+
bind:selectedAll
|
|
129
|
+
bind:excluded
|
|
130
|
+
>
|
|
116
131
|
{#snippet selectAllBanner({ selectedAll, totalCount, selectAll, clearSelection })}
|
|
117
132
|
<div class="my-banner">
|
|
118
133
|
{#if selectedAll}
|
|
@@ -189,44 +204,44 @@ Replace the entire `<tr>` on desktop. When this snippet is provided, DataTable d
|
|
|
189
204
|
|
|
190
205
|
## Props
|
|
191
206
|
|
|
192
|
-
| Prop
|
|
193
|
-
|
|
|
194
|
-
| `columns`
|
|
195
|
-
| `data`
|
|
196
|
-
| `getRowId`
|
|
197
|
-
| `paging`
|
|
198
|
-
| `onPageChange`
|
|
199
|
-
| `selectable`
|
|
200
|
-
| `selected`
|
|
201
|
-
| `selectOnRowClick`
|
|
202
|
-
| `selectDisabledBy`
|
|
203
|
-
| `allowSelectAllPages` | `boolean`
|
|
204
|
-
| `selectedAll`
|
|
205
|
-
| `excluded`
|
|
206
|
-
| `onRowClick`
|
|
207
|
-
| `loading`
|
|
208
|
-
| `small`
|
|
209
|
-
| `t`
|
|
210
|
-
| `cell`
|
|
211
|
-
| `row`
|
|
212
|
-
| `mobileRow`
|
|
213
|
-
| `batchActions`
|
|
214
|
-
| `selectAllBanner`
|
|
215
|
-
| `empty`
|
|
216
|
-
| `unstyled`
|
|
217
|
-
| `class`
|
|
218
|
-
| `el`
|
|
207
|
+
| Prop | Type | Default | Description |
|
|
208
|
+
| --------------------- | ---------------------------------- | ------------- | ------------------------------------------------------------------------ |
|
|
209
|
+
| `columns` | `DataTableColumn<T>[]` | required | Column definitions |
|
|
210
|
+
| `data` | `T[]` | required | Array of row data |
|
|
211
|
+
| `getRowId` | `(row, index) => string \| number` | `(_, i) => i` | Row ID extractor |
|
|
212
|
+
| `paging` | `PagingCalcResult` | - | Paging state (from `@marianmeres/paging-store`) |
|
|
213
|
+
| `onPageChange` | `(offset: number) => void` | - | Called with the new offset when the user navigates pages |
|
|
214
|
+
| `selectable` | `boolean` | `false` | Enable selection checkboxes |
|
|
215
|
+
| `selected` | `Set<string \| number>` | `new Set()` | Selected row IDs (bindable) |
|
|
216
|
+
| `selectOnRowClick` | `boolean` | `false` | Clicking anywhere on a row toggles its selection |
|
|
217
|
+
| `selectDisabledBy` | `(row, index) => boolean` | - | Return `true` to disable selection for a specific row |
|
|
218
|
+
| `allowSelectAllPages` | `boolean` | `false` | Show a banner offering "select all results" across paged data |
|
|
219
|
+
| `selectedAll` | `boolean` | `false` | All-pages mode flag (bindable). In this mode `excluded` drives selection |
|
|
220
|
+
| `excluded` | `Set<string \| number>` | `new Set()` | Deselected row IDs while in all-pages mode (bindable) |
|
|
221
|
+
| `onRowClick` | `(row, index) => void` | - | Row click callback |
|
|
222
|
+
| `loading` | `boolean` | `false` | Show loading overlay |
|
|
223
|
+
| `small` | `boolean` | `false` | Force mobile/card layout regardless of viewport |
|
|
224
|
+
| `t` | `TranslateFn` | built-in | Optional translation function |
|
|
225
|
+
| `cell` | `Snippet` | - | Custom cell renderer (desktop + mobile) |
|
|
226
|
+
| `row` | `Snippet` | - | Custom desktop `<tr>` renderer (overrides default row) |
|
|
227
|
+
| `mobileRow` | `Snippet` | - | Custom mobile card renderer |
|
|
228
|
+
| `batchActions` | `Snippet` | - | Batch action bar content |
|
|
229
|
+
| `selectAllBanner` | `Snippet` | - | Override default "select all across pages" banner |
|
|
230
|
+
| `empty` | `Snippet` | - | Custom empty state |
|
|
231
|
+
| `unstyled` | `boolean` | `false` | Skip default styling |
|
|
232
|
+
| `class` | `string` | - | Additional CSS classes |
|
|
233
|
+
| `el` | `HTMLDivElement` | - | Bindable element ref |
|
|
219
234
|
|
|
220
235
|
### Snippet signatures
|
|
221
236
|
|
|
222
|
-
| Snippet
|
|
223
|
-
|
|
|
224
|
-
| `cell`
|
|
225
|
-
| `row`
|
|
226
|
-
| `mobileRow`
|
|
227
|
-
| `batchActions`
|
|
228
|
-
| `selectAllBanner`
|
|
229
|
-
| `empty`
|
|
237
|
+
| Snippet | Props |
|
|
238
|
+
| ----------------- | ----------------------------------------------------------------------------------------------- |
|
|
239
|
+
| `cell` | `{ column, row, value, rowIndex, variant: "desktop" \| "mobile" }` |
|
|
240
|
+
| `row` | `{ row, columns, rowIndex, isSelected }` — desktop only |
|
|
241
|
+
| `mobileRow` | `{ row, columns, rowIndex }` — mobile only |
|
|
242
|
+
| `batchActions` | `{ selected, selectedRows, selectedAll, excluded, effectiveCount, totalCount, clearSelection }` |
|
|
243
|
+
| `selectAllBanner` | `{ selectedAll, effectiveCount, totalCount, pageCount, selectAll, clearSelection }` |
|
|
244
|
+
| `empty` | — |
|
|
230
245
|
|
|
231
246
|
> **Note:** "Select all rows" affects only the rows currently in `data` (i.e. the current page when using external paging). Rows for which `selectDisabledBy` returns `true` are excluded from "select all". To select across pages, enable `allowSelectAllPages` and use the banner that appears.
|
|
232
247
|
>
|
|
@@ -247,29 +262,29 @@ Replace the entire `<tr>` on desktop. When this snippet is provided, DataTable d
|
|
|
247
262
|
|
|
248
263
|
## CSS Variables
|
|
249
264
|
|
|
250
|
-
| Variable
|
|
251
|
-
|
|
|
252
|
-
| `--stuic-data-table-radius`
|
|
253
|
-
| `--stuic-data-table-border-color`
|
|
254
|
-
| `--stuic-data-table-header-bg`
|
|
255
|
-
| `--stuic-data-table-header-color`
|
|
256
|
-
| `--stuic-data-table-header-font-size`
|
|
257
|
-
| `--stuic-data-table-header-font-weight`
|
|
258
|
-
| `--stuic-data-table-header-padding-x`
|
|
259
|
-
| `--stuic-data-table-header-padding-y`
|
|
260
|
-
| `--stuic-data-table-row-bg`
|
|
261
|
-
| `--stuic-data-table-row-bg-hover`
|
|
262
|
-
| `--stuic-data-table-row-bg-selected`
|
|
263
|
-
| `--stuic-data-table-row-border-color`
|
|
264
|
-
| `--stuic-data-table-cell-padding-x`
|
|
265
|
-
| `--stuic-data-table-cell-padding-y`
|
|
266
|
-
| `--stuic-data-table-cell-font-size`
|
|
267
|
-
| `--stuic-data-table-loading-opacity`
|
|
268
|
-
| `--stuic-data-table-card-bg`
|
|
269
|
-
| `--stuic-data-table-card-border-color`
|
|
270
|
-
| `--stuic-data-table-card-radius`
|
|
271
|
-
| `--stuic-data-table-card-padding`
|
|
272
|
-
| `--stuic-data-table-card-gap`
|
|
273
|
-
| `--stuic-data-table-select-all-bg`
|
|
274
|
-
| `--stuic-data-table-select-all-padding-x` | `0.75rem`
|
|
275
|
-
| `--stuic-data-table-select-all-padding-y` | `0.5rem`
|
|
265
|
+
| Variable | Default | Description |
|
|
266
|
+
| ----------------------------------------- | ------------------------------------- | ---------------------------- |
|
|
267
|
+
| `--stuic-data-table-radius` | `var(--radius-md)` | Border radius |
|
|
268
|
+
| `--stuic-data-table-border-color` | `var(--stuic-color-border)` | Border color |
|
|
269
|
+
| `--stuic-data-table-header-bg` | `var(--stuic-color-muted)` | Header background |
|
|
270
|
+
| `--stuic-data-table-header-color` | `var(--stuic-color-muted-foreground)` | Header text |
|
|
271
|
+
| `--stuic-data-table-header-font-size` | `0.875rem` | Header font size |
|
|
272
|
+
| `--stuic-data-table-header-font-weight` | `var(--font-weight-semibold)` | Header font weight |
|
|
273
|
+
| `--stuic-data-table-header-padding-x` | `0.75rem` | Header horizontal padding |
|
|
274
|
+
| `--stuic-data-table-header-padding-y` | `0.5rem` | Header vertical padding |
|
|
275
|
+
| `--stuic-data-table-row-bg` | `transparent` | Row background |
|
|
276
|
+
| `--stuic-data-table-row-bg-hover` | `var(--stuic-color-muted)` | Row hover background |
|
|
277
|
+
| `--stuic-data-table-row-bg-selected` | `color-mix(primary 10%)` | Selected row background |
|
|
278
|
+
| `--stuic-data-table-row-border-color` | `var(--stuic-color-border)` | Row border color |
|
|
279
|
+
| `--stuic-data-table-cell-padding-x` | `0.75rem` | Cell horizontal padding |
|
|
280
|
+
| `--stuic-data-table-cell-padding-y` | `0.75rem` | Cell vertical padding |
|
|
281
|
+
| `--stuic-data-table-cell-font-size` | `0.875rem` | Cell font size |
|
|
282
|
+
| `--stuic-data-table-loading-opacity` | `0.5` | Loading state opacity |
|
|
283
|
+
| `--stuic-data-table-card-bg` | `var(--stuic-color-background)` | Mobile card background |
|
|
284
|
+
| `--stuic-data-table-card-border-color` | `var(--stuic-color-border)` | Mobile card border |
|
|
285
|
+
| `--stuic-data-table-card-radius` | `var(--radius-md)` | Mobile card radius |
|
|
286
|
+
| `--stuic-data-table-card-padding` | `0.75rem` | Mobile card padding |
|
|
287
|
+
| `--stuic-data-table-card-gap` | `0.5rem` | Gap between mobile cards |
|
|
288
|
+
| `--stuic-data-table-select-all-bg` | `color-mix(primary 10%)` | Select-all banner background |
|
|
289
|
+
| `--stuic-data-table-select-all-padding-x` | `0.75rem` | Banner horizontal padding |
|
|
290
|
+
| `--stuic-data-table-select-all-padding-y` | `0.5rem` | Banner vertical padding |
|
|
@@ -835,7 +835,9 @@
|
|
|
835
835
|
<button
|
|
836
836
|
bind:this={triggerEl}
|
|
837
837
|
id={triggerId}
|
|
838
|
-
class={unstyled
|
|
838
|
+
class={unstyled
|
|
839
|
+
? classTrigger
|
|
840
|
+
: twMerge(DROPDOWN_MENU_TRIGGER_CLASSES, classTrigger)}
|
|
839
841
|
onclick={() => (isOpen = !isOpen)}
|
|
840
842
|
aria-haspopup="menu"
|
|
841
843
|
aria-expanded={isOpen}
|
|
@@ -858,7 +860,9 @@
|
|
|
858
860
|
{#if isOpen && !isSupported && showBackdrop}
|
|
859
861
|
<!-- svelte-ignore a11y_click_events_have_key_events -->
|
|
860
862
|
<div
|
|
861
|
-
class={unstyled
|
|
863
|
+
class={unstyled
|
|
864
|
+
? classBackdrop
|
|
865
|
+
: twMerge(DROPDOWN_MENU_BACKDROP_CLASSES, classBackdrop)}
|
|
862
866
|
onclick={() => {
|
|
863
867
|
if (closeOnClickOutside) {
|
|
864
868
|
isOpen = false;
|