@shwfed/config 2.2.4 → 2.3.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/dist/module.json +1 -1
- package/dist/runtime/components/config/blocks/2026-05-06/com.shwfed.block.table/config.d.vue.ts +8 -8
- package/dist/runtime/components/config/blocks/2026-05-06/com.shwfed.block.table/config.vue.d.ts +8 -8
- package/dist/runtime/components/config/blocks/2026-05-06/com.shwfed.block.table/runtime.d.vue.ts +8 -8
- package/dist/runtime/components/config/blocks/2026-05-06/com.shwfed.block.table/runtime.vue.d.ts +8 -8
- package/dist/runtime/components/config/blocks/2026-05-06/com.shwfed.block.table/schema.d.ts +9 -15
- package/dist/runtime/components/form/fields/2026-05-13/com.shwfed.form.field.list/row.d.vue.ts +3 -4
- package/dist/runtime/components/form/fields/2026-05-13/com.shwfed.form.field.list/row.vue +1 -1
- package/dist/runtime/components/form/fields/2026-05-13/com.shwfed.form.field.list/row.vue.d.ts +3 -4
- package/dist/runtime/components/form/fields/2026-05-13/com.shwfed.form.field.list/runtime.vue +9 -2
- package/dist/runtime/components/form/fields/2026-05-18/com.shwfed.form.field.table/config.d.vue.ts +2 -2
- package/dist/runtime/components/form/fields/2026-05-18/com.shwfed.form.field.table/config.vue +32 -52
- package/dist/runtime/components/form/fields/2026-05-18/com.shwfed.form.field.table/config.vue.d.ts +2 -2
- package/dist/runtime/components/form/fields/2026-05-18/com.shwfed.form.field.table/runtime.vue +19 -8
- package/dist/runtime/components/form/fields/2026-05-18/com.shwfed.form.field.table/schema.d.ts +2 -2
- package/dist/runtime/components/form/fields/2026-05-18/com.shwfed.form.field.table/schema.js +4 -3
- package/dist/runtime/components/form/utils/state.d.ts +10 -2
- package/dist/runtime/components/form/utils/state.js +10 -3
- package/dist/runtime/components/table/columns/2026-05-13/com.shwfed.table.column.switch/config.vue +25 -0
- package/dist/runtime/components/table/columns/2026-05-13/com.shwfed.table.column.switch/runtime.vue +2 -8
- package/dist/runtime/components/table/columns/2026-05-13/com.shwfed.table.column.switch/schema.d.ts +4 -0
- package/dist/runtime/components/table/columns/2026-05-13/com.shwfed.table.column.switch/schema.js +5 -0
- package/dist/runtime/components/table/columns/2026-05-20/com.shwfed.table.column.combobox-single/config.d.vue.ts +133 -0
- package/dist/runtime/components/table/columns/2026-05-20/com.shwfed.table.column.combobox-single/config.vue +533 -0
- package/dist/runtime/components/table/columns/2026-05-20/com.shwfed.table.column.combobox-single/config.vue.d.ts +133 -0
- package/dist/runtime/components/table/columns/2026-05-20/com.shwfed.table.column.combobox-single/runtime.d.vue.ts +9 -0
- package/dist/runtime/components/table/columns/2026-05-20/com.shwfed.table.column.combobox-single/runtime.vue +237 -0
- package/dist/runtime/components/table/columns/2026-05-20/com.shwfed.table.column.combobox-single/runtime.vue.d.ts +9 -0
- package/dist/runtime/components/table/columns/2026-05-20/com.shwfed.table.column.combobox-single/schema.d.ts +124 -0
- package/dist/runtime/components/table/columns/2026-05-20/com.shwfed.table.column.combobox-single/schema.js +96 -0
- package/dist/runtime/components/table/columns/2026-05-20/com.shwfed.table.column.number-input/config.d.vue.ts +10 -0
- package/dist/runtime/components/table/columns/2026-05-20/com.shwfed.table.column.number-input/config.vue +475 -0
- package/dist/runtime/components/table/columns/2026-05-20/com.shwfed.table.column.number-input/config.vue.d.ts +10 -0
- package/dist/runtime/components/table/columns/2026-05-20/com.shwfed.table.column.number-input/runtime.d.vue.ts +9 -0
- package/dist/runtime/components/table/columns/2026-05-20/com.shwfed.table.column.number-input/runtime.vue +156 -0
- package/dist/runtime/components/table/columns/2026-05-20/com.shwfed.table.column.number-input/runtime.vue.d.ts +9 -0
- package/dist/runtime/components/table/columns/2026-05-20/com.shwfed.table.column.number-input/schema.d.ts +56 -0
- package/dist/runtime/components/table/columns/2026-05-20/com.shwfed.table.column.number-input/schema.js +81 -0
- package/dist/runtime/components/table/columns/2026-05-20/com.shwfed.table.column.text-input/config.d.vue.ts +10 -0
- package/dist/runtime/components/table/columns/2026-05-20/com.shwfed.table.column.text-input/config.vue +292 -0
- package/dist/runtime/components/table/columns/2026-05-20/com.shwfed.table.column.text-input/config.vue.d.ts +10 -0
- package/dist/runtime/components/table/columns/2026-05-20/com.shwfed.table.column.text-input/runtime.d.vue.ts +9 -0
- package/dist/runtime/components/table/columns/2026-05-20/com.shwfed.table.column.text-input/runtime.vue +140 -0
- package/dist/runtime/components/table/columns/2026-05-20/com.shwfed.table.column.text-input/runtime.vue.d.ts +9 -0
- package/dist/runtime/components/table/columns/2026-05-20/com.shwfed.table.column.text-input/schema.d.ts +50 -0
- package/dist/runtime/components/table/columns/2026-05-20/com.shwfed.table.column.text-input/schema.js +53 -0
- package/dist/runtime/components/table/config.d.vue.ts +2 -0
- package/dist/runtime/components/table/config.vue +136 -109
- package/dist/runtime/components/table/config.vue.d.ts +2 -0
- package/dist/runtime/components/table/index.d.vue.ts +2 -2
- package/dist/runtime/components/table/index.vue +46 -53
- package/dist/runtime/components/table/index.vue.d.ts +2 -2
- package/dist/runtime/components/table/row-provider.d.vue.ts +23 -0
- package/dist/runtime/components/table/row-provider.vue +55 -0
- package/dist/runtime/components/table/row-provider.vue.d.ts +23 -0
- package/dist/runtime/components/table/schema.d.ts +17 -29
- package/dist/runtime/components/table/schema.js +22 -18
- package/dist/runtime/components/table/utils/shared.d.ts +28 -0
- package/dist/runtime/components/table/utils/shared.js +40 -0
- package/dist/runtime/components/ui/field/index.js +6 -1
- package/dist/runtime/components/ui/input/Input.vue +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,475 @@
|
|
|
1
|
+
<script setup>
|
|
2
|
+
import { computed } from "vue";
|
|
3
|
+
import { Icon } from "@iconify/vue";
|
|
4
|
+
import { ExpressionEditor } from "../../../../ui/expression-editor";
|
|
5
|
+
import { Switch } from "../../../../ui/switch";
|
|
6
|
+
import { Separator } from "../../../../ui/separator";
|
|
7
|
+
import { Field, FieldLabel } from "../../../../ui/field";
|
|
8
|
+
import { Locale } from "../../../../ui/locale";
|
|
9
|
+
import {
|
|
10
|
+
DropdownMenu,
|
|
11
|
+
DropdownMenuContent,
|
|
12
|
+
DropdownMenuItem,
|
|
13
|
+
DropdownMenuTrigger
|
|
14
|
+
} from "../../../../ui/dropdown-menu";
|
|
15
|
+
import {
|
|
16
|
+
InputGroup,
|
|
17
|
+
InputGroupAddon,
|
|
18
|
+
InputGroupButton,
|
|
19
|
+
InputGroupInput,
|
|
20
|
+
InputGroupNumberField
|
|
21
|
+
} from "../../../../ui/input-group";
|
|
22
|
+
import { getStructFieldDescription, getStructFieldTitle } from "../../../utils/schema-meta";
|
|
23
|
+
import { Markdown } from "../../../../ui/markdown";
|
|
24
|
+
import DerivedValueEditor from "../../../../form/DerivedValueEditor.vue";
|
|
25
|
+
import { schema } from "./schema";
|
|
26
|
+
defineOptions({ name: "ShwfedTableNumberInputRendererConfig" });
|
|
27
|
+
const value = defineModel({ type: Object, ...{ required: true } });
|
|
28
|
+
const fieldSchema = schema(() => {
|
|
29
|
+
});
|
|
30
|
+
const fieldTitle = (field) => getStructFieldTitle(fieldSchema, field) ?? field;
|
|
31
|
+
const fieldDescription = (field) => getStructFieldDescription(fieldSchema, field);
|
|
32
|
+
const ROW_VARS = {
|
|
33
|
+
row: { type: "dyn", label: "\u5F53\u524D\u884C\u6570\u636E" },
|
|
34
|
+
index: { type: "number", label: "\u884C\u7D22\u5F15" }
|
|
35
|
+
};
|
|
36
|
+
const ROUNDING_MODE_OPTIONS = [
|
|
37
|
+
{ value: "round", label: "\u56DB\u820D\u4E94\u5165" },
|
|
38
|
+
{ value: "floor", label: "\u5411\u4E0B\u53D6\u6574" },
|
|
39
|
+
{ value: "ceil", label: "\u5411\u4E0A\u53D6\u6574" }
|
|
40
|
+
];
|
|
41
|
+
const bindingText = computed({
|
|
42
|
+
get: () => value.value.binding ?? "",
|
|
43
|
+
set: (v) => {
|
|
44
|
+
const trimmed = v.trim();
|
|
45
|
+
if (trimmed === "") delete value.value.binding;
|
|
46
|
+
else value.value.binding = trimmed;
|
|
47
|
+
}
|
|
48
|
+
});
|
|
49
|
+
const hiddenModel = computed({
|
|
50
|
+
get: () => value.value.hidden ?? "",
|
|
51
|
+
set: (v) => {
|
|
52
|
+
if (v === "") delete value.value.hidden;
|
|
53
|
+
else value.value.hidden = v;
|
|
54
|
+
}
|
|
55
|
+
});
|
|
56
|
+
const disabledModel = computed({
|
|
57
|
+
get: () => value.value.disabled ?? "",
|
|
58
|
+
set: (v) => {
|
|
59
|
+
if (v === "") delete value.value.disabled;
|
|
60
|
+
else value.value.disabled = v;
|
|
61
|
+
}
|
|
62
|
+
});
|
|
63
|
+
const readonlyModel = computed({
|
|
64
|
+
get: () => value.value.readonly ?? "",
|
|
65
|
+
set: (v) => {
|
|
66
|
+
if (v === "") delete value.value.readonly;
|
|
67
|
+
else value.value.readonly = v;
|
|
68
|
+
}
|
|
69
|
+
});
|
|
70
|
+
const derivedModel = computed({
|
|
71
|
+
get: () => value.value.derived,
|
|
72
|
+
set: (v) => {
|
|
73
|
+
if (v == null) delete value.value.derived;
|
|
74
|
+
else value.value.derived = v;
|
|
75
|
+
}
|
|
76
|
+
});
|
|
77
|
+
const currentRoundingModeLabel = computed(
|
|
78
|
+
() => ROUNDING_MODE_OPTIONS.find((o) => o.value === (value.value.roundingMode ?? "round"))?.label
|
|
79
|
+
);
|
|
80
|
+
function onPrecisionChange(v) {
|
|
81
|
+
if (v === void 0) {
|
|
82
|
+
delete value.value.precision;
|
|
83
|
+
delete value.value.roundingMode;
|
|
84
|
+
} else {
|
|
85
|
+
value.value.precision = v;
|
|
86
|
+
if (value.value.roundingMode === void 0) value.value.roundingMode = "round";
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
function onRoundingModeChange(mode) {
|
|
90
|
+
value.value.roundingMode = mode;
|
|
91
|
+
}
|
|
92
|
+
function onStepChange(v) {
|
|
93
|
+
if (v === void 0 || !(v > 0)) delete value.value.step;
|
|
94
|
+
else value.value.step = v;
|
|
95
|
+
}
|
|
96
|
+
function onValueAsStringChange(next) {
|
|
97
|
+
if (next) value.value.valueAsString = true;
|
|
98
|
+
else delete value.value.valueAsString;
|
|
99
|
+
}
|
|
100
|
+
</script>
|
|
101
|
+
|
|
102
|
+
<template>
|
|
103
|
+
<div class="space-y-5">
|
|
104
|
+
<div class="grid grid-cols-2 gap-x-6 gap-y-4">
|
|
105
|
+
<Field orientation="vertical">
|
|
106
|
+
<FieldLabel class="text-xs text-zinc-500">
|
|
107
|
+
<template
|
|
108
|
+
v-if="fieldDescription('title')"
|
|
109
|
+
#tooltip
|
|
110
|
+
>
|
|
111
|
+
<Markdown
|
|
112
|
+
:source="fieldDescription('title')"
|
|
113
|
+
block
|
|
114
|
+
class="prose prose-sm prose-zinc"
|
|
115
|
+
/>
|
|
116
|
+
</template>
|
|
117
|
+
{{ fieldTitle("title") }}
|
|
118
|
+
</FieldLabel>
|
|
119
|
+
<Locale v-model="value.title" />
|
|
120
|
+
</Field>
|
|
121
|
+
<Field orientation="vertical">
|
|
122
|
+
<FieldLabel class="text-xs text-zinc-500">
|
|
123
|
+
<template
|
|
124
|
+
v-if="fieldDescription('tooltip')"
|
|
125
|
+
#tooltip
|
|
126
|
+
>
|
|
127
|
+
<Markdown
|
|
128
|
+
:source="fieldDescription('tooltip')"
|
|
129
|
+
block
|
|
130
|
+
class="prose prose-sm prose-zinc"
|
|
131
|
+
/>
|
|
132
|
+
</template>
|
|
133
|
+
{{ fieldTitle("tooltip") }}
|
|
134
|
+
</FieldLabel>
|
|
135
|
+
<Locale
|
|
136
|
+
v-model="value.tooltip"
|
|
137
|
+
markdown
|
|
138
|
+
/>
|
|
139
|
+
</Field>
|
|
140
|
+
</div>
|
|
141
|
+
<div class="grid grid-cols-2 gap-x-6 gap-y-4">
|
|
142
|
+
<Field orientation="vertical">
|
|
143
|
+
<FieldLabel class="text-xs text-zinc-500">
|
|
144
|
+
<template
|
|
145
|
+
v-if="fieldDescription('binding')"
|
|
146
|
+
#tooltip
|
|
147
|
+
>
|
|
148
|
+
<Markdown
|
|
149
|
+
:source="fieldDescription('binding')"
|
|
150
|
+
block
|
|
151
|
+
class="prose prose-sm prose-zinc"
|
|
152
|
+
/>
|
|
153
|
+
</template>
|
|
154
|
+
{{ fieldTitle("binding") }}
|
|
155
|
+
</FieldLabel>
|
|
156
|
+
<InputGroup>
|
|
157
|
+
<InputGroupInput
|
|
158
|
+
v-model="bindingText"
|
|
159
|
+
placeholder="例:age"
|
|
160
|
+
class="font-mono"
|
|
161
|
+
/>
|
|
162
|
+
</InputGroup>
|
|
163
|
+
</Field>
|
|
164
|
+
<Field orientation="vertical">
|
|
165
|
+
<FieldLabel class="text-xs text-zinc-500">
|
|
166
|
+
<template
|
|
167
|
+
v-if="fieldDescription('placeholder')"
|
|
168
|
+
#tooltip
|
|
169
|
+
>
|
|
170
|
+
<Markdown
|
|
171
|
+
:source="fieldDescription('placeholder')"
|
|
172
|
+
block
|
|
173
|
+
class="prose prose-sm prose-zinc"
|
|
174
|
+
/>
|
|
175
|
+
</template>
|
|
176
|
+
{{ fieldTitle("placeholder") }}
|
|
177
|
+
</FieldLabel>
|
|
178
|
+
<Locale v-model="value.placeholder" />
|
|
179
|
+
</Field>
|
|
180
|
+
<Field orientation="vertical">
|
|
181
|
+
<FieldLabel class="text-xs text-zinc-500">
|
|
182
|
+
<template
|
|
183
|
+
v-if="fieldDescription('size')"
|
|
184
|
+
#tooltip
|
|
185
|
+
>
|
|
186
|
+
<Markdown
|
|
187
|
+
:source="fieldDescription('size')"
|
|
188
|
+
block
|
|
189
|
+
class="prose prose-sm prose-zinc"
|
|
190
|
+
/>
|
|
191
|
+
</template>
|
|
192
|
+
{{ fieldTitle("size") }}
|
|
193
|
+
</FieldLabel>
|
|
194
|
+
<InputGroup>
|
|
195
|
+
<InputGroupNumberField
|
|
196
|
+
:model-value="value.size"
|
|
197
|
+
:disabled="value.grow"
|
|
198
|
+
:min="0"
|
|
199
|
+
@update:model-value="(v) => value.size = v"
|
|
200
|
+
/>
|
|
201
|
+
<InputGroupAddon align="inline-end">
|
|
202
|
+
<InputGroupButton
|
|
203
|
+
:variant="value.grow ? 'primary' : 'ghost'"
|
|
204
|
+
size="xs"
|
|
205
|
+
@click="value.grow = !value.grow"
|
|
206
|
+
>
|
|
207
|
+
<Icon :icon="value.grow ? 'fluent:lock-closed-20-regular' : 'fluent:arrow-autofit-width-20-regular'" />
|
|
208
|
+
{{ fieldTitle("grow") }}
|
|
209
|
+
</InputGroupButton>
|
|
210
|
+
</InputGroupAddon>
|
|
211
|
+
</InputGroup>
|
|
212
|
+
</Field>
|
|
213
|
+
<Field orientation="vertical">
|
|
214
|
+
<FieldLabel class="text-xs text-zinc-500">
|
|
215
|
+
<template
|
|
216
|
+
v-if="fieldDescription('precision')"
|
|
217
|
+
#tooltip
|
|
218
|
+
>
|
|
219
|
+
<Markdown
|
|
220
|
+
:source="fieldDescription('precision')"
|
|
221
|
+
block
|
|
222
|
+
class="prose prose-sm prose-zinc"
|
|
223
|
+
/>
|
|
224
|
+
</template>
|
|
225
|
+
{{ fieldTitle("precision") }}
|
|
226
|
+
</FieldLabel>
|
|
227
|
+
<InputGroup>
|
|
228
|
+
<InputGroupNumberField
|
|
229
|
+
:model-value="value.precision"
|
|
230
|
+
:min="0"
|
|
231
|
+
@update:model-value="onPrecisionChange"
|
|
232
|
+
/>
|
|
233
|
+
<InputGroupAddon
|
|
234
|
+
v-if="value.precision !== void 0"
|
|
235
|
+
align="inline-end"
|
|
236
|
+
>
|
|
237
|
+
<DropdownMenu>
|
|
238
|
+
<DropdownMenuTrigger as-child>
|
|
239
|
+
<InputGroupButton
|
|
240
|
+
variant="ghost"
|
|
241
|
+
class="pr-1.5! text-xs"
|
|
242
|
+
>
|
|
243
|
+
{{ currentRoundingModeLabel }}
|
|
244
|
+
<Icon
|
|
245
|
+
icon="lucide:chevron-down"
|
|
246
|
+
class="size-3"
|
|
247
|
+
/>
|
|
248
|
+
</InputGroupButton>
|
|
249
|
+
</DropdownMenuTrigger>
|
|
250
|
+
<DropdownMenuContent align="end">
|
|
251
|
+
<DropdownMenuItem
|
|
252
|
+
v-for="opt in ROUNDING_MODE_OPTIONS"
|
|
253
|
+
:key="opt.value"
|
|
254
|
+
@select="onRoundingModeChange(opt.value)"
|
|
255
|
+
>
|
|
256
|
+
{{ opt.label }}
|
|
257
|
+
</DropdownMenuItem>
|
|
258
|
+
</DropdownMenuContent>
|
|
259
|
+
</DropdownMenu>
|
|
260
|
+
</InputGroupAddon>
|
|
261
|
+
</InputGroup>
|
|
262
|
+
</Field>
|
|
263
|
+
<Field orientation="vertical">
|
|
264
|
+
<FieldLabel class="text-xs text-zinc-500">
|
|
265
|
+
<template
|
|
266
|
+
v-if="fieldDescription('step')"
|
|
267
|
+
#tooltip
|
|
268
|
+
>
|
|
269
|
+
<Markdown
|
|
270
|
+
:source="fieldDescription('step')"
|
|
271
|
+
block
|
|
272
|
+
class="prose prose-sm prose-zinc"
|
|
273
|
+
/>
|
|
274
|
+
</template>
|
|
275
|
+
{{ fieldTitle("step") }}
|
|
276
|
+
</FieldLabel>
|
|
277
|
+
<InputGroup>
|
|
278
|
+
<InputGroupNumberField
|
|
279
|
+
:model-value="value.step"
|
|
280
|
+
:min="0"
|
|
281
|
+
@update:model-value="onStepChange"
|
|
282
|
+
/>
|
|
283
|
+
</InputGroup>
|
|
284
|
+
</Field>
|
|
285
|
+
<Field orientation="vertical">
|
|
286
|
+
<FieldLabel class="text-xs text-zinc-500">
|
|
287
|
+
<template
|
|
288
|
+
v-if="fieldDescription('valueAsString')"
|
|
289
|
+
#tooltip
|
|
290
|
+
>
|
|
291
|
+
<Markdown
|
|
292
|
+
:source="fieldDescription('valueAsString')"
|
|
293
|
+
block
|
|
294
|
+
class="prose prose-sm prose-zinc"
|
|
295
|
+
/>
|
|
296
|
+
</template>
|
|
297
|
+
{{ fieldTitle("valueAsString") }}
|
|
298
|
+
</FieldLabel>
|
|
299
|
+
<div>
|
|
300
|
+
<Switch
|
|
301
|
+
:model-value="value.valueAsString ?? false"
|
|
302
|
+
@update:model-value="onValueAsStringChange"
|
|
303
|
+
/>
|
|
304
|
+
</div>
|
|
305
|
+
</Field>
|
|
306
|
+
</div>
|
|
307
|
+
<div class="grid grid-cols-2 gap-x-6 gap-y-4">
|
|
308
|
+
<Field orientation="vertical">
|
|
309
|
+
<FieldLabel class="text-xs text-zinc-500">
|
|
310
|
+
<template
|
|
311
|
+
v-if="fieldDescription('min')"
|
|
312
|
+
#tooltip
|
|
313
|
+
>
|
|
314
|
+
<Markdown
|
|
315
|
+
:source="fieldDescription('min')"
|
|
316
|
+
block
|
|
317
|
+
class="prose prose-sm prose-zinc"
|
|
318
|
+
/>
|
|
319
|
+
</template>
|
|
320
|
+
{{ fieldTitle("min") }}
|
|
321
|
+
</FieldLabel>
|
|
322
|
+
<ExpressionEditor
|
|
323
|
+
:model-value="value.min ?? ''"
|
|
324
|
+
placeholder="例:0"
|
|
325
|
+
result-type="number"
|
|
326
|
+
class="min-h-10"
|
|
327
|
+
:extra-vars="ROW_VARS"
|
|
328
|
+
@update:model-value="(v) => {
|
|
329
|
+
if (v.length > 0) value.min = v;
|
|
330
|
+
else delete value.min;
|
|
331
|
+
}"
|
|
332
|
+
/>
|
|
333
|
+
</Field>
|
|
334
|
+
<Field orientation="vertical">
|
|
335
|
+
<FieldLabel class="text-xs text-zinc-500">
|
|
336
|
+
<template
|
|
337
|
+
v-if="fieldDescription('max')"
|
|
338
|
+
#tooltip
|
|
339
|
+
>
|
|
340
|
+
<Markdown
|
|
341
|
+
:source="fieldDescription('max')"
|
|
342
|
+
block
|
|
343
|
+
class="prose prose-sm prose-zinc"
|
|
344
|
+
/>
|
|
345
|
+
</template>
|
|
346
|
+
{{ fieldTitle("max") }}
|
|
347
|
+
</FieldLabel>
|
|
348
|
+
<ExpressionEditor
|
|
349
|
+
:model-value="value.max ?? ''"
|
|
350
|
+
placeholder="例:100"
|
|
351
|
+
result-type="number"
|
|
352
|
+
class="min-h-10"
|
|
353
|
+
:extra-vars="ROW_VARS"
|
|
354
|
+
@update:model-value="(v) => {
|
|
355
|
+
if (v.length > 0) value.max = v;
|
|
356
|
+
else delete value.max;
|
|
357
|
+
}"
|
|
358
|
+
/>
|
|
359
|
+
</Field>
|
|
360
|
+
</div>
|
|
361
|
+
<div class="grid grid-cols-2 gap-x-6 gap-y-4">
|
|
362
|
+
<Field orientation="vertical">
|
|
363
|
+
<FieldLabel class="text-xs text-zinc-500">
|
|
364
|
+
<template
|
|
365
|
+
v-if="fieldDescription('hidden')"
|
|
366
|
+
#tooltip
|
|
367
|
+
>
|
|
368
|
+
<Markdown
|
|
369
|
+
:source="fieldDescription('hidden')"
|
|
370
|
+
block
|
|
371
|
+
class="prose prose-sm prose-zinc"
|
|
372
|
+
/>
|
|
373
|
+
</template>
|
|
374
|
+
{{ fieldTitle("hidden") }}
|
|
375
|
+
</FieldLabel>
|
|
376
|
+
<ExpressionEditor
|
|
377
|
+
v-model="hiddenModel"
|
|
378
|
+
placeholder="例:row.archived"
|
|
379
|
+
result-type="bool"
|
|
380
|
+
:extra-vars="ROW_VARS"
|
|
381
|
+
/>
|
|
382
|
+
</Field>
|
|
383
|
+
<Field orientation="vertical">
|
|
384
|
+
<FieldLabel class="text-xs text-zinc-500">
|
|
385
|
+
<template
|
|
386
|
+
v-if="fieldDescription('disabled')"
|
|
387
|
+
#tooltip
|
|
388
|
+
>
|
|
389
|
+
<Markdown
|
|
390
|
+
:source="fieldDescription('disabled')"
|
|
391
|
+
block
|
|
392
|
+
class="prose prose-sm prose-zinc"
|
|
393
|
+
/>
|
|
394
|
+
</template>
|
|
395
|
+
{{ fieldTitle("disabled") }}
|
|
396
|
+
</FieldLabel>
|
|
397
|
+
<ExpressionEditor
|
|
398
|
+
v-model="disabledModel"
|
|
399
|
+
placeholder="例:row.locked"
|
|
400
|
+
result-type="bool"
|
|
401
|
+
:extra-vars="ROW_VARS"
|
|
402
|
+
/>
|
|
403
|
+
</Field>
|
|
404
|
+
<Field orientation="vertical">
|
|
405
|
+
<FieldLabel class="text-xs text-zinc-500">
|
|
406
|
+
<template
|
|
407
|
+
v-if="fieldDescription('readonly')"
|
|
408
|
+
#tooltip
|
|
409
|
+
>
|
|
410
|
+
<Markdown
|
|
411
|
+
:source="fieldDescription('readonly')"
|
|
412
|
+
block
|
|
413
|
+
class="prose prose-sm prose-zinc"
|
|
414
|
+
/>
|
|
415
|
+
</template>
|
|
416
|
+
{{ fieldTitle("readonly") }}
|
|
417
|
+
</FieldLabel>
|
|
418
|
+
<ExpressionEditor
|
|
419
|
+
v-model="readonlyModel"
|
|
420
|
+
placeholder="例:row.id != null"
|
|
421
|
+
result-type="bool"
|
|
422
|
+
:extra-vars="ROW_VARS"
|
|
423
|
+
/>
|
|
424
|
+
</Field>
|
|
425
|
+
<Field
|
|
426
|
+
orientation="vertical"
|
|
427
|
+
class="col-span-2"
|
|
428
|
+
>
|
|
429
|
+
<FieldLabel class="text-xs text-zinc-500">
|
|
430
|
+
<template
|
|
431
|
+
v-if="fieldDescription('derived')"
|
|
432
|
+
#tooltip
|
|
433
|
+
>
|
|
434
|
+
<Markdown
|
|
435
|
+
:source="fieldDescription('derived')"
|
|
436
|
+
block
|
|
437
|
+
class="prose prose-sm prose-zinc"
|
|
438
|
+
/>
|
|
439
|
+
</template>
|
|
440
|
+
{{ fieldTitle("derived") }}
|
|
441
|
+
</FieldLabel>
|
|
442
|
+
<DerivedValueEditor
|
|
443
|
+
v-model="derivedModel"
|
|
444
|
+
result-type="number"
|
|
445
|
+
placeholder="例:row.unitPrice * row.quantity"
|
|
446
|
+
/>
|
|
447
|
+
</Field>
|
|
448
|
+
</div>
|
|
449
|
+
<Separator />
|
|
450
|
+
<div class="flex flex-wrap gap-x-8 gap-y-3">
|
|
451
|
+
<Field
|
|
452
|
+
orientation="horizontal"
|
|
453
|
+
class="w-auto gap-2"
|
|
454
|
+
>
|
|
455
|
+
<Switch
|
|
456
|
+
:model-value="value.enableSorting ?? false"
|
|
457
|
+
@update:model-value="(v) => value.enableSorting = v"
|
|
458
|
+
/>
|
|
459
|
+
<FieldLabel class="text-sm text-zinc-600">
|
|
460
|
+
<template
|
|
461
|
+
v-if="fieldDescription('enableSorting')"
|
|
462
|
+
#tooltip
|
|
463
|
+
>
|
|
464
|
+
<Markdown
|
|
465
|
+
:source="fieldDescription('enableSorting')"
|
|
466
|
+
block
|
|
467
|
+
class="prose prose-sm prose-zinc"
|
|
468
|
+
/>
|
|
469
|
+
</template>
|
|
470
|
+
{{ fieldTitle("enableSorting") }}
|
|
471
|
+
</FieldLabel>
|
|
472
|
+
</Field>
|
|
473
|
+
</div>
|
|
474
|
+
</div>
|
|
475
|
+
</template>
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
type __VLS_ModelProps = {
|
|
2
|
+
modelValue: Record<string, any>;
|
|
3
|
+
};
|
|
4
|
+
declare const __VLS_export: import("vue").DefineComponent<__VLS_ModelProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
5
|
+
"update:modelValue": (value: Record<string, any>) => any;
|
|
6
|
+
}, string, import("vue").PublicProps, Readonly<__VLS_ModelProps> & Readonly<{
|
|
7
|
+
"onUpdate:modelValue"?: ((value: Record<string, any>) => any) | undefined;
|
|
8
|
+
}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
9
|
+
declare const _default: typeof __VLS_export;
|
|
10
|
+
export default _default;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { CellContext } from '@tanstack/vue-table';
|
|
2
|
+
import type { Value } from './schema.js';
|
|
3
|
+
type __VLS_Props = {
|
|
4
|
+
column: Value;
|
|
5
|
+
ctx: CellContext<unknown, unknown>;
|
|
6
|
+
};
|
|
7
|
+
declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
8
|
+
declare const _default: typeof __VLS_export;
|
|
9
|
+
export default _default;
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
<script setup>
|
|
2
|
+
import { Icon } from "@iconify/vue";
|
|
3
|
+
import { Effect } from "effect";
|
|
4
|
+
import { computed, nextTick } from "vue";
|
|
5
|
+
import { useI18n } from "vue-i18n";
|
|
6
|
+
import { cel as _rawCel } from "../../../../../utils/cel";
|
|
7
|
+
import { celBindings, injectCELContext } from "../../../../../utils/cel-context";
|
|
8
|
+
import { getLocalizedText } from "../../../../../share/locale";
|
|
9
|
+
import { InputGroup, InputGroupAddon, InputGroupButton, InputGroupNumberField } from "../../../../ui/input-group";
|
|
10
|
+
import { useFieldValue } from "../../../../form/utils/field-value";
|
|
11
|
+
defineOptions({ name: "ShwfedTableNumberInputRendererRuntime" });
|
|
12
|
+
const props = defineProps({
|
|
13
|
+
column: { type: null, required: true },
|
|
14
|
+
ctx: { type: Object, required: true }
|
|
15
|
+
});
|
|
16
|
+
const { locale } = useI18n();
|
|
17
|
+
const inherited = injectCELContext();
|
|
18
|
+
const $cel = (expression, context) => _rawCel(expression, { ...celBindings(inherited), ...context });
|
|
19
|
+
const placeholderText = computed(
|
|
20
|
+
() => props.column.placeholder ? getLocalizedText(props.column.placeholder, locale.value) : void 0
|
|
21
|
+
);
|
|
22
|
+
function evalBool(expression, label) {
|
|
23
|
+
if (!expression) return false;
|
|
24
|
+
try {
|
|
25
|
+
return Effect.runSync($cel(expression)) === true;
|
|
26
|
+
} catch (e) {
|
|
27
|
+
console.error(`[shwfed-table] number-input ${label} failed`, e);
|
|
28
|
+
return false;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
function evalNumber(expression, label) {
|
|
32
|
+
if (!expression) return void 0;
|
|
33
|
+
try {
|
|
34
|
+
const result = Effect.runSync($cel(expression));
|
|
35
|
+
return typeof result === "number" && Number.isFinite(result) ? result : void 0;
|
|
36
|
+
} catch (e) {
|
|
37
|
+
console.error(`[shwfed-table] number-input ${label} failed`, e);
|
|
38
|
+
return void 0;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
const isHidden = computed(() => evalBool(props.column.hidden, "hidden"));
|
|
42
|
+
const isDisabled = computed(() => evalBool(props.column.disabled, "disabled"));
|
|
43
|
+
const isReadonly = computed(() => evalBool(props.column.readonly, "readonly"));
|
|
44
|
+
const effectiveReadonly = computed(
|
|
45
|
+
() => isReadonly.value || props.column.derived?.mode === "formula"
|
|
46
|
+
);
|
|
47
|
+
const minValue = computed(() => evalNumber(props.column.min, "min"));
|
|
48
|
+
const maxValue = computed(() => evalNumber(props.column.max, "max"));
|
|
49
|
+
const formatOptions = computed(() => ({
|
|
50
|
+
useGrouping: false,
|
|
51
|
+
maximumFractionDigits: 20
|
|
52
|
+
}));
|
|
53
|
+
const { draft, commit } = useFieldValue({
|
|
54
|
+
binding: () => props.column.binding,
|
|
55
|
+
fromState: (raw) => {
|
|
56
|
+
if (typeof raw === "number" && Number.isFinite(raw)) return raw;
|
|
57
|
+
if (typeof raw === "string" && raw.length > 0) {
|
|
58
|
+
const n = Number(raw);
|
|
59
|
+
return Number.isFinite(n) ? n : void 0;
|
|
60
|
+
}
|
|
61
|
+
return void 0;
|
|
62
|
+
},
|
|
63
|
+
toState: (next) => {
|
|
64
|
+
if (typeof next !== "number" || !Number.isFinite(next)) return null;
|
|
65
|
+
return props.column.valueAsString ? String(next) : next;
|
|
66
|
+
}
|
|
67
|
+
});
|
|
68
|
+
function applyRounding(n, precision, mode) {
|
|
69
|
+
const factor = 10 ** precision;
|
|
70
|
+
switch (mode) {
|
|
71
|
+
case "floor":
|
|
72
|
+
return Math.floor(n * factor) / factor;
|
|
73
|
+
case "ceil":
|
|
74
|
+
return Math.ceil(n * factor) / factor;
|
|
75
|
+
default:
|
|
76
|
+
return Math.round(n * factor) / factor;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
const showClear = computed(() => !isDisabled.value && draft.value !== void 0);
|
|
80
|
+
function handleClear() {
|
|
81
|
+
draft.value = void 0;
|
|
82
|
+
commit();
|
|
83
|
+
}
|
|
84
|
+
async function onBlur() {
|
|
85
|
+
await nextTick();
|
|
86
|
+
const precision = props.column.precision;
|
|
87
|
+
if (precision !== void 0) {
|
|
88
|
+
const current = draft.value;
|
|
89
|
+
if (current !== void 0) {
|
|
90
|
+
const rounded = applyRounding(current, precision, props.column.roundingMode ?? "round");
|
|
91
|
+
if (rounded !== current) draft.value = rounded;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
commit();
|
|
95
|
+
}
|
|
96
|
+
</script>
|
|
97
|
+
|
|
98
|
+
<template>
|
|
99
|
+
<!--
|
|
100
|
+
Row budget matches the text-input cell: 2px outer inset around an `h-7`
|
|
101
|
+
(28px) input — 32px total. Every branch (hidden / readonly / editable)
|
|
102
|
+
is sized identically so rows do not jump when a CEL condition flips.
|
|
103
|
+
Both `text-[0.75rem]` breakpoints are explicit so `Input`'s default
|
|
104
|
+
`md:text-sm` cannot beat the override at md+.
|
|
105
|
+
-->
|
|
106
|
+
<div class="p-[0.125rem] w-full">
|
|
107
|
+
<span
|
|
108
|
+
v-if="isHidden"
|
|
109
|
+
class="block h-7 w-full"
|
|
110
|
+
/>
|
|
111
|
+
<span
|
|
112
|
+
v-else-if="effectiveReadonly"
|
|
113
|
+
class="flex items-center h-7 w-full px-2 text-[0.75rem] text-zinc-700 truncate"
|
|
114
|
+
>
|
|
115
|
+
{{ draft ?? "\u2014" }}
|
|
116
|
+
</span>
|
|
117
|
+
<InputGroup
|
|
118
|
+
v-else
|
|
119
|
+
class="group/number-input h-7 rounded border-zinc-200/30 hover:border-zinc-200 focus-within:border-zinc-200 transition-colors ease-out duration-180"
|
|
120
|
+
:data-disabled="isDisabled ? 'true' : void 0"
|
|
121
|
+
>
|
|
122
|
+
<InputGroupNumberField
|
|
123
|
+
:model-value="draft"
|
|
124
|
+
:step="column.step"
|
|
125
|
+
:step-snapping="column.step !== void 0"
|
|
126
|
+
:min="minValue"
|
|
127
|
+
:max="maxValue"
|
|
128
|
+
:format-options="formatOptions"
|
|
129
|
+
:disabled="isDisabled"
|
|
130
|
+
:placeholder="placeholderText"
|
|
131
|
+
input-class="h-7 text-[0.75rem] md:text-[0.75rem] px-2 text-left"
|
|
132
|
+
@update:model-value="(v) => draft = v"
|
|
133
|
+
@blur="onBlur"
|
|
134
|
+
/>
|
|
135
|
+
<InputGroupAddon
|
|
136
|
+
v-if="showClear"
|
|
137
|
+
align="inline-end"
|
|
138
|
+
class="[@media(hover:hover)]:opacity-0 transition-opacity group-hover/number-input:opacity-100 focus-within:opacity-100"
|
|
139
|
+
>
|
|
140
|
+
<InputGroupButton
|
|
141
|
+
size="icon-xs"
|
|
142
|
+
data-slot="number-input-clear"
|
|
143
|
+
class="size-4 text-zinc-500 hover:text-zinc-700"
|
|
144
|
+
tabindex="-1"
|
|
145
|
+
@mousedown.prevent
|
|
146
|
+
@click.stop="handleClear"
|
|
147
|
+
>
|
|
148
|
+
<Icon
|
|
149
|
+
icon="fluent:dismiss-20-regular"
|
|
150
|
+
class="size-3"
|
|
151
|
+
/>
|
|
152
|
+
</InputGroupButton>
|
|
153
|
+
</InputGroupAddon>
|
|
154
|
+
</InputGroup>
|
|
155
|
+
</div>
|
|
156
|
+
</template>
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { CellContext } from '@tanstack/vue-table';
|
|
2
|
+
import type { Value } from './schema.js';
|
|
3
|
+
type __VLS_Props = {
|
|
4
|
+
column: Value;
|
|
5
|
+
ctx: CellContext<unknown, unknown>;
|
|
6
|
+
};
|
|
7
|
+
declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
8
|
+
declare const _default: typeof __VLS_export;
|
|
9
|
+
export default _default;
|