@svadmin/ui 0.74.0 → 0.76.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 (65) hide show
  1. package/dist/app.css +14 -0
  2. package/dist/app.theme.css +14 -0
  3. package/dist/components/AdminApp.svelte +5 -5
  4. package/dist/components/AppFooter.svelte +137 -0
  5. package/dist/components/AppFooter.svelte.d.ts +25 -0
  6. package/dist/components/CodeEditor.svelte +145 -0
  7. package/dist/components/CodeEditor.svelte.d.ts +26 -0
  8. package/dist/components/DatePicker.svelte +2 -2
  9. package/dist/components/DatePicker.svelte.d.ts +1 -1
  10. package/dist/components/DateRangePicker.svelte +2 -2
  11. package/dist/components/DateRangePicker.svelte.d.ts +1 -1
  12. package/dist/components/DateTimeInput.svelte +18 -18
  13. package/dist/components/DateTimeInput.svelte.d.ts +18 -18
  14. package/dist/components/DateTimePicker.svelte +2 -2
  15. package/dist/components/DateTimePicker.svelte.d.ts +1 -1
  16. package/dist/components/FieldRenderer.svelte +1 -1
  17. package/dist/components/HighlightText.svelte +46 -0
  18. package/dist/components/HighlightText.svelte.d.ts +13 -0
  19. package/dist/components/JsonEditor.svelte +182 -0
  20. package/dist/components/JsonEditor.svelte.d.ts +22 -0
  21. package/dist/components/LazyPage.svelte +3 -3
  22. package/dist/components/LazyPage.svelte.d.ts +2 -2
  23. package/dist/components/Marquee.svelte +104 -0
  24. package/dist/components/Marquee.svelte.d.ts +20 -0
  25. package/dist/components/MediaPlayer.svelte +104 -0
  26. package/dist/components/MediaPlayer.svelte.d.ts +21 -0
  27. package/dist/components/PasswordInput.svelte +3 -3
  28. package/dist/components/PasswordInput.svelte.d.ts +2 -1
  29. package/dist/components/PhoneInput.svelte +157 -0
  30. package/dist/components/PhoneInput.svelte.d.ts +26 -0
  31. package/dist/components/QRCode.svelte +88 -0
  32. package/dist/components/QRCode.svelte.d.ts +22 -0
  33. package/dist/components/ResizableGrid.svelte +252 -0
  34. package/dist/components/ResizableGrid.svelte.d.ts +34 -0
  35. package/dist/components/ResourceOperationsPage.svelte +5 -1
  36. package/dist/components/TimePicker.svelte +2 -2
  37. package/dist/components/TimePicker.svelte.d.ts +1 -1
  38. package/dist/components/TooltipButton.svelte +3 -4
  39. package/dist/components/TopProgressBar.svelte +90 -0
  40. package/dist/components/TopProgressBar.svelte.d.ts +15 -0
  41. package/dist/components/browser.svelte.d.ts +65 -0
  42. package/dist/components/browser.svelte.js +228 -0
  43. package/dist/components/charts/AreaChart.svelte +78 -0
  44. package/dist/components/charts/AreaChart.svelte.d.ts +17 -0
  45. package/dist/components/charts/ScatterChart.svelte +82 -0
  46. package/dist/components/charts/ScatterChart.svelte.d.ts +17 -0
  47. package/dist/components/charts/index.d.ts +2 -0
  48. package/dist/components/charts/index.js +2 -0
  49. package/dist/components/code-editor-presets.d.ts +14 -0
  50. package/dist/components/code-editor-presets.js +14 -0
  51. package/dist/components/fields/MarkdownField.svelte +14 -5
  52. package/dist/components/highlight.d.ts +16 -0
  53. package/dist/components/highlight.js +68 -0
  54. package/dist/components/media.svelte.d.ts +27 -0
  55. package/dist/components/media.svelte.js +60 -0
  56. package/dist/components/phone-dial-codes.d.ts +19 -0
  57. package/dist/components/phone-dial-codes.js +112 -0
  58. package/dist/components/ui/DesignSystemShowcase.svelte +1 -1
  59. package/dist/components/ui/dropdown-menu/dropdown-menu-trigger.svelte +1 -2
  60. package/dist/editor-config.svelte.d.ts +4 -2
  61. package/dist/index.d.ts +19 -1
  62. package/dist/index.js +14 -1
  63. package/dist/styles/recipes.css +1262 -0
  64. package/dist/types.d.ts +4 -4
  65. package/package.json +64 -4
package/dist/app.css CHANGED
@@ -5539,6 +5539,7 @@
5539
5539
  --leading-tight: 1.25;
5540
5540
  --shadow-lg: 0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1);
5541
5541
  --drop-shadow-sm: 0 1px 2px rgb(0 0 0 / 0.15);
5542
+ --ease-in-out: cubic-bezier(0.4, 0, 0.2, 1);
5542
5543
  --default-transition-duration: 150ms;
5543
5544
  --default-transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
5544
5545
  }
@@ -6019,6 +6020,10 @@
6019
6020
  .opacity-50 {
6020
6021
  opacity: 50%;
6021
6022
  }
6023
+ .shadow {
6024
+ --tw-shadow: 0 1px 3px 0 var(--tw-shadow-color, rgb(0 0 0 / 0.1)), 0 1px 2px -1px var(--tw-shadow-color, rgb(0 0 0 / 0.1));
6025
+ box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);
6026
+ }
6022
6027
  .shadow-sm {
6023
6028
  --tw-shadow: 0 1px 3px 0 var(--tw-shadow-color, rgb(0 0 0 / 0.1)), 0 1px 2px -1px var(--tw-shadow-color, rgb(0 0 0 / 0.1));
6024
6029
  box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);
@@ -6045,6 +6050,10 @@
6045
6050
  transition-timing-function: var(--tw-ease, var(--default-transition-timing-function));
6046
6051
  transition-duration: var(--tw-duration, var(--default-transition-duration));
6047
6052
  }
6053
+ .ease-in-out {
6054
+ --tw-ease: var(--ease-in-out);
6055
+ transition-timing-function: var(--ease-in-out);
6056
+ }
6048
6057
  .select-none {
6049
6058
  -webkit-user-select: none;
6050
6059
  user-select: none;
@@ -6389,6 +6398,10 @@
6389
6398
  syntax: "*";
6390
6399
  inherits: false;
6391
6400
  }
6401
+ @property --tw-ease {
6402
+ syntax: "*";
6403
+ inherits: false;
6404
+ }
6392
6405
  @layer properties {
6393
6406
  @supports ((-webkit-hyphens: none) and (not (margin-trim: inline))) or ((-moz-orient: inline) and (not (color:rgb(from red r g b)))) {
6394
6407
  *, ::before, ::after, ::backdrop {
@@ -6434,6 +6447,7 @@
6434
6447
  --tw-drop-shadow-color: initial;
6435
6448
  --tw-drop-shadow-alpha: 100%;
6436
6449
  --tw-drop-shadow-size: initial;
6450
+ --tw-ease: initial;
6437
6451
  }
6438
6452
  }
6439
6453
  }
@@ -5539,6 +5539,7 @@
5539
5539
  --leading-tight: 1.25;
5540
5540
  --shadow-lg: 0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1);
5541
5541
  --drop-shadow-sm: 0 1px 2px rgb(0 0 0 / 0.15);
5542
+ --ease-in-out: cubic-bezier(0.4, 0, 0.2, 1);
5542
5543
  --default-transition-duration: 150ms;
5543
5544
  --default-transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
5544
5545
  }
@@ -6019,6 +6020,10 @@
6019
6020
  .opacity-50 {
6020
6021
  opacity: 50%;
6021
6022
  }
6023
+ .shadow {
6024
+ --tw-shadow: 0 1px 3px 0 var(--tw-shadow-color, rgb(0 0 0 / 0.1)), 0 1px 2px -1px var(--tw-shadow-color, rgb(0 0 0 / 0.1));
6025
+ box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);
6026
+ }
6022
6027
  .shadow-sm {
6023
6028
  --tw-shadow: 0 1px 3px 0 var(--tw-shadow-color, rgb(0 0 0 / 0.1)), 0 1px 2px -1px var(--tw-shadow-color, rgb(0 0 0 / 0.1));
6024
6029
  box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);
@@ -6045,6 +6050,10 @@
6045
6050
  transition-timing-function: var(--tw-ease, var(--default-transition-timing-function));
6046
6051
  transition-duration: var(--tw-duration, var(--default-transition-duration));
6047
6052
  }
6053
+ .ease-in-out {
6054
+ --tw-ease: var(--ease-in-out);
6055
+ transition-timing-function: var(--ease-in-out);
6056
+ }
6048
6057
  .select-none {
6049
6058
  -webkit-user-select: none;
6050
6059
  user-select: none;
@@ -6389,6 +6398,10 @@
6389
6398
  syntax: "*";
6390
6399
  inherits: false;
6391
6400
  }
6401
+ @property --tw-ease {
6402
+ syntax: "*";
6403
+ inherits: false;
6404
+ }
6392
6405
  @layer properties {
6393
6406
  @supports ((-webkit-hyphens: none) and (not (margin-trim: inline))) or ((-moz-orient: inline) and (not (color:rgb(from red r g b)))) {
6394
6407
  *, ::before, ::after, ::backdrop {
@@ -6434,6 +6447,7 @@
6434
6447
  --tw-drop-shadow-color: initial;
6435
6448
  --tw-drop-shadow-alpha: 100%;
6436
6449
  --tw-drop-shadow-size: initial;
6450
+ --tw-ease: initial;
6437
6451
  }
6438
6452
  }
6439
6453
  }
@@ -575,15 +575,15 @@
575
575
  {#key renderedRoute + (renderedParams['resource'] ?? '') + (renderedParams['id'] ?? '') + (renderedParams['variant'] ?? '') + (renderedParams['columns'] ?? '')}
576
576
  <div class="svadmin-page-enter">
577
577
  {#if renderedRoute === '/public-profile'}
578
- <LazyPage loader={loadPublicProfilePage} props={{ variant: 'default', initialTab: 'projects' }} />
578
+ <LazyPage loader={loadPublicProfilePage} props={{ variant: 'default', initialTab: 'projects' } as const} />
579
579
  {:else if renderedRoute === '/public-profile/projects/:columns'}
580
- <LazyPage loader={loadPublicProfilePage} props={{ variant: 'default', initialTab: 'projects', columns: renderedParams['columns']?.includes('3') ? 3 : 2 }} />
580
+ <LazyPage loader={loadPublicProfilePage} props={{ variant: 'default', initialTab: 'projects', columns: renderedParams['columns']?.includes('3') ? 3 : 2 } as const} />
581
581
  {:else if renderedRoute === '/public-profile/activity'}
582
- <LazyPage loader={loadPublicProfilePage} props={{ variant: 'default', initialTab: 'activity' }} />
582
+ <LazyPage loader={loadPublicProfilePage} props={{ variant: 'default', initialTab: 'activity' } as const} />
583
583
  {:else if renderedRoute === '/public-profile/teams'}
584
- <LazyPage loader={loadPublicProfilePage} props={{ variant: 'default', initialTab: 'teams' }} />
584
+ <LazyPage loader={loadPublicProfilePage} props={{ variant: 'default', initialTab: 'teams' } as const} />
585
585
  {:else if renderedRoute === '/public-profile/profiles/:variant'}
586
- <LazyPage loader={loadPublicProfilePage} props={{ variant: (renderedParams['variant'] === 'company' || renderedParams['variant'] === 'gamer' || renderedParams['variant'] === 'default' ? renderedParams['variant'] : 'default') as 'company' | 'gamer' | 'default', showSections: true }} />
586
+ <LazyPage loader={loadPublicProfilePage} props={{ variant: (renderedParams['variant'] === 'company' || renderedParams['variant'] === 'gamer' || renderedParams['variant'] === 'default' ? renderedParams['variant'] : 'default') as 'company' | 'gamer' | 'default', showSections: true } as const} />
587
587
  {:else if renderedRoute === '/account/get-started' || renderedRoute === '/account/home/get-started'}
588
588
  <LazyPage loader={loadGetStartedPage} props={{}} />
589
589
  {:else if renderedRoute === '/account/home/user-profile'}
@@ -0,0 +1,137 @@
1
+ <script lang="ts">
2
+ import type { Snippet } from 'svelte';
3
+ import { cn } from '../utils.js';
4
+
5
+ export interface FooterLink {
6
+ label: string;
7
+ href?: string;
8
+ external?: boolean;
9
+ onclick?: () => void;
10
+ }
11
+
12
+ export interface FooterColumn {
13
+ title: string;
14
+ links: FooterLink[];
15
+ }
16
+
17
+ interface Props {
18
+ /** Bottom-line copyright text. */
19
+ copyright?: string;
20
+ /** Flat links rendered in the bottom bar. */
21
+ links?: FooterLink[];
22
+ /** Link columns rendered above the bottom bar. */
23
+ columns?: FooterColumn[];
24
+ ariaLabel?: string;
25
+ class?: string;
26
+ children?: Snippet;
27
+ }
28
+
29
+ let {
30
+ copyright,
31
+ links = [],
32
+ columns = [],
33
+ ariaLabel = 'Footer',
34
+ class: className = '',
35
+ children,
36
+ }: Props = $props();
37
+ </script>
38
+
39
+ <footer class={cn('svadmin-app-footer', className)} data-slot="app-footer" aria-label={ariaLabel}>
40
+ {#if columns.length}
41
+ <div class="svadmin-app-footer__columns">
42
+ {#each columns as column (column.title)}
43
+ <nav class="svadmin-app-footer__column" aria-label={column.title}>
44
+ <h2 class="svadmin-app-footer__heading">{column.title}</h2>
45
+ <ul class="svadmin-app-footer__list">
46
+ {#each column.links as link (link.label)}
47
+ <li>
48
+ {#if link.href}
49
+ <a
50
+ class="svadmin-app-footer__link"
51
+ href={link.href}
52
+ rel={link.external ? 'noreferrer noopener' : undefined}
53
+ target={link.external ? '_blank' : undefined}
54
+ >{link.label}</a>
55
+ {:else}
56
+ <button class="svadmin-app-footer__link" type="button" onclick={() => link.onclick?.()}>{link.label}</button>
57
+ {/if}
58
+ </li>
59
+ {/each}
60
+ </ul>
61
+ </nav>
62
+ {/each}
63
+ </div>
64
+ {/if}
65
+
66
+ {#if children}<div class="svadmin-app-footer__content">{@render children()}</div>{/if}
67
+
68
+ {#if copyright || links.length}
69
+ <div class="svadmin-app-footer__bar">
70
+ {#if copyright}<span class="svadmin-app-footer__copyright">{copyright}</span>{/if}
71
+ {#if links.length}
72
+ <ul class="svadmin-app-footer__list svadmin-app-footer__list--inline">
73
+ {#each links as link (link.label)}
74
+ <li>
75
+ {#if link.href}
76
+ <a
77
+ class="svadmin-app-footer__link"
78
+ href={link.href}
79
+ rel={link.external ? 'noreferrer noopener' : undefined}
80
+ target={link.external ? '_blank' : undefined}
81
+ >{link.label}</a>
82
+ {:else}
83
+ <button class="svadmin-app-footer__link" type="button" onclick={() => link.onclick?.()}>{link.label}</button>
84
+ {/if}
85
+ </li>
86
+ {/each}
87
+ </ul>
88
+ {/if}
89
+ </div>
90
+ {/if}
91
+ </footer>
92
+
93
+ <style>
94
+ .svadmin-app-footer {
95
+ display: grid;
96
+ gap: 1.5rem;
97
+ border-block-start: 1px solid var(--border, currentColor);
98
+ padding: 1.5rem;
99
+ background: var(--card, var(--background, transparent));
100
+ color: var(--muted-foreground, currentColor);
101
+ font-size: 0.8125rem;
102
+ }
103
+
104
+ .svadmin-app-footer__columns {
105
+ display: grid;
106
+ grid-template-columns: repeat(auto-fit, minmax(10rem, 1fr));
107
+ gap: 1.5rem;
108
+ }
109
+
110
+ .svadmin-app-footer__column { display: grid; gap: 0.625rem; }
111
+ .svadmin-app-footer__heading { margin: 0; color: var(--foreground, currentColor); font-size: 0.8125rem; font-weight: 600; }
112
+ .svadmin-app-footer__list { display: grid; gap: 0.375rem; margin: 0; padding: 0; list-style: none; }
113
+ .svadmin-app-footer__list--inline { display: flex; flex-wrap: wrap; gap: 1rem; }
114
+
115
+ .svadmin-app-footer__link {
116
+ border: 0;
117
+ padding: 0;
118
+ background: transparent;
119
+ color: inherit;
120
+ font: inherit;
121
+ text-decoration: none;
122
+ cursor: pointer;
123
+ }
124
+ .svadmin-app-footer__link:hover { color: var(--foreground, currentColor); text-decoration: underline; text-underline-offset: 0.2em; }
125
+ .svadmin-app-footer__link:focus-visible { outline: 2px solid var(--ring, currentColor); outline-offset: 2px; }
126
+
127
+ .svadmin-app-footer__bar {
128
+ display: flex;
129
+ flex-wrap: wrap;
130
+ align-items: center;
131
+ justify-content: space-between;
132
+ gap: 0.75rem;
133
+ border-block-start: 1px solid var(--border, currentColor);
134
+ padding-block-start: 1rem;
135
+ color: var(--muted-foreground, currentColor);
136
+ }
137
+ </style>
@@ -0,0 +1,25 @@
1
+ import type { Snippet } from 'svelte';
2
+ export interface FooterLink {
3
+ label: string;
4
+ href?: string;
5
+ external?: boolean;
6
+ onclick?: () => void;
7
+ }
8
+ export interface FooterColumn {
9
+ title: string;
10
+ links: FooterLink[];
11
+ }
12
+ interface Props {
13
+ /** Bottom-line copyright text. */
14
+ copyright?: string;
15
+ /** Flat links rendered in the bottom bar. */
16
+ links?: FooterLink[];
17
+ /** Link columns rendered above the bottom bar. */
18
+ columns?: FooterColumn[];
19
+ ariaLabel?: string;
20
+ class?: string;
21
+ children?: Snippet;
22
+ }
23
+ declare const AppFooter: import("svelte").Component<Props, {}, "">;
24
+ type AppFooter = ReturnType<typeof AppFooter>;
25
+ export default AppFooter;
@@ -0,0 +1,145 @@
1
+ <script lang="ts">
2
+ import type { Component } from 'svelte';
3
+ import { onMount } from 'svelte';
4
+ import { cn } from '../utils.js';
5
+
6
+ /**
7
+ * Thin adapter over the Svelte ecosystem `svelte-codemirror-editor` package.
8
+ * The dependency is optional: if it cannot be loaded, an accessible
9
+ * `<textarea>` fallback keeps the field usable.
10
+ */
11
+ interface Props {
12
+ value?: string;
13
+ placeholder?: string;
14
+ readonly?: boolean;
15
+ editable?: boolean;
16
+ lineNumbers?: boolean;
17
+ lineWrapping?: boolean;
18
+ tabSize?: number;
19
+ /** CodeMirror extensions supplied by the host (languages, themes, …). */
20
+ extensions?: readonly unknown[];
21
+ lang?: unknown;
22
+ theme?: unknown;
23
+ ariaLabel?: string;
24
+ class?: string;
25
+ onchange?: (value: string) => void;
26
+ onready?: (view: unknown) => void;
27
+ }
28
+
29
+ let {
30
+ value = $bindable(''),
31
+ placeholder = 'Write code…',
32
+ readonly = false,
33
+ editable = true,
34
+ lineNumbers = true,
35
+ lineWrapping = true,
36
+ tabSize = 2,
37
+ extensions,
38
+ lang,
39
+ theme,
40
+ ariaLabel = 'Code editor',
41
+ class: className = '',
42
+ onchange,
43
+ onready,
44
+ }: Props = $props();
45
+
46
+ let Editor = $state<Component<Record<string, unknown>> | null>(null);
47
+ let unavailable = $state(false);
48
+
49
+ onMount(() => {
50
+ let active = true;
51
+ import('svelte-codemirror-editor')
52
+ .then((module) => {
53
+ if (active) Editor = module.default as unknown as Component<Record<string, unknown>>;
54
+ })
55
+ .catch(() => {
56
+ if (active) unavailable = true;
57
+ });
58
+ return () => {
59
+ active = false;
60
+ };
61
+ });
62
+
63
+ const editorProps = $derived({
64
+ value,
65
+ placeholder,
66
+ readonly,
67
+ editable,
68
+ lineNumbers,
69
+ lineWrapping,
70
+ tabSize,
71
+ ...(extensions ? { extensions: [...extensions] } : {}),
72
+ ...(lang ? { lang } : {}),
73
+ ...(theme ? { theme } : {}),
74
+ ...(onready ? { onready } : {}),
75
+ onchange: (next: string) => {
76
+ value = next;
77
+ onchange?.(next);
78
+ },
79
+ });
80
+
81
+ const editorState = $derived(Editor ? 'ready' : unavailable ? 'unavailable' : 'loading');
82
+ </script>
83
+
84
+ <div
85
+ class={cn('svadmin-code-editor', className)}
86
+ data-slot="code-editor"
87
+ data-state={editorState}
88
+ >
89
+ {#if Editor}
90
+ <Editor {...editorProps} />
91
+ {:else}
92
+ <textarea
93
+ class="svadmin-code-editor__fallback"
94
+ bind:value
95
+ {placeholder}
96
+ {readonly}
97
+ disabled={!editable || readonly}
98
+ aria-label={ariaLabel}
99
+ spellcheck="false"
100
+ autocapitalize="off"
101
+ autocomplete="off"
102
+ wrap={lineWrapping ? 'soft' : 'off'}
103
+ oninput={(event) => onchange?.((event.currentTarget as HTMLTextAreaElement).value)}
104
+ ></textarea>
105
+ {#if unavailable}
106
+ <p class="svadmin-code-editor__hint" role="status">
107
+ Install <code>svelte-codemirror-editor</code> and <code>codemirror</code> to enable syntax highlighting.
108
+ </p>
109
+ {/if}
110
+ {/if}
111
+ </div>
112
+
113
+ <style>
114
+ .svadmin-code-editor {
115
+ overflow: hidden;
116
+ border: 1px solid var(--border, currentColor);
117
+ border-radius: min(var(--radius, 0.5rem), 0.5rem);
118
+ background: var(--card, var(--background, transparent));
119
+ color: var(--card-foreground, var(--foreground, currentColor));
120
+ }
121
+
122
+ .svadmin-code-editor:focus-within { outline: 2px solid var(--ring, currentColor); outline-offset: 1px; }
123
+ .svadmin-code-editor__fallback {
124
+ display: block;
125
+ width: 100%;
126
+ min-height: 8rem;
127
+ border: 0;
128
+ padding: 0.75rem;
129
+ background: transparent;
130
+ color: inherit;
131
+ font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
132
+ font-size: 0.8125rem;
133
+ line-height: 1.6;
134
+ resize: vertical;
135
+ }
136
+ .svadmin-code-editor__fallback:focus { outline: none; }
137
+ .svadmin-code-editor__hint {
138
+ margin: 0;
139
+ border-top: 1px solid var(--border, currentColor);
140
+ padding: 0.5rem 0.75rem;
141
+ color: var(--muted-foreground, currentColor);
142
+ font-size: 0.75rem;
143
+ }
144
+ .svadmin-code-editor__hint code { color: var(--foreground, currentColor); }
145
+ </style>
@@ -0,0 +1,26 @@
1
+ import type { Component } from 'svelte';
2
+ /**
3
+ * Thin adapter over the Svelte ecosystem `svelte-codemirror-editor` package.
4
+ * The dependency is optional: if it cannot be loaded, an accessible
5
+ * `<textarea>` fallback keeps the field usable.
6
+ */
7
+ interface Props {
8
+ value?: string;
9
+ placeholder?: string;
10
+ readonly?: boolean;
11
+ editable?: boolean;
12
+ lineNumbers?: boolean;
13
+ lineWrapping?: boolean;
14
+ tabSize?: number;
15
+ /** CodeMirror extensions supplied by the host (languages, themes, …). */
16
+ extensions?: readonly unknown[];
17
+ lang?: unknown;
18
+ theme?: unknown;
19
+ ariaLabel?: string;
20
+ class?: string;
21
+ onchange?: (value: string) => void;
22
+ onready?: (view: unknown) => void;
23
+ }
24
+ declare const CodeEditor: Component<Props, {}, "value">;
25
+ type CodeEditor = ReturnType<typeof CodeEditor>;
26
+ export default CodeEditor;
@@ -4,7 +4,7 @@
4
4
 
5
5
  export type DatePickerProps = Omit<ComponentProps<typeof DateTimeInput>, 'mode'>;
6
6
 
7
- let props: DatePickerProps = $props();
7
+ let { value = $bindable(null), ...props }: DatePickerProps = $props();
8
8
  </script>
9
9
 
10
- <DateTimeInput {...props} mode="date" />
10
+ <DateTimeInput {...props} bind:value mode="date" />
@@ -1,6 +1,6 @@
1
1
  import type { ComponentProps } from 'svelte';
2
2
  import DateTimeInput from './DateTimeInput.svelte';
3
3
  export type DatePickerProps = Omit<ComponentProps<typeof DateTimeInput>, 'mode'>;
4
- declare const DatePicker: import("svelte").Component<DatePickerProps, {}, "">;
4
+ declare const DatePicker: import("svelte").Component<DatePickerProps, {}, "value">;
5
5
  type DatePicker = ReturnType<typeof DatePicker>;
6
6
  export default DatePicker;
@@ -4,7 +4,7 @@
4
4
 
5
5
  export type DateRangePickerProps = Omit<ComponentProps<typeof DateRangeInput>, 'mode'>;
6
6
 
7
- let props: DateRangePickerProps = $props();
7
+ let { value = $bindable({ start: null, end: null }), ...props }: DateRangePickerProps = $props();
8
8
  </script>
9
9
 
10
- <DateRangeInput {...props} mode="date" />
10
+ <DateRangeInput {...props} bind:value mode="date" />
@@ -1,6 +1,6 @@
1
1
  import type { ComponentProps } from 'svelte';
2
2
  import DateRangeInput from './DateRangeInput.svelte';
3
3
  export type DateRangePickerProps = Omit<ComponentProps<typeof DateRangeInput>, 'mode'>;
4
- declare const DateRangePicker: import("svelte").Component<DateRangePickerProps, {}, "">;
4
+ declare const DateRangePicker: import("svelte").Component<DateRangePickerProps, {}, "value">;
5
5
  type DateRangePicker = ReturnType<typeof DateRangePicker>;
6
6
  export default DateRangePicker;
@@ -11,24 +11,24 @@
11
11
  interface Props {
12
12
  value?: string | null;
13
13
  mode?: DateTimeInputMode;
14
- min?: string;
15
- max?: string;
16
- minInstant?: string;
17
- maxInstant?: string;
18
- step?: number;
19
- disabledDate?: (date: string) => boolean;
20
- id?: string;
21
- name?: string;
22
- disabled?: boolean;
23
- required?: boolean;
24
- invalid?: boolean;
25
- describedby?: string;
26
- ariaLabel?: string;
27
- class?: string;
28
- onchange?: (value: string | null) => void;
29
- timeZone?: string;
30
- valueMode?: DateTimeValueMode;
31
- disambiguation?: DateTimeDisambiguation;
14
+ min?: string | undefined;
15
+ max?: string | undefined;
16
+ minInstant?: string | undefined;
17
+ maxInstant?: string | undefined;
18
+ step?: number | undefined;
19
+ disabledDate?: ((date: string) => boolean) | undefined;
20
+ id?: string | undefined;
21
+ name?: string | undefined;
22
+ disabled?: boolean | undefined;
23
+ required?: boolean | undefined;
24
+ invalid?: boolean | undefined;
25
+ describedby?: string | undefined;
26
+ ariaLabel?: string | undefined;
27
+ class?: string | undefined;
28
+ onchange?: ((value: string | null) => void) | undefined;
29
+ timeZone?: string | undefined;
30
+ valueMode?: DateTimeValueMode | undefined;
31
+ disambiguation?: DateTimeDisambiguation | undefined;
32
32
  }
33
33
 
34
34
  let {
@@ -3,24 +3,24 @@ export type DateTimeInputMode = 'date' | 'time' | 'datetime';
3
3
  interface Props {
4
4
  value?: string | null;
5
5
  mode?: DateTimeInputMode;
6
- min?: string;
7
- max?: string;
8
- minInstant?: string;
9
- maxInstant?: string;
10
- step?: number;
11
- disabledDate?: (date: string) => boolean;
12
- id?: string;
13
- name?: string;
14
- disabled?: boolean;
15
- required?: boolean;
16
- invalid?: boolean;
17
- describedby?: string;
18
- ariaLabel?: string;
19
- class?: string;
20
- onchange?: (value: string | null) => void;
21
- timeZone?: string;
22
- valueMode?: DateTimeValueMode;
23
- disambiguation?: DateTimeDisambiguation;
6
+ min?: string | undefined;
7
+ max?: string | undefined;
8
+ minInstant?: string | undefined;
9
+ maxInstant?: string | undefined;
10
+ step?: number | undefined;
11
+ disabledDate?: ((date: string) => boolean) | undefined;
12
+ id?: string | undefined;
13
+ name?: string | undefined;
14
+ disabled?: boolean | undefined;
15
+ required?: boolean | undefined;
16
+ invalid?: boolean | undefined;
17
+ describedby?: string | undefined;
18
+ ariaLabel?: string | undefined;
19
+ class?: string | undefined;
20
+ onchange?: ((value: string | null) => void) | undefined;
21
+ timeZone?: string | undefined;
22
+ valueMode?: DateTimeValueMode | undefined;
23
+ disambiguation?: DateTimeDisambiguation | undefined;
24
24
  }
25
25
  declare const DateTimeInput: import("svelte").Component<Props, {}, "value">;
26
26
  type DateTimeInput = ReturnType<typeof DateTimeInput>;
@@ -4,7 +4,7 @@
4
4
 
5
5
  export type DateTimePickerProps = Omit<ComponentProps<typeof DateTimeInput>, 'mode'>;
6
6
 
7
- let props: DateTimePickerProps = $props();
7
+ let { value = $bindable(null), ...props }: DateTimePickerProps = $props();
8
8
  </script>
9
9
 
10
- <DateTimeInput {...props} mode="datetime" />
10
+ <DateTimeInput {...props} bind:value mode="datetime" />
@@ -1,6 +1,6 @@
1
1
  import type { ComponentProps } from 'svelte';
2
2
  import DateTimeInput from './DateTimeInput.svelte';
3
3
  export type DateTimePickerProps = Omit<ComponentProps<typeof DateTimeInput>, 'mode'>;
4
- declare const DateTimePicker: import("svelte").Component<DateTimePickerProps, {}, "">;
4
+ declare const DateTimePicker: import("svelte").Component<DateTimePickerProps, {}, "value">;
5
5
  type DateTimePicker = ReturnType<typeof DateTimePicker>;
6
6
  export default DateTimePicker;
@@ -38,6 +38,7 @@
38
38
  import { cn } from '../utils.js';
39
39
  import { numericInputValue } from '../numeric-input.js';
40
40
 
41
+ type FieldOption = NonNullable<FieldDefinition['options']>[number];
41
42
  const i18n = useTranslation();
42
43
 
43
44
  let { field, value, onchange, disabled, invalid = false, errorId, density = 'comfortable', children } = $props<{
@@ -59,7 +60,6 @@
59
60
  const boolVal = $derived((value as boolean) ?? false);
60
61
  const tagsVal = $derived((value as string[]) ?? []);
61
62
  const multiVal = $derived((value as (string | number)[]) ?? []);
62
- type FieldOption = NonNullable<FieldDefinition['options']>[number];
63
63
  const selectToken = $derived.by(() => {
64
64
  const index = field.options?.findIndex((option: FieldOption) => option.value === value) ?? -1;
65
65
  return index < 0 ? '' : `option:${index}`;
@@ -0,0 +1,46 @@
1
+ <script lang="ts">
2
+ import { cn } from '../utils.js';
3
+ import { splitHighlights } from './highlight.js';
4
+
5
+ interface Props {
6
+ text: string;
7
+ /** One term or a list of terms to highlight. */
8
+ query?: string | readonly string[];
9
+ caseSensitive?: boolean;
10
+ wholeWord?: boolean;
11
+ class?: string;
12
+ /** Overrides the `<mark>` styling without leaving the semantic token system. */
13
+ highlightClass?: string;
14
+ }
15
+
16
+ let {
17
+ text,
18
+ query,
19
+ caseSensitive = false,
20
+ wholeWord = false,
21
+ class: className = '',
22
+ highlightClass = '',
23
+ }: Props = $props();
24
+
25
+ const segments = $derived(
26
+ splitHighlights(text, query, { caseSensitive, wholeWord }),
27
+ );
28
+ </script>
29
+
30
+ <span class={cn('svadmin-highlight-text', className)} data-slot="highlight-text">
31
+ {#each segments as segment, index (index)}{#if segment.match}<mark class={cn('svadmin-highlight-text__mark', highlightClass)}>{segment.text}</mark>{:else}{segment.text}{/if}{/each}
32
+ </span>
33
+
34
+ <style>
35
+ .svadmin-highlight-text {
36
+ color: inherit;
37
+ overflow-wrap: anywhere;
38
+ }
39
+
40
+ .svadmin-highlight-text__mark {
41
+ border-radius: 0.2rem;
42
+ padding-inline: 0.1rem;
43
+ background: color-mix(in oklch, var(--warning, var(--primary, currentColor)) 28%, transparent);
44
+ color: var(--foreground, currentColor);
45
+ }
46
+ </style>