@orochibraru/ui 1.0.0 → 1.0.1

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 (112) hide show
  1. package/README.md +84 -3
  2. package/dist/components/blocks/accent-toggle.svelte +7 -3
  3. package/dist/components/blocks/accent-toggle.svelte.d.ts +1 -1
  4. package/dist/components/blocks/bottom-nav.svelte +1 -1
  5. package/dist/components/blocks/command-palette.svelte +268 -0
  6. package/dist/components/blocks/command-palette.svelte.d.ts +37 -0
  7. package/dist/components/blocks/error-page.svelte +23 -7
  8. package/dist/components/blocks/error-page.svelte.d.ts +4 -0
  9. package/dist/components/blocks/fab.svelte +1 -1
  10. package/dist/components/blocks/install-prompt.svelte +14 -8
  11. package/dist/components/blocks/install-prompt.svelte.d.ts +2 -1
  12. package/dist/components/blocks/music-player/labelled-slider.svelte +3 -12
  13. package/dist/components/blocks/music-player/labelled-slider.svelte.d.ts +1 -2
  14. package/dist/components/blocks/music-player.svelte +13 -12
  15. package/dist/components/blocks/otp-field.svelte +77 -33
  16. package/dist/components/blocks/otp-field.svelte.d.ts +7 -0
  17. package/dist/components/blocks/password-input.svelte +56 -16
  18. package/dist/components/blocks/password-input.svelte.d.ts +3 -0
  19. package/dist/components/blocks/stepper/stepper-phone-header.svelte +93 -0
  20. package/dist/components/blocks/stepper/stepper-phone-header.svelte.d.ts +13 -0
  21. package/dist/components/blocks/stepper.svelte +175 -0
  22. package/dist/components/blocks/stepper.svelte.d.ts +30 -0
  23. package/dist/components/blocks/time-range-picker.svelte +229 -0
  24. package/dist/components/blocks/time-range-picker.svelte.d.ts +33 -0
  25. package/dist/components/blocks/time-series-chart/data-table.svelte +43 -0
  26. package/dist/components/blocks/time-series-chart/data-table.svelte.d.ts +15 -0
  27. package/dist/components/blocks/time-series-chart/legend.svelte +23 -0
  28. package/dist/components/blocks/time-series-chart/legend.svelte.d.ts +10 -0
  29. package/dist/components/blocks/time-series-chart/marks.svelte +118 -0
  30. package/dist/components/blocks/time-series-chart/marks.svelte.d.ts +29 -0
  31. package/dist/components/blocks/time-series-chart/messages.d.ts +13 -0
  32. package/dist/components/blocks/time-series-chart/messages.js +12 -0
  33. package/dist/components/blocks/time-series-chart/readout.svelte +44 -0
  34. package/dist/components/blocks/time-series-chart/readout.svelte.d.ts +15 -0
  35. package/dist/components/blocks/time-series-chart/scale.d.ts +24 -0
  36. package/dist/components/blocks/time-series-chart/scale.js +136 -0
  37. package/dist/components/blocks/time-series-chart/time.d.ts +7 -0
  38. package/dist/components/blocks/time-series-chart/time.js +96 -0
  39. package/dist/components/blocks/time-series-chart.svelte +492 -0
  40. package/dist/components/blocks/time-series-chart.svelte.d.ts +18 -0
  41. package/dist/components/blocks/top-loading-bar.svelte +1 -1
  42. package/dist/components/blocks/video-player/center-controls.svelte +7 -7
  43. package/dist/components/blocks/video-player/control-bar.svelte +41 -35
  44. package/dist/components/blocks/video-player/control-button.svelte +1 -1
  45. package/dist/components/blocks/video-player/option-menu.svelte +1 -1
  46. package/dist/components/blocks/video-player/scrub-bar.svelte +39 -12
  47. package/dist/components/blocks/video-player/scrub-bar.svelte.d.ts +2 -0
  48. package/dist/components/blocks/video-player.svelte +2 -2
  49. package/dist/components/kit/accordion.svelte +70 -0
  50. package/dist/components/kit/accordion.svelte.d.ts +37 -0
  51. package/dist/components/kit/avatar-group.svelte +84 -0
  52. package/dist/components/kit/avatar-group.svelte.d.ts +14 -0
  53. package/dist/components/kit/bar-list.svelte +104 -0
  54. package/dist/components/kit/bar-list.svelte.d.ts +22 -0
  55. package/dist/components/kit/breadcrumbs.svelte +102 -0
  56. package/dist/components/kit/breadcrumbs.svelte.d.ts +14 -0
  57. package/dist/components/kit/checkbox-list.svelte +98 -0
  58. package/dist/components/kit/checkbox-list.svelte.d.ts +15 -0
  59. package/dist/components/kit/checkbox.svelte +84 -0
  60. package/dist/components/kit/checkbox.svelte.d.ts +8 -0
  61. package/dist/components/kit/confirm-dialog.svelte +127 -0
  62. package/dist/components/kit/confirm-dialog.svelte.d.ts +19 -0
  63. package/dist/components/kit/data-table.svelte +280 -0
  64. package/dist/components/kit/data-table.svelte.d.ts +46 -0
  65. package/dist/components/kit/date-field.svelte +210 -0
  66. package/dist/components/kit/date-field.svelte.d.ts +14 -0
  67. package/dist/components/kit/field-frame.svelte +71 -0
  68. package/dist/components/kit/field-frame.svelte.d.ts +26 -0
  69. package/dist/components/kit/fieldset-frame.svelte +69 -0
  70. package/dist/components/kit/fieldset-frame.svelte.d.ts +14 -0
  71. package/dist/components/kit/file-dropzone/files.d.ts +14 -0
  72. package/dist/components/kit/file-dropzone/files.js +69 -0
  73. package/dist/components/kit/file-dropzone.svelte +253 -0
  74. package/dist/components/kit/file-dropzone.svelte.d.ts +25 -0
  75. package/dist/components/kit/form.svelte +335 -0
  76. package/dist/components/kit/form.svelte.d.ts +61 -0
  77. package/dist/components/kit/input.svelte +73 -0
  78. package/dist/components/kit/input.svelte.d.ts +9 -0
  79. package/dist/components/kit/menu.svelte +163 -0
  80. package/dist/components/kit/menu.svelte.d.ts +28 -0
  81. package/dist/components/kit/pagination.svelte +134 -0
  82. package/dist/components/kit/pagination.svelte.d.ts +17 -0
  83. package/dist/components/kit/radio-list.svelte +131 -0
  84. package/dist/components/kit/radio-list.svelte.d.ts +15 -0
  85. package/dist/components/kit/segmented-control/segment.svelte +47 -0
  86. package/dist/components/kit/segmented-control/segment.svelte.d.ts +11 -0
  87. package/dist/components/kit/segmented-control.svelte +70 -0
  88. package/dist/components/kit/segmented-control.svelte.d.ts +16 -0
  89. package/dist/components/kit/select.svelte +244 -0
  90. package/dist/components/kit/select.svelte.d.ts +26 -0
  91. package/dist/components/kit/status-badge.svelte +54 -0
  92. package/dist/components/kit/status-badge.svelte.d.ts +31 -0
  93. package/dist/components/kit/switch.svelte +84 -0
  94. package/dist/components/kit/switch.svelte.d.ts +8 -0
  95. package/dist/components/kit/tabs.svelte +86 -0
  96. package/dist/components/kit/tabs.svelte.d.ts +20 -0
  97. package/dist/components/kit/textarea.svelte +92 -0
  98. package/dist/components/kit/textarea.svelte.d.ts +11 -0
  99. package/dist/components/ui/drawer/drawer-content.svelte +1 -1
  100. package/dist/components/ui/input-group/input-group-input.svelte.d.ts +1 -1
  101. package/dist/components/ui/sidebar/sidebar-input.svelte.d.ts +1 -1
  102. package/dist/components/ui/sonner/sonner.svelte +2 -4
  103. package/dist/mcp-content.json +1 -1
  104. package/dist/mcp.js +11 -11
  105. package/dist/server/hooks.d.ts +9 -0
  106. package/dist/server/hooks.js +41 -0
  107. package/dist/server/logger.d.ts +39 -0
  108. package/dist/server/logger.js +144 -0
  109. package/dist/server/telemetry.d.ts +23 -0
  110. package/dist/server/telemetry.js +82 -0
  111. package/dist/theme.css +18 -6
  112. package/package.json +40 -1
@@ -0,0 +1,15 @@
1
+ import { type FieldProps } from "./field-frame.svelte";
2
+ interface Option {
3
+ value: string;
4
+ label: string;
5
+ description?: string;
6
+ disabled?: boolean;
7
+ }
8
+ type Props = FieldProps & {
9
+ options: readonly Option[];
10
+ value?: string[];
11
+ orientation?: "vertical" | "horizontal";
12
+ };
13
+ declare const CheckboxList: import("svelte").Component<Props, {}, "value">;
14
+ type CheckboxList = ReturnType<typeof CheckboxList>;
15
+ export default CheckboxList;
@@ -0,0 +1,84 @@
1
+ <script lang="ts">
2
+ import { Checkbox } from "../ui/checkbox/index.js";
3
+ import * as Field from "../ui/field/index.js";
4
+ import { cn } from "../../utils.js";
5
+
6
+ import { errorList, type FieldProps } from "./field-frame.svelte";
7
+
8
+ type Props = FieldProps & {
9
+ checked?: boolean;
10
+ };
11
+
12
+ let {
13
+ checked = $bindable(false),
14
+ name,
15
+ label,
16
+ description,
17
+ error,
18
+ required = false,
19
+ disabled = false,
20
+ id,
21
+ class: className,
22
+ }: Props = $props();
23
+
24
+ const generatedId = $props.id();
25
+ const checkboxId = $derived(id ?? generatedId);
26
+ const errors = $derived(errorList(error));
27
+ const invalid = $derived(errors.length > 0);
28
+ const describedBy = $derived(
29
+ invalid
30
+ ? `${checkboxId}-error`
31
+ : description
32
+ ? `${checkboxId}-description`
33
+ : undefined,
34
+ );
35
+ </script>
36
+
37
+ <div
38
+ class={cn("flex w-full flex-col", className)}
39
+ data-invalid={invalid || undefined}
40
+ >
41
+ <div
42
+ class="group/row relative flex min-h-11 items-start gap-3 py-2.5 has-disabled:opacity-50"
43
+ >
44
+ <Checkbox
45
+ id={checkboxId}
46
+ {name}
47
+ {required}
48
+ {disabled}
49
+ bind:checked
50
+ aria-invalid={invalid || undefined}
51
+ aria-describedby={describedBy}
52
+ class="z-10 size-5"
53
+ />
54
+ <span class="min-w-0 flex-1">
55
+ {#if label}
56
+ <label
57
+ for={checkboxId}
58
+ class={cn(
59
+ "block cursor-pointer text-sm leading-snug font-medium after:absolute after:inset-0 group-has-disabled/row:cursor-not-allowed",
60
+ invalid && "text-destructive",
61
+ )}
62
+ >
63
+ {label}
64
+ {#if required}
65
+ <span class="text-destructive" aria-hidden="true">*</span>
66
+ {/if}
67
+ </label>
68
+ {/if}
69
+ {#if description && !invalid}
70
+ <span
71
+ id="{checkboxId}-description"
72
+ class="text-muted-foreground mt-0.5 block text-sm">{description}</span
73
+ >
74
+ {/if}
75
+ </span>
76
+ </div>
77
+ {#if invalid}
78
+ <Field.Error
79
+ id="{checkboxId}-error"
80
+ class="pl-8"
81
+ errors={errors.map((message) => ({ message }))}
82
+ />
83
+ {/if}
84
+ </div>
@@ -0,0 +1,8 @@
1
+ import { Checkbox } from "../ui/checkbox/index.js";
2
+ import { type FieldProps } from "./field-frame.svelte";
3
+ type Props = FieldProps & {
4
+ checked?: boolean;
5
+ };
6
+ declare const Checkbox: import("svelte").Component<Props, {}, "checked">;
7
+ type Checkbox = ReturnType<typeof Checkbox>;
8
+ export default Checkbox;
@@ -0,0 +1,127 @@
1
+ <script lang="ts">
2
+ import type { Snippet } from "svelte";
3
+ import { MediaQuery } from "svelte/reactivity";
4
+
5
+ import * as AlertDialog from "../ui/alert-dialog/index.js";
6
+ import { Button } from "../ui/button/index.js";
7
+ import * as Drawer from "../ui/drawer/index.js";
8
+ import { Spinner } from "../ui/spinner/index.js";
9
+
10
+ const defaultMessages = {
11
+ confirm: "Confirm",
12
+ cancel: "Cancel",
13
+ working: "Working…",
14
+ };
15
+
16
+ interface Props {
17
+ open?: boolean;
18
+ title: string;
19
+ description?: string;
20
+ confirmLabel?: string;
21
+ cancelLabel?: string;
22
+ destructive?: boolean;
23
+ /** A returned promise keeps the dialog open with a spinner until it settles: it closes on success and stays open on rejection, so report the error yourself. */
24
+ onconfirm: () => unknown;
25
+ children?: Snippet;
26
+ messages?: Partial<typeof defaultMessages>;
27
+ }
28
+
29
+ let {
30
+ open = $bindable(false),
31
+ title,
32
+ description,
33
+ confirmLabel,
34
+ cancelLabel,
35
+ destructive = false,
36
+ onconfirm,
37
+ children,
38
+ messages = {},
39
+ }: Props = $props();
40
+
41
+ const desktop = new MediaQuery("(min-width: 768px)");
42
+ const text = $derived({ ...defaultMessages, ...messages });
43
+
44
+ let pending = $state(false);
45
+
46
+ function setOpen(next: boolean) {
47
+ if (!pending) {
48
+ open = next;
49
+ }
50
+ }
51
+
52
+ async function confirm() {
53
+ const result = onconfirm();
54
+ if (!(result instanceof Promise)) {
55
+ open = false;
56
+ return;
57
+ }
58
+ pending = true;
59
+ const succeeded = await result.then(
60
+ () => true,
61
+ () => false,
62
+ );
63
+ pending = false;
64
+ if (succeeded) {
65
+ open = false;
66
+ }
67
+ }
68
+ </script>
69
+
70
+ {#snippet actions()}
71
+ <Button
72
+ variant="outline"
73
+ class="h-11 rounded-xl md:h-9"
74
+ disabled={pending}
75
+ onclick={() => setOpen(false)}
76
+ >
77
+ {cancelLabel ?? text.cancel}
78
+ </Button>
79
+ <Button
80
+ variant={destructive ? "destructive" : "default"}
81
+ class="h-11 rounded-xl md:h-9"
82
+ disabled={pending}
83
+ aria-busy={pending || undefined}
84
+ onclick={confirm}
85
+ >
86
+ {#if pending}
87
+ <Spinner aria-label={text.working} />
88
+ {/if}
89
+ {confirmLabel ?? text.confirm}
90
+ </Button>
91
+ {/snippet}
92
+
93
+ {#if desktop.current}
94
+ <AlertDialog.Root bind:open={() => open, setOpen}>
95
+ <AlertDialog.Content>
96
+ <AlertDialog.Header>
97
+ <AlertDialog.Title>{title}</AlertDialog.Title>
98
+ {#if description}
99
+ <AlertDialog.Description>{description}</AlertDialog.Description>
100
+ {/if}
101
+ </AlertDialog.Header>
102
+ {#if children}
103
+ <div class="grid gap-3">{@render children()}</div>
104
+ {/if}
105
+ <AlertDialog.Footer>
106
+ {@render actions()}
107
+ </AlertDialog.Footer>
108
+ </AlertDialog.Content>
109
+ </AlertDialog.Root>
110
+ {:else}
111
+ <Drawer.Root bind:open={() => open, setOpen} dismissible={!pending}>
112
+ <Drawer.Content>
113
+ <Drawer.Header class="px-5 text-left">
114
+ <Drawer.Title>{title}</Drawer.Title>
115
+ {#if description}
116
+ <Drawer.Description>{description}</Drawer.Description>
117
+ {/if}
118
+ </Drawer.Header>
119
+ {#if children}
120
+ <div class="grid gap-3 px-5">{@render children()}</div>
121
+ {/if}
122
+ <div class="flex flex-col-reverse gap-2 px-5 pt-4 pb-4">
123
+ {@render actions()}
124
+ </div>
125
+ </Drawer.Content>
126
+ </Drawer.Root>
127
+ {/if}
@@ -0,0 +1,19 @@
1
+ import type { Snippet } from "svelte";
2
+ declare const ConfirmDialog: import("svelte").Component<{
3
+ open?: boolean;
4
+ title: string;
5
+ description?: string;
6
+ confirmLabel?: string;
7
+ cancelLabel?: string;
8
+ destructive?: boolean;
9
+ /** A returned promise keeps the dialog open with a spinner until it settles: it closes on success and stays open on rejection, so report the error yourself. */
10
+ onconfirm: () => unknown;
11
+ children?: Snippet;
12
+ messages?: Partial<{
13
+ confirm: string;
14
+ cancel: string;
15
+ working: string;
16
+ }>;
17
+ }, {}, "open">;
18
+ type ConfirmDialog = ReturnType<typeof ConfirmDialog>;
19
+ export default ConfirmDialog;
@@ -0,0 +1,280 @@
1
+ <script lang="ts" module>
2
+ export type DataTableColumn<Row extends object> = {
3
+ [Key in keyof Row & string]: {
4
+ key: Key;
5
+ label: string;
6
+ align?: "left" | "center" | "right";
7
+ format?: (value: Row[Key], row: Row) => string;
8
+ sortable?: boolean;
9
+ hideOnMobile?: boolean;
10
+ };
11
+ }[keyof Row & string];
12
+
13
+ function isMissing(value: unknown): boolean {
14
+ return value === null || value === undefined;
15
+ }
16
+
17
+ function compareValues(left: unknown, right: unknown): number {
18
+ if (typeof left === "number" && typeof right === "number") {
19
+ return left - right;
20
+ }
21
+ if (left instanceof Date && right instanceof Date) {
22
+ return left.getTime() - right.getTime();
23
+ }
24
+ return String(left).localeCompare(String(right), undefined, {
25
+ numeric: true,
26
+ });
27
+ }
28
+ </script>
29
+
30
+ <script lang="ts" generics="Row extends object">
31
+ import ArrowDownIcon from "@lucide/svelte/icons/arrow-down";
32
+ import ArrowUpIcon from "@lucide/svelte/icons/arrow-up";
33
+ import ChevronsUpDownIcon from "@lucide/svelte/icons/chevrons-up-down";
34
+ import type { Snippet } from "svelte";
35
+
36
+ import { Skeleton } from "../ui/skeleton/index.js";
37
+ import * as Table from "../ui/table/index.js";
38
+ import { cn } from "../../utils.js";
39
+
40
+ const defaultMessages = {
41
+ empty: "Nothing here yet.",
42
+ };
43
+
44
+ interface Props {
45
+ columns: DataTableColumn<Row>[];
46
+ rows: Row[];
47
+ cell?: Snippet<[Row, DataTableColumn<Row>, string]>;
48
+ rowHref?: (row: Row) => string;
49
+ onrowclick?: (row: Row) => void;
50
+ loading?: boolean;
51
+ messages?: Partial<typeof defaultMessages>;
52
+ class?: string;
53
+ }
54
+
55
+ const {
56
+ columns,
57
+ rows,
58
+ cell,
59
+ rowHref,
60
+ onrowclick,
61
+ loading = false,
62
+ messages = {},
63
+ class: className,
64
+ }: Props = $props();
65
+
66
+ const text = $derived({ ...defaultMessages, ...messages });
67
+ const interactive = $derived(Boolean(rowHref || onrowclick));
68
+ const firstColumn = $derived(columns[0]);
69
+ const detailColumns = $derived(
70
+ columns.slice(1).filter((column) => !column.hideOnMobile),
71
+ );
72
+ const placeholders = [0, 1, 2, 3, 4];
73
+ const alignment = {
74
+ left: "text-left",
75
+ center: "text-center",
76
+ right: "text-right",
77
+ };
78
+ const raisedControls =
79
+ "[&_a]:relative [&_a]:z-10 [&_button]:relative [&_button]:z-10";
80
+
81
+ let sortKey = $state<keyof Row & string>();
82
+ let descending = $state(false);
83
+
84
+ const sortedRows = $derived.by(() => {
85
+ const key = sortKey;
86
+ if (key === undefined) {
87
+ return rows;
88
+ }
89
+ return rows.toSorted((left, right) => {
90
+ const leftValue = left[key];
91
+ const rightValue = right[key];
92
+ if (isMissing(leftValue) || isMissing(rightValue)) {
93
+ return Number(isMissing(leftValue)) - Number(isMissing(rightValue));
94
+ }
95
+ const order = compareValues(leftValue, rightValue);
96
+ return descending ? -order : order;
97
+ });
98
+ });
99
+
100
+ function toggleSort(key: keyof Row & string) {
101
+ if (sortKey === key) {
102
+ descending = !descending;
103
+ return;
104
+ }
105
+ sortKey = key;
106
+ descending = false;
107
+ }
108
+
109
+ function display(row: Row, column: DataTableColumn<Row>): string {
110
+ const value = row[column.key];
111
+ const format = column.format as
112
+ ((value: unknown, row: Row) => string) | undefined;
113
+ if (format) {
114
+ return format(value, row);
115
+ }
116
+ return isMissing(value) ? "–" : String(value);
117
+ }
118
+
119
+ function ariaSort(column: DataTableColumn<Row>) {
120
+ if (!column.sortable || sortKey !== column.key) {
121
+ return undefined;
122
+ }
123
+ return descending ? "descending" : "ascending";
124
+ }
125
+ </script>
126
+
127
+ {#snippet content(row: Row, column: DataTableColumn<Row>)}
128
+ {#if cell}
129
+ {@render cell(row, column, display(row, column))}
130
+ {:else}
131
+ {display(row, column)}
132
+ {/if}
133
+ {/snippet}
134
+
135
+ {#snippet primary(row: Row, column: DataTableColumn<Row>)}
136
+ {#if rowHref}
137
+ <a
138
+ href={rowHref(row)}
139
+ class="font-medium outline-none after:absolute after:inset-0 after:rounded-[inherit] focus-visible:after:ring-3 focus-visible:after:ring-ring/50"
140
+ >
141
+ {@render content(row, column)}
142
+ </a>
143
+ {:else if onrowclick}
144
+ <button
145
+ type="button"
146
+ onclick={() => onrowclick(row)}
147
+ class="text-left font-medium outline-none after:absolute after:inset-0 after:rounded-[inherit] focus-visible:after:ring-3 focus-visible:after:ring-ring/50"
148
+ >
149
+ {@render content(row, column)}
150
+ </button>
151
+ {:else}
152
+ <span class="font-medium">{@render content(row, column)}</span>
153
+ {/if}
154
+ {/snippet}
155
+
156
+ {#if !loading && rows.length === 0}
157
+ <p
158
+ class={cn(
159
+ "glass text-muted-foreground w-full rounded-2xl px-4 py-10 text-center text-sm",
160
+ className,
161
+ )}
162
+ >
163
+ {text.empty}
164
+ </p>
165
+ {:else}
166
+ <div class={cn("w-full", className)} aria-busy={loading || undefined}>
167
+ <div class="glass hidden overflow-hidden rounded-2xl md:block">
168
+ <Table.Root>
169
+ <Table.Header>
170
+ <Table.Row class="hover:bg-transparent">
171
+ {#each columns as column, index (index)}
172
+ <Table.Head
173
+ aria-sort={ariaSort(column)}
174
+ class={cn(
175
+ "text-muted-foreground h-11 px-4 text-xs",
176
+ alignment[column.align ?? "left"],
177
+ )}
178
+ >
179
+ {#if column.sortable}
180
+ <button
181
+ type="button"
182
+ onclick={() => toggleSort(column.key)}
183
+ class="hover:text-foreground focus-visible:ring-ring/50 inline-flex items-center gap-1 rounded-sm font-medium outline-none focus-visible:ring-3"
184
+ >
185
+ {column.label}
186
+ {#if sortKey !== column.key}
187
+ <ChevronsUpDownIcon class="size-3.5 opacity-50" />
188
+ {:else if descending}
189
+ <ArrowDownIcon class="size-3.5" />
190
+ {:else}
191
+ <ArrowUpIcon class="size-3.5" />
192
+ {/if}
193
+ </button>
194
+ {:else}
195
+ {column.label}
196
+ {/if}
197
+ </Table.Head>
198
+ {/each}
199
+ </Table.Row>
200
+ </Table.Header>
201
+ <Table.Body>
202
+ {#if loading}
203
+ {#each placeholders as placeholder (placeholder)}
204
+ <Table.Row class="hover:bg-transparent">
205
+ {#each columns as column, index (index)}
206
+ <Table.Cell class="px-4 py-3">
207
+ <Skeleton class="h-4 w-full" />
208
+ </Table.Cell>
209
+ {/each}
210
+ </Table.Row>
211
+ {/each}
212
+ {:else}
213
+ {#each sortedRows as row, rowIndex (rowIndex)}
214
+ <Table.Row
215
+ class={cn(
216
+ "relative",
217
+ interactive ? "cursor-pointer" : "hover:bg-transparent",
218
+ )}
219
+ >
220
+ {#each columns as column, index (index)}
221
+ <Table.Cell
222
+ class={cn(
223
+ "tabular px-4 py-3",
224
+ alignment[column.align ?? "left"],
225
+ index > 0 && raisedControls,
226
+ )}
227
+ >
228
+ {#if index === 0}
229
+ {@render primary(row, column)}
230
+ {:else}
231
+ {@render content(row, column)}
232
+ {/if}
233
+ </Table.Cell>
234
+ {/each}
235
+ </Table.Row>
236
+ {/each}
237
+ {/if}
238
+ </Table.Body>
239
+ </Table.Root>
240
+ </div>
241
+
242
+ <ul class="flex flex-col gap-3 md:hidden">
243
+ {#if loading}
244
+ {#each placeholders as placeholder (placeholder)}
245
+ <li class="glass flex flex-col gap-3 rounded-2xl p-4">
246
+ <Skeleton class="h-5 w-1/2" />
247
+ <Skeleton class="h-4 w-full" />
248
+ </li>
249
+ {/each}
250
+ {:else if firstColumn}
251
+ {#each sortedRows as row, rowIndex (rowIndex)}
252
+ <li class="glass relative flex flex-col gap-2 rounded-2xl p-4">
253
+ <div class="min-w-0 wrap-break-word">
254
+ {@render primary(row, firstColumn)}
255
+ </div>
256
+ {#if detailColumns.length > 0}
257
+ <dl class="flex flex-col gap-1.5 text-sm">
258
+ {#each detailColumns as column, index (index)}
259
+ <div class="flex items-baseline justify-between gap-4">
260
+ <dt class="text-muted-foreground shrink-0">
261
+ {column.label}
262
+ </dt>
263
+ <dd
264
+ class={cn(
265
+ "tabular min-w-0 text-right wrap-break-word",
266
+ raisedControls,
267
+ )}
268
+ >
269
+ {@render content(row, column)}
270
+ </dd>
271
+ </div>
272
+ {/each}
273
+ </dl>
274
+ {/if}
275
+ </li>
276
+ {/each}
277
+ {/if}
278
+ </ul>
279
+ </div>
280
+ {/if}
@@ -0,0 +1,46 @@
1
+ export type DataTableColumn<Row extends object> = {
2
+ [Key in keyof Row & string]: {
3
+ key: Key;
4
+ label: string;
5
+ align?: "left" | "center" | "right";
6
+ format?: (value: Row[Key], row: Row) => string;
7
+ sortable?: boolean;
8
+ hideOnMobile?: boolean;
9
+ };
10
+ }[keyof Row & string];
11
+ import type { Snippet } from "svelte";
12
+ declare function $$render<Row extends object>(): {
13
+ props: {
14
+ columns: DataTableColumn<Row>[];
15
+ rows: Row[];
16
+ cell?: Snippet<[Row, DataTableColumn<Row>, string]>;
17
+ rowHref?: (row: Row) => string;
18
+ onrowclick?: (row: Row) => void;
19
+ loading?: boolean;
20
+ messages?: Partial<{
21
+ empty: string;
22
+ }>;
23
+ class?: string;
24
+ };
25
+ exports: {};
26
+ bindings: "";
27
+ slots: {};
28
+ events: {};
29
+ };
30
+ declare class __sveltets_Render<Row extends object> {
31
+ props(): ReturnType<typeof $$render<Row>>['props'];
32
+ events(): ReturnType<typeof $$render<Row>>['events'];
33
+ slots(): ReturnType<typeof $$render<Row>>['slots'];
34
+ bindings(): "";
35
+ exports(): {};
36
+ }
37
+ interface $$IsomorphicComponent {
38
+ new <Row extends object>(options: import('svelte').ComponentConstructorOptions<ReturnType<__sveltets_Render<Row>['props']>>): import('svelte').SvelteComponent<ReturnType<__sveltets_Render<Row>['props']>, ReturnType<__sveltets_Render<Row>['events']>, ReturnType<__sveltets_Render<Row>['slots']>> & {
39
+ $$bindings?: ReturnType<__sveltets_Render<Row>['bindings']>;
40
+ } & ReturnType<__sveltets_Render<Row>['exports']>;
41
+ <Row extends object>(internal: unknown, props: ReturnType<__sveltets_Render<Row>['props']> & {}): ReturnType<__sveltets_Render<Row>['exports']>;
42
+ z_$$bindings?: ReturnType<__sveltets_Render<any>['bindings']>;
43
+ }
44
+ declare const DataTable: $$IsomorphicComponent;
45
+ type DataTable<Row extends object> = InstanceType<typeof DataTable<Row>>;
46
+ export default DataTable;