runeforge 0.0.61 → 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 (67) 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/components/table/state.svelte.js +7 -2
  49. package/dist/icons/defaults/Clear.svelte +6 -6
  50. package/dist/icons/defaults/Create.svelte +6 -6
  51. package/dist/icons/defaults/Delete.svelte +6 -6
  52. package/dist/icons/defaults/Download.svelte +7 -7
  53. package/dist/icons/defaults/Edit.svelte +7 -7
  54. package/dist/icons/defaults/Filter.svelte +6 -6
  55. package/dist/icons/defaults/FilterActive.svelte +6 -6
  56. package/dist/icons/defaults/Folder.svelte +6 -6
  57. package/dist/icons/defaults/Grip.svelte +7 -7
  58. package/dist/icons/defaults/Home.svelte +6 -6
  59. package/dist/icons/defaults/PasswordHide.svelte +9 -9
  60. package/dist/icons/defaults/PasswordShow.svelte +7 -7
  61. package/dist/icons/defaults/SortAsc.svelte +6 -6
  62. package/dist/icons/defaults/SortDesc.svelte +6 -6
  63. package/dist/icons/defaults/SortNone.svelte +6 -6
  64. package/dist/icons/defaults/View.svelte +7 -7
  65. package/dist/types/attribute.d.ts +3 -0
  66. package/dist/types/crud/fields.d.ts +3 -0
  67. package/package.json +1 -1
@@ -1,31 +1,31 @@
1
- <script lang="ts">
2
- let {
3
- src = null,
4
- text = '',
5
- alt = '',
6
- class: className = 'w-10 rounded-full',
7
- textClass = '',
8
- }: {
9
- src?: string | null;
10
- text?: string;
11
- alt?: string;
12
- class?: string;
13
- textClass?: string;
14
- } = $props();
15
-
16
- const placeholder = $derived(text.trim().slice(0, 2).toUpperCase() || '?');
17
- </script>
18
-
19
- {#if src}
20
- <div class="avatar">
21
- <div class={className}>
22
- <img {src} {alt} />
23
- </div>
24
- </div>
25
- {:else}
26
- <div class="avatar avatar-placeholder">
27
- <div class="bg-neutral text-neutral-content {className}">
28
- <span class={textClass}>{placeholder}</span>
29
- </div>
30
- </div>
31
- {/if}
1
+ <script lang="ts">
2
+ let {
3
+ src = null,
4
+ text = '',
5
+ alt = '',
6
+ class: className = 'w-10 rounded-full',
7
+ textClass = '',
8
+ }: {
9
+ src?: string | null;
10
+ text?: string;
11
+ alt?: string;
12
+ class?: string;
13
+ textClass?: string;
14
+ } = $props();
15
+
16
+ const placeholder = $derived(text.trim().slice(0, 2).toUpperCase() || '?');
17
+ </script>
18
+
19
+ {#if src}
20
+ <div class="avatar">
21
+ <div class={className}>
22
+ <img {src} {alt} />
23
+ </div>
24
+ </div>
25
+ {:else}
26
+ <div class="avatar avatar-placeholder">
27
+ <div class="bg-neutral text-neutral-content {className}">
28
+ <span class={textClass}>{placeholder}</span>
29
+ </div>
30
+ </div>
31
+ {/if}
@@ -1,73 +1,73 @@
1
- <script lang="ts" module>
2
- // Module-scoped so every IconRenderer instance shares one fetch/cache per
3
- // URL instead of re-requesting the same SVG file.
4
- // eslint-disable-next-line svelte/prefer-svelte-reactivity
5
- const cache = new Map<string, Promise<string | null>>();
6
-
7
- async function loadSvg(url: string): Promise<string | null> {
8
- let pending = cache.get(url);
9
- if (!pending) {
10
- pending = fetch(url)
11
- .then((res) => (res.ok ? res.text() : null))
12
- .catch(() => null);
13
- cache.set(url, pending);
14
- }
15
- const svg = await pending;
16
- if (svg === null) cache.delete(url);
17
- return svg;
18
- }
19
-
20
- /** Stamps `class`/width/height onto the fetched markup's root `<svg>` tag
21
- * so Tailwind sizing and `currentColor` theming apply the same way they
22
- * would to a hand-written inline SVG. */
23
- function styleSvg(svg: string, className: string, size: string): string {
24
- return svg.replace(
25
- '<svg',
26
- `<svg class="${className}" width="${size}" height="${size}"`
27
- );
28
- }
29
- </script>
30
-
31
- <script lang="ts">
32
- import { getIconAssetsPath } from '../icons/context.js';
33
-
34
- let {
35
- name,
36
- basePath,
37
- size = '1em',
38
- class: className = '',
39
- }: {
40
- name: string;
41
- /** Overrides the `setIconAssetsPath` context value for this instance. */
42
- basePath?: string;
43
- size?: string | number;
44
- class?: string;
45
- } = $props();
46
-
47
- const resolvedBasePath = $derived(basePath ?? getIconAssetsPath());
48
- const dimension = $derived(typeof size === 'number' ? `${size}px` : size);
49
- const src = $derived(name ? `${resolvedBasePath}/${name}` : null);
50
-
51
- let markup = $state<string | null>(null);
52
-
53
- $effect(() => {
54
- if (!src) {
55
- markup = null;
56
- return;
57
- }
58
- let cancelled = false;
59
- loadSvg(src).then((svg) => {
60
- if (!cancelled) markup = svg;
61
- });
62
- return () => {
63
- cancelled = true;
64
- };
65
- });
66
- </script>
67
-
68
- {#if markup}
69
- <!-- eslint-disable-next-line svelte/no-at-html-tags -->
70
- {@html styleSvg(markup, className, dimension)}
71
- {:else}
72
- <span class={className} title={name}></span>
73
- {/if}
1
+ <script lang="ts" module>
2
+ // Module-scoped so every IconRenderer instance shares one fetch/cache per
3
+ // URL instead of re-requesting the same SVG file.
4
+ // eslint-disable-next-line svelte/prefer-svelte-reactivity
5
+ const cache = new Map<string, Promise<string | null>>();
6
+
7
+ async function loadSvg(url: string): Promise<string | null> {
8
+ let pending = cache.get(url);
9
+ if (!pending) {
10
+ pending = fetch(url)
11
+ .then((res) => (res.ok ? res.text() : null))
12
+ .catch(() => null);
13
+ cache.set(url, pending);
14
+ }
15
+ const svg = await pending;
16
+ if (svg === null) cache.delete(url);
17
+ return svg;
18
+ }
19
+
20
+ /** Stamps `class`/width/height onto the fetched markup's root `<svg>` tag
21
+ * so Tailwind sizing and `currentColor` theming apply the same way they
22
+ * would to a hand-written inline SVG. */
23
+ function styleSvg(svg: string, className: string, size: string): string {
24
+ return svg.replace(
25
+ '<svg',
26
+ `<svg class="${className}" width="${size}" height="${size}"`
27
+ );
28
+ }
29
+ </script>
30
+
31
+ <script lang="ts">
32
+ import { getIconAssetsPath } from '../icons/context.js';
33
+
34
+ let {
35
+ name,
36
+ basePath,
37
+ size = '1em',
38
+ class: className = '',
39
+ }: {
40
+ name: string;
41
+ /** Overrides the `setIconAssetsPath` context value for this instance. */
42
+ basePath?: string;
43
+ size?: string | number;
44
+ class?: string;
45
+ } = $props();
46
+
47
+ const resolvedBasePath = $derived(basePath ?? getIconAssetsPath());
48
+ const dimension = $derived(typeof size === 'number' ? `${size}px` : size);
49
+ const src = $derived(name ? `${resolvedBasePath}/${name}` : null);
50
+
51
+ let markup = $state<string | null>(null);
52
+
53
+ $effect(() => {
54
+ if (!src) {
55
+ markup = null;
56
+ return;
57
+ }
58
+ let cancelled = false;
59
+ loadSvg(src).then((svg) => {
60
+ if (!cancelled) markup = svg;
61
+ });
62
+ return () => {
63
+ cancelled = true;
64
+ };
65
+ });
66
+ </script>
67
+
68
+ {#if markup}
69
+ <!-- eslint-disable-next-line svelte/no-at-html-tags -->
70
+ {@html styleSvg(markup, className, dimension)}
71
+ {:else}
72
+ <span class={className} title={name}></span>
73
+ {/if}
@@ -1,75 +1,75 @@
1
- <script lang="ts">
2
- import type { Snippet } from 'svelte';
3
- import Button from './form/Button.svelte';
4
-
5
- let {
6
- title = '',
7
- onClose,
8
- closeOnClickOutside = true,
9
- onClickOutside,
10
- children,
11
- class: additionalClass,
12
- width,
13
- maxWidth,
14
- height,
15
- maxHeight,
16
- }: {
17
- title?: string;
18
- onClose?: () => void;
19
- /** Whether clicking the backdrop (outside the modal box) closes the modal. */
20
- closeOnClickOutside?: boolean;
21
- /** Callback invoked when clicking outside the modal. Defaults to `onClose`. */
22
- onClickOutside?: () => void;
23
- children: Snippet;
24
- /** Extra classes merged onto the modal box, e.g. Tailwind size utilities
25
- * like `max-w-4xl` or `w-11/12`. */
26
- class?: string;
27
- /** Explicit size overrides (any valid CSS length, e.g. '600px', '90vw').
28
- * Applied as inline styles, so they take priority over `class` utilities. */
29
- width?: string;
30
- maxWidth?: string;
31
- height?: string;
32
- maxHeight?: string;
33
- } = $props();
34
-
35
- const handleClickOutside = $derived(onClickOutside ?? onClose);
36
-
37
- const boxStyle = $derived(
38
- [
39
- width ? `width:${width}` : '',
40
- maxWidth ? `max-width:${maxWidth}` : '',
41
- height ? `height:${height}` : '',
42
- maxHeight ? `max-height:${maxHeight}` : '',
43
- ]
44
- .filter(Boolean)
45
- .join(';')
46
- );
47
- </script>
48
-
49
- <dialog class="modal" open>
50
- <div class={['modal-box', additionalClass]} style={boxStyle}>
51
- <div class="flex items-center justify-between gap-4">
52
- <h3 class="text-lg font-bold">{title}</h3>
53
- {#if onClose}
54
- <Button
55
- variant="ghost"
56
- class="btn-circle"
57
- aria-label="Cerrar"
58
- onclick={onClose}
59
- >
60
- ✕
61
- </Button>
62
- {/if}
63
- </div>
64
-
65
- <div class="divider my-2"></div>
66
-
67
- {@render children()}
68
- </div>
69
-
70
- {#if closeOnClickOutside && handleClickOutside}
71
- <div class="modal-backdrop">
72
- <button onclick={handleClickOutside} aria-label="Cerrar"></button>
73
- </div>
74
- {/if}
75
- </dialog>
1
+ <script lang="ts">
2
+ import type { Snippet } from 'svelte';
3
+ import Button from './form/Button.svelte';
4
+
5
+ let {
6
+ title = '',
7
+ onClose,
8
+ closeOnClickOutside = true,
9
+ onClickOutside,
10
+ children,
11
+ class: additionalClass,
12
+ width,
13
+ maxWidth,
14
+ height,
15
+ maxHeight,
16
+ }: {
17
+ title?: string;
18
+ onClose?: () => void;
19
+ /** Whether clicking the backdrop (outside the modal box) closes the modal. */
20
+ closeOnClickOutside?: boolean;
21
+ /** Callback invoked when clicking outside the modal. Defaults to `onClose`. */
22
+ onClickOutside?: () => void;
23
+ children: Snippet;
24
+ /** Extra classes merged onto the modal box, e.g. Tailwind size utilities
25
+ * like `max-w-4xl` or `w-11/12`. */
26
+ class?: string;
27
+ /** Explicit size overrides (any valid CSS length, e.g. '600px', '90vw').
28
+ * Applied as inline styles, so they take priority over `class` utilities. */
29
+ width?: string;
30
+ maxWidth?: string;
31
+ height?: string;
32
+ maxHeight?: string;
33
+ } = $props();
34
+
35
+ const handleClickOutside = $derived(onClickOutside ?? onClose);
36
+
37
+ const boxStyle = $derived(
38
+ [
39
+ width ? `width:${width}` : '',
40
+ maxWidth ? `max-width:${maxWidth}` : '',
41
+ height ? `height:${height}` : '',
42
+ maxHeight ? `max-height:${maxHeight}` : '',
43
+ ]
44
+ .filter(Boolean)
45
+ .join(';')
46
+ );
47
+ </script>
48
+
49
+ <dialog class="modal" open>
50
+ <div class={['modal-box', additionalClass]} style={boxStyle}>
51
+ <div class="flex items-center justify-between gap-4">
52
+ <h3 class="text-lg font-bold">{title}</h3>
53
+ {#if onClose}
54
+ <Button
55
+ variant="ghost"
56
+ class="btn-circle"
57
+ aria-label="Cerrar"
58
+ onclick={onClose}
59
+ >
60
+ ✕
61
+ </Button>
62
+ {/if}
63
+ </div>
64
+
65
+ <div class="divider my-2"></div>
66
+
67
+ {@render children()}
68
+ </div>
69
+
70
+ {#if closeOnClickOutside && handleClickOutside}
71
+ <div class="modal-backdrop">
72
+ <button onclick={handleClickOutside} aria-label="Cerrar"></button>
73
+ </div>
74
+ {/if}
75
+ </dialog>
@@ -1,40 +1,40 @@
1
- <script lang="ts">
2
- import type { Snippet } from 'svelte';
3
- import Breadcrumbs from '../navigation/Breadcrumbs.svelte';
4
- import type { BreadcrumbItem } from '../../types/breadcrumb.js';
5
-
6
- let {
7
- title,
8
- breadcrumbs = [],
9
- buttons,
10
- }: {
11
- title: string;
12
- breadcrumbs?: BreadcrumbItem[];
13
- buttons?: Snippet;
14
- } = $props();
15
- </script>
16
-
17
- <div class="header-root flex flex-col gap-4 sm:flex-row sm:items-start sm:justify-between">
18
- <div class="flex flex-col gap-1 flex-1">
19
- <h1>{title}</h1>
20
- <Breadcrumbs items={breadcrumbs} />
21
- </div>
22
-
23
- {#if buttons}
24
- <div class="flex min-w-0 items-center gap-2 sm:pt-1">
25
- {@render buttons()}
26
- </div>
27
- {/if}
28
- </div>
29
-
30
- <style>
31
- h1 {
32
- font-size: var(--runeforge-crud-title-size, 1.875rem);
33
- }
34
-
35
- .header-root {
36
- width: 100%;
37
- max-width: var(--runeforge-crud-max-width);
38
- margin-inline: auto;
39
- }
40
- </style>
1
+ <script lang="ts">
2
+ import type { Snippet } from 'svelte';
3
+ import Breadcrumbs from '../navigation/Breadcrumbs.svelte';
4
+ import type { BreadcrumbItem } from '../../types/breadcrumb.js';
5
+
6
+ let {
7
+ title,
8
+ breadcrumbs = [],
9
+ buttons,
10
+ }: {
11
+ title: string;
12
+ breadcrumbs?: BreadcrumbItem[];
13
+ buttons?: Snippet;
14
+ } = $props();
15
+ </script>
16
+
17
+ <div class="header-root flex flex-col gap-4 sm:flex-row sm:items-start sm:justify-between">
18
+ <div class="flex flex-col gap-1 flex-1">
19
+ <h1>{title}</h1>
20
+ <Breadcrumbs items={breadcrumbs} />
21
+ </div>
22
+
23
+ {#if buttons}
24
+ <div class="flex min-w-0 items-center gap-2 sm:pt-1">
25
+ {@render buttons()}
26
+ </div>
27
+ {/if}
28
+ </div>
29
+
30
+ <style>
31
+ h1 {
32
+ font-size: var(--runeforge-crud-title-size, 1.875rem);
33
+ }
34
+
35
+ .header-root {
36
+ width: 100%;
37
+ max-width: var(--runeforge-crud-max-width);
38
+ margin-inline: auto;
39
+ }
40
+ </style>