@r2digisolutions/ui 0.21.3 → 0.22.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 (36) hide show
  1. package/dist/components/container/DataTable/DataTable.svelte +380 -0
  2. package/dist/components/container/DataTable/DataTable.svelte.d.ts +51 -0
  3. package/dist/components/container/DataTable/components/Cell.svelte +90 -0
  4. package/dist/components/container/DataTable/components/Cell.svelte.d.ts +30 -0
  5. package/dist/components/container/DataTable/components/ColumnVisibilityToggle.svelte +118 -0
  6. package/dist/components/container/DataTable/components/ColumnVisibilityToggle.svelte.d.ts +10 -0
  7. package/dist/components/container/DataTable/components/ContextMenu.svelte +203 -0
  8. package/dist/components/container/DataTable/components/ContextMenu.svelte.d.ts +21 -0
  9. package/dist/components/container/DataTable/components/FilterPanel.svelte +195 -0
  10. package/dist/components/container/DataTable/components/FilterPanel.svelte.d.ts +10 -0
  11. package/dist/components/container/DataTable/components/Pagination.svelte +59 -0
  12. package/dist/components/container/DataTable/components/Pagination.svelte.d.ts +11 -0
  13. package/dist/components/container/DataTable/components/QuickFilters.svelte +38 -0
  14. package/dist/components/container/DataTable/components/QuickFilters.svelte.d.ts +8 -0
  15. package/dist/components/container/DataTable/core/DataTableManager.svelte.d.ts +39 -0
  16. package/dist/components/container/DataTable/core/DataTableManager.svelte.js +245 -0
  17. package/dist/components/container/DataTable/core/filters/types.d.ts +18 -0
  18. package/dist/components/container/DataTable/core/filters/types.js +1 -0
  19. package/dist/components/container/DataTable/core/filters/utils.d.ts +3 -0
  20. package/dist/components/container/DataTable/core/filters/utils.js +43 -0
  21. package/dist/components/container/DataTable/core/types.d.ts +101 -0
  22. package/dist/components/container/DataTable/core/types.js +1 -0
  23. package/dist/components/container/DataTable/core/utils.d.ts +5 -0
  24. package/dist/components/container/DataTable/core/utils.js +66 -0
  25. package/dist/components/container/index.d.ts +2 -0
  26. package/dist/components/container/index.js +2 -0
  27. package/dist/components/ui/Card/Card.svelte +8 -8
  28. package/dist/components/ui/Card/CardContent.svelte +11 -3
  29. package/dist/components/ui/Card/CardContent.svelte.d.ts +8 -10
  30. package/dist/components/ui/Card/CardFooter.svelte +12 -2
  31. package/dist/components/ui/Card/CardFooter.svelte.d.ts +7 -3
  32. package/dist/components/ui/Card/CardHeader.svelte +10 -2
  33. package/dist/components/ui/Card/CardHeader.svelte.d.ts +7 -3
  34. package/dist/index.d.ts +1 -0
  35. package/dist/index.js +1 -0
  36. package/package.json +27 -27
@@ -0,0 +1,245 @@
1
+ import { SvelteSet } from 'svelte/reactivity';
2
+ import { normalize, defaultAccessor, compareValues, applyFilterOp } from './utils.js';
3
+ export class DataTableManager {
4
+ options = $state({
5
+ perPage: 10,
6
+ perPageOptions: [10, 20, 50, 100],
7
+ multiSelect: true,
8
+ columns: [],
9
+ loadMode: 'local',
10
+ data: [],
11
+ });
12
+ state = $state({
13
+ ready: false,
14
+ items: [],
15
+ page: 1,
16
+ perPage: this.options.perPage,
17
+ total: 0,
18
+ sortBy: null,
19
+ sortDir: null,
20
+ filters: [],
21
+ visibleColumns: [],
22
+ hiddenColumns: [],
23
+ selected: new SvelteSet(),
24
+ loading: false,
25
+ error: undefined
26
+ });
27
+ measured = $state({});
28
+ reservedWidth = $state(0);
29
+ forcedVisible = new SvelteSet();
30
+ forcedHidden = new SvelteSet();
31
+ expanded = new SvelteSet();
32
+ lastWidth = $state(null);
33
+ constructor(opts) {
34
+ const columns = normalize(opts.columns);
35
+ this.options = ({
36
+ ...opts,
37
+ columns
38
+ });
39
+ this.state = ({
40
+ ...this.state,
41
+ perPage: this.options.perPage,
42
+ sortBy: opts.initialSortBy ?? null,
43
+ sortDir: opts.initialSortDir ?? null,
44
+ filters: opts.initialFilters ?? [],
45
+ visibleColumns: columns.map((c) => c.id),
46
+ });
47
+ }
48
+ setMeasuredWidths(map) {
49
+ this.measured = map;
50
+ this.reflow();
51
+ }
52
+ get columns() { return this.options.columns; }
53
+ getColumn(id) { return this.columns.find((c) => c.id === id); }
54
+ isExpanded(id) { return this.expanded.has(id); }
55
+ toggleExpand(id) { this.isExpanded(id) ? this.expanded.delete(id) : this.expanded.add(id); }
56
+ setColumnVisibility(id, show) {
57
+ if (show) {
58
+ this.forcedVisible.add(id);
59
+ this.forcedHidden.delete(id);
60
+ }
61
+ else {
62
+ this.forcedHidden.add(id);
63
+ this.forcedVisible.delete(id);
64
+ }
65
+ this.reflow();
66
+ }
67
+ setReservedWidth(n) {
68
+ if (this.reservedWidth === n)
69
+ return;
70
+ this.reservedWidth = n;
71
+ this.reflow();
72
+ }
73
+ clearColumnOverrides() {
74
+ this.forcedVisible.clear();
75
+ this.forcedHidden.clear();
76
+ this.reflow();
77
+ }
78
+ visibilityPlan(containerWidth) {
79
+ const available = Math.max(0, Math.floor(containerWidth) - (this.reservedWidth ?? 0));
80
+ const cols = this.columns;
81
+ const origOrder = cols.map((c) => c.id);
82
+ const needOf = (id) => {
83
+ const c = this.getColumn(id);
84
+ const measured = this.measured[id];
85
+ const fallback = Math.max(c.minWidth ?? 0, c.width ?? 0, 160);
86
+ return Math.ceil(measured ?? fallback);
87
+ };
88
+ // columnas que siempre se ocultan en móvil, aunque quepan
89
+ const mustHide = new Set();
90
+ if (available < 640) {
91
+ for (const c of cols)
92
+ if (c.hideOnMobile)
93
+ mustHide.add(c.id);
94
+ }
95
+ // empezamos conservando el orden original
96
+ let visible = origOrder.filter((id) => !mustHide.has(id));
97
+ const totalNeed = () => visible.reduce((sum, id) => sum + needOf(id), 0);
98
+ if (totalNeed() > available) {
99
+ // hay que ocultar: orden de descarte por prioridad (más alta => se quita antes)
100
+ // empate: quitamos antes las columnas que están más a la derecha (idx más alto)
101
+ const dropOrder = cols
102
+ .map((c, idx) => ({ id: c.id, pr: c.priority ?? 999, idx }))
103
+ .filter((x) => !mustHide.has(x.id))
104
+ .sort((a, b) => (b.pr - a.pr) || (b.idx - a.idx));
105
+ const hidden = new Set([...mustHide]);
106
+ for (const d of dropOrder) {
107
+ if (totalNeed() <= available)
108
+ break;
109
+ const k = visible.indexOf(d.id);
110
+ if (k !== -1) {
111
+ visible.splice(k, 1);
112
+ hidden.add(d.id);
113
+ }
114
+ }
115
+ // overrides manuales
116
+ const visSet = new Set(visible);
117
+ for (const id of this.forcedHidden)
118
+ visSet.delete(id);
119
+ for (const id of this.forcedVisible)
120
+ if (!mustHide.has(id))
121
+ visSet.add(id);
122
+ const finalVisible = origOrder.filter((id) => visSet.has(id) && !mustHide.has(id));
123
+ const finalHidden = origOrder.filter((id) => !finalVisible.includes(id));
124
+ return { visible: finalVisible, hidden: finalHidden };
125
+ }
126
+ // TODO cabe: respetamos tu orden original
127
+ const visSet = new Set(visible);
128
+ for (const id of this.forcedHidden)
129
+ visSet.delete(id);
130
+ for (const id of this.forcedVisible)
131
+ if (!mustHide.has(id))
132
+ visSet.add(id);
133
+ const finalVisible = origOrder.filter((id) => visSet.has(id) && !mustHide.has(id));
134
+ const finalHidden = origOrder.filter((id) => !finalVisible.includes(id));
135
+ return { visible: finalVisible, hidden: finalHidden };
136
+ }
137
+ mergeWithOverrides(plan) {
138
+ const vis = new Set(plan.visible);
139
+ const hid = new Set(plan.hidden);
140
+ for (const id of this.forcedVisible) {
141
+ vis.add(id);
142
+ hid.delete(id);
143
+ }
144
+ for (const id of this.forcedHidden) {
145
+ hid.add(id);
146
+ vis.delete(id);
147
+ }
148
+ return { visible: [...vis], hidden: [...hid] };
149
+ }
150
+ applyVisibility(plan) {
151
+ this.state.visibleColumns = plan.visible;
152
+ this.state.hiddenColumns = plan.hidden;
153
+ }
154
+ // NUEVO: para usar desde el ResizeObserver
155
+ reflowForWidth(width) {
156
+ this.lastWidth = width;
157
+ const base = this.visibilityPlan(width);
158
+ this.applyVisibility(this.mergeWithOverrides(base));
159
+ }
160
+ // NUEVO: reflow con el último ancho conocido (o infinito si no hay)
161
+ reflow() {
162
+ const width = this.lastWidth ?? Number.POSITIVE_INFINITY;
163
+ const base = this.visibilityPlan(width);
164
+ this.applyVisibility(this.mergeWithOverrides(base));
165
+ }
166
+ // Selección / paginación / sort / filtros (sin cambios relevantes)
167
+ setPerPage(n) { this.state.perPage = n; this.state.page = 1; return this.load(); }
168
+ setPage(p) { this.state.page = p; return this.load(); }
169
+ setSort(id) {
170
+ if (this.state.sortBy !== id) {
171
+ this.state.sortBy = id;
172
+ this.state.sortDir = 'asc';
173
+ }
174
+ else {
175
+ this.state.sortDir = this.state.sortDir === 'asc' ? 'desc' : (this.state.sortDir === 'desc' ? null : 'asc');
176
+ }
177
+ this.state.page = 1;
178
+ return this.load();
179
+ }
180
+ setFilters(filters) { this.state.filters = filters; this.state.page = 1; return this.load(); }
181
+ clearFilters() { this.state.filters = []; this.state.page = 1; return this.load(); }
182
+ toggleSelect(rowId) { const s = this.state.selected; s.has(rowId) ? s.delete(rowId) : s.add(rowId); }
183
+ clearSelection() { this.state.selected.clear(); }
184
+ selectAllCurrentPage(getId = (r) => r.id) { this.state.items.forEach((r) => this.state.selected.add(getId(r))); }
185
+ async load() {
186
+ const { loadMode } = this.options;
187
+ this.state.loading = true;
188
+ this.state.error = undefined;
189
+ try {
190
+ if (loadMode === 'local')
191
+ return await this.loadLocal();
192
+ else
193
+ return await this.loadRemote();
194
+ }
195
+ catch (e) {
196
+ this.state.error = e?.message ?? 'Error al cargar';
197
+ }
198
+ finally {
199
+ this.state.loading = false;
200
+ this.state.ready = true;
201
+ }
202
+ this.reflow(); // asegura visibilidad coherente tras cargar
203
+ }
204
+ async loadRemote() {
205
+ const { fetcher } = this.options;
206
+ if (!fetcher)
207
+ throw new Error('fetcher requerido para modo remoto/cursor');
208
+ const params = {
209
+ page: this.state.page,
210
+ perPage: this.state.perPage,
211
+ cursor: this.state.cursor,
212
+ sortBy: this.state.sortBy,
213
+ sortDir: this.state.sortDir,
214
+ filters: this.state.filters
215
+ };
216
+ const res = await fetcher(params);
217
+ this.state.items = res.items;
218
+ this.state.total = res.total;
219
+ this.state.cursor = res.nextCursor;
220
+ }
221
+ async loadLocal() {
222
+ const data = this.options.data ?? [];
223
+ let rows = [...data];
224
+ for (const f of this.state.filters) {
225
+ const col = f.columnId ? this.getColumn(f.columnId) : undefined;
226
+ rows = rows.filter((r) => {
227
+ const value = col ? (col.accessor ? col.accessor(r) : r[col.id]) : r;
228
+ return applyFilterOp(value, f.op, f.value);
229
+ });
230
+ }
231
+ if (this.state.sortBy && this.state.sortDir) {
232
+ const col = this.getColumn(this.state.sortBy);
233
+ rows.sort((a, b) => {
234
+ const va = col.accessor ? col.accessor(a) : defaultAccessor(a, col.id);
235
+ const vb = col.accessor ? col.accessor(b) : defaultAccessor(b, col.id);
236
+ const cmp = compareValues(va, vb);
237
+ return this.state.sortDir === 'asc' ? cmp : -cmp;
238
+ });
239
+ }
240
+ const start = (this.state.page - 1) * this.state.perPage;
241
+ const end = start + this.state.perPage;
242
+ this.state.total = rows.length;
243
+ this.state.items = rows.slice(start, end);
244
+ }
245
+ }
@@ -0,0 +1,18 @@
1
+ import type { FilterOp } from "../types.js";
2
+ export type FilterInputType = 'text' | 'select' | 'number' | 'range' | 'checkbox' | 'multiselect' | 'date' | 'rating';
3
+ export type SelectOption = {
4
+ label: string;
5
+ value: any;
6
+ };
7
+ export type FilterField<T> = {
8
+ id: string;
9
+ label: string;
10
+ type: FilterInputType;
11
+ columnId?: string;
12
+ options?: SelectOption[];
13
+ op?: FilterOp;
14
+ placeholder?: string;
15
+ min?: number;
16
+ max?: number;
17
+ step?: number;
18
+ };
@@ -0,0 +1,3 @@
1
+ import type { FilterDef } from "../types.js";
2
+ import type { FilterField } from "./types.js";
3
+ export declare function buildFilterDefs<T>(fields: FilterField<T>[], values: Record<string, any>): FilterDef<T>[];
@@ -0,0 +1,43 @@
1
+ export function buildFilterDefs(fields, values) {
2
+ const defs = [];
3
+ for (const f of fields) {
4
+ const v = values[f.id];
5
+ if (v == null || v === '' || (Array.isArray(v) && v.length === 0))
6
+ continue;
7
+ if (f.type === 'range') {
8
+ const { min, max } = (v ?? {});
9
+ if (min != null)
10
+ defs.push({ id: `${f.id}_min`, label: f.label, columnId: f.columnId, op: 'gte', value: min, meta: { field: f.id, part: 'min' } });
11
+ if (max != null)
12
+ defs.push({ id: `${f.id}_max`, label: f.label, columnId: f.columnId, op: 'lte', value: max, meta: { field: f.id, part: 'max' } });
13
+ continue;
14
+ }
15
+ switch (f.type) {
16
+ case 'text':
17
+ defs.push({ id: f.id, label: f.label, columnId: f.columnId, op: f.op ?? 'contains', value: String(v) });
18
+ break;
19
+ case 'number':
20
+ defs.push({ id: f.id, label: f.label, columnId: f.columnId, op: f.op ?? 'equals', value: Number(v) });
21
+ break;
22
+ case 'date':
23
+ defs.push({ id: f.id, label: f.label, columnId: f.columnId, op: f.op ?? 'equals', value: v });
24
+ break;
25
+ case 'checkbox':
26
+ if (v === true)
27
+ defs.push({ id: f.id, label: f.label, columnId: f.columnId, op: f.op ?? 'equals', value: true });
28
+ break;
29
+ case 'select':
30
+ defs.push({ id: f.id, label: f.label, columnId: f.columnId, op: f.op ?? 'equals', value: v });
31
+ break;
32
+ case 'multiselect':
33
+ defs.push({ id: f.id, label: f.label, columnId: f.columnId, op: f.op ?? 'in', value: Array.isArray(v) ? v : [v] });
34
+ break;
35
+ case 'rating':
36
+ defs.push({ id: f.id, label: f.label, columnId: f.columnId, op: f.op ?? 'gte', value: Number(v) });
37
+ break;
38
+ default:
39
+ break;
40
+ }
41
+ }
42
+ return defs;
43
+ }
@@ -0,0 +1,101 @@
1
+ export type RowId = string | number;
2
+ export type SortDir = 'asc' | 'desc' | null;
3
+ export type ColumnKey<T> = Extract<keyof T, string>;
4
+ export type Accessor<T, R = any> = (row: T) => R;
5
+ export type ColumnType = 'text' | 'number' | 'currency' | 'date' | 'datetime' | 'boolean' | 'badge' | 'link' | 'code';
6
+ type BaseColumn<T> = {
7
+ header: string;
8
+ width?: number;
9
+ minWidth?: number;
10
+ priority?: number;
11
+ align?: 'left' | 'center' | 'right';
12
+ sortable?: boolean;
13
+ hideOnMobile?: boolean;
14
+ responsiveLabel?: string;
15
+ class?: string;
16
+ type?: ColumnType;
17
+ format?: Intl.NumberFormatOptions | Intl.DateTimeFormatOptions;
18
+ trueLabel?: string;
19
+ falseLabel?: string;
20
+ };
21
+ /** Columna ligada a una key existente de T (autocomplete de keys) */
22
+ export type KeyColumn<T, K extends ColumnKey<T> = ColumnKey<T>> = BaseColumn<T> & {
23
+ id: K;
24
+ accessor?: (row: T) => T[K];
25
+ renderCell?: (row: T) => any;
26
+ renderCollapsed?: (row: T) => any;
27
+ };
28
+ /** Columna virtual (id libre), requiere accessor explícito */
29
+ export type VirtualColumn<T> = BaseColumn<T> & {
30
+ id: string;
31
+ accessor: Accessor<T>;
32
+ renderCell?: (row: T) => any;
33
+ renderCollapsed?: (row: T) => any;
34
+ };
35
+ export type ColumnDef<T> = KeyColumn<T>;
36
+ export type FilterOp = 'equals' | 'not_equals' | 'contains' | 'starts_with' | 'ends_with' | 'gt' | 'lt' | 'gte' | 'lte' | 'in' | 'not_in' | 'is_empty' | 'is_not_empty';
37
+ export type FilterDef<T> = {
38
+ id: string;
39
+ label: string;
40
+ columnId?: string;
41
+ op: FilterOp;
42
+ value?: any;
43
+ meta?: Record<string, any>;
44
+ };
45
+ export type FetchResult<T> = {
46
+ items: T[];
47
+ total: number;
48
+ nextCursor?: string;
49
+ };
50
+ export type FetchParams = {
51
+ page: number;
52
+ perPage: number;
53
+ cursor?: string;
54
+ sortBy?: string | null;
55
+ sortDir?: SortDir;
56
+ filters: FilterDef<any>[];
57
+ };
58
+ export type LoadMode = 'local' | 'remote' | 'cursor';
59
+ export type TableOptions<T> = {
60
+ id?: string;
61
+ columns: ColumnDef<T>[];
62
+ loadMode: LoadMode;
63
+ data?: T[];
64
+ fetcher?: (params: FetchParams) => Promise<FetchResult<T>>;
65
+ perPage?: number;
66
+ perPageOptions?: number[];
67
+ multiSelect?: boolean;
68
+ keepSelectionOnPageChange?: boolean;
69
+ initialSortBy?: string | null;
70
+ initialSortDir?: SortDir;
71
+ initialFilters?: FilterDef<T>[];
72
+ };
73
+ export type TableState<T> = {
74
+ ready: boolean;
75
+ items: T[];
76
+ page: number;
77
+ perPage: number;
78
+ total: number;
79
+ cursor?: string;
80
+ sortBy: string | null;
81
+ sortDir: SortDir;
82
+ filters: FilterDef<T>[];
83
+ visibleColumns: string[];
84
+ hiddenColumns: string[];
85
+ selected: Set<RowId>;
86
+ loading: boolean;
87
+ error?: string;
88
+ };
89
+ export type VisibilityPlan = {
90
+ visible: string[];
91
+ hidden: string[];
92
+ };
93
+ export type CellContext<T> = {
94
+ row: T | null;
95
+ rowIndex: number | null;
96
+ columnId: string | null;
97
+ column: ColumnDef<T> | null;
98
+ columnIndex: number | null;
99
+ event: MouseEvent;
100
+ };
101
+ export {};
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,5 @@
1
+ import type { ColumnDef, FilterOp } from './types.js';
2
+ export declare function normalize<T>(columns: ColumnDef<T>[]): ColumnDef<T>[];
3
+ export declare function defaultAccessor<T>(row: any, id: string): any;
4
+ export declare function compareValues(a: any, b: any): number;
5
+ export declare function applyFilterOp(value: any, op: FilterOp, target: any): boolean;
@@ -0,0 +1,66 @@
1
+ export function normalize(columns) {
2
+ return columns.map((c, i) => ({
3
+ width: 160,
4
+ minWidth: 96,
5
+ priority: i,
6
+ align: 'left',
7
+ sortable: true,
8
+ ...c
9
+ }));
10
+ }
11
+ export function defaultAccessor(row, id) {
12
+ return row?.[id];
13
+ }
14
+ export function compareValues(a, b) {
15
+ if (a == null && b == null)
16
+ return 0;
17
+ if (a == null)
18
+ return -1;
19
+ if (b == null)
20
+ return 1;
21
+ if (typeof a === 'string' && typeof b === 'string')
22
+ return a.localeCompare(b);
23
+ if (a > b)
24
+ return 1;
25
+ if (a < b)
26
+ return -1;
27
+ return 0;
28
+ }
29
+ export function applyFilterOp(value, op, target) {
30
+ switch (op) {
31
+ case 'equals':
32
+ return value === target;
33
+ case 'not_equals':
34
+ return value !== target;
35
+ case 'contains':
36
+ return String(value ?? '')
37
+ .toLowerCase()
38
+ .includes(String(target ?? '').toLowerCase());
39
+ case 'starts_with':
40
+ return String(value ?? '')
41
+ .toLowerCase()
42
+ .startsWith(String(target ?? '').toLowerCase());
43
+ case 'ends_with':
44
+ return String(value ?? '')
45
+ .toLowerCase()
46
+ .endsWith(String(target ?? '').toLowerCase());
47
+ case 'gt':
48
+ return value > target;
49
+ case 'lt':
50
+ return value < target;
51
+ case 'gte':
52
+ return value >= target;
53
+ case 'lte':
54
+ return value <= target;
55
+ case 'in':
56
+ return Array.isArray(target) ? target.includes(value) : false;
57
+ case 'not_in':
58
+ return Array.isArray(target) ? !target.includes(value) : false;
59
+ case 'is_empty':
60
+ return value == null || value === '';
61
+ case 'is_not_empty':
62
+ return !(value == null || value === '');
63
+ default:
64
+ return true;
65
+ }
66
+ }
@@ -0,0 +1,2 @@
1
+ import DataTable from './DataTable/DataTable.svelte';
2
+ export { DataTable };
@@ -0,0 +1,2 @@
1
+ import DataTable from './DataTable/DataTable.svelte';
2
+ export { DataTable };
@@ -1,7 +1,9 @@
1
1
  <script lang="ts">
2
2
  import type { Props } from './type.js';
3
+ import CardFooter from './CardFooter.svelte';
4
+ import CardHeader from './CardHeader.svelte';
3
5
 
4
- const { children, footer, header, onclick, ...props }: Props = $props();
6
+ const { children, footer, header, onclick, body_class, ...props }: Props = $props();
5
7
  </script>
6
8
 
7
9
  <svelte:element
@@ -18,20 +20,18 @@
18
20
  ]}
19
21
  >
20
22
  {#if header}
21
- <header class="flex flex-row p-6 pb-2">
23
+ <CardHeader>
22
24
  {@render header()}
23
- </header>
25
+ </CardHeader>
24
26
  {/if}
25
27
 
26
- <section class={['flex flex-1 flex-col', props.body_class]}>
28
+ <section class={['flex flex-1 flex-col', body_class]}>
27
29
  {@render children()}
28
30
  </section>
29
31
 
30
32
  {#if footer}
31
- <footer
32
- class="flex justify-between rounded-b-xl border-t border-gray-200 bg-gray-50 p-3 pt-2 dark:border-neutral-700 dark:bg-neutral-800"
33
- >
33
+ <CardFooter>
34
34
  {@render footer()}
35
- </footer>
35
+ </CardFooter>
36
36
  {/if}
37
37
  </svelte:element>
@@ -1,7 +1,15 @@
1
- <script>
2
- const { children } = $props();
1
+ <script lang="ts">
2
+ import type { Snippet } from 'svelte';
3
+ import type { ClassValue } from 'svelte/elements';
4
+
5
+ interface Props {
6
+ children: Snippet;
7
+ class?: ClassValue;
8
+ }
9
+
10
+ const { children, ...props }: Props = $props();
3
11
  </script>
4
12
 
5
- <div class="flex flex-1 flex-col gap-2 p-6">
13
+ <div class={['flex flex-1 flex-col p-3', props.class]}>
6
14
  {@render children()}
7
15
  </div>
@@ -1,11 +1,9 @@
1
+ import type { Snippet } from 'svelte';
2
+ import type { ClassValue } from 'svelte/elements';
3
+ interface Props {
4
+ children: Snippet;
5
+ class?: ClassValue;
6
+ }
7
+ declare const CardContent: import("svelte").Component<Props, {}, "">;
8
+ type CardContent = ReturnType<typeof CardContent>;
1
9
  export default CardContent;
2
- type CardContent = {
3
- $on?(type: string, callback: (e: any) => void): () => void;
4
- $set?(props: Partial<$$ComponentProps>): void;
5
- };
6
- declare const CardContent: import("svelte").Component<{
7
- children: any;
8
- }, {}, "">;
9
- type $$ComponentProps = {
10
- children: any;
11
- };
@@ -1,9 +1,19 @@
1
1
  <script lang="ts">
2
- const { children } = $props();
2
+ import type { Snippet } from 'svelte';
3
+ import type { ClassValue } from 'svelte/elements';
4
+
5
+ interface Props {
6
+ children: Snippet;
7
+ class?: ClassValue;
8
+ }
9
+ const { children, ...props }: Props = $props();
3
10
  </script>
4
11
 
5
12
  <footer
6
- class="flex justify-between rounded-b-xl border-t border-gray-200 bg-gray-50 p-3 pt-2 dark:border-neutral-700 dark:bg-neutral-800"
13
+ class={[
14
+ 'flex justify-between rounded-b-xl border-t border-gray-200 bg-gray-50 p-3 pt-2 dark:border-neutral-700 dark:bg-neutral-800',
15
+ props.class
16
+ ]}
7
17
  >
8
18
  {@render children()}
9
19
  </footer>
@@ -1,5 +1,9 @@
1
- declare const CardFooter: import("svelte").Component<{
2
- children: any;
3
- }, {}, "">;
1
+ import type { Snippet } from 'svelte';
2
+ import type { ClassValue } from 'svelte/elements';
3
+ interface Props {
4
+ children: Snippet;
5
+ class?: ClassValue;
6
+ }
7
+ declare const CardFooter: import("svelte").Component<Props, {}, "">;
4
8
  type CardFooter = ReturnType<typeof CardFooter>;
5
9
  export default CardFooter;
@@ -1,7 +1,15 @@
1
1
  <script lang="ts">
2
- const { children } = $props();
2
+ import type { Snippet } from 'svelte';
3
+ import type { ClassValue } from 'svelte/elements';
4
+
5
+ interface Props {
6
+ children: Snippet;
7
+ class?: ClassValue;
8
+ }
9
+
10
+ const { children, ...props }: Props = $props();
3
11
  </script>
4
12
 
5
- <header class="flex flex-row gap-2">
13
+ <header class={['flex flex-row gap-2 p-3 pb-2', props.class]}>
6
14
  {@render children()}
7
15
  </header>
@@ -1,5 +1,9 @@
1
- declare const CardHeader: import("svelte").Component<{
2
- children: any;
3
- }, {}, "">;
1
+ import type { Snippet } from 'svelte';
2
+ import type { ClassValue } from 'svelte/elements';
3
+ interface Props {
4
+ children: Snippet;
5
+ class?: ClassValue;
6
+ }
7
+ declare const CardHeader: import("svelte").Component<Props, {}, "">;
4
8
  type CardHeader = ReturnType<typeof CardHeader>;
5
9
  export default CardHeader;
package/dist/index.d.ts CHANGED
@@ -2,3 +2,4 @@ export * from './stores/I18n.svelte.js';
2
2
  export * from './settings/index.js';
3
3
  export * from './types/index.js';
4
4
  export * from './components/index.js';
5
+ export * from './components/container/index.js';
package/dist/index.js CHANGED
@@ -2,3 +2,4 @@ export * from './stores/I18n.svelte.js';
2
2
  export * from './settings/index.js';
3
3
  export * from './types/index.js';
4
4
  export * from './components/index.js';
5
+ export * from './components/container/index.js';