@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.
- package/README.md +85 -9
- package/dist/components/LiteDynamicFormList.svelte +169 -0
- package/dist/components/LiteDynamicFormList.svelte.d.ts +45 -0
- package/dist/components/LiteFilterBuilder.svelte +205 -0
- package/dist/components/LiteFilterBuilder.svelte.d.ts +19 -0
- package/dist/components/LiteShowField.svelte +22 -0
- package/dist/components/LiteTransfer.svelte +185 -0
- package/dist/components/LiteTransfer.svelte.d.ts +18 -0
- package/dist/components/fields/LiteAvatarField.svelte +127 -0
- package/dist/components/fields/LiteAvatarField.svelte.d.ts +21 -0
- package/dist/components/fields/LiteCascader.svelte +119 -0
- package/dist/components/fields/LiteCascader.svelte.d.ts +24 -0
- package/dist/components/fields/LiteCodeField.svelte +71 -0
- package/dist/components/fields/LiteCodeField.svelte.d.ts +16 -0
- package/dist/components/fields/LiteCopyField.svelte +74 -0
- package/dist/components/fields/LiteCopyField.svelte.d.ts +18 -0
- package/dist/components/fields/LiteCurrencyField.svelte +126 -0
- package/dist/components/fields/LiteCurrencyField.svelte.d.ts +21 -0
- package/dist/components/fields/LiteDateRangeField.svelte +147 -0
- package/dist/components/fields/LiteDateRangeField.svelte.d.ts +26 -0
- package/dist/components/fields/LitePercentField.svelte +124 -0
- package/dist/components/fields/LitePercentField.svelte.d.ts +17 -0
- package/dist/components/fields/LitePhoneField.svelte +81 -0
- package/dist/components/fields/LitePhoneField.svelte.d.ts +17 -0
- package/dist/components/fields/LiteRatingField.svelte +105 -0
- package/dist/components/fields/LiteRatingField.svelte.d.ts +16 -0
- package/dist/components/fields/LiteTreeSelect.svelte +143 -0
- package/dist/components/fields/LiteTreeSelect.svelte.d.ts +23 -0
- package/dist/components/fields/index.d.ts +12 -0
- package/dist/components/fields/index.js +10 -0
- package/dist/components/pages/LiteListPage.svelte +14 -12
- package/dist/index.d.ts +5 -0
- package/dist/index.js +3 -0
- package/dist/lite.css +205 -0
- package/dist/schema-generator.js +15 -4
- package/package.json +4 -3
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import type { FieldDefinition } from '@svadmin/core';
|
|
3
|
+
import { t } from '@svadmin/core/i18n';
|
|
4
|
+
|
|
5
|
+
export interface TreeSelectOption {
|
|
6
|
+
value: string | number;
|
|
7
|
+
label: string;
|
|
8
|
+
children?: TreeSelectOption[];
|
|
9
|
+
disabled?: boolean;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
interface Props {
|
|
13
|
+
field?: FieldDefinition;
|
|
14
|
+
name?: string;
|
|
15
|
+
label?: string;
|
|
16
|
+
value?: string | number | (string | number)[];
|
|
17
|
+
options?: TreeSelectOption[];
|
|
18
|
+
multiple?: boolean;
|
|
19
|
+
placeholder?: string;
|
|
20
|
+
disabled?: boolean;
|
|
21
|
+
required?: boolean;
|
|
22
|
+
error?: string[];
|
|
23
|
+
mode?: 'show' | 'edit' | 'create';
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
let {
|
|
27
|
+
field,
|
|
28
|
+
name = field?.key ?? 'treeSelect',
|
|
29
|
+
label = field?.label,
|
|
30
|
+
value,
|
|
31
|
+
options = [],
|
|
32
|
+
multiple = false,
|
|
33
|
+
placeholder,
|
|
34
|
+
disabled = false,
|
|
35
|
+
required = field?.required ?? false,
|
|
36
|
+
error = [],
|
|
37
|
+
mode = 'show',
|
|
38
|
+
}: Props = $props();
|
|
39
|
+
|
|
40
|
+
const hasError = $derived(error.length > 0);
|
|
41
|
+
|
|
42
|
+
interface FlatTreeOption {
|
|
43
|
+
value: string | number;
|
|
44
|
+
label: string;
|
|
45
|
+
level: number;
|
|
46
|
+
disabled?: boolean;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function flattenTree(nodes: TreeSelectOption[], level = 0): FlatTreeOption[] {
|
|
50
|
+
const list: FlatTreeOption[] = [];
|
|
51
|
+
for (const node of nodes) {
|
|
52
|
+
list.push({
|
|
53
|
+
value: node.value,
|
|
54
|
+
label: node.label,
|
|
55
|
+
level,
|
|
56
|
+
disabled: node.disabled,
|
|
57
|
+
});
|
|
58
|
+
if (node.children && node.children.length > 0) {
|
|
59
|
+
list.push(...flattenTree(node.children, level + 1));
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
return list;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
const flattenedOptions = $derived(flattenTree(options));
|
|
66
|
+
|
|
67
|
+
function getIndentPrefix(level: number): string {
|
|
68
|
+
if (level === 0) return '';
|
|
69
|
+
return ' '.repeat(level) + '├─ ';
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
function formatDisplay(v: unknown): string {
|
|
73
|
+
if (v == null || v === '') return '—';
|
|
74
|
+
const values = Array.isArray(v) ? v.map(String) : [String(v)];
|
|
75
|
+
const labels = values.map((val) => {
|
|
76
|
+
const match = flattenedOptions.find((o) => String(o.value) === val);
|
|
77
|
+
return match ? match.label : val;
|
|
78
|
+
});
|
|
79
|
+
return labels.join(', ');
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
const selectedValues = $derived(
|
|
83
|
+
Array.isArray(value) ? value.map(String) : value != null ? [String(value)] : []
|
|
84
|
+
);
|
|
85
|
+
</script>
|
|
86
|
+
|
|
87
|
+
{#if mode === 'show'}
|
|
88
|
+
<span class="lite-badge">{formatDisplay(value)}</span>
|
|
89
|
+
{:else}
|
|
90
|
+
<div class="lite-form-group">
|
|
91
|
+
{#if label}
|
|
92
|
+
<label class="lite-label" for={name}>
|
|
93
|
+
{label}
|
|
94
|
+
{#if required}<span class="required">*</span>{/if}
|
|
95
|
+
</label>
|
|
96
|
+
{/if}
|
|
97
|
+
{#if multiple}
|
|
98
|
+
<select
|
|
99
|
+
id={name}
|
|
100
|
+
name="{name}[]"
|
|
101
|
+
multiple
|
|
102
|
+
class="lite-select lite-select-multiple {hasError ? 'lite-input-error' : ''}"
|
|
103
|
+
{disabled}
|
|
104
|
+
{required}
|
|
105
|
+
size={Math.min(8, Math.max(4, flattenedOptions.length + 1))}
|
|
106
|
+
>
|
|
107
|
+
{#each flattenedOptions as opt (opt.value)}
|
|
108
|
+
<option
|
|
109
|
+
value={String(opt.value)}
|
|
110
|
+
disabled={opt.disabled}
|
|
111
|
+
selected={selectedValues.includes(String(opt.value))}
|
|
112
|
+
>
|
|
113
|
+
{getIndentPrefix(opt.level)}{opt.label}
|
|
114
|
+
</option>
|
|
115
|
+
{/each}
|
|
116
|
+
</select>
|
|
117
|
+
{:else}
|
|
118
|
+
<select
|
|
119
|
+
id={name}
|
|
120
|
+
{name}
|
|
121
|
+
class="lite-select {hasError ? 'lite-input-error' : ''}"
|
|
122
|
+
{disabled}
|
|
123
|
+
{required}
|
|
124
|
+
>
|
|
125
|
+
<option value="">-- {placeholder || t('common.select') || 'Select'} --</option>
|
|
126
|
+
{#each flattenedOptions as opt (opt.value)}
|
|
127
|
+
<option
|
|
128
|
+
value={String(opt.value)}
|
|
129
|
+
disabled={opt.disabled}
|
|
130
|
+
selected={selectedValues.includes(String(opt.value))}
|
|
131
|
+
>
|
|
132
|
+
{getIndentPrefix(opt.level)}{opt.label}
|
|
133
|
+
</option>
|
|
134
|
+
{/each}
|
|
135
|
+
</select>
|
|
136
|
+
{/if}
|
|
137
|
+
{#if hasError}
|
|
138
|
+
{#each error as err, i (i)}
|
|
139
|
+
<div class="lite-error-text">{err}</div>
|
|
140
|
+
{/each}
|
|
141
|
+
{/if}
|
|
142
|
+
</div>
|
|
143
|
+
{/if}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { FieldDefinition } from '@svadmin/core';
|
|
2
|
+
export interface TreeSelectOption {
|
|
3
|
+
value: string | number;
|
|
4
|
+
label: string;
|
|
5
|
+
children?: TreeSelectOption[];
|
|
6
|
+
disabled?: boolean;
|
|
7
|
+
}
|
|
8
|
+
interface Props {
|
|
9
|
+
field?: FieldDefinition;
|
|
10
|
+
name?: string;
|
|
11
|
+
label?: string;
|
|
12
|
+
value?: string | number | (string | number)[];
|
|
13
|
+
options?: TreeSelectOption[];
|
|
14
|
+
multiple?: boolean;
|
|
15
|
+
placeholder?: string;
|
|
16
|
+
disabled?: boolean;
|
|
17
|
+
required?: boolean;
|
|
18
|
+
error?: string[];
|
|
19
|
+
mode?: 'show' | 'edit' | 'create';
|
|
20
|
+
}
|
|
21
|
+
declare const LiteTreeSelect: import("svelte").Component<Props, {}, "">;
|
|
22
|
+
type LiteTreeSelect = ReturnType<typeof LiteTreeSelect>;
|
|
23
|
+
export default LiteTreeSelect;
|
|
@@ -13,3 +13,15 @@ export { default as LiteFileField } from './LiteFileField.svelte';
|
|
|
13
13
|
export { default as LiteRichTextField } from './LiteRichTextField.svelte';
|
|
14
14
|
export { default as LiteMarkdownField } from './LiteMarkdownField.svelte';
|
|
15
15
|
export { default as LiteJsonField } from './LiteJsonField.svelte';
|
|
16
|
+
export { default as LiteAvatarField } from './LiteAvatarField.svelte';
|
|
17
|
+
export { default as LiteCodeField } from './LiteCodeField.svelte';
|
|
18
|
+
export { default as LiteCopyField } from './LiteCopyField.svelte';
|
|
19
|
+
export { default as LiteCurrencyField } from './LiteCurrencyField.svelte';
|
|
20
|
+
export { default as LiteDateRangeField } from './LiteDateRangeField.svelte';
|
|
21
|
+
export { default as LitePercentField } from './LitePercentField.svelte';
|
|
22
|
+
export { default as LitePhoneField } from './LitePhoneField.svelte';
|
|
23
|
+
export { default as LiteRatingField } from './LiteRatingField.svelte';
|
|
24
|
+
export { default as LiteTreeSelect } from './LiteTreeSelect.svelte';
|
|
25
|
+
export type { TreeSelectOption } from './LiteTreeSelect.svelte';
|
|
26
|
+
export { default as LiteCascader } from './LiteCascader.svelte';
|
|
27
|
+
export type { CascaderOption } from './LiteCascader.svelte';
|
|
@@ -13,3 +13,13 @@ export { default as LiteFileField } from './LiteFileField.svelte';
|
|
|
13
13
|
export { default as LiteRichTextField } from './LiteRichTextField.svelte';
|
|
14
14
|
export { default as LiteMarkdownField } from './LiteMarkdownField.svelte';
|
|
15
15
|
export { default as LiteJsonField } from './LiteJsonField.svelte';
|
|
16
|
+
export { default as LiteAvatarField } from './LiteAvatarField.svelte';
|
|
17
|
+
export { default as LiteCodeField } from './LiteCodeField.svelte';
|
|
18
|
+
export { default as LiteCopyField } from './LiteCopyField.svelte';
|
|
19
|
+
export { default as LiteCurrencyField } from './LiteCurrencyField.svelte';
|
|
20
|
+
export { default as LiteDateRangeField } from './LiteDateRangeField.svelte';
|
|
21
|
+
export { default as LitePercentField } from './LitePercentField.svelte';
|
|
22
|
+
export { default as LitePhoneField } from './LitePhoneField.svelte';
|
|
23
|
+
export { default as LiteRatingField } from './LiteRatingField.svelte';
|
|
24
|
+
export { default as LiteTreeSelect } from './LiteTreeSelect.svelte';
|
|
25
|
+
export { default as LiteCascader } from './LiteCascader.svelte';
|
|
@@ -130,18 +130,20 @@
|
|
|
130
130
|
</span>
|
|
131
131
|
</div>
|
|
132
132
|
|
|
133
|
-
<
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
133
|
+
<div class="lite-table-scroll">
|
|
134
|
+
<LiteTable
|
|
135
|
+
{records}
|
|
136
|
+
{resource}
|
|
137
|
+
{currentSort}
|
|
138
|
+
{currentOrder}
|
|
139
|
+
{currentSearch}
|
|
140
|
+
{basePath}
|
|
141
|
+
canShow={showView}
|
|
142
|
+
canEdit={showEdit}
|
|
143
|
+
canDelete={showDelete}
|
|
144
|
+
{enableBatch}
|
|
145
|
+
/>
|
|
146
|
+
</div>
|
|
145
147
|
|
|
146
148
|
{#if total > pagination.perPage}
|
|
147
149
|
<LitePagination
|
package/dist/index.d.ts
CHANGED
|
@@ -15,6 +15,11 @@ export { default as LiteAlert } from './components/LiteAlert.svelte';
|
|
|
15
15
|
export { default as LitePermissionMatrix } from './components/LitePermissionMatrix.svelte';
|
|
16
16
|
export { default as LiteAuditLog } from './components/LiteAuditLog.svelte';
|
|
17
17
|
export { default as LiteArrayField } from './components/LiteArrayField.svelte';
|
|
18
|
+
export { default as LiteDynamicFormList } from './components/LiteDynamicFormList.svelte';
|
|
19
|
+
export { default as LiteTransfer } from './components/LiteTransfer.svelte';
|
|
20
|
+
export type { TransferItem } from './components/LiteTransfer.svelte';
|
|
21
|
+
export { default as LiteFilterBuilder } from './components/LiteFilterBuilder.svelte';
|
|
22
|
+
export type { FilterRuleItem } from './components/LiteFilterBuilder.svelte';
|
|
18
23
|
export { default as LiteBreadcrumbs } from './components/LiteBreadcrumbs.svelte';
|
|
19
24
|
export { default as LiteStatsCard } from './components/LiteStatsCard.svelte';
|
|
20
25
|
export { default as LiteConfirmDialog } from './components/LiteConfirmDialog.svelte';
|
package/dist/index.js
CHANGED
|
@@ -19,6 +19,9 @@ export { default as LiteAlert } from './components/LiteAlert.svelte';
|
|
|
19
19
|
export { default as LitePermissionMatrix } from './components/LitePermissionMatrix.svelte';
|
|
20
20
|
export { default as LiteAuditLog } from './components/LiteAuditLog.svelte';
|
|
21
21
|
export { default as LiteArrayField } from './components/LiteArrayField.svelte';
|
|
22
|
+
export { default as LiteDynamicFormList } from './components/LiteDynamicFormList.svelte';
|
|
23
|
+
export { default as LiteTransfer } from './components/LiteTransfer.svelte';
|
|
24
|
+
export { default as LiteFilterBuilder } from './components/LiteFilterBuilder.svelte';
|
|
22
25
|
export { default as LiteBreadcrumbs } from './components/LiteBreadcrumbs.svelte';
|
|
23
26
|
export { default as LiteStatsCard } from './components/LiteStatsCard.svelte';
|
|
24
27
|
export { default as LiteConfirmDialog } from './components/LiteConfirmDialog.svelte';
|
package/dist/lite.css
CHANGED
|
@@ -1066,6 +1066,211 @@ textarea.lite-input {
|
|
|
1066
1066
|
.lite-mt-0 { margin-top: 0; }
|
|
1067
1067
|
.lite-mb-lg { margin-bottom: 24px; }
|
|
1068
1068
|
|
|
1069
|
+
/* ─── Avatar ───────────────────────────────────────────────── */
|
|
1070
|
+
.lite-avatar-wrapper {
|
|
1071
|
+
display: inline-flex;
|
|
1072
|
+
align-items: center;
|
|
1073
|
+
}
|
|
1074
|
+
.lite-avatar-container {
|
|
1075
|
+
position: relative;
|
|
1076
|
+
display: inline-block;
|
|
1077
|
+
vertical-align: middle;
|
|
1078
|
+
flex-shrink: 0;
|
|
1079
|
+
}
|
|
1080
|
+
.lite-avatar {
|
|
1081
|
+
display: inline-flex;
|
|
1082
|
+
align-items: center;
|
|
1083
|
+
justify-content: center;
|
|
1084
|
+
background: #f1f5f9;
|
|
1085
|
+
color: #64748b;
|
|
1086
|
+
font-weight: 500;
|
|
1087
|
+
overflow: hidden;
|
|
1088
|
+
vertical-align: middle;
|
|
1089
|
+
}
|
|
1090
|
+
.lite-avatar-circle { border-radius: 50%; }
|
|
1091
|
+
.lite-avatar-square { border-radius: 6px; }
|
|
1092
|
+
|
|
1093
|
+
.lite-avatar-xs { width: 20px; height: 20px; font-size: 10px; }
|
|
1094
|
+
.lite-avatar-sm { width: 28px; height: 28px; font-size: 12px; }
|
|
1095
|
+
.lite-avatar-default { width: 36px; height: 36px; font-size: 14px; }
|
|
1096
|
+
.lite-avatar-lg { width: 44px; height: 44px; font-size: 16px; }
|
|
1097
|
+
|
|
1098
|
+
.lite-avatar-img {
|
|
1099
|
+
width: 100%;
|
|
1100
|
+
height: 100%;
|
|
1101
|
+
object-fit: cover;
|
|
1102
|
+
}
|
|
1103
|
+
.lite-avatar-dot {
|
|
1104
|
+
position: absolute;
|
|
1105
|
+
bottom: 0;
|
|
1106
|
+
right: 0;
|
|
1107
|
+
border-radius: 50%;
|
|
1108
|
+
border: 2px solid #ffffff;
|
|
1109
|
+
}
|
|
1110
|
+
.lite-avatar-dot-xs { width: 6px; height: 6px; }
|
|
1111
|
+
.lite-avatar-dot-sm { width: 8px; height: 8px; }
|
|
1112
|
+
.lite-avatar-dot-default { width: 10px; height: 10px; }
|
|
1113
|
+
.lite-avatar-dot-lg { width: 12px; height: 12px; }
|
|
1114
|
+
|
|
1115
|
+
.lite-avatar-status-online, .lite-avatar-status-success { background: #22c55e; }
|
|
1116
|
+
.lite-avatar-status-busy, .lite-avatar-status-error { background: #ef4444; }
|
|
1117
|
+
.lite-avatar-status-warning, .lite-avatar-status-away { background: #f59e0b; }
|
|
1118
|
+
.lite-avatar-status-offline, .lite-avatar-status-neutral { background: #94a3b8; }
|
|
1119
|
+
|
|
1120
|
+
.lite-avatar-text-block {
|
|
1121
|
+
display: inline-flex;
|
|
1122
|
+
flex-direction: column;
|
|
1123
|
+
margin-left: 10px;
|
|
1124
|
+
text-align: left;
|
|
1125
|
+
vertical-align: middle;
|
|
1126
|
+
}
|
|
1127
|
+
.lite-avatar-name {
|
|
1128
|
+
font-size: 13px;
|
|
1129
|
+
font-weight: 500;
|
|
1130
|
+
color: #0f172a;
|
|
1131
|
+
line-height: 1.2;
|
|
1132
|
+
}
|
|
1133
|
+
.lite-avatar-subtitle {
|
|
1134
|
+
font-size: 11px;
|
|
1135
|
+
color: #64748b;
|
|
1136
|
+
line-height: 1.2;
|
|
1137
|
+
margin-top: 2px;
|
|
1138
|
+
}
|
|
1139
|
+
|
|
1140
|
+
/* ─── Code Block ───────────────────────────────────────────── */
|
|
1141
|
+
.lite-code-block {
|
|
1142
|
+
border: 1px solid #e2e8f0;
|
|
1143
|
+
border-radius: 6px;
|
|
1144
|
+
background: #f8fafc;
|
|
1145
|
+
overflow: hidden;
|
|
1146
|
+
margin: 4px 0;
|
|
1147
|
+
}
|
|
1148
|
+
.lite-code-header {
|
|
1149
|
+
padding: 4px 10px;
|
|
1150
|
+
background: #f1f5f9;
|
|
1151
|
+
border-bottom: 1px solid #e2e8f0;
|
|
1152
|
+
font-size: 11px;
|
|
1153
|
+
}
|
|
1154
|
+
.lite-code-pre {
|
|
1155
|
+
margin: 0;
|
|
1156
|
+
padding: 10px 12px;
|
|
1157
|
+
font-family: Menlo, Monaco, Consolas, "Courier New", monospace;
|
|
1158
|
+
font-size: 12px;
|
|
1159
|
+
line-height: 1.5;
|
|
1160
|
+
overflow-x: auto;
|
|
1161
|
+
overflow-y: auto;
|
|
1162
|
+
color: #0f172a;
|
|
1163
|
+
}
|
|
1164
|
+
|
|
1165
|
+
/* ─── Copy Field ───────────────────────────────────────────── */
|
|
1166
|
+
.lite-copy-field {
|
|
1167
|
+
display: inline-flex;
|
|
1168
|
+
align-items: center;
|
|
1169
|
+
}
|
|
1170
|
+
.lite-copy-text {
|
|
1171
|
+
font-size: 13px;
|
|
1172
|
+
color: #0f172a;
|
|
1173
|
+
}
|
|
1174
|
+
|
|
1175
|
+
/* ─── Currency & Numbers ───────────────────────────────────── */
|
|
1176
|
+
.lite-currency-field {
|
|
1177
|
+
display: inline-flex;
|
|
1178
|
+
align-items: center;
|
|
1179
|
+
font-size: 13px;
|
|
1180
|
+
}
|
|
1181
|
+
|
|
1182
|
+
/* ─── Date Range ───────────────────────────────────────────── */
|
|
1183
|
+
.lite-date-range {
|
|
1184
|
+
display: inline-flex;
|
|
1185
|
+
align-items: center;
|
|
1186
|
+
font-size: 13px;
|
|
1187
|
+
}
|
|
1188
|
+
|
|
1189
|
+
/* ─── Percentage & Progress ────────────────────────────────── */
|
|
1190
|
+
.lite-percent-container {
|
|
1191
|
+
display: inline-flex;
|
|
1192
|
+
align-items: center;
|
|
1193
|
+
}
|
|
1194
|
+
.lite-progress-track {
|
|
1195
|
+
display: inline-block;
|
|
1196
|
+
width: 64px;
|
|
1197
|
+
height: 6px;
|
|
1198
|
+
background: #e2e8f0;
|
|
1199
|
+
border-radius: 3px;
|
|
1200
|
+
overflow: hidden;
|
|
1201
|
+
margin-left: 8px;
|
|
1202
|
+
vertical-align: middle;
|
|
1203
|
+
}
|
|
1204
|
+
.lite-progress-fill {
|
|
1205
|
+
display: block;
|
|
1206
|
+
height: 100%;
|
|
1207
|
+
background: #4f46e5;
|
|
1208
|
+
border-radius: 3px;
|
|
1209
|
+
}
|
|
1210
|
+
.lite-progress-success { background: #22c55e; }
|
|
1211
|
+
.lite-progress-warning { background: #f59e0b; }
|
|
1212
|
+
.lite-progress-danger { background: #ef4444; }
|
|
1213
|
+
.lite-progress-info { background: #3b82f6; }
|
|
1214
|
+
|
|
1215
|
+
/* ─── Phone Field ──────────────────────────────────────────── */
|
|
1216
|
+
.lite-phone-container {
|
|
1217
|
+
display: inline-flex;
|
|
1218
|
+
align-items: center;
|
|
1219
|
+
font-size: 13px;
|
|
1220
|
+
}
|
|
1221
|
+
.lite-phone-icon {
|
|
1222
|
+
margin-right: 6px;
|
|
1223
|
+
font-size: 12px;
|
|
1224
|
+
}
|
|
1225
|
+
.lite-phone-link {
|
|
1226
|
+
color: #4f46e5;
|
|
1227
|
+
font-weight: 500;
|
|
1228
|
+
text-decoration: none;
|
|
1229
|
+
}
|
|
1230
|
+
.lite-phone-link:hover {
|
|
1231
|
+
text-decoration: underline;
|
|
1232
|
+
}
|
|
1233
|
+
|
|
1234
|
+
/* ─── Rating Field ─────────────────────────────────────────── */
|
|
1235
|
+
.lite-rating-container {
|
|
1236
|
+
display: inline-flex;
|
|
1237
|
+
align-items: center;
|
|
1238
|
+
}
|
|
1239
|
+
.lite-rating {
|
|
1240
|
+
display: inline-flex;
|
|
1241
|
+
align-items: center;
|
|
1242
|
+
}
|
|
1243
|
+
.lite-rating-star {
|
|
1244
|
+
display: inline-block;
|
|
1245
|
+
margin-right: 2px;
|
|
1246
|
+
line-height: 1;
|
|
1247
|
+
}
|
|
1248
|
+
.lite-rating-star-full, .lite-rating-star-half {
|
|
1249
|
+
color: #f59e0b;
|
|
1250
|
+
}
|
|
1251
|
+
.lite-rating-star-empty {
|
|
1252
|
+
color: #cbd5e1;
|
|
1253
|
+
}
|
|
1254
|
+
.lite-rating-sm { font-size: 12px; }
|
|
1255
|
+
.lite-rating-default { font-size: 14px; }
|
|
1256
|
+
.lite-rating-lg { font-size: 18px; }
|
|
1257
|
+
.lite-rating-value {
|
|
1258
|
+
margin-left: 6px;
|
|
1259
|
+
font-size: 13px;
|
|
1260
|
+
color: #0f172a;
|
|
1261
|
+
font-weight: 500;
|
|
1262
|
+
}
|
|
1263
|
+
|
|
1264
|
+
/* ─── Semantic Tone Utilities ──────────────────────────────── */
|
|
1265
|
+
.lite-font-mono {
|
|
1266
|
+
font-family: Menlo, Monaco, Consolas, "Courier New", monospace;
|
|
1267
|
+
}
|
|
1268
|
+
.lite-text-success { color: #16a34a; font-weight: 500; }
|
|
1269
|
+
.lite-text-warning { color: #d97706; font-weight: 500; }
|
|
1270
|
+
.lite-text-danger { color: #dc2626; font-weight: 500; }
|
|
1271
|
+
.lite-text-info { color: #2563eb; font-weight: 500; }
|
|
1272
|
+
.lite-text-primary { color: #4f46e5; font-weight: 500; }
|
|
1273
|
+
|
|
1069
1274
|
/* ─── Responsive ───────────────────────────────────────────── */
|
|
1070
1275
|
@media (max-width: 768px) {
|
|
1071
1276
|
.lite-wrapper {
|
package/dist/schema-generator.js
CHANGED
|
@@ -49,6 +49,7 @@ function coerceAndValidateField(field, value, mode, withinArray = false, path =
|
|
|
49
49
|
const issues = [];
|
|
50
50
|
let coerced = value;
|
|
51
51
|
switch (field.type) {
|
|
52
|
+
case "currency":
|
|
52
53
|
case "number": {
|
|
53
54
|
if (coerced === undefined || coerced === null || coerced === "") {
|
|
54
55
|
coerced = undefined;
|
|
@@ -57,7 +58,7 @@ function coerceAndValidateField(field, value, mode, withinArray = false, path =
|
|
|
57
58
|
}
|
|
58
59
|
}
|
|
59
60
|
else if (typeof coerced === "string") {
|
|
60
|
-
const trimmed = coerced.trim();
|
|
61
|
+
const trimmed = coerced.trim().replace(/^[$€£¥₹]/u, "");
|
|
61
62
|
if (trimmed === "") {
|
|
62
63
|
coerced = undefined;
|
|
63
64
|
if (field.required) {
|
|
@@ -251,7 +252,7 @@ function coerceAndValidateField(field, value, mode, withinArray = false, path =
|
|
|
251
252
|
}
|
|
252
253
|
case "phone": {
|
|
253
254
|
if (typeof coerced === "string" && coerced.length > 0) {
|
|
254
|
-
if (!/^[+\d\s()-]
|
|
255
|
+
if (!/^[+\d\s()-]*$/u.test(coerced)) {
|
|
255
256
|
issues.push({ path, message: `${field.label} must be a valid phone number` });
|
|
256
257
|
}
|
|
257
258
|
}
|
|
@@ -309,7 +310,13 @@ function coerceAndValidateField(field, value, mode, withinArray = false, path =
|
|
|
309
310
|
break;
|
|
310
311
|
}
|
|
311
312
|
// Check required
|
|
312
|
-
if (field.type !== "number"
|
|
313
|
+
if (field.type !== "number"
|
|
314
|
+
&& field.type !== "currency"
|
|
315
|
+
&& field.type !== "boolean"
|
|
316
|
+
&& field.type !== "array"
|
|
317
|
+
&& field.type !== "file"
|
|
318
|
+
&& field.type !== "image"
|
|
319
|
+
&& field.type !== "images") {
|
|
313
320
|
if (field.required && !hasRequiredValue(coerced)) {
|
|
314
321
|
issues.push({ path, message: `${field.label} is required` });
|
|
315
322
|
}
|
|
@@ -339,6 +346,7 @@ export function fieldsToTypeBoxSchema(fields, mode = "create") {
|
|
|
339
346
|
activeFields.push(field);
|
|
340
347
|
switch (field.type) {
|
|
341
348
|
case "number":
|
|
349
|
+
case "currency":
|
|
342
350
|
shape[field.key] = field.required ? Type.Number() : Type.Optional(Type.Number());
|
|
343
351
|
break;
|
|
344
352
|
case "boolean":
|
|
@@ -434,7 +442,9 @@ export const resourceToZodSchema = resourceToTypeBoxSchema;
|
|
|
434
442
|
*/
|
|
435
443
|
export function fieldToInputType(field) {
|
|
436
444
|
switch (field.type) {
|
|
437
|
-
case "number":
|
|
445
|
+
case "number":
|
|
446
|
+
case "currency": return "text";
|
|
447
|
+
case "color": return "color";
|
|
438
448
|
case "email": return "text";
|
|
439
449
|
case "url": return "text";
|
|
440
450
|
case "phone": return "tel";
|
|
@@ -464,6 +474,7 @@ export function fieldToPlaceholder(field) {
|
|
|
464
474
|
case "url": return "https://example.com";
|
|
465
475
|
case "phone": return "+1 (555) 000-0000";
|
|
466
476
|
case "number": return "0";
|
|
477
|
+
case "currency": return "0.00";
|
|
467
478
|
default: return "";
|
|
468
479
|
}
|
|
469
480
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@svadmin/lite",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.7.0",
|
|
4
4
|
"description": "SSR-first lightweight admin UI for @svadmin with optional progressive enhancement",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"sideEffects": [
|
|
@@ -49,7 +49,7 @@
|
|
|
49
49
|
},
|
|
50
50
|
"peerDependencies": {
|
|
51
51
|
"svelte": "^5.56.10",
|
|
52
|
-
"@svadmin/core": ">=0.34.2 <0.
|
|
52
|
+
"@svadmin/core": ">=0.34.2 <0.47.0",
|
|
53
53
|
"@sveltejs/kit": "^2.70.3"
|
|
54
54
|
},
|
|
55
55
|
"dependencies": {
|
|
@@ -70,7 +70,8 @@
|
|
|
70
70
|
"test": "bun run test:components && bun run test:server && bun run test:security",
|
|
71
71
|
"test:components": "vitest run --config ./vitest.config.ts",
|
|
72
72
|
"test:server": "bun test ./src/schema-generator.test.ts ./src/server-adapter.test.ts ./src/fragment-id.test.ts ./src/compatibility.test.ts ./src/ie11-ssr-contract.test.ts",
|
|
73
|
-
"test:security": "vitest run --config ./src/security.test.config.ts"
|
|
73
|
+
"test:security": "vitest run --config ./src/security.test.config.ts",
|
|
74
|
+
"check:parity": "bun ../../scripts/check-parity.ts --write"
|
|
74
75
|
},
|
|
75
76
|
"license": "MIT",
|
|
76
77
|
"publishConfig": {
|