runeforge 0.0.55 → 0.0.56

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 (54) hide show
  1. package/LICENSE +21 -21
  2. package/README.md +1342 -1342
  3. package/dist/components/Avatar.svelte +31 -31
  4. package/dist/components/IconRenderer.svelte +22 -22
  5. package/dist/components/Modal.svelte +75 -75
  6. package/dist/components/common/Header.svelte +40 -40
  7. package/dist/components/crud/EmbeddedField.svelte +175 -175
  8. package/dist/components/crud/Field.svelte +469 -376
  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/views/Create.svelte +232 -232
  14. package/dist/components/crud/views/Read.svelte +124 -124
  15. package/dist/components/crud/views/Update.svelte +208 -208
  16. package/dist/components/crud/views/list/List.svelte +291 -291
  17. package/dist/components/crud/views/list/Modals.svelte +56 -56
  18. package/dist/components/crud/views/list/Table.svelte +176 -176
  19. package/dist/components/crud/views/list/Toolbar.svelte +341 -341
  20. package/dist/components/form/Button.svelte +27 -27
  21. package/dist/components/form/Label.svelte +37 -37
  22. package/dist/components/form/MultiSelect.svelte +248 -248
  23. package/dist/components/form/PasswordInput.svelte +68 -68
  24. package/dist/components/form/Required.svelte +1 -1
  25. package/dist/components/form/Select.svelte +209 -209
  26. package/dist/components/form/Tree.svelte +62 -62
  27. package/dist/components/form/TreeNode.svelte +66 -66
  28. package/dist/components/navigation/Breadcrumbs.svelte +111 -111
  29. package/dist/components/table/ColumnFilter.svelte +168 -168
  30. package/dist/components/table/PaginatedTable.svelte +536 -536
  31. package/dist/components/table/Paginator.svelte +113 -113
  32. package/dist/components/table/SortHeader.svelte +43 -43
  33. package/dist/components/table/TableBody.svelte +150 -150
  34. package/dist/components/table/TableHeader.svelte +88 -88
  35. package/dist/i18n/en.js +1 -0
  36. package/dist/i18n/es.js +1 -0
  37. package/dist/i18n/types.d.ts +1 -0
  38. package/dist/icons/defaults/Clear.svelte +6 -6
  39. package/dist/icons/defaults/Create.svelte +6 -6
  40. package/dist/icons/defaults/Delete.svelte +6 -6
  41. package/dist/icons/defaults/Download.svelte +7 -7
  42. package/dist/icons/defaults/Edit.svelte +7 -7
  43. package/dist/icons/defaults/Filter.svelte +6 -6
  44. package/dist/icons/defaults/FilterActive.svelte +6 -6
  45. package/dist/icons/defaults/Folder.svelte +6 -6
  46. package/dist/icons/defaults/Grip.svelte +7 -7
  47. package/dist/icons/defaults/Home.svelte +6 -6
  48. package/dist/icons/defaults/PasswordHide.svelte +9 -9
  49. package/dist/icons/defaults/PasswordShow.svelte +7 -7
  50. package/dist/icons/defaults/SortAsc.svelte +6 -6
  51. package/dist/icons/defaults/SortDesc.svelte +6 -6
  52. package/dist/icons/defaults/SortNone.svelte +6 -6
  53. package/dist/icons/defaults/View.svelte +7 -7
  54. package/package.json +1 -1
@@ -1,62 +1,62 @@
1
- <script lang="ts">
2
- import type { SelectOption } from '../../types/attribute.js';
3
- import { buildChildrenByParent, collectDescendantIds } from '../crud/utils/tree.js';
4
- import TreeNode from './TreeNode.svelte';
5
-
6
- let {
7
- name,
8
- value = $bindable([]),
9
- options = [],
10
- disabled = false,
11
- columns = 1,
12
- defaultExpanded = true,
13
- }: {
14
- name?: string;
15
- value?: string[];
16
- options?: SelectOption[];
17
- disabled?: boolean;
18
- columns?: number;
19
- defaultExpanded?: boolean;
20
- } = $props();
21
-
22
- const childrenByParent = $derived(buildChildrenByParent(options));
23
- const selected = $derived(new Set(value));
24
- const roots = $derived(childrenByParent.get(null) ?? []);
25
-
26
- function toggle(nodeValue: string, checked: boolean) {
27
- const affected = [nodeValue, ...collectDescendantIds(nodeValue, childrenByParent)];
28
- if (checked) {
29
- value = [...new Set([...value, ...affected])];
30
- } else {
31
- const affectedSet = new Set(affected);
32
- value = value.filter((v) => !affectedSet.has(v));
33
- }
34
- }
35
- </script>
36
-
37
- <div
38
- class="overflow-y-auto rounded-box border border-base-300 p-2"
39
- style="max-height: var(--runeforge-tree-max-height, 24rem)"
40
- class:opacity-50={disabled}
41
- class:pointer-events-none={disabled}
42
- >
43
- {#if name}
44
- <input type="hidden" {name} value={JSON.stringify(value)} />
45
- {/if}
46
- {#if roots.length === 0}
47
- <p class="px-1 py-2 text-sm text-base-content/40">—</p>
48
- {/if}
49
- <div class:leaf-columns={columns > 1} style={`--columns: ${columns}`}>
50
- {#each roots as root (root.value)}
51
- <TreeNode node={root} {childrenByParent} {selected} onToggle={toggle} {disabled} depth={0} {columns} {defaultExpanded} />
52
- {/each}
53
- </div>
54
- </div>
55
-
56
- <style>
57
- @media (min-width: 1024px) {
58
- .leaf-columns {
59
- columns: var(--columns);
60
- }
61
- }
62
- </style>
1
+ <script lang="ts">
2
+ import type { SelectOption } from '../../types/attribute.js';
3
+ import { buildChildrenByParent, collectDescendantIds } from '../crud/utils/tree.js';
4
+ import TreeNode from './TreeNode.svelte';
5
+
6
+ let {
7
+ name,
8
+ value = $bindable([]),
9
+ options = [],
10
+ disabled = false,
11
+ columns = 1,
12
+ defaultExpanded = true,
13
+ }: {
14
+ name?: string;
15
+ value?: string[];
16
+ options?: SelectOption[];
17
+ disabled?: boolean;
18
+ columns?: number;
19
+ defaultExpanded?: boolean;
20
+ } = $props();
21
+
22
+ const childrenByParent = $derived(buildChildrenByParent(options));
23
+ const selected = $derived(new Set(value));
24
+ const roots = $derived(childrenByParent.get(null) ?? []);
25
+
26
+ function toggle(nodeValue: string, checked: boolean) {
27
+ const affected = [nodeValue, ...collectDescendantIds(nodeValue, childrenByParent)];
28
+ if (checked) {
29
+ value = [...new Set([...value, ...affected])];
30
+ } else {
31
+ const affectedSet = new Set(affected);
32
+ value = value.filter((v) => !affectedSet.has(v));
33
+ }
34
+ }
35
+ </script>
36
+
37
+ <div
38
+ class="overflow-y-auto rounded-box border border-base-300 p-2"
39
+ style="max-height: var(--runeforge-tree-max-height, 24rem)"
40
+ class:opacity-50={disabled}
41
+ class:pointer-events-none={disabled}
42
+ >
43
+ {#if name}
44
+ <input type="hidden" {name} value={JSON.stringify(value)} />
45
+ {/if}
46
+ {#if roots.length === 0}
47
+ <p class="px-1 py-2 text-sm text-base-content/40">—</p>
48
+ {/if}
49
+ <div class:leaf-columns={columns > 1} style={`--columns: ${columns}`}>
50
+ {#each roots as root (root.value)}
51
+ <TreeNode node={root} {childrenByParent} {selected} onToggle={toggle} {disabled} depth={0} {columns} {defaultExpanded} />
52
+ {/each}
53
+ </div>
54
+ </div>
55
+
56
+ <style>
57
+ @media (min-width: 1024px) {
58
+ .leaf-columns {
59
+ columns: var(--columns);
60
+ }
61
+ }
62
+ </style>
@@ -1,66 +1,66 @@
1
- <script lang="ts">
2
- import type { SelectOption } from '../../types/attribute.js';
3
- import TreeNode from './TreeNode.svelte';
4
-
5
- let {
6
- node,
7
- childrenByParent,
8
- selected,
9
- onToggle,
10
- disabled,
11
- depth,
12
- columns,
13
- defaultExpanded,
14
- }: {
15
- node: SelectOption;
16
- childrenByParent: Map<string | null, SelectOption[]>;
17
- selected: Set<string>;
18
- onToggle: (value: string, checked: boolean) => void;
19
- disabled: boolean;
20
- depth: number;
21
- columns: number;
22
- defaultExpanded: boolean;
23
- } = $props();
24
-
25
- let expanded = $state(defaultExpanded);
26
-
27
- const children = $derived(childrenByParent.get(node.value) ?? []);
28
- const hasChildren = $derived(children.length > 0);
29
- </script>
30
-
31
- <div class="flex flex-col" style={`--columns: ${columns}`}>
32
- <div
33
- class="flex w-full items-center gap-1 rounded py-1 pr-2 transition-colors hover:bg-base-200"
34
- style={`padding-left: ${depth * 1.25}rem`}
35
- >
36
- {#if hasChildren}
37
- <button
38
- type="button"
39
- class="btn btn-ghost btn-xs btn-circle"
40
- aria-label={expanded ? 'Collapse' : 'Expand'}
41
- onclick={() => (expanded = !expanded)}
42
- >
43
- <span class="inline-block text-xs transition-transform" class:rotate-90={expanded}>▸</span>
44
- </button>
45
- {:else}
46
- <span class="inline-block size-6"></span>
47
- {/if}
48
-
49
- <input
50
- type="checkbox"
51
- class="checkbox checkbox-sm"
52
- checked={selected.has(node.value)}
53
- {disabled}
54
- onchange={(e) => onToggle(node.value, (e.currentTarget as HTMLInputElement).checked)}
55
- aria-label={node.label}
56
- />
57
-
58
- <span>{node.label}</span>
59
- </div>
60
-
61
- {#if expanded && hasChildren}
62
- {#each children as child (child.value)}
63
- <TreeNode node={child} {childrenByParent} {selected} {onToggle} {disabled} depth={depth + 1} {columns} {defaultExpanded} />
64
- {/each}
65
- {/if}
66
- </div>
1
+ <script lang="ts">
2
+ import type { SelectOption } from '../../types/attribute.js';
3
+ import TreeNode from './TreeNode.svelte';
4
+
5
+ let {
6
+ node,
7
+ childrenByParent,
8
+ selected,
9
+ onToggle,
10
+ disabled,
11
+ depth,
12
+ columns,
13
+ defaultExpanded,
14
+ }: {
15
+ node: SelectOption;
16
+ childrenByParent: Map<string | null, SelectOption[]>;
17
+ selected: Set<string>;
18
+ onToggle: (value: string, checked: boolean) => void;
19
+ disabled: boolean;
20
+ depth: number;
21
+ columns: number;
22
+ defaultExpanded: boolean;
23
+ } = $props();
24
+
25
+ let expanded = $state(defaultExpanded);
26
+
27
+ const children = $derived(childrenByParent.get(node.value) ?? []);
28
+ const hasChildren = $derived(children.length > 0);
29
+ </script>
30
+
31
+ <div class="flex flex-col" style={`--columns: ${columns}`}>
32
+ <div
33
+ class="flex w-full items-center gap-1 rounded py-1 pr-2 transition-colors hover:bg-base-200"
34
+ style={`padding-left: ${depth * 1.25}rem`}
35
+ >
36
+ {#if hasChildren}
37
+ <button
38
+ type="button"
39
+ class="btn btn-ghost btn-xs btn-circle"
40
+ aria-label={expanded ? 'Collapse' : 'Expand'}
41
+ onclick={() => (expanded = !expanded)}
42
+ >
43
+ <span class="inline-block text-xs transition-transform" class:rotate-90={expanded}>▸</span>
44
+ </button>
45
+ {:else}
46
+ <span class="inline-block size-6"></span>
47
+ {/if}
48
+
49
+ <input
50
+ type="checkbox"
51
+ class="checkbox checkbox-sm"
52
+ checked={selected.has(node.value)}
53
+ {disabled}
54
+ onchange={(e) => onToggle(node.value, (e.currentTarget as HTMLInputElement).checked)}
55
+ aria-label={node.label}
56
+ />
57
+
58
+ <span>{node.label}</span>
59
+ </div>
60
+
61
+ {#if expanded && hasChildren}
62
+ {#each children as child (child.value)}
63
+ <TreeNode node={child} {childrenByParent} {selected} {onToggle} {disabled} depth={depth + 1} {columns} {defaultExpanded} />
64
+ {/each}
65
+ {/if}
66
+ </div>
@@ -1,111 +1,111 @@
1
- <script lang="ts">
2
- import { getIconSet } from '../../icons/context.js';
3
- import { defaultIconSet } from '../../icons/sets/default.js';
4
- import { getConfig } from '../../config/context.js';
5
- import type { BreadcrumbItem } from '../../types/breadcrumb.js';
6
-
7
- let {
8
- items = [],
9
- homeHref,
10
- }: {
11
- items?: BreadcrumbItem[];
12
- homeHref?: string;
13
- } = $props();
14
-
15
- const icons = $derived(getIconSet() ?? defaultIconSet);
16
-
17
- const home: BreadcrumbItem = $derived({
18
- label: 'Inicio',
19
- icon: icons.home,
20
- link: { href: homeHref ?? getConfig().homeHref ?? '/' },
21
- });
22
-
23
- const allItems = $derived([home, ...items]);
24
- </script>
25
-
26
- <div class="breadcrumbs">
27
- <ul>
28
- {#each allItems as item, i (i)}
29
- <li>
30
- {#if item.link !== undefined}
31
- <a class="inline-flex items-center gap-2" {...item.link}>
32
- {#if item.icon}
33
- {@const ItemIcon = item.icon}
34
- <ItemIcon />
35
- {/if}
36
- <span>{item.label}</span>
37
- </a>
38
- {:else}
39
- <span class="inline-flex items-center gap-2">
40
- {#if item.icon}
41
- {@const ItemIcon = item.icon}
42
- <ItemIcon />
43
- {/if}
44
- <span>{item.label}</span>
45
- </span>
46
- {/if}
47
- </li>
48
- {/each}
49
- </ul>
50
- </div>
51
-
52
- <style>
53
- div {
54
- font-size: var(--runeforge-breadcrumb-font-size, 0.875rem);
55
- }
56
-
57
- :global(.breadcrumbs svg) {
58
- width: var(--runeforge-breadcrumb-icon-size, 1rem);
59
- height: var(--runeforge-breadcrumb-icon-size, 1rem);
60
- flex-shrink: 0;
61
- }
62
-
63
- /*
64
- * DaisyUI breadcrumbs use @layer rules that Tailwind v4 doesn't propagate
65
- * from node_modules. These unlayered rules override that gap.
66
- */
67
- :global(.breadcrumbs > ul),
68
- :global(.breadcrumbs > ol),
69
- :global(.breadcrumbs > menu) {
70
- display: flex;
71
- align-items: center;
72
- white-space: nowrap;
73
- overflow-x: auto;
74
- }
75
-
76
- :global(.breadcrumbs > ul > li),
77
- :global(.breadcrumbs > ol > li),
78
- :global(.breadcrumbs > menu > li) {
79
- display: flex;
80
- align-items: center;
81
- }
82
-
83
- :global(.breadcrumbs > ul > li + li::before),
84
- :global(.breadcrumbs > ol > li + li::before),
85
- :global(.breadcrumbs > menu > li + li::before) {
86
- content: '';
87
- display: block;
88
- opacity: 0.4;
89
- border-top: 1px solid;
90
- border-right: 1px solid;
91
- width: 0.375rem;
92
- height: 0.375rem;
93
- margin-inline: 0.5rem 0.75rem;
94
- rotate: 45deg;
95
- }
96
-
97
- /*
98
- * Tailwind preflight sets svg { display: block }, which stacks icons above
99
- * labels when the <a>/<span> inline-flex class isn't generated from node_modules.
100
- */
101
- :global(.breadcrumbs > ul > li > a),
102
- :global(.breadcrumbs > ul > li > span),
103
- :global(.breadcrumbs > ol > li > a),
104
- :global(.breadcrumbs > ol > li > span),
105
- :global(.breadcrumbs > menu > li > a),
106
- :global(.breadcrumbs > menu > li > span) {
107
- display: inline-flex;
108
- align-items: center;
109
- gap: 0.5rem;
110
- }
111
- </style>
1
+ <script lang="ts">
2
+ import { getIconSet } from '../../icons/context.js';
3
+ import { defaultIconSet } from '../../icons/sets/default.js';
4
+ import { getConfig } from '../../config/context.js';
5
+ import type { BreadcrumbItem } from '../../types/breadcrumb.js';
6
+
7
+ let {
8
+ items = [],
9
+ homeHref,
10
+ }: {
11
+ items?: BreadcrumbItem[];
12
+ homeHref?: string;
13
+ } = $props();
14
+
15
+ const icons = $derived(getIconSet() ?? defaultIconSet);
16
+
17
+ const home: BreadcrumbItem = $derived({
18
+ label: 'Inicio',
19
+ icon: icons.home,
20
+ link: { href: homeHref ?? getConfig().homeHref ?? '/' },
21
+ });
22
+
23
+ const allItems = $derived([home, ...items]);
24
+ </script>
25
+
26
+ <div class="breadcrumbs">
27
+ <ul>
28
+ {#each allItems as item, i (i)}
29
+ <li>
30
+ {#if item.link !== undefined}
31
+ <a class="inline-flex items-center gap-2" {...item.link}>
32
+ {#if item.icon}
33
+ {@const ItemIcon = item.icon}
34
+ <ItemIcon />
35
+ {/if}
36
+ <span>{item.label}</span>
37
+ </a>
38
+ {:else}
39
+ <span class="inline-flex items-center gap-2">
40
+ {#if item.icon}
41
+ {@const ItemIcon = item.icon}
42
+ <ItemIcon />
43
+ {/if}
44
+ <span>{item.label}</span>
45
+ </span>
46
+ {/if}
47
+ </li>
48
+ {/each}
49
+ </ul>
50
+ </div>
51
+
52
+ <style>
53
+ div {
54
+ font-size: var(--runeforge-breadcrumb-font-size, 0.875rem);
55
+ }
56
+
57
+ :global(.breadcrumbs svg) {
58
+ width: var(--runeforge-breadcrumb-icon-size, 1rem);
59
+ height: var(--runeforge-breadcrumb-icon-size, 1rem);
60
+ flex-shrink: 0;
61
+ }
62
+
63
+ /*
64
+ * DaisyUI breadcrumbs use @layer rules that Tailwind v4 doesn't propagate
65
+ * from node_modules. These unlayered rules override that gap.
66
+ */
67
+ :global(.breadcrumbs > ul),
68
+ :global(.breadcrumbs > ol),
69
+ :global(.breadcrumbs > menu) {
70
+ display: flex;
71
+ align-items: center;
72
+ white-space: nowrap;
73
+ overflow-x: auto;
74
+ }
75
+
76
+ :global(.breadcrumbs > ul > li),
77
+ :global(.breadcrumbs > ol > li),
78
+ :global(.breadcrumbs > menu > li) {
79
+ display: flex;
80
+ align-items: center;
81
+ }
82
+
83
+ :global(.breadcrumbs > ul > li + li::before),
84
+ :global(.breadcrumbs > ol > li + li::before),
85
+ :global(.breadcrumbs > menu > li + li::before) {
86
+ content: '';
87
+ display: block;
88
+ opacity: 0.4;
89
+ border-top: 1px solid;
90
+ border-right: 1px solid;
91
+ width: 0.375rem;
92
+ height: 0.375rem;
93
+ margin-inline: 0.5rem 0.75rem;
94
+ rotate: 45deg;
95
+ }
96
+
97
+ /*
98
+ * Tailwind preflight sets svg { display: block }, which stacks icons above
99
+ * labels when the <a>/<span> inline-flex class isn't generated from node_modules.
100
+ */
101
+ :global(.breadcrumbs > ul > li > a),
102
+ :global(.breadcrumbs > ul > li > span),
103
+ :global(.breadcrumbs > ol > li > a),
104
+ :global(.breadcrumbs > ol > li > span),
105
+ :global(.breadcrumbs > menu > li > a),
106
+ :global(.breadcrumbs > menu > li > span) {
107
+ display: inline-flex;
108
+ align-items: center;
109
+ gap: 0.5rem;
110
+ }
111
+ </style>