runeforge 0.0.10 → 0.0.12

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/README.md CHANGED
@@ -326,7 +326,7 @@ Key props:
326
326
  - `labelOne` / `labelMany` — singular and plural names for the entity
327
327
  - `columns` — `ColumnDefinition[]` for the table view
328
328
  - `fields` — `FieldDefinition[]` for form views
329
- - `creation`, `update`, `read`, `deletion` — `ActionConfiguration` objects that define handlers and permissions for each operation
329
+ - `creation`, `update`, `read`, `deletion` — `ActionConfiguration` objects that define handlers and permissions for each operation. Set `confirm: true` on `deletion` to show a confirmation dialog before any delete (single row or batch)
330
330
 
331
331
  ### PaginatedTable
332
332
 
@@ -584,6 +584,8 @@ All UI strings default to **Spanish** (Argentina). To switch to another language
584
584
  | `saveAndContinue` | `string` | `Guardar y continuar` |
585
585
  | `cancel` | `string` | `Cancelar` |
586
586
  | `back` | `string` | `Volver` |
587
+ | `confirm` | `string` | `Confirmar` |
588
+ | `deleteConfirm` | `(count) => string` | `¿Seguro que querés eliminar 3 elementos?` |
587
589
  | `required` | `(field) => string` | `Título es requerido` |
588
590
  | `serverError` | `string` | `Error inesperado del servidor.` |
589
591
 
@@ -3,6 +3,7 @@
3
3
  import { invalidateAll } from '$app/navigation';
4
4
  import Button from '../../form/Button.svelte';
5
5
  import Header from '../../common/Header.svelte';
6
+ import Modal from '../../Modal.svelte';
6
7
  import PaginatedTable from '../../table/PaginatedTable.svelte';
7
8
  import { getIconSet } from '../../../icons/context.js';
8
9
  import { defaultIconSet } from '../../../icons/sets/default.js';
@@ -65,6 +66,7 @@
65
66
  const showRowActions = $derived(allowRead || allowUpdate || allowDelete || actions.length > 0);
66
67
 
67
68
  let selected = new SvelteSet<number>();
69
+ let pendingDeletion = $state<T[] | null>(null);
68
70
 
69
71
  async function runEndpointAction(endpoint: string, items: T[]) {
70
72
  await Promise.all(items.map((item) => {
@@ -83,12 +85,27 @@
83
85
  }
84
86
  }
85
87
 
88
+ function requestDeletion(items: T[]) {
89
+ if (deletion.confirm) {
90
+ pendingDeletion = items;
91
+ } else {
92
+ runDeletion(items);
93
+ }
94
+ }
95
+
86
96
  function handleCreate() { onCreate?.(); }
87
97
 
88
- async function handleDelete() {
98
+ function handleDelete() {
89
99
  const items = [...selected].map(i => data[i]);
90
100
  selected.clear();
91
- await runDeletion(items);
101
+ requestDeletion(items);
102
+ }
103
+
104
+ async function confirmDeletion() {
105
+ if (pendingDeletion) {
106
+ await runDeletion(pendingDeletion);
107
+ pendingDeletion = null;
108
+ }
92
109
  }
93
110
 
94
111
  const rowActions = $derived<RowAction<T>[]>([
@@ -100,7 +117,7 @@
100
117
  })),
101
118
  ...(allowRead ? [{ label: readLabel, icon: icons.view, run: (item: T) => onView?.(item) }] : []),
102
119
  ...(allowUpdate ? [{ label: updateLabel, icon: icons.edit, run: (item: T) => onEdit?.(item) }] : []),
103
- ...(allowDelete ? [{ label: deleteLabel, icon: icons.delete, class: 'text-error', run: (item: T) => runDeletion([item]) }] : []),
120
+ ...(allowDelete ? [{ label: deleteLabel, icon: icons.delete, class: 'text-error', run: (item: T) => requestDeletion([item]) }] : []),
104
121
  ]);
105
122
  </script>
106
123
 
@@ -172,6 +189,20 @@
172
189
  </div>
173
190
  </div>
174
191
 
192
+ {#if pendingDeletion !== null}
193
+ <Modal title={deleteLabel} onClose={() => (pendingDeletion = null)}>
194
+ <p>{strings.deleteConfirm(pendingDeletion.length, deleteLabel)}</p>
195
+ <div class="flex justify-end gap-2 mt-4">
196
+ <Button variant="ghost" onclick={() => (pendingDeletion = null)}>
197
+ {strings.cancel}
198
+ </Button>
199
+ <Button variant="error" onclick={confirmDeletion}>
200
+ {strings.confirm}
201
+ </Button>
202
+ </div>
203
+ </Modal>
204
+ {/if}
205
+
175
206
  <style>
176
207
  .table-wrapper {
177
208
  width: 100%;
package/dist/i18n/en.js CHANGED
@@ -19,6 +19,8 @@ export const en = {
19
19
  saveAndContinue: 'Save and continue',
20
20
  cancel: 'Cancel',
21
21
  back: 'Back',
22
+ confirm: 'Confirm',
23
+ deleteConfirm: (count, actionLabel) => `Are you sure you want to ${String(actionLabel).toLowerCase()} ${count} item${count === 1 ? '' : 's'}?`,
22
24
  required: (field) => `${field} is required`,
23
25
  serverError: 'Unexpected server error.',
24
26
  };
package/dist/i18n/es.js CHANGED
@@ -19,6 +19,8 @@ export const es = {
19
19
  saveAndContinue: 'Guardar y continuar',
20
20
  cancel: 'Cancelar',
21
21
  back: 'Volver',
22
+ confirm: 'Confirmar',
23
+ deleteConfirm: (count, actionLabel) => `¿Seguro que querés ${String(actionLabel).toLowerCase()} ${count} elemento${count === 1 ? '' : 's'}?`,
22
24
  required: (field) => `${field} es requerido`,
23
25
  serverError: 'Error inesperado del servidor.',
24
26
  };
@@ -19,6 +19,8 @@ export interface RuneforgeStrings {
19
19
  saveAndContinue: string;
20
20
  cancel: string;
21
21
  back: string;
22
+ confirm: string;
23
+ deleteConfirm: (count: number, actionLabel: string) => string;
22
24
  required: (field: string) => string;
23
25
  serverError: string;
24
26
  }
@@ -30,6 +30,7 @@ export interface ActionConfiguration<T extends object = Record<string, unknown>>
30
30
  enabled?: boolean;
31
31
  label?: string;
32
32
  endpoint?: string;
33
+ confirm?: boolean;
33
34
  callback?: (items: T[]) => void | Promise<void>;
34
35
  }
35
36
  export interface CustomAction<T extends object = Record<string, unknown>> {
package/package.json CHANGED
@@ -1,79 +1,81 @@
1
1
  {
2
- "name": "runeforge",
3
- "version": "0.0.10",
4
- "description": "SvelteKit toolkit for building metadata-driven CRUD interfaces with tables, forms, and actions",
5
- "license": "MIT",
6
- "author": "Ezequiel Puerta",
7
- "keywords": [
8
- "svelte",
9
- "sveltekit",
10
- "crud",
11
- "table",
12
- "form",
13
- "daisyui",
14
- "tailwindcss",
15
- "ui"
16
- ],
17
- "files": [
18
- "dist",
19
- "!dist/**/*.test.*",
20
- "!dist/**/*.spec.*"
21
- ],
22
- "sideEffects": [
23
- "**/*.css"
24
- ],
25
- "svelte": "./dist/index.js",
26
- "types": "./dist/index.d.ts",
27
- "type": "module",
28
- "exports": {
29
- ".": {
30
- "types": "./dist/index.d.ts",
31
- "svelte": "./dist/index.js"
32
- }
33
- },
34
- "peerDependencies": {
35
- "@sveltejs/kit": "^2.0.0",
36
- "daisyui": "^5.0.0",
37
- "svelte": "^5.0.0",
38
- "tailwindcss": "^4.0.0"
39
- },
40
- "devDependencies": {
41
- "@eslint/js": "^10.0.1",
42
- "@playwright/test": "^1.60.0",
43
- "@sveltejs/adapter-auto": "^7.0.1",
44
- "@sveltejs/kit": "^2.63.0",
45
- "@sveltejs/package": "^2.5.8",
46
- "@sveltejs/vite-plugin-svelte": "^7.1.2",
47
- "@tailwindcss/vite": "^4.3.1",
48
- "@types/node": "^22",
49
- "daisyui": "^5.5.23",
50
- "eslint": "^10.4.1",
51
- "eslint-config-prettier": "^10.1.8",
52
- "eslint-plugin-svelte": "^3.19.0",
53
- "globals": "^17.6.0",
54
- "prettier": "^3.8.3",
55
- "prettier-plugin-svelte": "^4.1.0",
56
- "publint": "^0.3.21",
57
- "svelte": "^5.56.1",
58
- "svelte-bootstrap-icons": "^3.3.0",
59
- "svelte-check": "^4.6.0",
60
- "tailwindcss": "^4.3.1",
61
- "typescript": "^6.0.3",
62
- "typescript-eslint": "^8.60.1",
63
- "vite": "^8.0.16",
64
- "vitest": "^4.1.8"
65
- },
66
- "scripts": {
67
- "dev": "vite dev",
68
- "build": "vite build && npm run prepack",
69
- "preview": "vite preview",
70
- "check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
71
- "check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch",
72
- "test": "pnpm run test:unit && pnpm run test:e2e",
73
- "test:unit": "vitest run",
74
- "test:unit:watch": "vitest",
75
- "test:e2e": "playwright test",
76
- "lint": "prettier --check . && eslint .",
77
- "format": "prettier --write ."
78
- }
79
- }
2
+ "name": "runeforge",
3
+ "version": "0.0.12",
4
+ "description": "SvelteKit toolkit for building metadata-driven CRUD interfaces with tables, forms, and actions",
5
+ "license": "MIT",
6
+ "author": "Ezequiel Puerta",
7
+ "keywords": [
8
+ "svelte",
9
+ "sveltekit",
10
+ "crud",
11
+ "table",
12
+ "form",
13
+ "daisyui",
14
+ "tailwindcss",
15
+ "ui"
16
+ ],
17
+ "scripts": {
18
+ "dev": "vite dev",
19
+ "build": "vite build && npm run prepack",
20
+ "preview": "vite preview",
21
+ "prepare": "svelte-kit sync || echo ''",
22
+ "prepack": "svelte-kit sync && svelte-package && publint",
23
+ "check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
24
+ "check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch",
25
+ "test": "pnpm run test:unit && pnpm run test:e2e",
26
+ "test:unit": "vitest run",
27
+ "test:unit:watch": "vitest",
28
+ "test:e2e": "playwright test",
29
+ "lint": "prettier --check . && eslint .",
30
+ "format": "prettier --write ."
31
+ },
32
+ "files": [
33
+ "dist",
34
+ "!dist/**/*.test.*",
35
+ "!dist/**/*.spec.*"
36
+ ],
37
+ "sideEffects": [
38
+ "**/*.css"
39
+ ],
40
+ "svelte": "./dist/index.js",
41
+ "types": "./dist/index.d.ts",
42
+ "type": "module",
43
+ "exports": {
44
+ ".": {
45
+ "types": "./dist/index.d.ts",
46
+ "svelte": "./dist/index.js"
47
+ }
48
+ },
49
+ "peerDependencies": {
50
+ "@sveltejs/kit": "^2.0.0",
51
+ "daisyui": "^5.0.0",
52
+ "svelte": "^5.0.0",
53
+ "tailwindcss": "^4.0.0"
54
+ },
55
+ "devDependencies": {
56
+ "@eslint/js": "^10.0.1",
57
+ "@playwright/test": "^1.60.0",
58
+ "@sveltejs/adapter-auto": "^7.0.1",
59
+ "@sveltejs/kit": "^2.63.0",
60
+ "@sveltejs/package": "^2.5.8",
61
+ "@sveltejs/vite-plugin-svelte": "^7.1.2",
62
+ "@tailwindcss/vite": "^4.3.1",
63
+ "@types/node": "^22",
64
+ "daisyui": "^5.5.23",
65
+ "eslint": "^10.4.1",
66
+ "eslint-config-prettier": "^10.1.8",
67
+ "eslint-plugin-svelte": "^3.19.0",
68
+ "globals": "^17.6.0",
69
+ "prettier": "^3.8.3",
70
+ "prettier-plugin-svelte": "^4.1.0",
71
+ "publint": "^0.3.21",
72
+ "svelte": "^5.56.1",
73
+ "svelte-bootstrap-icons": "^3.3.0",
74
+ "svelte-check": "^4.6.0",
75
+ "tailwindcss": "^4.3.1",
76
+ "typescript": "^6.0.3",
77
+ "typescript-eslint": "^8.60.1",
78
+ "vite": "^8.0.16",
79
+ "vitest": "^4.1.8"
80
+ }
81
+ }