@svadmin/ui 0.49.3 → 0.51.0

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 (51) hide show
  1. package/dist/components/AutoForm.svelte +105 -54
  2. package/dist/components/AutoForm.svelte.d.ts +4 -0
  3. package/dist/components/AutoTable.svelte +223 -106
  4. package/dist/components/AutoTable.svelte.d.ts +5 -0
  5. package/dist/components/Breadcrumbs.svelte +3 -2
  6. package/dist/components/Breadcrumbs.svelte.d.ts +1 -0
  7. package/dist/components/CreatePage.svelte +25 -5
  8. package/dist/components/CreatePage.svelte.d.ts +3 -0
  9. package/dist/components/DrawerForm.svelte +1 -1
  10. package/dist/components/EditPage.svelte +25 -5
  11. package/dist/components/EditPage.svelte.d.ts +3 -0
  12. package/dist/components/FieldRenderer.svelte +15 -2
  13. package/dist/components/FieldRenderer.svelte.d.ts +1 -0
  14. package/dist/components/ListPage.svelte +29 -3
  15. package/dist/components/ListPage.svelte.d.ts +9 -0
  16. package/dist/components/ModalForm.svelte +1 -1
  17. package/dist/components/PageHeader.svelte +57 -10
  18. package/dist/components/PageHeader.svelte.d.ts +6 -0
  19. package/dist/components/ShowPage.svelte +97 -26
  20. package/dist/components/ShowPage.svelte.d.ts +10 -3
  21. package/dist/components/buttons/CloneButton.svelte +23 -2
  22. package/dist/components/buttons/CloneButton.svelte.d.ts +3 -0
  23. package/dist/components/buttons/CreateButton.svelte +22 -2
  24. package/dist/components/buttons/CreateButton.svelte.d.ts +3 -0
  25. package/dist/components/buttons/DeleteButton.svelte +23 -3
  26. package/dist/components/buttons/DeleteButton.svelte.d.ts +3 -0
  27. package/dist/components/buttons/EditButton.svelte +23 -2
  28. package/dist/components/buttons/EditButton.svelte.d.ts +3 -0
  29. package/dist/components/buttons/ExportButton.svelte +22 -3
  30. package/dist/components/buttons/ExportButton.svelte.d.ts +3 -0
  31. package/dist/components/buttons/ImportButton.svelte +39 -17
  32. package/dist/components/buttons/ImportButton.svelte.d.ts +3 -0
  33. package/dist/components/buttons/ListButton.svelte +29 -4
  34. package/dist/components/buttons/ListButton.svelte.d.ts +4 -0
  35. package/dist/components/buttons/RefreshButton.svelte +22 -2
  36. package/dist/components/buttons/RefreshButton.svelte.d.ts +3 -0
  37. package/dist/components/buttons/SaveButton.svelte +23 -2
  38. package/dist/components/buttons/SaveButton.svelte.d.ts +3 -0
  39. package/dist/components/buttons/ShowButton.svelte +32 -4
  40. package/dist/components/buttons/ShowButton.svelte.d.ts +4 -0
  41. package/dist/components/content/DescriptionList.svelte +125 -15
  42. package/dist/components/content/DescriptionList.svelte.d.ts +6 -2
  43. package/dist/components/content/FilterToolbar.svelte +81 -8
  44. package/dist/components/content/FilterToolbar.svelte.d.ts +7 -1
  45. package/dist/components/content/StatusTabs.svelte +156 -0
  46. package/dist/components/content/StatusTabs.svelte.d.ts +18 -0
  47. package/dist/components/content/index.d.ts +2 -0
  48. package/dist/components/content/index.js +1 -0
  49. package/dist/index.d.ts +2 -0
  50. package/dist/index.js +1 -0
  51. package/package.json +2 -2
@@ -1,4 +1,5 @@
1
1
  <script lang="ts">
2
+ import type { Snippet } from 'svelte';
2
3
  import { useNavigation, useCan, useTranslation } from '@svadmin/core';
3
4
  import { Button } from '../ui/button/index.js';
4
5
  import { Copy } from '@lucide/svelte';
@@ -7,9 +8,19 @@
7
8
 
8
9
  const i18n = useTranslation();
9
10
 
10
- let { resource, recordItemId, hideText = false, accessControl = { enabled: true, hideIfUnauthorized: true }, class: className = '' } = $props<{
11
+ let {
12
+ resource,
13
+ recordItemId,
14
+ label,
15
+ children,
16
+ hideText = false,
17
+ accessControl = { enabled: true, hideIfUnauthorized: true },
18
+ class: className = '',
19
+ } = $props<{
11
20
  resource: string;
12
21
  recordItemId: string | number;
22
+ label?: string;
23
+ children?: Snippet;
13
24
  hideText?: boolean;
14
25
  accessControl?: ButtonAccessControl;
15
26
  class?: string;
@@ -24,6 +35,7 @@
24
35
  queryOptions: { enabled: accessControl?.enabled ?? true }
25
36
  }));
26
37
  const hidden = $derived(accessControl?.hideIfUnauthorized && !can.allowed);
38
+ const displayText = $derived(label ?? i18n.t('common.clone'));
27
39
  </script>
28
40
 
29
41
  {#if !hidden}
@@ -31,10 +43,19 @@
31
43
  variant="outline"
32
44
  size={hideText ? 'icon' : 'sm'}
33
45
  class={className}
46
+ aria-label={hideText ? displayText : undefined}
34
47
  disabled={!can.allowed}
35
48
  onclick={() => nav.clone(resource, recordItemId)}
36
49
  >
37
50
  <Copy class="h-4 w-4" />
38
- {#if !hideText}<span class="ml-1">{i18n.t('common.clone')}</span>{/if}
51
+ {#if !hideText}
52
+ <span class="ml-1">
53
+ {#if children}
54
+ {@render children()}
55
+ {:else}
56
+ {displayText}
57
+ {/if}
58
+ </span>
59
+ {/if}
39
60
  </Button>
40
61
  {/if}
@@ -1,7 +1,10 @@
1
+ import type { Snippet } from 'svelte';
1
2
  import type { ButtonAccessControl } from './access-control';
2
3
  type $$ComponentProps = {
3
4
  resource: string;
4
5
  recordItemId: string | number;
6
+ label?: string;
7
+ children?: Snippet;
5
8
  hideText?: boolean;
6
9
  accessControl?: ButtonAccessControl;
7
10
  class?: string;
@@ -1,4 +1,5 @@
1
1
  <script lang="ts">
2
+ import type { Snippet } from 'svelte';
2
3
  import { useNavigation, useCan, useTranslation } from '@svadmin/core';
3
4
  import { Button } from '../ui/button/index.js';
4
5
  import { Plus } from '@lucide/svelte';
@@ -6,8 +7,17 @@
6
7
 
7
8
  const i18n = useTranslation();
8
9
 
9
- let { resource, hideText = false, accessControl = { enabled: true, hideIfUnauthorized: true }, class: className = '' } = $props<{
10
+ let {
11
+ resource,
12
+ label,
13
+ children,
14
+ hideText = false,
15
+ accessControl = { enabled: true, hideIfUnauthorized: true },
16
+ class: className = '',
17
+ } = $props<{
10
18
  resource: string;
19
+ label?: string;
20
+ children?: Snippet;
11
21
  hideText?: boolean;
12
22
  accessControl?: ButtonAccessControl;
13
23
  class?: string;
@@ -22,6 +32,7 @@
22
32
  queryOptions: { enabled: accessControl?.enabled ?? true }
23
33
  }));
24
34
  const hidden = $derived(accessControl?.hideIfUnauthorized && !can.allowed);
35
+ const displayText = $derived(label ?? i18n.t('common.create'));
25
36
  </script>
26
37
 
27
38
  {#if !hidden}
@@ -29,10 +40,19 @@
29
40
  variant="default"
30
41
  size={hideText ? 'icon' : 'default'}
31
42
  class={className}
43
+ aria-label={hideText ? displayText : undefined}
32
44
  disabled={!can.allowed}
33
45
  onclick={() => nav.create(resource)}
34
46
  >
35
47
  <Plus class="h-4 w-4" />
36
- {#if !hideText}<span class="ml-1">{i18n.t('common.create')}</span>{/if}
48
+ {#if !hideText}
49
+ <span class="ml-1">
50
+ {#if children}
51
+ {@render children()}
52
+ {:else}
53
+ {displayText}
54
+ {/if}
55
+ </span>
56
+ {/if}
37
57
  </Button>
38
58
  {/if}
@@ -1,6 +1,9 @@
1
+ import type { Snippet } from 'svelte';
1
2
  import type { ButtonAccessControl } from './access-control';
2
3
  type $$ComponentProps = {
3
4
  resource: string;
5
+ label?: string;
6
+ children?: Snippet;
4
7
  hideText?: boolean;
5
8
  accessControl?: ButtonAccessControl;
6
9
  class?: string;
@@ -1,4 +1,5 @@
1
1
  <script lang="ts">
2
+ import type { Snippet } from 'svelte';
2
3
  import { useDelete, useCan, useTranslation } from '@svadmin/core';
3
4
  import { Button } from '../ui/button/index.js';
4
5
  import { Trash2 } from '@lucide/svelte';
@@ -8,11 +9,20 @@
8
9
  const i18n = useTranslation();
9
10
 
10
11
  let {
11
- resource, recordItemId, hideText = false,
12
- accessControl = { enabled: true, hideIfUnauthorized: true }, onSuccess, undoable = false, class: className = '',
12
+ resource,
13
+ recordItemId,
14
+ label,
15
+ children,
16
+ hideText = false,
17
+ accessControl = { enabled: true, hideIfUnauthorized: true },
18
+ onSuccess,
19
+ undoable = false,
20
+ class: className = '',
13
21
  } = $props<{
14
22
  resource: string;
15
23
  recordItemId: string | number;
24
+ label?: string;
25
+ children?: Snippet;
16
26
  hideText?: boolean;
17
27
  accessControl?: ButtonAccessControl;
18
28
  onSuccess?: () => void;
@@ -29,6 +39,7 @@
29
39
  queryOptions: { enabled: accessControl?.enabled ?? true }
30
40
  }));
31
41
  const hidden = $derived(accessControl?.hideIfUnauthorized && !can.allowed);
42
+ const displayText = $derived(label ?? i18n.t('common.delete'));
32
43
  let confirming = $state(false);
33
44
 
34
45
  async function handleDelete() {
@@ -59,11 +70,20 @@
59
70
  variant="ghost"
60
71
  size={hideText ? 'icon' : 'sm'}
61
72
  class="text-destructive hover:text-destructive {className}"
73
+ aria-label={hideText ? displayText : undefined}
62
74
  disabled={!can.allowed}
63
75
  onclick={handleDelete}
64
76
  >
65
77
  <Trash2 class="h-4 w-4" />
66
- {#if !hideText}<span class="ml-1">{i18n.t('common.delete')}</span>{/if}
78
+ {#if !hideText}
79
+ <span class="ml-1">
80
+ {#if children}
81
+ {@render children()}
82
+ {:else}
83
+ {displayText}
84
+ {/if}
85
+ </span>
86
+ {/if}
67
87
  </Button>
68
88
  {/if}
69
89
  {/if}
@@ -1,7 +1,10 @@
1
+ import type { Snippet } from 'svelte';
1
2
  import type { ButtonAccessControl } from './access-control';
2
3
  type $$ComponentProps = {
3
4
  resource: string;
4
5
  recordItemId: string | number;
6
+ label?: string;
7
+ children?: Snippet;
5
8
  hideText?: boolean;
6
9
  accessControl?: ButtonAccessControl;
7
10
  onSuccess?: () => void;
@@ -1,4 +1,5 @@
1
1
  <script lang="ts">
2
+ import type { Snippet } from 'svelte';
2
3
  import { useNavigation, useCan, useTranslation } from '@svadmin/core';
3
4
  import { Button } from '../ui/button/index.js';
4
5
  import { Pencil } from '@lucide/svelte';
@@ -7,9 +8,19 @@
7
8
 
8
9
  const i18n = useTranslation();
9
10
 
10
- let { resource, recordItemId, hideText = false, accessControl = { enabled: true, hideIfUnauthorized: true }, class: className = '' } = $props<{
11
+ let {
12
+ resource,
13
+ recordItemId,
14
+ label,
15
+ children,
16
+ hideText = false,
17
+ accessControl = { enabled: true, hideIfUnauthorized: true },
18
+ class: className = '',
19
+ } = $props<{
11
20
  resource: string;
12
21
  recordItemId: string | number;
22
+ label?: string;
23
+ children?: Snippet;
13
24
  hideText?: boolean;
14
25
  accessControl?: ButtonAccessControl;
15
26
  class?: string;
@@ -24,6 +35,7 @@
24
35
  queryOptions: { enabled: accessControl?.enabled ?? true }
25
36
  }));
26
37
  const hidden = $derived(accessControl?.hideIfUnauthorized && !can.allowed);
38
+ const displayText = $derived(label ?? i18n.t('common.edit'));
27
39
  </script>
28
40
 
29
41
  {#if !hidden}
@@ -31,10 +43,19 @@
31
43
  variant="outline"
32
44
  size={hideText ? 'icon' : 'sm'}
33
45
  class={className}
46
+ aria-label={hideText ? displayText : undefined}
34
47
  disabled={!can.allowed}
35
48
  onclick={() => nav.edit(resource, recordItemId)}
36
49
  >
37
50
  <Pencil class="h-4 w-4" />
38
- {#if !hideText}<span class="ml-1">{i18n.t('common.edit')}</span>{/if}
51
+ {#if !hideText}
52
+ <span class="ml-1">
53
+ {#if children}
54
+ {@render children()}
55
+ {:else}
56
+ {displayText}
57
+ {/if}
58
+ </span>
59
+ {/if}
39
60
  </Button>
40
61
  {/if}
@@ -1,7 +1,10 @@
1
+ import type { Snippet } from 'svelte';
1
2
  import type { ButtonAccessControl } from './access-control';
2
3
  type $$ComponentProps = {
3
4
  resource: string;
4
5
  recordItemId: string | number;
6
+ label?: string;
7
+ children?: Snippet;
5
8
  hideText?: boolean;
6
9
  accessControl?: ButtonAccessControl;
7
10
  class?: string;
@@ -1,4 +1,5 @@
1
1
  <script lang="ts">
2
+ import type { Snippet } from 'svelte';
2
3
  import { useExport, useCan, useTranslation } from '@svadmin/core';
3
4
  import { Button } from '../ui/button/index.js';
4
5
  import { Download } from '@lucide/svelte';
@@ -6,8 +7,17 @@
6
7
 
7
8
  const i18n = useTranslation();
8
9
 
9
- let { resource, hideText = false, accessControl = { enabled: true, hideIfUnauthorized: true }, class: className = '' } = $props<{
10
+ let {
11
+ resource,
12
+ label,
13
+ children,
14
+ hideText = false,
15
+ accessControl = { enabled: true, hideIfUnauthorized: true },
16
+ class: className = '',
17
+ } = $props<{
10
18
  resource: string;
19
+ label?: string;
20
+ children?: Snippet;
11
21
  hideText?: boolean;
12
22
  accessControl?: ButtonAccessControl;
13
23
  class?: string;
@@ -22,18 +32,27 @@
22
32
  queryOptions: { enabled: accessControl?.enabled ?? true }
23
33
  }));
24
34
  const hidden = $derived(accessControl?.hideIfUnauthorized && !can.allowed);
35
+ const displayText = $derived(label ?? i18n.t('common.export'));
25
36
  </script>
26
37
 
27
38
  {#if !hidden}
28
-
29
39
  <Button
30
40
  variant="outline"
31
41
  size={hideText ? 'icon' : 'sm'}
32
42
  class={className}
43
+ aria-label={hideText ? displayText : undefined}
33
44
  disabled={isLoading || !can.allowed}
34
45
  onclick={triggerExport}
35
46
  >
36
47
  <Download class="h-4 w-4" />
37
- {#if !hideText}<span class="ml-1">{i18n.t('common.export')}</span>{/if}
48
+ {#if !hideText}
49
+ <span class="ml-1">
50
+ {#if children}
51
+ {@render children()}
52
+ {:else}
53
+ {displayText}
54
+ {/if}
55
+ </span>
56
+ {/if}
38
57
  </Button>
39
58
  {/if}
@@ -1,6 +1,9 @@
1
+ import type { Snippet } from 'svelte';
1
2
  import type { ButtonAccessControl } from './access-control';
2
3
  type $$ComponentProps = {
3
4
  resource: string;
5
+ label?: string;
6
+ children?: Snippet;
4
7
  hideText?: boolean;
5
8
  accessControl?: ButtonAccessControl;
6
9
  class?: string;
@@ -1,4 +1,5 @@
1
1
  <script lang="ts">
2
+ import type { Snippet } from 'svelte';
2
3
  import { useImport, useCan, useTranslation } from '@svadmin/core';
3
4
  import { Button } from '../ui/button/index.js';
4
5
  import { Upload } from '@lucide/svelte';
@@ -6,8 +7,18 @@
6
7
 
7
8
  const i18n = useTranslation();
8
9
 
9
- let { resource, hideText = false, onFinish, accessControl = { enabled: true, hideIfUnauthorized: true }, class: className = '' } = $props<{
10
+ let {
11
+ resource,
12
+ label,
13
+ children,
14
+ hideText = false,
15
+ onFinish,
16
+ accessControl = { enabled: true, hideIfUnauthorized: true },
17
+ class: className = '',
18
+ } = $props<{
10
19
  resource: string;
20
+ label?: string;
21
+ children?: Snippet;
11
22
  hideText?: boolean;
12
23
  onFinish?: (result: { succeeded: unknown[]; errored: { request: unknown; error: unknown }[] }) => void;
13
24
  accessControl?: ButtonAccessControl;
@@ -21,6 +32,15 @@
21
32
  onFinish: (result) => onFinish?.(result),
22
33
  });
23
34
 
35
+ const can = useCan(() => ({
36
+ resource,
37
+ action: 'import',
38
+ params: accessControl?.params,
39
+ meta: accessControl?.meta,
40
+ queryOptions: { enabled: accessControl?.enabled ?? true },
41
+ }));
42
+ const hidden = $derived(accessControl?.hideIfUnauthorized && !can.allowed);
43
+
24
44
  function triggerImport() {
25
45
  fileInput?.click();
26
46
  }
@@ -34,32 +54,34 @@
34
54
  }
35
55
  }
36
56
 
37
- const can = useCan(() => ({
38
- resource,
39
- action: 'import',
40
- params: accessControl?.params,
41
- meta: accessControl?.meta,
42
- queryOptions: { enabled: accessControl?.enabled ?? true }
43
- }));
44
- const hidden = $derived(accessControl?.hideIfUnauthorized && !can.allowed);
57
+ const displayText = $derived(label ?? i18n.t('common.import'));
45
58
  </script>
46
59
 
47
60
  {#if !hidden}
48
- <input
49
- bind:this={fileInput}
50
- type="file"
51
- accept=".csv"
52
- style="display:none"
53
- onchange={handleFileChange}
54
- />
61
+ <input
62
+ type="file"
63
+ accept={importHook.inputProps.accept}
64
+ class="hidden"
65
+ bind:this={fileInput}
66
+ onchange={handleFileChange}
67
+ />
55
68
  <Button
56
69
  variant="outline"
57
70
  size={hideText ? 'icon' : 'sm'}
58
71
  class={className}
72
+ aria-label={hideText ? displayText : undefined}
59
73
  disabled={importHook.isLoading || !can.allowed}
60
74
  onclick={triggerImport}
61
75
  >
62
76
  <Upload class="h-4 w-4" />
63
- {#if !hideText}<span class="ml-1">{i18n.t('common.import')}</span>{/if}
77
+ {#if !hideText}
78
+ <span class="ml-1">
79
+ {#if children}
80
+ {@render children()}
81
+ {:else}
82
+ {displayText}
83
+ {/if}
84
+ </span>
85
+ {/if}
64
86
  </Button>
65
87
  {/if}
@@ -1,6 +1,9 @@
1
+ import type { Snippet } from 'svelte';
1
2
  import type { ButtonAccessControl } from './access-control';
2
3
  type $$ComponentProps = {
3
4
  resource: string;
5
+ label?: string;
6
+ children?: Snippet;
4
7
  hideText?: boolean;
5
8
  onFinish?: (result: {
6
9
  succeeded: unknown[];
@@ -1,23 +1,48 @@
1
1
  <script lang="ts">
2
- import { useNavigation } from '@svadmin/core';
2
+ import type { Snippet } from 'svelte';
3
+ import { useNavigation, getResource, useTranslation } from '@svadmin/core';
3
4
  import { Button } from '../ui/button/index.js';
4
5
  import { List } from '@lucide/svelte';
5
6
 
6
- let { resource, hideText = false, class: className = '' } = $props<{
7
+ const i18n = useTranslation();
8
+
9
+ let { resource: resourceName, hideText = false, label, children, onBeforeNavigate, class: className = '' } = $props<{
7
10
  resource: string;
8
11
  hideText?: boolean;
12
+ label?: string;
13
+ children?: Snippet;
14
+ onBeforeNavigate?: (navigate: () => void) => void;
9
15
  class?: string;
10
16
  }>();
11
17
 
12
18
  const nav = useNavigation();
19
+ const res = $derived((() => {
20
+ try { return getResource(resourceName); } catch { return null; }
21
+ })());
22
+ const displayLabel = $derived(label ?? res?.label ?? i18n.t('common.list') ?? resourceName);
23
+
24
+ function navigateToList() {
25
+ const navigate = () => nav.list(resourceName);
26
+ if (onBeforeNavigate) onBeforeNavigate(navigate);
27
+ else navigate();
28
+ }
13
29
  </script>
14
30
 
15
31
  <Button
16
32
  variant="outline"
17
33
  size={hideText ? 'icon' : 'sm'}
18
34
  class={className}
19
- onclick={() => nav.list(resource)}
35
+ aria-label={hideText ? displayLabel : undefined}
36
+ onclick={navigateToList}
20
37
  >
21
38
  <List class="h-4 w-4" />
22
- {#if !hideText}<span class="ml-1">{resource}</span>{/if}
39
+ {#if !hideText}
40
+ <span class="ml-1">
41
+ {#if children}
42
+ {@render children()}
43
+ {:else}
44
+ {displayLabel}
45
+ {/if}
46
+ </span>
47
+ {/if}
23
48
  </Button>
@@ -1,6 +1,10 @@
1
+ import type { Snippet } from 'svelte';
1
2
  type $$ComponentProps = {
2
3
  resource: string;
3
4
  hideText?: boolean;
5
+ label?: string;
6
+ children?: Snippet;
7
+ onBeforeNavigate?: (navigate: () => void) => void;
4
8
  class?: string;
5
9
  };
6
10
  declare const ListButton: import("svelte").Component<$$ComponentProps, {}, "">;
@@ -1,12 +1,21 @@
1
1
  <script lang="ts">
2
+ import type { Snippet } from 'svelte';
2
3
  import { useInvalidate, useTranslation } from '@svadmin/core';
3
4
  import { Button } from '../ui/button/index.js';
4
5
  import { RefreshCw } from '@lucide/svelte';
5
6
 
6
7
  const i18n = useTranslation();
7
8
 
8
- let { resource, hideText = false, class: className = '' } = $props<{
9
+ let {
10
+ resource,
11
+ label,
12
+ children,
13
+ hideText = false,
14
+ class: className = '',
15
+ } = $props<{
9
16
  resource: string;
17
+ label?: string;
18
+ children?: Snippet;
10
19
  hideText?: boolean;
11
20
  class?: string;
12
21
  }>();
@@ -25,14 +34,25 @@
25
34
  if (spinTimer) clearTimeout(spinTimer);
26
35
  spinTimer = setTimeout(() => { spinning = false; }, 600);
27
36
  }
37
+
38
+ const displayText = $derived(label ?? i18n.t('common.refresh'));
28
39
  </script>
29
40
 
30
41
  <Button
31
42
  variant="ghost"
32
43
  size={hideText ? 'icon' : 'sm'}
33
44
  class={className}
45
+ aria-label={hideText ? displayText : undefined}
34
46
  onclick={refresh}
35
47
  >
36
48
  <RefreshCw class="h-4 w-4 {spinning ? 'animate-spin' : ''}" />
37
- {#if !hideText}<span class="ml-1">{i18n.t('common.retry')}</span>{/if}
49
+ {#if !hideText}
50
+ <span class="ml-1">
51
+ {#if children}
52
+ {@render children()}
53
+ {:else}
54
+ {displayText}
55
+ {/if}
56
+ </span>
57
+ {/if}
38
58
  </Button>
@@ -1,5 +1,8 @@
1
+ import type { Snippet } from 'svelte';
1
2
  type $$ComponentProps = {
2
3
  resource: string;
4
+ label?: string;
5
+ children?: Snippet;
3
6
  hideText?: boolean;
4
7
  class?: string;
5
8
  };
@@ -1,16 +1,28 @@
1
1
  <script lang="ts">
2
+ import type { Snippet } from 'svelte';
2
3
  import { useTranslation } from '@svadmin/core';
3
4
  import { Button } from '../ui/button/index.js';
4
5
  import { Save, Loader2 } from '@lucide/svelte';
5
6
 
6
7
  const i18n = useTranslation();
7
8
 
8
- let { loading = false, hideText = false, type = 'submit', class: className = '' } = $props<{
9
+ let {
10
+ loading = false,
11
+ label,
12
+ children,
13
+ hideText = false,
14
+ type = 'submit',
15
+ class: className = '',
16
+ } = $props<{
9
17
  loading?: boolean;
18
+ label?: string;
19
+ children?: Snippet;
10
20
  hideText?: boolean;
11
21
  type?: 'submit' | 'button';
12
22
  class?: string;
13
23
  }>();
24
+
25
+ const displayText = $derived(label ?? i18n.t('common.save'));
14
26
  </script>
15
27
 
16
28
  <Button
@@ -18,6 +30,7 @@
18
30
  variant="default"
19
31
  size={hideText ? 'icon' : 'default'}
20
32
  class={className}
33
+ aria-label={hideText ? displayText : undefined}
21
34
  disabled={loading}
22
35
  >
23
36
  {#if loading}
@@ -25,5 +38,13 @@
25
38
  {:else}
26
39
  <Save class="h-4 w-4" />
27
40
  {/if}
28
- {#if !hideText}<span class="ml-1">{i18n.t('common.save')}</span>{/if}
41
+ {#if !hideText}
42
+ <span class="ml-1">
43
+ {#if children}
44
+ {@render children()}
45
+ {:else}
46
+ {displayText}
47
+ {/if}
48
+ </span>
49
+ {/if}
29
50
  </Button>
@@ -1,5 +1,8 @@
1
+ import type { Snippet } from 'svelte';
1
2
  type $$ComponentProps = {
2
3
  loading?: boolean;
4
+ label?: string;
5
+ children?: Snippet;
3
6
  hideText?: boolean;
4
7
  type?: 'submit' | 'button';
5
8
  class?: string;