runeforge 0.0.62 → 0.0.63

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 (66) hide show
  1. package/LICENSE +21 -21
  2. package/README.md +1410 -1407
  3. package/dist/components/Avatar.svelte +31 -31
  4. package/dist/components/IconRenderer.svelte +73 -73
  5. package/dist/components/Modal.svelte +75 -75
  6. package/dist/components/common/Header.svelte +40 -40
  7. package/dist/components/crud/EmbeddedField.svelte +203 -203
  8. package/dist/components/crud/Field.svelte +122 -122
  9. package/dist/components/crud/GenericCRUD.svelte +426 -426
  10. package/dist/components/crud/SearchInput.svelte +53 -53
  11. package/dist/components/crud/columns/Avatar.svelte +15 -15
  12. package/dist/components/crud/columns/Icon.svelte +8 -8
  13. package/dist/components/crud/fields/BooleanField.svelte +38 -38
  14. package/dist/components/crud/fields/DatetimeField.svelte +250 -250
  15. package/dist/components/crud/fields/DefaultField.svelte +67 -67
  16. package/dist/components/crud/fields/FileField.svelte +70 -70
  17. package/dist/components/crud/fields/MultiSelectField.svelte +70 -70
  18. package/dist/components/crud/fields/SelectField.svelte +67 -67
  19. package/dist/components/crud/fields/TextareaField.svelte +55 -55
  20. package/dist/components/crud/fields/TreeField.svelte +1 -0
  21. package/dist/components/crud/utils/resolution.js +1 -0
  22. package/dist/components/crud/utils/tree.d.ts +5 -0
  23. package/dist/components/crud/utils/tree.js +29 -0
  24. package/dist/components/crud/views/Create.svelte +239 -239
  25. package/dist/components/crud/views/Read.svelte +131 -131
  26. package/dist/components/crud/views/Update.svelte +215 -215
  27. package/dist/components/crud/views/list/List.svelte +291 -291
  28. package/dist/components/crud/views/list/Modals.svelte +56 -56
  29. package/dist/components/crud/views/list/Table.svelte +173 -173
  30. package/dist/components/crud/views/list/Toolbar.svelte +340 -340
  31. package/dist/components/form/Button.svelte +27 -27
  32. package/dist/components/form/Label.svelte +37 -37
  33. package/dist/components/form/MultiSelect.svelte +248 -248
  34. package/dist/components/form/PasswordInput.svelte +68 -68
  35. package/dist/components/form/Required.svelte +1 -1
  36. package/dist/components/form/Select.svelte +209 -209
  37. package/dist/components/form/Tree.svelte +43 -4
  38. package/dist/components/form/Tree.svelte.d.ts +1 -0
  39. package/dist/components/form/TreeNode.svelte +31 -2
  40. package/dist/components/form/TreeNode.svelte.d.ts +2 -0
  41. package/dist/components/navigation/Breadcrumbs.svelte +111 -111
  42. package/dist/components/table/ColumnFilter.svelte +168 -168
  43. package/dist/components/table/PaginatedTable.svelte +542 -542
  44. package/dist/components/table/Paginator.svelte +113 -113
  45. package/dist/components/table/SortHeader.svelte +43 -43
  46. package/dist/components/table/TableBody.svelte +150 -150
  47. package/dist/components/table/TableHeader.svelte +88 -88
  48. package/dist/icons/defaults/Clear.svelte +6 -6
  49. package/dist/icons/defaults/Create.svelte +6 -6
  50. package/dist/icons/defaults/Delete.svelte +6 -6
  51. package/dist/icons/defaults/Download.svelte +7 -7
  52. package/dist/icons/defaults/Edit.svelte +7 -7
  53. package/dist/icons/defaults/Filter.svelte +6 -6
  54. package/dist/icons/defaults/FilterActive.svelte +6 -6
  55. package/dist/icons/defaults/Folder.svelte +6 -6
  56. package/dist/icons/defaults/Grip.svelte +7 -7
  57. package/dist/icons/defaults/Home.svelte +6 -6
  58. package/dist/icons/defaults/PasswordHide.svelte +9 -9
  59. package/dist/icons/defaults/PasswordShow.svelte +7 -7
  60. package/dist/icons/defaults/SortAsc.svelte +6 -6
  61. package/dist/icons/defaults/SortDesc.svelte +6 -6
  62. package/dist/icons/defaults/SortNone.svelte +6 -6
  63. package/dist/icons/defaults/View.svelte +7 -7
  64. package/dist/types/attribute.d.ts +3 -0
  65. package/dist/types/crud/fields.d.ts +3 -0
  66. package/package.json +1 -1
@@ -1,56 +1,56 @@
1
- <script lang="ts" generics="T extends object = Record<string, unknown>">
2
- import Button from '../../../form/Button.svelte';
3
- import Modal from '../../../Modal.svelte';
4
- import type { CustomBulkAction } from '../../../../types/crud/actions.js';
5
- import { getStrings } from '../../../../i18n/context.js';
6
-
7
- const strings = getStrings();
8
-
9
- let {
10
- deleteLabel = '',
11
- pendingDeletion = null as T[] | null,
12
- pendingBulkAction = null as { action: CustomBulkAction<T>; items: T[] } | null,
13
- onCancelDeletion,
14
- onConfirmDeletion,
15
- onCancelBulkAction,
16
- onConfirmBulkAction
17
- }: {
18
- deleteLabel?: string;
19
- pendingDeletion?: T[] | null;
20
- pendingBulkAction?: { action: CustomBulkAction<T>; items: T[] } | null;
21
- onCancelDeletion?: () => void;
22
- onConfirmDeletion?: () => void;
23
- onCancelBulkAction?: () => void;
24
- onConfirmBulkAction?: () => void;
25
- } = $props();
26
- </script>
27
-
28
- {#if pendingDeletion !== null}
29
- <Modal title={deleteLabel} onClose={onCancelDeletion}>
30
- <p>{strings.deleteConfirm(pendingDeletion.length, deleteLabel)}</p>
31
- <div class="flex justify-end gap-2 mt-4">
32
- <Button variant="ghost" onclick={onCancelDeletion}>
33
- {strings.cancel}
34
- </Button>
35
- <Button variant="error" onclick={onConfirmDeletion}>
36
- {strings.confirm}
37
- </Button>
38
- </div>
39
- </Modal>
40
- {/if}
41
-
42
- {#if pendingBulkAction !== null}
43
- {@const pendingActionLabel =
44
- pendingBulkAction.action.label ?? pendingBulkAction.action.tooltip ?? strings.actions}
45
- <Modal title={pendingActionLabel} onClose={onCancelBulkAction}>
46
- <p>{strings.deleteConfirm(pendingBulkAction.items.length, pendingActionLabel)}</p>
47
- <div class="flex justify-end gap-2 mt-4">
48
- <Button variant="ghost" onclick={onCancelBulkAction}>
49
- {strings.cancel}
50
- </Button>
51
- <Button variant={pendingBulkAction.action.variant ?? 'primary'} onclick={onConfirmBulkAction}>
52
- {strings.confirm}
53
- </Button>
54
- </div>
55
- </Modal>
56
- {/if}
1
+ <script lang="ts" generics="T extends object = Record<string, unknown>">
2
+ import Button from '../../../form/Button.svelte';
3
+ import Modal from '../../../Modal.svelte';
4
+ import type { CustomBulkAction } from '../../../../types/crud/actions.js';
5
+ import { getStrings } from '../../../../i18n/context.js';
6
+
7
+ const strings = getStrings();
8
+
9
+ let {
10
+ deleteLabel = '',
11
+ pendingDeletion = null as T[] | null,
12
+ pendingBulkAction = null as { action: CustomBulkAction<T>; items: T[] } | null,
13
+ onCancelDeletion,
14
+ onConfirmDeletion,
15
+ onCancelBulkAction,
16
+ onConfirmBulkAction
17
+ }: {
18
+ deleteLabel?: string;
19
+ pendingDeletion?: T[] | null;
20
+ pendingBulkAction?: { action: CustomBulkAction<T>; items: T[] } | null;
21
+ onCancelDeletion?: () => void;
22
+ onConfirmDeletion?: () => void;
23
+ onCancelBulkAction?: () => void;
24
+ onConfirmBulkAction?: () => void;
25
+ } = $props();
26
+ </script>
27
+
28
+ {#if pendingDeletion !== null}
29
+ <Modal title={deleteLabel} onClose={onCancelDeletion}>
30
+ <p>{strings.deleteConfirm(pendingDeletion.length, deleteLabel)}</p>
31
+ <div class="flex justify-end gap-2 mt-4">
32
+ <Button variant="ghost" onclick={onCancelDeletion}>
33
+ {strings.cancel}
34
+ </Button>
35
+ <Button variant="error" onclick={onConfirmDeletion}>
36
+ {strings.confirm}
37
+ </Button>
38
+ </div>
39
+ </Modal>
40
+ {/if}
41
+
42
+ {#if pendingBulkAction !== null}
43
+ {@const pendingActionLabel =
44
+ pendingBulkAction.action.label ?? pendingBulkAction.action.tooltip ?? strings.actions}
45
+ <Modal title={pendingActionLabel} onClose={onCancelBulkAction}>
46
+ <p>{strings.deleteConfirm(pendingBulkAction.items.length, pendingActionLabel)}</p>
47
+ <div class="flex justify-end gap-2 mt-4">
48
+ <Button variant="ghost" onclick={onCancelBulkAction}>
49
+ {strings.cancel}
50
+ </Button>
51
+ <Button variant={pendingBulkAction.action.variant ?? 'primary'} onclick={onConfirmBulkAction}>
52
+ {strings.confirm}
53
+ </Button>
54
+ </div>
55
+ </Modal>
56
+ {/if}
@@ -1,173 +1,173 @@
1
- <script lang="ts" generics="T extends object = Record<string, unknown>">
2
- import { SvelteSet } from 'svelte/reactivity';
3
- import Button from '../../../form/Button.svelte';
4
- import PaginatedTable from '../../../table/PaginatedTable.svelte';
5
- import { getIconSet } from '../../../../icons/context.js';
6
- import { defaultIconSet } from '../../../../icons/sets/default.js';
7
- import type { ColumnDefinition } from '../../../../types/crud/columns.js';
8
- import type { CustomAction, RowAction } from '../../../../types/crud/actions.js';
9
- import type { ReorderConfiguration } from '../../../../types/crud/reorder.js';
10
- import type {
11
- FilterSnapshot,
12
- ServerPagination,
13
- SortDirection,
14
- TableQuery
15
- } from '../../../../types/table.js';
16
-
17
- const icons = $derived(getIconSet() ?? defaultIconSet);
18
-
19
- let {
20
- data = [] as T[],
21
- columns = [] as ColumnDefinition<T>[],
22
- pageSize = 10,
23
- selectable = true,
24
- selected = $bindable(new SvelteSet<number>()),
25
- pagination = undefined as ServerPagination | undefined,
26
- initialSort = undefined as { column: string; direction: SortDirection } | undefined,
27
- initialFilters = undefined as Partial<FilterSnapshot> | undefined,
28
- onPaginationChange = undefined as ((query: TableQuery) => void) | undefined,
29
- visibleRows = $bindable<T[]>([]),
30
- query = $bindable<TableQuery | undefined>(undefined),
31
- customActions = [] as CustomAction<T>[],
32
- allowRead = true,
33
- allowUpdate = true,
34
- allowDelete = true,
35
- readLabel = '',
36
- updateLabel = '',
37
- deleteLabel = '',
38
- reorder = undefined as ReorderConfiguration<T> | undefined,
39
- onView,
40
- onEdit,
41
- onAction,
42
- onRequestDeletion,
43
- onReorder
44
- }: {
45
- data?: T[];
46
- columns?: ColumnDefinition<T>[];
47
- pageSize?: number;
48
- selectable?: boolean;
49
- selected?: SvelteSet<number>;
50
- pagination?: ServerPagination;
51
- initialSort?: { column: string; direction: SortDirection };
52
- initialFilters?: Partial<FilterSnapshot>;
53
- onPaginationChange?: (query: TableQuery) => void;
54
- visibleRows?: T[];
55
- query?: TableQuery;
56
- customActions?: CustomAction<T>[];
57
- allowRead?: boolean;
58
- allowUpdate?: boolean;
59
- allowDelete?: boolean;
60
- readLabel?: string;
61
- updateLabel?: string;
62
- deleteLabel?: string;
63
- /** Drag-to-reorder configuration — see `ReorderConfiguration`. Ignored
64
- * in server-pagination mode (`pagination` set). */
65
- reorder?: ReorderConfiguration<T>;
66
- onView?: (item: T) => void;
67
- onEdit?: (item: T) => void;
68
- onAction?: (action: CustomAction<T>, item: T) => void;
69
- onRequestDeletion?: (item: T) => void;
70
- /** Fires with the complete reordered row list after a drag; the caller
71
- * (the list orchestrator) owns persisting it. */
72
- onReorder?: (rows: T[]) => void;
73
- } = $props();
74
-
75
- const reorderActive = $derived(!!reorder && reorder.enabled !== false && !pagination);
76
-
77
- const showRowActions = $derived(
78
- allowRead || allowUpdate || allowDelete || customActions.length > 0
79
- );
80
-
81
- const rowActions = $derived<RowAction<T>[]>([
82
- ...customActions.map((action) => ({
83
- label: action.label,
84
- icon: action.icon,
85
- toggle: action.toggle,
86
- class: action.class,
87
- condition: action.condition,
88
- run: (item: T) => onAction?.(action, item)
89
- })),
90
- ...(allowRead
91
- ? [{ label: readLabel, icon: icons.view, run: (item: T) => onView?.(item) }]
92
- : []),
93
- ...(allowUpdate
94
- ? [{ label: updateLabel, icon: icons.edit, run: (item: T) => onEdit?.(item) }]
95
- : []),
96
- ...(allowDelete
97
- ? [
98
- {
99
- label: deleteLabel,
100
- icon: icons.delete,
101
- class: 'text-error',
102
- run: (item: T) => onRequestDeletion?.(item)
103
- }
104
- ]
105
- : [])
106
- ]);
107
- </script>
108
-
109
- {#snippet actionsCell(item: T)}
110
- <div class="flex justify-end items-center gap-1">
111
- {#each rowActions as action (action.label)}
112
- {#if action.condition?.(item) ?? true}
113
- {@const resolvedClass =
114
- typeof action.class === 'function' ? action.class(item) : action.class}
115
- {#if action.toggle}
116
- <input
117
- type="checkbox"
118
- class={['toggle toggle-sm', resolvedClass]}
119
- title={action.label}
120
- aria-label={action.label}
121
- checked={action.toggle(item)}
122
- onclick={(e) => {
123
- e.preventDefault();
124
- e.stopPropagation();
125
- action.run(item);
126
- }}
127
- />
128
- {:else}
129
- {@const Icon = action.icon}
130
- <Button
131
- variant="ghost"
132
- class={['btn-xs', resolvedClass]}
133
- title={action.label}
134
- aria-label={action.label}
135
- onclick={(e) => {
136
- e.stopPropagation();
137
- action.run(item);
138
- }}
139
- >
140
- <Icon class="size-4" />
141
- </Button>
142
- {/if}
143
- {/if}
144
- {/each}
145
- </div>
146
- {/snippet}
147
-
148
- <div class="table-wrapper">
149
- <PaginatedTable
150
- {data}
151
- {columns}
152
- {pageSize}
153
- {selectable}
154
- bind:selected
155
- rowActions={showRowActions ? actionsCell : undefined}
156
- {pagination}
157
- {initialSort}
158
- {initialFilters}
159
- {onPaginationChange}
160
- bind:visibleRows
161
- bind:query
162
- reorder={reorderActive ? reorder : undefined}
163
- {onReorder}
164
- />
165
- </div>
166
-
167
- <style>
168
- .table-wrapper {
169
- width: 100%;
170
- max-width: var(--runeforge-crud-max-width);
171
- margin-inline: auto;
172
- }
173
- </style>
1
+ <script lang="ts" generics="T extends object = Record<string, unknown>">
2
+ import { SvelteSet } from 'svelte/reactivity';
3
+ import Button from '../../../form/Button.svelte';
4
+ import PaginatedTable from '../../../table/PaginatedTable.svelte';
5
+ import { getIconSet } from '../../../../icons/context.js';
6
+ import { defaultIconSet } from '../../../../icons/sets/default.js';
7
+ import type { ColumnDefinition } from '../../../../types/crud/columns.js';
8
+ import type { CustomAction, RowAction } from '../../../../types/crud/actions.js';
9
+ import type { ReorderConfiguration } from '../../../../types/crud/reorder.js';
10
+ import type {
11
+ FilterSnapshot,
12
+ ServerPagination,
13
+ SortDirection,
14
+ TableQuery
15
+ } from '../../../../types/table.js';
16
+
17
+ const icons = $derived(getIconSet() ?? defaultIconSet);
18
+
19
+ let {
20
+ data = [] as T[],
21
+ columns = [] as ColumnDefinition<T>[],
22
+ pageSize = 10,
23
+ selectable = true,
24
+ selected = $bindable(new SvelteSet<number>()),
25
+ pagination = undefined as ServerPagination | undefined,
26
+ initialSort = undefined as { column: string; direction: SortDirection } | undefined,
27
+ initialFilters = undefined as Partial<FilterSnapshot> | undefined,
28
+ onPaginationChange = undefined as ((query: TableQuery) => void) | undefined,
29
+ visibleRows = $bindable<T[]>([]),
30
+ query = $bindable<TableQuery | undefined>(undefined),
31
+ customActions = [] as CustomAction<T>[],
32
+ allowRead = true,
33
+ allowUpdate = true,
34
+ allowDelete = true,
35
+ readLabel = '',
36
+ updateLabel = '',
37
+ deleteLabel = '',
38
+ reorder = undefined as ReorderConfiguration<T> | undefined,
39
+ onView,
40
+ onEdit,
41
+ onAction,
42
+ onRequestDeletion,
43
+ onReorder
44
+ }: {
45
+ data?: T[];
46
+ columns?: ColumnDefinition<T>[];
47
+ pageSize?: number;
48
+ selectable?: boolean;
49
+ selected?: SvelteSet<number>;
50
+ pagination?: ServerPagination;
51
+ initialSort?: { column: string; direction: SortDirection };
52
+ initialFilters?: Partial<FilterSnapshot>;
53
+ onPaginationChange?: (query: TableQuery) => void;
54
+ visibleRows?: T[];
55
+ query?: TableQuery;
56
+ customActions?: CustomAction<T>[];
57
+ allowRead?: boolean;
58
+ allowUpdate?: boolean;
59
+ allowDelete?: boolean;
60
+ readLabel?: string;
61
+ updateLabel?: string;
62
+ deleteLabel?: string;
63
+ /** Drag-to-reorder configuration — see `ReorderConfiguration`. Ignored
64
+ * in server-pagination mode (`pagination` set). */
65
+ reorder?: ReorderConfiguration<T>;
66
+ onView?: (item: T) => void;
67
+ onEdit?: (item: T) => void;
68
+ onAction?: (action: CustomAction<T>, item: T) => void;
69
+ onRequestDeletion?: (item: T) => void;
70
+ /** Fires with the complete reordered row list after a drag; the caller
71
+ * (the list orchestrator) owns persisting it. */
72
+ onReorder?: (rows: T[]) => void;
73
+ } = $props();
74
+
75
+ const reorderActive = $derived(!!reorder && reorder.enabled !== false && !pagination);
76
+
77
+ const showRowActions = $derived(
78
+ allowRead || allowUpdate || allowDelete || customActions.length > 0
79
+ );
80
+
81
+ const rowActions = $derived<RowAction<T>[]>([
82
+ ...customActions.map((action) => ({
83
+ label: action.label,
84
+ icon: action.icon,
85
+ toggle: action.toggle,
86
+ class: action.class,
87
+ condition: action.condition,
88
+ run: (item: T) => onAction?.(action, item)
89
+ })),
90
+ ...(allowRead
91
+ ? [{ label: readLabel, icon: icons.view, run: (item: T) => onView?.(item) }]
92
+ : []),
93
+ ...(allowUpdate
94
+ ? [{ label: updateLabel, icon: icons.edit, run: (item: T) => onEdit?.(item) }]
95
+ : []),
96
+ ...(allowDelete
97
+ ? [
98
+ {
99
+ label: deleteLabel,
100
+ icon: icons.delete,
101
+ class: 'text-error',
102
+ run: (item: T) => onRequestDeletion?.(item)
103
+ }
104
+ ]
105
+ : [])
106
+ ]);
107
+ </script>
108
+
109
+ {#snippet actionsCell(item: T)}
110
+ <div class="flex justify-end items-center gap-1">
111
+ {#each rowActions as action (action.label)}
112
+ {#if action.condition?.(item) ?? true}
113
+ {@const resolvedClass =
114
+ typeof action.class === 'function' ? action.class(item) : action.class}
115
+ {#if action.toggle}
116
+ <input
117
+ type="checkbox"
118
+ class={['toggle toggle-sm', resolvedClass]}
119
+ title={action.label}
120
+ aria-label={action.label}
121
+ checked={action.toggle(item)}
122
+ onclick={(e) => {
123
+ e.preventDefault();
124
+ e.stopPropagation();
125
+ action.run(item);
126
+ }}
127
+ />
128
+ {:else}
129
+ {@const Icon = action.icon}
130
+ <Button
131
+ variant="ghost"
132
+ class={['btn-xs', resolvedClass]}
133
+ title={action.label}
134
+ aria-label={action.label}
135
+ onclick={(e) => {
136
+ e.stopPropagation();
137
+ action.run(item);
138
+ }}
139
+ >
140
+ <Icon class="size-4" />
141
+ </Button>
142
+ {/if}
143
+ {/if}
144
+ {/each}
145
+ </div>
146
+ {/snippet}
147
+
148
+ <div class="table-wrapper">
149
+ <PaginatedTable
150
+ {data}
151
+ {columns}
152
+ {pageSize}
153
+ {selectable}
154
+ bind:selected
155
+ rowActions={showRowActions ? actionsCell : undefined}
156
+ {pagination}
157
+ {initialSort}
158
+ {initialFilters}
159
+ {onPaginationChange}
160
+ bind:visibleRows
161
+ bind:query
162
+ reorder={reorderActive ? reorder : undefined}
163
+ {onReorder}
164
+ />
165
+ </div>
166
+
167
+ <style>
168
+ .table-wrapper {
169
+ width: 100%;
170
+ max-width: var(--runeforge-crud-max-width);
171
+ margin-inline: auto;
172
+ }
173
+ </style>