runeforge 0.0.17 → 0.0.19
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/dist/components/crud/GenericCRUD.svelte +346 -311
- package/dist/components/crud/GenericCRUD.svelte.d.ts +13 -1
- package/dist/components/crud/SearchInput.svelte +53 -0
- package/dist/components/crud/SearchInput.svelte.d.ts +7 -0
- package/dist/components/crud/views/List.svelte +379 -221
- package/dist/components/crud/views/List.svelte.d.ts +12 -1
- package/dist/components/table/PaginatedTable.svelte +16 -0
- package/dist/components/table/PaginatedTable.svelte.d.ts +8 -2
- package/dist/components/table/export.d.ts +17 -0
- package/dist/components/table/export.js +31 -0
- package/dist/i18n/en.js +5 -1
- package/dist/i18n/es.js +5 -1
- package/dist/i18n/types.d.ts +4 -0
- package/dist/icons/defaults/Download.svelte +7 -0
- package/dist/icons/defaults/Download.svelte.d.ts +7 -0
- package/dist/icons/sets/bootstrap.js +2 -1
- package/dist/icons/sets/default.js +2 -0
- package/dist/icons/types.d.ts +1 -0
- package/dist/index.d.ts +2 -1
- package/dist/index.js +1 -0
- package/dist/types/crud.d.ts +13 -0
- package/package.json +1 -1
|
@@ -30,6 +30,8 @@
|
|
|
30
30
|
initialSort = undefined as { column: string; direction: SortDirection } | undefined,
|
|
31
31
|
initialFilters = undefined as Partial<FilterSnapshot> | undefined,
|
|
32
32
|
onPaginationChange = undefined as ((query: TableQuery) => void) | undefined,
|
|
33
|
+
visibleRows = $bindable<T[]>([]),
|
|
34
|
+
query = $bindable<TableQuery | undefined>(undefined),
|
|
33
35
|
}: {
|
|
34
36
|
data?: T[];
|
|
35
37
|
columns?: ColumnDefinition<T>[];
|
|
@@ -45,6 +47,12 @@
|
|
|
45
47
|
initialSort?: { column: string; direction: SortDirection };
|
|
46
48
|
initialFilters?: Partial<FilterSnapshot>;
|
|
47
49
|
onPaginationChange?: (query: TableQuery) => void;
|
|
50
|
+
/** Filtered + sorted rows before page slicing (client mode), or the
|
|
51
|
+
* current page's rows as-is (server mode). Read-only for callers. */
|
|
52
|
+
visibleRows?: T[];
|
|
53
|
+
/** Current ordering + filters snapshot, kept in sync for callers that
|
|
54
|
+
* need to replicate the active query (e.g. exporting server-side). */
|
|
55
|
+
query?: TableQuery;
|
|
48
56
|
} = $props();
|
|
49
57
|
|
|
50
58
|
// Intentional one-time hydration of local state from the initial prop
|
|
@@ -107,6 +115,14 @@
|
|
|
107
115
|
}
|
|
108
116
|
});
|
|
109
117
|
|
|
118
|
+
// Surface the filtered+sorted rows and current query for callers (e.g. export).
|
|
119
|
+
$effect(() => {
|
|
120
|
+
visibleRows = sorted.map((e) => e.row);
|
|
121
|
+
});
|
|
122
|
+
$effect(() => {
|
|
123
|
+
query = currentQuery(displayPage);
|
|
124
|
+
});
|
|
125
|
+
|
|
110
126
|
function currentQuery(page: number): TableQuery {
|
|
111
127
|
return {
|
|
112
128
|
page,
|
|
@@ -21,9 +21,15 @@ declare function $$render<T extends object = Record<string, unknown>>(): {
|
|
|
21
21
|
};
|
|
22
22
|
initialFilters?: Partial<FilterSnapshot>;
|
|
23
23
|
onPaginationChange?: (query: TableQuery) => void;
|
|
24
|
+
/** Filtered + sorted rows before page slicing (client mode), or the
|
|
25
|
+
* current page's rows as-is (server mode). Read-only for callers. */
|
|
26
|
+
visibleRows?: T[];
|
|
27
|
+
/** Current ordering + filters snapshot, kept in sync for callers that
|
|
28
|
+
* need to replicate the active query (e.g. exporting server-side). */
|
|
29
|
+
query?: TableQuery;
|
|
24
30
|
};
|
|
25
31
|
exports: {};
|
|
26
|
-
bindings: "selected";
|
|
32
|
+
bindings: "selected" | "visibleRows" | "query";
|
|
27
33
|
slots: {};
|
|
28
34
|
events: {};
|
|
29
35
|
};
|
|
@@ -31,7 +37,7 @@ declare class __sveltets_Render<T extends object = Record<string, unknown>> {
|
|
|
31
37
|
props(): ReturnType<typeof $$render<T>>['props'];
|
|
32
38
|
events(): ReturnType<typeof $$render<T>>['events'];
|
|
33
39
|
slots(): ReturnType<typeof $$render<T>>['slots'];
|
|
34
|
-
bindings(): "selected";
|
|
40
|
+
bindings(): "selected" | "visibleRows" | "query";
|
|
35
41
|
exports(): {};
|
|
36
42
|
}
|
|
37
43
|
interface $$IsomorphicComponent {
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { ColumnDefinition } from '../../types/crud.js';
|
|
2
|
+
/**
|
|
3
|
+
* Minimal duck-typed subset of the SheetJS (`xlsx`) module API used for
|
|
4
|
+
* building a workbook. Runeforge never imports `xlsx` itself — the consumer
|
|
5
|
+
* installs it and passes the resolved module in, so the dependency stays
|
|
6
|
+
* fully optional and never affects consumers who don't use Excel export.
|
|
7
|
+
*/
|
|
8
|
+
export interface XlsxModule {
|
|
9
|
+
utils: {
|
|
10
|
+
aoa_to_sheet: (data: unknown[][]) => unknown;
|
|
11
|
+
book_new: () => unknown;
|
|
12
|
+
book_append_sheet: (workbook: unknown, worksheet: unknown, name?: string) => void;
|
|
13
|
+
};
|
|
14
|
+
writeFile: (workbook: unknown, filename: string) => void;
|
|
15
|
+
}
|
|
16
|
+
export declare function downloadCsv<T extends object>(rows: T[], columns: ColumnDefinition<T>[], filename: string): void;
|
|
17
|
+
export declare function downloadXlsx<T extends object>(rows: T[], columns: ColumnDefinition<T>[], filename: string, xlsx: XlsxModule): void;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { cellRenderedText } from './utils.js';
|
|
2
|
+
function buildTable(rows, columns) {
|
|
3
|
+
const headers = columns.map((col) => col.title ?? col.attribute);
|
|
4
|
+
const body = rows.map((row) => columns.map((col) => cellRenderedText(row, col)));
|
|
5
|
+
return { headers, body };
|
|
6
|
+
}
|
|
7
|
+
function escapeCsvCell(value) {
|
|
8
|
+
return /[",\n]/.test(value) ? `"${value.replace(/"/g, '""')}"` : value;
|
|
9
|
+
}
|
|
10
|
+
function triggerDownload(blob, filename) {
|
|
11
|
+
const url = URL.createObjectURL(blob);
|
|
12
|
+
const link = document.createElement('a');
|
|
13
|
+
link.href = url;
|
|
14
|
+
link.download = filename;
|
|
15
|
+
link.click();
|
|
16
|
+
URL.revokeObjectURL(url);
|
|
17
|
+
}
|
|
18
|
+
export function downloadCsv(rows, columns, filename) {
|
|
19
|
+
const { headers, body } = buildTable(rows, columns);
|
|
20
|
+
const csv = [headers, ...body]
|
|
21
|
+
.map((line) => line.map(escapeCsvCell).join(','))
|
|
22
|
+
.join('\r\n');
|
|
23
|
+
triggerDownload(new Blob([csv], { type: 'text/csv;charset=utf-8;' }), `${filename}.csv`);
|
|
24
|
+
}
|
|
25
|
+
export function downloadXlsx(rows, columns, filename, xlsx) {
|
|
26
|
+
const { headers, body } = buildTable(rows, columns);
|
|
27
|
+
const worksheet = xlsx.utils.aoa_to_sheet([headers, ...body]);
|
|
28
|
+
const workbook = xlsx.utils.book_new();
|
|
29
|
+
xlsx.utils.book_append_sheet(workbook, worksheet);
|
|
30
|
+
xlsx.writeFile(workbook, `${filename}.xlsx`);
|
|
31
|
+
}
|
package/dist/i18n/en.js
CHANGED
|
@@ -15,6 +15,10 @@ export const en = {
|
|
|
15
15
|
edit: 'Edit',
|
|
16
16
|
delete: 'Delete',
|
|
17
17
|
create: 'Create',
|
|
18
|
+
searchPlaceholder: 'Search...',
|
|
19
|
+
export: 'Export',
|
|
20
|
+
exportCsv: 'Export as CSV',
|
|
21
|
+
exportExcel: 'Export as Excel',
|
|
18
22
|
save: 'Save',
|
|
19
23
|
saveAndContinue: 'Save and continue',
|
|
20
24
|
cancel: 'Cancel',
|
|
@@ -22,5 +26,5 @@ export const en = {
|
|
|
22
26
|
confirm: 'Confirm',
|
|
23
27
|
deleteConfirm: (count, actionLabel) => `Are you sure you want to ${String(actionLabel).toLowerCase()} ${count} item${count === 1 ? '' : 's'}?`,
|
|
24
28
|
required: (field) => `${field} is required`,
|
|
25
|
-
serverError: 'Unexpected server error.'
|
|
29
|
+
serverError: 'Unexpected server error.'
|
|
26
30
|
};
|
package/dist/i18n/es.js
CHANGED
|
@@ -15,6 +15,10 @@ export const es = {
|
|
|
15
15
|
edit: 'Editar',
|
|
16
16
|
delete: 'Eliminar',
|
|
17
17
|
create: 'Crear',
|
|
18
|
+
searchPlaceholder: 'Buscar...',
|
|
19
|
+
export: 'Exportar',
|
|
20
|
+
exportCsv: 'Exportar a CSV',
|
|
21
|
+
exportExcel: 'Exportar a Excel',
|
|
18
22
|
save: 'Guardar',
|
|
19
23
|
saveAndContinue: 'Guardar y continuar',
|
|
20
24
|
cancel: 'Cancelar',
|
|
@@ -22,5 +26,5 @@ export const es = {
|
|
|
22
26
|
confirm: 'Confirmar',
|
|
23
27
|
deleteConfirm: (count, actionLabel) => `¿Seguro que querés ${String(actionLabel).toLowerCase()} ${count} elemento${count === 1 ? '' : 's'}?`,
|
|
24
28
|
required: (field) => `${field} es requerido`,
|
|
25
|
-
serverError: 'Error inesperado del servidor.'
|
|
29
|
+
serverError: 'Error inesperado del servidor.'
|
|
26
30
|
};
|
package/dist/i18n/types.d.ts
CHANGED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
let { size = '1em', class: cls = '' }: { size?: string | number; class?: string } = $props();
|
|
3
|
+
</script>
|
|
4
|
+
<svg xmlns="http://www.w3.org/2000/svg" width={size} height={size} viewBox="0 0 16 16" fill="currentColor" class={cls}>
|
|
5
|
+
<path d="M.5 9.9a.5.5 0 0 1 .5.5v2.5a1 1 0 0 0 1 1h12a1 1 0 0 0 1-1v-2.5a.5.5 0 0 1 1 0v2.5a2 2 0 0 1-2 2H2a2 2 0 0 1-2-2v-2.5a.5.5 0 0 1 .5-.5"/>
|
|
6
|
+
<path d="M7.646 11.854a.5.5 0 0 0 .708 0l3-3a.5.5 0 0 0-.708-.708L8.5 10.293V1.5a.5.5 0 0 0-1 0v8.793L5.354 8.146a.5.5 0 1 0-.708.708z"/>
|
|
7
|
+
</svg>
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
* setIconSet(bootstrapIconSet);
|
|
11
11
|
*/
|
|
12
12
|
import * as Icons from 'svelte-bootstrap-icons';
|
|
13
|
-
const { ChevronExpand, CaretUpFill, CaretDownFill, Funnel, FunnelFill, Plus, Eye, PencilSquare, Trash3, HouseDoor, Folder, EyeSlash, X, } = Icons;
|
|
13
|
+
const { ChevronExpand, CaretUpFill, CaretDownFill, Funnel, FunnelFill, Plus, Eye, PencilSquare, Trash3, HouseDoor, Folder, EyeSlash, X, Download, } = Icons;
|
|
14
14
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
15
15
|
function asIcon(c) { return c; }
|
|
16
16
|
export const bootstrapIconSet = {
|
|
@@ -28,6 +28,7 @@ export const bootstrapIconSet = {
|
|
|
28
28
|
folder: asIcon(Folder),
|
|
29
29
|
passwordShow: asIcon(Eye),
|
|
30
30
|
passwordHide: asIcon(EyeSlash),
|
|
31
|
+
download: asIcon(Download),
|
|
31
32
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
32
33
|
getByName: (name) => asIcon(Icons[name]) ?? null,
|
|
33
34
|
};
|
|
@@ -12,6 +12,7 @@ import Home from '../defaults/Home.svelte';
|
|
|
12
12
|
import Folder from '../defaults/Folder.svelte';
|
|
13
13
|
import PasswordShow from '../defaults/PasswordShow.svelte';
|
|
14
14
|
import PasswordHide from '../defaults/PasswordHide.svelte';
|
|
15
|
+
import Download from '../defaults/Download.svelte';
|
|
15
16
|
export const defaultIconSet = {
|
|
16
17
|
sortNone: SortNone,
|
|
17
18
|
sortAsc: SortAsc,
|
|
@@ -27,4 +28,5 @@ export const defaultIconSet = {
|
|
|
27
28
|
folder: Folder,
|
|
28
29
|
passwordShow: PasswordShow,
|
|
29
30
|
passwordHide: PasswordHide,
|
|
31
|
+
download: Download,
|
|
30
32
|
};
|
package/dist/icons/types.d.ts
CHANGED
package/dist/index.d.ts
CHANGED
|
@@ -2,7 +2,7 @@ export type { BreadcrumbItem } from './types/breadcrumb.js';
|
|
|
2
2
|
export { AttributeType } from './types/attribute.js';
|
|
3
3
|
export type { AttributeMetadata, InterfaceMetadata, SelectOption, OptionsResolver, FormatterResolver } from './types/attribute.js';
|
|
4
4
|
export type { CellProps, CellComponent, CellFormatter, SortDirection, IndexedRow, DistinctEntry, PaginatedEnvelope, ServerPagination, FilterSnapshot, TableQuery } from './types/table.js';
|
|
5
|
-
export type { ColumnDefinition, FieldDefinition, ActionConfiguration, CustomAction, RowAction } from './types/crud.js';
|
|
5
|
+
export type { ColumnDefinition, FieldDefinition, ActionConfiguration, CustomAction, CustomBulkAction, RowAction, SearchConfiguration } from './types/crud.js';
|
|
6
6
|
export type { RuneforgeConfig } from './config/context.js';
|
|
7
7
|
export { setConfig, getConfig } from './config/context.js';
|
|
8
8
|
export type { CRUDIconSet, IconComponent } from './icons/types.js';
|
|
@@ -39,6 +39,7 @@ export { default as CRUDList } from './components/crud/views/List.svelte';
|
|
|
39
39
|
export { default as CRUDCreate } from './components/crud/views/Create.svelte';
|
|
40
40
|
export { default as CRUDRead } from './components/crud/views/Read.svelte';
|
|
41
41
|
export { default as CRUDUpdate } from './components/crud/views/Update.svelte';
|
|
42
|
+
export { default as SearchInput } from './components/crud/SearchInput.svelte';
|
|
42
43
|
export { AUTO_EXCLUDED } from './components/crud/utils/constants.js';
|
|
43
44
|
export { resolveOptions, resolveFormatter, inferType } from './components/crud/utils/resolution.js';
|
|
44
45
|
export { fieldLabel, initials } from './components/crud/utils/misc.js';
|
package/dist/index.js
CHANGED
|
@@ -36,6 +36,7 @@ export { default as CRUDList } from './components/crud/views/List.svelte';
|
|
|
36
36
|
export { default as CRUDCreate } from './components/crud/views/Create.svelte';
|
|
37
37
|
export { default as CRUDRead } from './components/crud/views/Read.svelte';
|
|
38
38
|
export { default as CRUDUpdate } from './components/crud/views/Update.svelte';
|
|
39
|
+
export { default as SearchInput } from './components/crud/SearchInput.svelte';
|
|
39
40
|
// CRUD utilities
|
|
40
41
|
export { AUTO_EXCLUDED } from './components/crud/utils/constants.js';
|
|
41
42
|
export { resolveOptions, resolveFormatter, inferType } from './components/crud/utils/resolution.js';
|
package/dist/types/crud.d.ts
CHANGED
|
@@ -47,3 +47,16 @@ export interface RowAction<T extends object = Record<string, unknown>> {
|
|
|
47
47
|
condition?: (item: T) => boolean;
|
|
48
48
|
run: (item: T) => void;
|
|
49
49
|
}
|
|
50
|
+
export interface CustomBulkAction<T extends object = Record<string, unknown>> {
|
|
51
|
+
label: string;
|
|
52
|
+
icon: any;
|
|
53
|
+
endpoint: string;
|
|
54
|
+
variant?: string;
|
|
55
|
+
confirm?: boolean;
|
|
56
|
+
condition?: (items: T[]) => boolean;
|
|
57
|
+
}
|
|
58
|
+
export interface SearchConfiguration {
|
|
59
|
+
param?: string;
|
|
60
|
+
placeholder?: string;
|
|
61
|
+
debounceMs?: number;
|
|
62
|
+
}
|