@svadmin/lite 0.6.0 → 0.7.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 (36) hide show
  1. package/README.md +85 -9
  2. package/dist/components/LiteDynamicFormList.svelte +169 -0
  3. package/dist/components/LiteDynamicFormList.svelte.d.ts +45 -0
  4. package/dist/components/LiteFilterBuilder.svelte +205 -0
  5. package/dist/components/LiteFilterBuilder.svelte.d.ts +19 -0
  6. package/dist/components/LiteShowField.svelte +22 -0
  7. package/dist/components/LiteTransfer.svelte +185 -0
  8. package/dist/components/LiteTransfer.svelte.d.ts +18 -0
  9. package/dist/components/fields/LiteAvatarField.svelte +127 -0
  10. package/dist/components/fields/LiteAvatarField.svelte.d.ts +21 -0
  11. package/dist/components/fields/LiteCascader.svelte +119 -0
  12. package/dist/components/fields/LiteCascader.svelte.d.ts +24 -0
  13. package/dist/components/fields/LiteCodeField.svelte +71 -0
  14. package/dist/components/fields/LiteCodeField.svelte.d.ts +16 -0
  15. package/dist/components/fields/LiteCopyField.svelte +74 -0
  16. package/dist/components/fields/LiteCopyField.svelte.d.ts +18 -0
  17. package/dist/components/fields/LiteCurrencyField.svelte +126 -0
  18. package/dist/components/fields/LiteCurrencyField.svelte.d.ts +21 -0
  19. package/dist/components/fields/LiteDateRangeField.svelte +147 -0
  20. package/dist/components/fields/LiteDateRangeField.svelte.d.ts +26 -0
  21. package/dist/components/fields/LitePercentField.svelte +124 -0
  22. package/dist/components/fields/LitePercentField.svelte.d.ts +17 -0
  23. package/dist/components/fields/LitePhoneField.svelte +81 -0
  24. package/dist/components/fields/LitePhoneField.svelte.d.ts +17 -0
  25. package/dist/components/fields/LiteRatingField.svelte +105 -0
  26. package/dist/components/fields/LiteRatingField.svelte.d.ts +16 -0
  27. package/dist/components/fields/LiteTreeSelect.svelte +143 -0
  28. package/dist/components/fields/LiteTreeSelect.svelte.d.ts +23 -0
  29. package/dist/components/fields/index.d.ts +12 -0
  30. package/dist/components/fields/index.js +10 -0
  31. package/dist/components/pages/LiteListPage.svelte +14 -12
  32. package/dist/index.d.ts +5 -0
  33. package/dist/index.js +3 -0
  34. package/dist/lite.css +205 -0
  35. package/dist/schema-generator.js +15 -4
  36. package/package.json +4 -3
@@ -0,0 +1,185 @@
1
+ <script lang="ts">
2
+ import { t } from '@svadmin/core/i18n';
3
+
4
+ export interface TransferItem {
5
+ key: string | number;
6
+ title: string;
7
+ description?: string;
8
+ disabled?: boolean;
9
+ }
10
+
11
+ interface Props {
12
+ dataSource?: TransferItem[];
13
+ targetKeys?: (string | number)[];
14
+ titles?: [string, string];
15
+ name?: string;
16
+ disabled?: boolean;
17
+ label?: string;
18
+ description?: string;
19
+ }
20
+
21
+ let {
22
+ dataSource = [],
23
+ targetKeys = [],
24
+ titles = ['Available', 'Selected'],
25
+ name = 'targetKeys',
26
+ disabled = false,
27
+ label,
28
+ description,
29
+ }: Props = $props();
30
+
31
+ const targetKeySet = $derived(new Set(targetKeys.map(String)));
32
+ const sourceItems = $derived(dataSource.filter((item) => !targetKeySet.has(String(item.key))));
33
+ const targetItems = $derived(dataSource.filter((item) => targetKeySet.has(String(item.key))));
34
+ </script>
35
+
36
+ <div class="lite-transfer-container lite-form-group">
37
+ {#if label}
38
+ <span class="lite-label">{label}</span>
39
+ {/if}
40
+ {#if description}
41
+ <p class="lite-help-text">{description}</p>
42
+ {/if}
43
+
44
+ <div class="lite-transfer-boxes">
45
+ <!-- Source Box -->
46
+ <div class="lite-transfer-panel">
47
+ <div class="lite-transfer-header">
48
+ <strong>{titles[0]}</strong>
49
+ <span class="lite-badge">{sourceItems.length}</span>
50
+ </div>
51
+ <div class="lite-transfer-body">
52
+ {#if sourceItems.length === 0}
53
+ <div class="lite-transfer-empty">{t('common.empty') || 'No items'}</div>
54
+ {:else}
55
+ {#each sourceItems as item (item.key)}
56
+ <label class="lite-transfer-item">
57
+ <input
58
+ type="checkbox"
59
+ name="_transfer_source_keys"
60
+ value={String(item.key)}
61
+ disabled={disabled || item.disabled}
62
+ />
63
+ <span class="lite-transfer-item-title">{item.title}</span>
64
+ </label>
65
+ {/each}
66
+ {/if}
67
+ </div>
68
+ </div>
69
+
70
+ <!-- Move Actions -->
71
+ <div class="lite-transfer-operations">
72
+ <button
73
+ type="submit"
74
+ name="_action"
75
+ value="transfer_to_target"
76
+ class="lite-btn lite-btn-sm lite-btn-primary"
77
+ {disabled}
78
+ title="Move selected right"
79
+ >
80
+
81
+ </button>
82
+ <button
83
+ type="submit"
84
+ name="_action"
85
+ value="transfer_to_source"
86
+ class="lite-btn lite-btn-sm"
87
+ {disabled}
88
+ title="Move selected left"
89
+ >
90
+
91
+ </button>
92
+ </div>
93
+
94
+ <!-- Target Box -->
95
+ <div class="lite-transfer-panel">
96
+ <div class="lite-transfer-header">
97
+ <strong>{titles[1]}</strong>
98
+ <span class="lite-badge lite-badge-indigo">{targetItems.length}</span>
99
+ </div>
100
+ <div class="lite-transfer-body">
101
+ {#if targetItems.length === 0}
102
+ <div class="lite-transfer-empty">{t('common.empty') || 'No items selected'}</div>
103
+ {:else}
104
+ {#each targetItems as item (item.key)}
105
+ <label class="lite-transfer-item">
106
+ <input
107
+ type="checkbox"
108
+ name="_transfer_target_keys"
109
+ value={String(item.key)}
110
+ disabled={disabled || item.disabled}
111
+ />
112
+ <input type="hidden" {name} value={String(item.key)} />
113
+ <span class="lite-transfer-item-title">{item.title}</span>
114
+ </label>
115
+ {/each}
116
+ {/if}
117
+ </div>
118
+ </div>
119
+ </div>
120
+ </div>
121
+
122
+ <style>
123
+ .lite-transfer-container {
124
+ margin-bottom: 16px;
125
+ }
126
+ .lite-transfer-boxes {
127
+ display: flex;
128
+ align-items: center;
129
+ }
130
+ .lite-transfer-panel {
131
+ flex: 1;
132
+ border: 1px solid #cbd5e1;
133
+ border-radius: 6px;
134
+ background: #ffffff;
135
+ min-height: 180px;
136
+ max-height: 280px;
137
+ display: flex;
138
+ flex-direction: column;
139
+ }
140
+ .lite-transfer-header {
141
+ display: flex;
142
+ justify-content: space-between;
143
+ align-items: center;
144
+ padding: 8px 12px;
145
+ background: #f8fafc;
146
+ border-bottom: 1px solid #e2e8f0;
147
+ font-size: 13px;
148
+ }
149
+ .lite-transfer-body {
150
+ flex: 1;
151
+ overflow-y: auto;
152
+ padding: 6px;
153
+ }
154
+ .lite-transfer-item {
155
+ display: flex;
156
+ align-items: center;
157
+ padding: 6px 8px;
158
+ border-radius: 4px;
159
+ cursor: pointer;
160
+ font-size: 13px;
161
+ }
162
+ .lite-transfer-item:hover {
163
+ background: #f1f5f9;
164
+ }
165
+ .lite-transfer-item input {
166
+ margin-right: 8px;
167
+ }
168
+ .lite-transfer-operations {
169
+ display: flex;
170
+ flex-direction: column;
171
+ margin: 0 12px;
172
+ }
173
+ .lite-transfer-operations .lite-btn:first-child {
174
+ margin-bottom: 6px;
175
+ }
176
+ .lite-transfer-boxes > .lite-transfer-panel:first-child {
177
+ margin-right: 0;
178
+ }
179
+ .lite-transfer-empty {
180
+ text-align: center;
181
+ padding: 30px 10px;
182
+ color: #94a3b8;
183
+ font-size: 12px;
184
+ }
185
+ </style>
@@ -0,0 +1,18 @@
1
+ export interface TransferItem {
2
+ key: string | number;
3
+ title: string;
4
+ description?: string;
5
+ disabled?: boolean;
6
+ }
7
+ interface Props {
8
+ dataSource?: TransferItem[];
9
+ targetKeys?: (string | number)[];
10
+ titles?: [string, string];
11
+ name?: string;
12
+ disabled?: boolean;
13
+ label?: string;
14
+ description?: string;
15
+ }
16
+ declare const LiteTransfer: import("svelte").Component<Props, {}, "">;
17
+ type LiteTransfer = ReturnType<typeof LiteTransfer>;
18
+ export default LiteTransfer;
@@ -0,0 +1,127 @@
1
+ <script module lang="ts">
2
+ export type LiteAvatarStatus = 'online' | 'offline' | 'busy' | 'away' | 'success' | 'warning' | 'error' | 'neutral';
3
+ export type LiteAvatarSize = 'xs' | 'sm' | 'default' | 'lg';
4
+ </script>
5
+
6
+ <script lang="ts">
7
+ import type { FieldDefinition } from '@svadmin/core';
8
+
9
+ interface Props {
10
+ field?: FieldDefinition;
11
+ value?: unknown;
12
+ error?: string[];
13
+ mode?: 'show' | 'edit' | 'create';
14
+ src?: string | null;
15
+ name?: string | null;
16
+ subtitle?: string | null;
17
+ status?: LiteAvatarStatus;
18
+ size?: LiteAvatarSize;
19
+ shape?: 'circle' | 'square';
20
+ showName?: boolean;
21
+ nullLabel?: string;
22
+ class?: string;
23
+ }
24
+
25
+ let {
26
+ field,
27
+ value,
28
+ error = [],
29
+ mode = 'show',
30
+ src,
31
+ name,
32
+ subtitle,
33
+ status,
34
+ size = 'sm',
35
+ shape = 'circle',
36
+ showName = false,
37
+ nullLabel = '—',
38
+ class: className = '',
39
+ }: Props = $props();
40
+
41
+ const resolvedSrc = $derived.by(() => {
42
+ if (src !== undefined) return src;
43
+ if (typeof value === 'string' && (value.startsWith('http://') || value.startsWith('https://') || value.startsWith('/'))) {
44
+ return value;
45
+ }
46
+ if (value && typeof value === 'object' && 'src' in (value as Record<string, unknown>)) {
47
+ return String((value as Record<string, unknown>).src ?? '');
48
+ }
49
+ return null;
50
+ });
51
+
52
+ const resolvedName = $derived.by(() => {
53
+ if (name !== undefined) return name;
54
+ if (typeof value === 'string' && !value.startsWith('http://') && !value.startsWith('https://') && !value.startsWith('/')) {
55
+ return value;
56
+ }
57
+ if (value && typeof value === 'object' && 'name' in (value as Record<string, unknown>)) {
58
+ return String((value as Record<string, unknown>).name ?? '');
59
+ }
60
+ return null;
61
+ });
62
+
63
+ function getInitials(text?: string | null): string {
64
+ const trimmed = text?.trim();
65
+ if (!trimmed) return '?';
66
+ const parts = trimmed.split(/\s+/);
67
+ if (parts.length >= 2) {
68
+ return `${parts[0][0]}${parts[parts.length - 1][0]}`.toUpperCase();
69
+ }
70
+ return trimmed.slice(0, 2).toUpperCase();
71
+ }
72
+
73
+ const initials = $derived(getInitials(resolvedName));
74
+ const hasContent = $derived(Boolean(resolvedSrc || resolvedName?.trim()));
75
+ const hasError = $derived(error.length > 0);
76
+ </script>
77
+
78
+ {#if mode === 'show'}
79
+ {#if !hasContent}
80
+ <span class="lite-text-muted lite-text-sm {className}">{nullLabel}</span>
81
+ {:else}
82
+ <span class="lite-avatar-wrapper {className}">
83
+ <span class="lite-avatar-container">
84
+ <span class="lite-avatar lite-avatar-{size} lite-avatar-{shape}">
85
+ {#if resolvedSrc}
86
+ <img src={resolvedSrc} alt={resolvedName?.trim() || 'Avatar'} class="lite-avatar-img" />
87
+ {:else}
88
+ <span class="lite-avatar-initials">{initials}</span>
89
+ {/if}
90
+ </span>
91
+ {#if status}
92
+ <span
93
+ class="lite-avatar-dot lite-avatar-dot-{size} lite-avatar-status-{status}"
94
+ title={`Status: ${status}`}
95
+ ></span>
96
+ {/if}
97
+ </span>
98
+ {#if showName && (resolvedName || subtitle)}
99
+ <span class="lite-avatar-text-block">
100
+ {#if resolvedName}
101
+ <span class="lite-avatar-name">{resolvedName}</span>
102
+ {/if}
103
+ {#if subtitle}
104
+ <span class="lite-avatar-subtitle">{subtitle}</span>
105
+ {/if}
106
+ </span>
107
+ {/if}
108
+ </span>
109
+ {/if}
110
+ {:else}
111
+ <div>
112
+ <input
113
+ type="text"
114
+ name={field?.key ?? 'avatar'}
115
+ id={field?.key ?? 'avatar'}
116
+ value={String(resolvedSrc ?? resolvedName ?? value ?? '')}
117
+ class="lite-input {hasError ? 'lite-input-error' : ''}"
118
+ placeholder={field?.label ?? 'Avatar URL or name'}
119
+ {...field?.required ? { required: true } : {}}
120
+ />
121
+ {#if hasError}
122
+ {#each error as err, _i (_i)}
123
+ <div class="lite-error-text">{err}</div>
124
+ {/each}
125
+ {/if}
126
+ </div>
127
+ {/if}
@@ -0,0 +1,21 @@
1
+ export type LiteAvatarStatus = 'online' | 'offline' | 'busy' | 'away' | 'success' | 'warning' | 'error' | 'neutral';
2
+ export type LiteAvatarSize = 'xs' | 'sm' | 'default' | 'lg';
3
+ import type { FieldDefinition } from '@svadmin/core';
4
+ interface Props {
5
+ field?: FieldDefinition;
6
+ value?: unknown;
7
+ error?: string[];
8
+ mode?: 'show' | 'edit' | 'create';
9
+ src?: string | null;
10
+ name?: string | null;
11
+ subtitle?: string | null;
12
+ status?: LiteAvatarStatus;
13
+ size?: LiteAvatarSize;
14
+ shape?: 'circle' | 'square';
15
+ showName?: boolean;
16
+ nullLabel?: string;
17
+ class?: string;
18
+ }
19
+ declare const LiteAvatarField: import("svelte").Component<Props, {}, "">;
20
+ type LiteAvatarField = ReturnType<typeof LiteAvatarField>;
21
+ export default LiteAvatarField;
@@ -0,0 +1,119 @@
1
+ <script lang="ts">
2
+ import type { FieldDefinition } from '@svadmin/core';
3
+ import { t } from '@svadmin/core/i18n';
4
+
5
+ export interface CascaderOption {
6
+ value: string | number;
7
+ label: string;
8
+ children?: CascaderOption[];
9
+ disabled?: boolean;
10
+ isLeaf?: boolean;
11
+ }
12
+
13
+ interface Props {
14
+ field?: FieldDefinition;
15
+ name?: string;
16
+ label?: string;
17
+ value?: (string | number)[];
18
+ options?: CascaderOption[];
19
+ separator?: string;
20
+ placeholder?: string;
21
+ disabled?: boolean;
22
+ required?: boolean;
23
+ error?: string[];
24
+ mode?: 'show' | 'edit' | 'create';
25
+ }
26
+
27
+ let {
28
+ field,
29
+ name = field?.key ?? 'cascader',
30
+ label = field?.label,
31
+ value = [],
32
+ options = [],
33
+ separator = ' / ',
34
+ placeholder,
35
+ disabled = false,
36
+ required = field?.required ?? false,
37
+ error = [],
38
+ mode = 'show',
39
+ }: Props = $props();
40
+
41
+ const hasError = $derived(error.length > 0);
42
+
43
+ interface FlatPathOption {
44
+ pathValue: string;
45
+ pathLabels: string[];
46
+ disabled?: boolean;
47
+ }
48
+
49
+ function generatePaths(
50
+ nodes: CascaderOption[],
51
+ currentValues: (string | number)[] = [],
52
+ currentLabels: string[] = []
53
+ ): FlatPathOption[] {
54
+ const paths: FlatPathOption[] = [];
55
+ for (const node of nodes) {
56
+ const nextValues = [...currentValues, node.value];
57
+ const nextLabels = [...currentLabels, node.label];
58
+
59
+ if (node.children && node.children.length > 0) {
60
+ paths.push(...generatePaths(node.children, nextValues, nextLabels));
61
+ } else {
62
+ paths.push({
63
+ pathValue: nextValues.join('/'),
64
+ pathLabels: nextLabels,
65
+ disabled: node.disabled,
66
+ });
67
+ }
68
+ }
69
+ return paths;
70
+ }
71
+
72
+ const allPaths = $derived(generatePaths(options));
73
+ const currentPathString = $derived(Array.isArray(value) ? value.join('/') : String(value ?? ''));
74
+
75
+ function formatDisplay(v: (string | number)[]): string {
76
+ if (!v || v.length === 0) return '—';
77
+ const str = v.join('/');
78
+ const matched = allPaths.find((p) => p.pathValue === str);
79
+ if (matched) return matched.pathLabels.join(separator);
80
+ return v.join(separator);
81
+ }
82
+ </script>
83
+
84
+ {#if mode === 'show'}
85
+ <span class="lite-badge">{formatDisplay(value)}</span>
86
+ {:else}
87
+ <div class="lite-form-group">
88
+ {#if label}
89
+ <label class="lite-label" for={name}>
90
+ {label}
91
+ {#if required}<span class="required">*</span>{/if}
92
+ </label>
93
+ {/if}
94
+ <select
95
+ id={name}
96
+ {name}
97
+ class="lite-select {hasError ? 'lite-input-error' : ''}"
98
+ {disabled}
99
+ {required}
100
+ value={currentPathString}
101
+ >
102
+ <option value="">-- {placeholder || t('common.select') || 'Select Path'} --</option>
103
+ {#each allPaths as p (p.pathValue)}
104
+ <option
105
+ value={p.pathValue}
106
+ disabled={p.disabled}
107
+ selected={p.pathValue === currentPathString}
108
+ >
109
+ {p.pathLabels.join(separator)}
110
+ </option>
111
+ {/each}
112
+ </select>
113
+ {#if hasError}
114
+ {#each error as err, i (i)}
115
+ <div class="lite-error-text">{err}</div>
116
+ {/each}
117
+ {/if}
118
+ </div>
119
+ {/if}
@@ -0,0 +1,24 @@
1
+ import type { FieldDefinition } from '@svadmin/core';
2
+ export interface CascaderOption {
3
+ value: string | number;
4
+ label: string;
5
+ children?: CascaderOption[];
6
+ disabled?: boolean;
7
+ isLeaf?: boolean;
8
+ }
9
+ interface Props {
10
+ field?: FieldDefinition;
11
+ name?: string;
12
+ label?: string;
13
+ value?: (string | number)[];
14
+ options?: CascaderOption[];
15
+ separator?: string;
16
+ placeholder?: string;
17
+ disabled?: boolean;
18
+ required?: boolean;
19
+ error?: string[];
20
+ mode?: 'show' | 'edit' | 'create';
21
+ }
22
+ declare const LiteCascader: import("svelte").Component<Props, {}, "">;
23
+ type LiteCascader = ReturnType<typeof LiteCascader>;
24
+ export default LiteCascader;
@@ -0,0 +1,71 @@
1
+ <script lang="ts">
2
+ import type { FieldDefinition } from '@svadmin/core';
3
+
4
+ interface Props {
5
+ field?: FieldDefinition;
6
+ value?: string | number | Record<string, unknown> | unknown[] | null;
7
+ language?: string;
8
+ copyable?: boolean;
9
+ title?: string;
10
+ nullLabel?: string;
11
+ maxHeight?: string;
12
+ class?: string;
13
+ error?: string[];
14
+ mode?: 'show' | 'edit' | 'create';
15
+ }
16
+
17
+ let {
18
+ field,
19
+ value,
20
+ language,
21
+ nullLabel = '—',
22
+ maxHeight = '200px',
23
+ class: className = '',
24
+ error = [],
25
+ mode = 'show',
26
+ }: Props = $props();
27
+
28
+ const formattedCode = $derived.by(() => {
29
+ if (value == null || value === '') return '';
30
+ if (typeof value === 'string') return value;
31
+ if (typeof value === 'number' || typeof value === 'boolean') return String(value);
32
+ try {
33
+ return JSON.stringify(value, null, 2);
34
+ } catch {
35
+ return String(value);
36
+ }
37
+ });
38
+
39
+ const hasError = $derived(error.length > 0);
40
+ </script>
41
+
42
+ {#if mode === 'show'}
43
+ {#if !formattedCode}
44
+ <span class="lite-text-muted lite-text-sm {className}">{nullLabel}</span>
45
+ {:else}
46
+ <div class="lite-code-block {className}">
47
+ {#if language}
48
+ <div class="lite-code-header">
49
+ <span class="lite-badge">{language.toUpperCase()}</span>
50
+ </div>
51
+ {/if}
52
+ <pre class="lite-code-pre" style="max-height: {maxHeight};"><code>{formattedCode}</code></pre>
53
+ </div>
54
+ {/if}
55
+ {:else}
56
+ <div>
57
+ <textarea
58
+ name={field?.key ?? 'code'}
59
+ id={field?.key ?? 'code'}
60
+ class="lite-input {hasError ? 'lite-input-error' : ''}"
61
+ style="min-height: 120px; font-family: monospace; font-size: 12px;"
62
+ placeholder={field?.label ?? 'Code / content'}
63
+ {...field?.required ? { required: true } : {}}
64
+ >{formattedCode}</textarea>
65
+ {#if hasError}
66
+ {#each error as err, _i (_i)}
67
+ <div class="lite-error-text">{err}</div>
68
+ {/each}
69
+ {/if}
70
+ </div>
71
+ {/if}
@@ -0,0 +1,16 @@
1
+ import type { FieldDefinition } from '@svadmin/core';
2
+ interface Props {
3
+ field?: FieldDefinition;
4
+ value?: string | number | Record<string, unknown> | unknown[] | null;
5
+ language?: string;
6
+ copyable?: boolean;
7
+ title?: string;
8
+ nullLabel?: string;
9
+ maxHeight?: string;
10
+ class?: string;
11
+ error?: string[];
12
+ mode?: 'show' | 'edit' | 'create';
13
+ }
14
+ declare const LiteCodeField: import("svelte").Component<Props, {}, "">;
15
+ type LiteCodeField = ReturnType<typeof LiteCodeField>;
16
+ export default LiteCodeField;
@@ -0,0 +1,74 @@
1
+ <script lang="ts">
2
+ import type { FieldDefinition } from '@svadmin/core';
3
+
4
+ interface Props {
5
+ field?: FieldDefinition;
6
+ value?: string | number | null;
7
+ displayValue?: string;
8
+ masked?: boolean;
9
+ monospace?: boolean;
10
+ copyable?: boolean;
11
+ title?: string;
12
+ nullLabel?: string;
13
+ oncopy?: (value: string) => void;
14
+ class?: string;
15
+ error?: string[];
16
+ mode?: 'show' | 'edit' | 'create';
17
+ }
18
+
19
+ let {
20
+ field,
21
+ value,
22
+ displayValue,
23
+ masked = false,
24
+ monospace = true,
25
+ nullLabel = '—',
26
+ class: className = '',
27
+ error = [],
28
+ mode = 'show',
29
+ }: Props = $props();
30
+
31
+ function maskText(str: string): string {
32
+ if (str.length <= 8) return '****';
33
+ return `${str.slice(0, 4)}...${str.slice(-4)}`;
34
+ }
35
+
36
+ const rawString = $derived(value != null && value !== '' ? String(value) : '');
37
+ const displayText = $derived.by(() => {
38
+ if (!rawString) return nullLabel;
39
+ if (displayValue) return displayValue;
40
+ if (masked) return maskText(rawString);
41
+ return rawString;
42
+ });
43
+
44
+ const hasError = $derived(error.length > 0);
45
+ </script>
46
+
47
+ {#if mode === 'show'}
48
+ {#if !rawString}
49
+ <span class="lite-text-muted lite-text-sm {className}">{nullLabel}</span>
50
+ {:else}
51
+ <span class="lite-copy-field {className}">
52
+ <span class="lite-copy-text {monospace ? 'lite-font-mono' : ''}">
53
+ {displayText}
54
+ </span>
55
+ </span>
56
+ {/if}
57
+ {:else}
58
+ <div>
59
+ <input
60
+ type="text"
61
+ name={field?.key ?? 'copy_text'}
62
+ id={field?.key ?? 'copy_text'}
63
+ value={rawString}
64
+ class="lite-input {hasError ? 'lite-input-error' : ''}"
65
+ placeholder={field?.label ?? 'Value'}
66
+ {...field?.required ? { required: true } : {}}
67
+ />
68
+ {#if hasError}
69
+ {#each error as err, _i (_i)}
70
+ <div class="lite-error-text">{err}</div>
71
+ {/each}
72
+ {/if}
73
+ </div>
74
+ {/if}
@@ -0,0 +1,18 @@
1
+ import type { FieldDefinition } from '@svadmin/core';
2
+ interface Props {
3
+ field?: FieldDefinition;
4
+ value?: string | number | null;
5
+ displayValue?: string;
6
+ masked?: boolean;
7
+ monospace?: boolean;
8
+ copyable?: boolean;
9
+ title?: string;
10
+ nullLabel?: string;
11
+ oncopy?: (value: string) => void;
12
+ class?: string;
13
+ error?: string[];
14
+ mode?: 'show' | 'edit' | 'create';
15
+ }
16
+ declare const LiteCopyField: import("svelte").Component<Props, {}, "">;
17
+ type LiteCopyField = ReturnType<typeof LiteCopyField>;
18
+ export default LiteCopyField;