@konomi-app/ui 5.2.1 → 5.3.2
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/index.cjs +886 -6
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +118 -2
- package/dist/index.d.ts +118 -2
- package/dist/index.js +886 -6
- package/dist/index.js.map +1 -1
- package/package.json +11 -4
package/dist/index.js
CHANGED
|
@@ -35,14 +35,168 @@ var createInitialState = () => ({
|
|
|
35
35
|
queues: [],
|
|
36
36
|
steps: [],
|
|
37
37
|
timer: null,
|
|
38
|
-
title: ""
|
|
38
|
+
title: "",
|
|
39
|
+
formFields: [],
|
|
40
|
+
formValues: {},
|
|
41
|
+
formErrors: {},
|
|
42
|
+
formTouched: {},
|
|
43
|
+
formLayout: {},
|
|
44
|
+
formValidateOnChange: true,
|
|
45
|
+
formValidateOnBlur: true,
|
|
46
|
+
stepFormSteps: [],
|
|
47
|
+
stepFormCurrentIndex: 0,
|
|
48
|
+
stepFormNextText: "\u6B21\u3078",
|
|
49
|
+
stepFormPrevText: "\u623B\u308B",
|
|
50
|
+
stepFormSubmitText: "OK"
|
|
39
51
|
});
|
|
40
52
|
|
|
53
|
+
// src/zod-utils.ts
|
|
54
|
+
function resolveTypeName(field) {
|
|
55
|
+
const raw = field._def.typeName ?? field._def.type;
|
|
56
|
+
if (!raw) return "";
|
|
57
|
+
const v4Map = {
|
|
58
|
+
string: "ZodString",
|
|
59
|
+
number: "ZodNumber",
|
|
60
|
+
boolean: "ZodBoolean",
|
|
61
|
+
enum: "ZodEnum",
|
|
62
|
+
date: "ZodDate",
|
|
63
|
+
optional: "ZodOptional",
|
|
64
|
+
nullable: "ZodNullable",
|
|
65
|
+
default: "ZodDefault",
|
|
66
|
+
object: "ZodObject",
|
|
67
|
+
pipe: "ZodPipe"
|
|
68
|
+
};
|
|
69
|
+
return v4Map[raw] ?? raw;
|
|
70
|
+
}
|
|
71
|
+
function unwrapType(zodType) {
|
|
72
|
+
let inner = zodType;
|
|
73
|
+
let required = true;
|
|
74
|
+
let defaultValue = void 0;
|
|
75
|
+
let description = zodType.description ?? "";
|
|
76
|
+
while (true) {
|
|
77
|
+
const typeName = resolveTypeName(inner);
|
|
78
|
+
if (typeName === "ZodOptional" || typeName === "ZodNullable") {
|
|
79
|
+
required = false;
|
|
80
|
+
inner = inner._def.innerType;
|
|
81
|
+
} else if (typeName === "ZodDefault") {
|
|
82
|
+
const raw = inner._def.defaultValue;
|
|
83
|
+
defaultValue = typeof raw === "function" ? raw() : raw;
|
|
84
|
+
inner = inner._def.innerType;
|
|
85
|
+
} else if (typeName === "ZodEffects") {
|
|
86
|
+
inner = inner._def.schema;
|
|
87
|
+
} else {
|
|
88
|
+
break;
|
|
89
|
+
}
|
|
90
|
+
if (!description && inner.description) {
|
|
91
|
+
description = inner.description;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
return { inner, required, defaultValue, description };
|
|
95
|
+
}
|
|
96
|
+
function extractFieldMeta(key, zodType) {
|
|
97
|
+
const { inner, required, defaultValue, description } = unwrapType(zodType);
|
|
98
|
+
const typeName = resolveTypeName(inner);
|
|
99
|
+
let inputType;
|
|
100
|
+
let options = [];
|
|
101
|
+
let min;
|
|
102
|
+
let max;
|
|
103
|
+
let minLength;
|
|
104
|
+
let maxLength;
|
|
105
|
+
switch (typeName) {
|
|
106
|
+
case "ZodString": {
|
|
107
|
+
inputType = "text";
|
|
108
|
+
if (inner.format === "email") inputType = "email";
|
|
109
|
+
else if (inner.format === "url") inputType = "url";
|
|
110
|
+
if (inner.minLength != null) minLength = inner.minLength;
|
|
111
|
+
if (inner.maxLength != null) maxLength = inner.maxLength;
|
|
112
|
+
const checks = inner._def.checks ?? [];
|
|
113
|
+
for (const check of checks) {
|
|
114
|
+
const kind = check.kind ?? check.def?.check;
|
|
115
|
+
const fmt = check.format ?? check.def?.format;
|
|
116
|
+
if (!fmt && (kind === "email" || fmt === "email")) inputType = "email";
|
|
117
|
+
else if (!fmt && (kind === "url" || fmt === "url")) inputType = "url";
|
|
118
|
+
else if (fmt === "email" && inputType === "text") inputType = "email";
|
|
119
|
+
else if (fmt === "url" && inputType === "text") inputType = "url";
|
|
120
|
+
if (kind === "min" && check.value != null && minLength == null) minLength = check.value;
|
|
121
|
+
if (kind === "max" && check.value != null && maxLength == null) maxLength = check.value;
|
|
122
|
+
}
|
|
123
|
+
break;
|
|
124
|
+
}
|
|
125
|
+
case "ZodNumber": {
|
|
126
|
+
inputType = "number";
|
|
127
|
+
if (inner.minValue != null) min = inner.minValue;
|
|
128
|
+
if (inner.maxValue != null) max = inner.maxValue;
|
|
129
|
+
if (min == null || max == null) {
|
|
130
|
+
const checks = inner._def.checks ?? [];
|
|
131
|
+
for (const check of checks) {
|
|
132
|
+
if (check.kind === "min" && check.value != null && min == null) min = check.value;
|
|
133
|
+
if (check.kind === "max" && check.value != null && max == null) max = check.value;
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
break;
|
|
137
|
+
}
|
|
138
|
+
case "ZodBoolean":
|
|
139
|
+
inputType = "checkbox";
|
|
140
|
+
break;
|
|
141
|
+
case "ZodEnum": {
|
|
142
|
+
inputType = "select";
|
|
143
|
+
if (inner.options?.length) {
|
|
144
|
+
options = [...inner.options];
|
|
145
|
+
} else if (inner._def.entries) {
|
|
146
|
+
options = Object.values(inner._def.entries);
|
|
147
|
+
} else if (inner._def.values?.length) {
|
|
148
|
+
options = [...inner._def.values];
|
|
149
|
+
}
|
|
150
|
+
break;
|
|
151
|
+
}
|
|
152
|
+
case "ZodNativeEnum": {
|
|
153
|
+
inputType = "select";
|
|
154
|
+
const enumValues = inner._def.values;
|
|
155
|
+
if (enumValues) {
|
|
156
|
+
options = Object.values(enumValues).filter((v) => typeof v === "string");
|
|
157
|
+
}
|
|
158
|
+
break;
|
|
159
|
+
}
|
|
160
|
+
case "ZodDate":
|
|
161
|
+
inputType = "date";
|
|
162
|
+
break;
|
|
163
|
+
default:
|
|
164
|
+
return null;
|
|
165
|
+
}
|
|
166
|
+
const label = description || key;
|
|
167
|
+
return {
|
|
168
|
+
key,
|
|
169
|
+
inputType,
|
|
170
|
+
label,
|
|
171
|
+
description: description && description !== label ? description : "",
|
|
172
|
+
required,
|
|
173
|
+
options,
|
|
174
|
+
placeholder: "",
|
|
175
|
+
min,
|
|
176
|
+
max,
|
|
177
|
+
minLength,
|
|
178
|
+
maxLength,
|
|
179
|
+
defaultValue
|
|
180
|
+
};
|
|
181
|
+
}
|
|
182
|
+
function extractFormFields(schema) {
|
|
183
|
+
const shapeDef = schema._def.shape;
|
|
184
|
+
if (!shapeDef) return [];
|
|
185
|
+
const shape = typeof shapeDef === "function" ? shapeDef() : shapeDef;
|
|
186
|
+
if (!shape) return [];
|
|
187
|
+
const fields = [];
|
|
188
|
+
for (const [key, zodType] of Object.entries(shape)) {
|
|
189
|
+
const meta = extractFieldMeta(key, zodType);
|
|
190
|
+
if (meta) fields.push(meta);
|
|
191
|
+
}
|
|
192
|
+
return fields;
|
|
193
|
+
}
|
|
194
|
+
|
|
41
195
|
// src/controller.ts
|
|
42
196
|
function normalizeItemInput(input) {
|
|
43
197
|
return typeof input === "string" ? { key: input, label: input } : input;
|
|
44
198
|
}
|
|
45
|
-
var _state, _listeners, _resolver, _timerId, _DialogController_instances, emit_fn, update_fn, createPromise_fn, resolve_fn, clearTimer_fn, updateItemStatus_fn;
|
|
199
|
+
var _state, _listeners, _resolver, _timerId, _formSchema, _formResult, _stepFormSchemas, _stepFormResults, _DialogController_instances, emit_fn, update_fn, validateFormField_fn, updateCurrentStep_fn, validateStepField_fn, createPromise_fn, resolve_fn, clearTimer_fn, updateItemStatus_fn;
|
|
46
200
|
var DialogController = class {
|
|
47
201
|
constructor() {
|
|
48
202
|
__privateAdd(this, _DialogController_instances);
|
|
@@ -50,6 +204,10 @@ var DialogController = class {
|
|
|
50
204
|
__privateAdd(this, _listeners, /* @__PURE__ */ new Set());
|
|
51
205
|
__privateAdd(this, _resolver, null);
|
|
52
206
|
__privateAdd(this, _timerId, null);
|
|
207
|
+
__privateAdd(this, _formSchema, null);
|
|
208
|
+
__privateAdd(this, _formResult, null);
|
|
209
|
+
__privateAdd(this, _stepFormSchemas, []);
|
|
210
|
+
__privateAdd(this, _stepFormResults, {});
|
|
53
211
|
__privateSet(this, _state, createInitialState());
|
|
54
212
|
}
|
|
55
213
|
// ─── Observable ──────────────────────────────────────────
|
|
@@ -195,9 +353,202 @@ var DialogController = class {
|
|
|
195
353
|
clearSteps() {
|
|
196
354
|
__privateMethod(this, _DialogController_instances, update_fn).call(this, { steps: [] });
|
|
197
355
|
}
|
|
356
|
+
// ─── Form ─────────────────────────────────────────────────
|
|
357
|
+
form(schema, options) {
|
|
358
|
+
__privateMethod(this, _DialogController_instances, clearTimer_fn).call(this);
|
|
359
|
+
__privateSet(this, _formSchema, schema);
|
|
360
|
+
__privateSet(this, _formResult, null);
|
|
361
|
+
const fields = extractFormFields(schema);
|
|
362
|
+
const defaultValues = {};
|
|
363
|
+
for (const field of fields) {
|
|
364
|
+
if (field.defaultValue !== void 0) {
|
|
365
|
+
defaultValues[field.key] = field.defaultValue;
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
if (options?.defaultValues) {
|
|
369
|
+
Object.assign(defaultValues, options.defaultValues);
|
|
370
|
+
}
|
|
371
|
+
__privateMethod(this, _DialogController_instances, update_fn).call(this, {
|
|
372
|
+
open: true,
|
|
373
|
+
dialogType: "form",
|
|
374
|
+
title: options?.title ?? "",
|
|
375
|
+
label: "",
|
|
376
|
+
description: options?.description ?? "",
|
|
377
|
+
icon: null,
|
|
378
|
+
showConfirmButton: true,
|
|
379
|
+
showCancelButton: true,
|
|
380
|
+
confirmButtonText: options?.confirmButtonText ?? "OK",
|
|
381
|
+
cancelButtonText: options?.cancelButtonText ?? "\u30AD\u30E3\u30F3\u30BB\u30EB",
|
|
382
|
+
allowOutsideClick: options?.allowOutsideClick ?? false,
|
|
383
|
+
allowEscapeKey: options?.allowEscapeKey ?? true,
|
|
384
|
+
progress: null,
|
|
385
|
+
timer: null,
|
|
386
|
+
formFields: fields,
|
|
387
|
+
formValues: defaultValues,
|
|
388
|
+
formErrors: {},
|
|
389
|
+
formTouched: {},
|
|
390
|
+
formLayout: options?.layout ?? {},
|
|
391
|
+
formValidateOnChange: options?.validateOnChange ?? true,
|
|
392
|
+
formValidateOnBlur: options?.validateOnBlur ?? true
|
|
393
|
+
});
|
|
394
|
+
return __privateMethod(this, _DialogController_instances, createPromise_fn).call(this, null).then((r) => {
|
|
395
|
+
const data = __privateGet(this, _formResult);
|
|
396
|
+
__privateSet(this, _formSchema, null);
|
|
397
|
+
__privateSet(this, _formResult, null);
|
|
398
|
+
return r.isConfirmed ? data : null;
|
|
399
|
+
});
|
|
400
|
+
}
|
|
401
|
+
updateFormField(key, value) {
|
|
402
|
+
const formValues = { ...__privateGet(this, _state).formValues, [key]: value };
|
|
403
|
+
const formTouched = { ...__privateGet(this, _state).formTouched, [key]: true };
|
|
404
|
+
let formErrors = { ...__privateGet(this, _state).formErrors };
|
|
405
|
+
if (__privateGet(this, _formSchema) && __privateGet(this, _state).formValidateOnChange) {
|
|
406
|
+
formErrors = __privateMethod(this, _DialogController_instances, validateFormField_fn).call(this, key, formValues, formErrors);
|
|
407
|
+
}
|
|
408
|
+
__privateMethod(this, _DialogController_instances, update_fn).call(this, { formValues, formTouched, formErrors });
|
|
409
|
+
}
|
|
410
|
+
touchFormField(key) {
|
|
411
|
+
const formTouched = { ...__privateGet(this, _state).formTouched, [key]: true };
|
|
412
|
+
let formErrors = { ...__privateGet(this, _state).formErrors };
|
|
413
|
+
if (__privateGet(this, _formSchema) && __privateGet(this, _state).formValidateOnBlur) {
|
|
414
|
+
formErrors = __privateMethod(this, _DialogController_instances, validateFormField_fn).call(this, key, __privateGet(this, _state).formValues, formErrors);
|
|
415
|
+
}
|
|
416
|
+
__privateMethod(this, _DialogController_instances, update_fn).call(this, { formTouched, formErrors });
|
|
417
|
+
}
|
|
418
|
+
// ─── Step Form ───────────────────────────────────────────
|
|
419
|
+
showStepForm(steps, options) {
|
|
420
|
+
__privateMethod(this, _DialogController_instances, clearTimer_fn).call(this);
|
|
421
|
+
__privateSet(this, _stepFormSchemas, steps.map((s) => s.schema ?? null));
|
|
422
|
+
__privateSet(this, _stepFormResults, {});
|
|
423
|
+
const stepFormSteps = steps.map((s) => {
|
|
424
|
+
const fields = s.schema ? extractFormFields(s.schema) : [];
|
|
425
|
+
const values = {};
|
|
426
|
+
for (const f of fields) {
|
|
427
|
+
if (f.defaultValue !== void 0) values[f.key] = f.defaultValue;
|
|
428
|
+
}
|
|
429
|
+
if (s.defaultValues) Object.assign(values, s.defaultValues);
|
|
430
|
+
return {
|
|
431
|
+
key: s.key,
|
|
432
|
+
label: s.label,
|
|
433
|
+
description: s.description ?? "",
|
|
434
|
+
fields,
|
|
435
|
+
values,
|
|
436
|
+
errors: {},
|
|
437
|
+
touched: {},
|
|
438
|
+
layout: s.layout ?? {}
|
|
439
|
+
};
|
|
440
|
+
});
|
|
441
|
+
__privateMethod(this, _DialogController_instances, update_fn).call(this, {
|
|
442
|
+
open: true,
|
|
443
|
+
dialogType: "step-form",
|
|
444
|
+
title: options?.title ?? "",
|
|
445
|
+
label: "",
|
|
446
|
+
description: "",
|
|
447
|
+
icon: null,
|
|
448
|
+
showConfirmButton: false,
|
|
449
|
+
showCancelButton: false,
|
|
450
|
+
allowOutsideClick: options?.allowOutsideClick ?? false,
|
|
451
|
+
allowEscapeKey: options?.allowEscapeKey ?? true,
|
|
452
|
+
progress: null,
|
|
453
|
+
timer: null,
|
|
454
|
+
stepFormSteps,
|
|
455
|
+
stepFormCurrentIndex: 0,
|
|
456
|
+
stepFormNextText: options?.nextButtonText ?? "\u6B21\u3078",
|
|
457
|
+
stepFormPrevText: options?.prevButtonText ?? "\u623B\u308B",
|
|
458
|
+
stepFormSubmitText: options?.submitButtonText ?? "OK",
|
|
459
|
+
cancelButtonText: options?.cancelButtonText ?? "\u30AD\u30E3\u30F3\u30BB\u30EB"
|
|
460
|
+
});
|
|
461
|
+
return __privateMethod(this, _DialogController_instances, createPromise_fn).call(this, null).then((r) => {
|
|
462
|
+
const data = __privateGet(this, _stepFormResults);
|
|
463
|
+
__privateSet(this, _stepFormSchemas, []);
|
|
464
|
+
__privateSet(this, _stepFormResults, {});
|
|
465
|
+
return r.isConfirmed ? data : null;
|
|
466
|
+
});
|
|
467
|
+
}
|
|
468
|
+
onStepNext() {
|
|
469
|
+
const s = __privateGet(this, _state);
|
|
470
|
+
const idx = s.stepFormCurrentIndex;
|
|
471
|
+
const step = s.stepFormSteps[idx];
|
|
472
|
+
if (!step) return;
|
|
473
|
+
const schema = __privateGet(this, _stepFormSchemas)[idx];
|
|
474
|
+
if (schema) {
|
|
475
|
+
const result = schema.safeParse(step.values);
|
|
476
|
+
if (!result.success) {
|
|
477
|
+
const errors = {};
|
|
478
|
+
for (const issue of result.error.issues) {
|
|
479
|
+
const key = issue.path[0]?.toString();
|
|
480
|
+
if (key && !errors[key]) errors[key] = issue.message;
|
|
481
|
+
}
|
|
482
|
+
const touched = {};
|
|
483
|
+
for (const f of step.fields) touched[f.key] = true;
|
|
484
|
+
__privateMethod(this, _DialogController_instances, updateCurrentStep_fn).call(this, { errors, touched });
|
|
485
|
+
return;
|
|
486
|
+
}
|
|
487
|
+
__privateGet(this, _stepFormResults)[step.key] = result.data;
|
|
488
|
+
}
|
|
489
|
+
const isLast = idx === s.stepFormSteps.length - 1;
|
|
490
|
+
if (isLast) {
|
|
491
|
+
const r = { isConfirmed: true, isCanceled: false, isDismissed: false };
|
|
492
|
+
__privateMethod(this, _DialogController_instances, update_fn).call(this, { ...createInitialState(), open: false });
|
|
493
|
+
__privateMethod(this, _DialogController_instances, resolve_fn).call(this, r);
|
|
494
|
+
return;
|
|
495
|
+
}
|
|
496
|
+
__privateMethod(this, _DialogController_instances, update_fn).call(this, { stepFormCurrentIndex: idx + 1 });
|
|
497
|
+
}
|
|
498
|
+
onStepPrev() {
|
|
499
|
+
const idx = __privateGet(this, _state).stepFormCurrentIndex;
|
|
500
|
+
if (idx <= 0) return;
|
|
501
|
+
__privateMethod(this, _DialogController_instances, update_fn).call(this, { stepFormCurrentIndex: idx - 1 });
|
|
502
|
+
}
|
|
503
|
+
updateStepFormField(fieldKey, value) {
|
|
504
|
+
const s = __privateGet(this, _state);
|
|
505
|
+
const idx = s.stepFormCurrentIndex;
|
|
506
|
+
const step = s.stepFormSteps[idx];
|
|
507
|
+
if (!step) return;
|
|
508
|
+
const values = { ...step.values, [fieldKey]: value };
|
|
509
|
+
const touched = { ...step.touched, [fieldKey]: true };
|
|
510
|
+
let errors = { ...step.errors };
|
|
511
|
+
const schema = __privateGet(this, _stepFormSchemas)[idx];
|
|
512
|
+
if (schema && s.formValidateOnChange) {
|
|
513
|
+
errors = __privateMethod(this, _DialogController_instances, validateStepField_fn).call(this, schema, fieldKey, values, errors);
|
|
514
|
+
}
|
|
515
|
+
__privateMethod(this, _DialogController_instances, updateCurrentStep_fn).call(this, { values, touched, errors });
|
|
516
|
+
}
|
|
517
|
+
touchStepFormField(fieldKey) {
|
|
518
|
+
const s = __privateGet(this, _state);
|
|
519
|
+
const idx = s.stepFormCurrentIndex;
|
|
520
|
+
const step = s.stepFormSteps[idx];
|
|
521
|
+
if (!step) return;
|
|
522
|
+
const touched = { ...step.touched, [fieldKey]: true };
|
|
523
|
+
let errors = { ...step.errors };
|
|
524
|
+
const schema = __privateGet(this, _stepFormSchemas)[idx];
|
|
525
|
+
if (schema && s.formValidateOnBlur) {
|
|
526
|
+
errors = __privateMethod(this, _DialogController_instances, validateStepField_fn).call(this, schema, fieldKey, step.values, errors);
|
|
527
|
+
}
|
|
528
|
+
__privateMethod(this, _DialogController_instances, updateCurrentStep_fn).call(this, { touched, errors });
|
|
529
|
+
}
|
|
198
530
|
// ─── Button actions (called from the component) ──────────
|
|
199
531
|
onConfirm() {
|
|
200
532
|
__privateMethod(this, _DialogController_instances, clearTimer_fn).call(this);
|
|
533
|
+
if (__privateGet(this, _state).dialogType === "form" && __privateGet(this, _formSchema)) {
|
|
534
|
+
const result = __privateGet(this, _formSchema).safeParse(__privateGet(this, _state).formValues);
|
|
535
|
+
if (!result.success) {
|
|
536
|
+
const formErrors = {};
|
|
537
|
+
for (const issue of result.error.issues) {
|
|
538
|
+
const key = issue.path[0]?.toString();
|
|
539
|
+
if (key && !formErrors[key]) {
|
|
540
|
+
formErrors[key] = issue.message;
|
|
541
|
+
}
|
|
542
|
+
}
|
|
543
|
+
const formTouched = {};
|
|
544
|
+
for (const field of __privateGet(this, _state).formFields) {
|
|
545
|
+
formTouched[field.key] = true;
|
|
546
|
+
}
|
|
547
|
+
__privateMethod(this, _DialogController_instances, update_fn).call(this, { formErrors, formTouched });
|
|
548
|
+
return;
|
|
549
|
+
}
|
|
550
|
+
__privateSet(this, _formResult, result.data);
|
|
551
|
+
}
|
|
201
552
|
const r = { isConfirmed: true, isCanceled: false, isDismissed: false };
|
|
202
553
|
__privateMethod(this, _DialogController_instances, update_fn).call(this, { ...createInitialState(), open: false });
|
|
203
554
|
__privateMethod(this, _DialogController_instances, resolve_fn).call(this, r);
|
|
@@ -221,6 +572,10 @@ _state = new WeakMap();
|
|
|
221
572
|
_listeners = new WeakMap();
|
|
222
573
|
_resolver = new WeakMap();
|
|
223
574
|
_timerId = new WeakMap();
|
|
575
|
+
_formSchema = new WeakMap();
|
|
576
|
+
_formResult = new WeakMap();
|
|
577
|
+
_stepFormSchemas = new WeakMap();
|
|
578
|
+
_stepFormResults = new WeakMap();
|
|
224
579
|
_DialogController_instances = new WeakSet();
|
|
225
580
|
emit_fn = function() {
|
|
226
581
|
const snapshot = { ...__privateGet(this, _state) };
|
|
@@ -230,6 +585,47 @@ update_fn = function(patch) {
|
|
|
230
585
|
Object.assign(__privateGet(this, _state), patch);
|
|
231
586
|
__privateMethod(this, _DialogController_instances, emit_fn).call(this);
|
|
232
587
|
};
|
|
588
|
+
validateFormField_fn = function(key, values, errors) {
|
|
589
|
+
const result = __privateGet(this, _formSchema).safeParse(values);
|
|
590
|
+
const updated = { ...errors };
|
|
591
|
+
if (result.success) {
|
|
592
|
+
delete updated[key];
|
|
593
|
+
} else {
|
|
594
|
+
const fieldIssue = result.error.issues.find(
|
|
595
|
+
(issue) => issue.path[0]?.toString() === key
|
|
596
|
+
);
|
|
597
|
+
if (fieldIssue) {
|
|
598
|
+
updated[key] = fieldIssue.message;
|
|
599
|
+
} else {
|
|
600
|
+
delete updated[key];
|
|
601
|
+
}
|
|
602
|
+
}
|
|
603
|
+
return updated;
|
|
604
|
+
};
|
|
605
|
+
updateCurrentStep_fn = function(patch) {
|
|
606
|
+
const idx = __privateGet(this, _state).stepFormCurrentIndex;
|
|
607
|
+
const stepFormSteps = __privateGet(this, _state).stepFormSteps.map(
|
|
608
|
+
(st, i) => i === idx ? { ...st, ...patch } : st
|
|
609
|
+
);
|
|
610
|
+
__privateMethod(this, _DialogController_instances, update_fn).call(this, { stepFormSteps });
|
|
611
|
+
};
|
|
612
|
+
validateStepField_fn = function(schema, fieldKey, values, errors) {
|
|
613
|
+
const result = schema.safeParse(values);
|
|
614
|
+
const updated = { ...errors };
|
|
615
|
+
if (result.success) {
|
|
616
|
+
delete updated[fieldKey];
|
|
617
|
+
} else {
|
|
618
|
+
const issue = result.error.issues.find(
|
|
619
|
+
(iss) => iss.path[0]?.toString() === fieldKey
|
|
620
|
+
);
|
|
621
|
+
if (issue) {
|
|
622
|
+
updated[fieldKey] = issue.message;
|
|
623
|
+
} else {
|
|
624
|
+
delete updated[fieldKey];
|
|
625
|
+
}
|
|
626
|
+
}
|
|
627
|
+
return updated;
|
|
628
|
+
};
|
|
233
629
|
// ─── Internal ────────────────────────────────────────────
|
|
234
630
|
createPromise_fn = function(timer) {
|
|
235
631
|
return new Promise((resolve) => {
|
|
@@ -318,6 +714,24 @@ var overlayStyles = css`
|
|
|
318
714
|
--dialog-spinner-track: rgb(59 130 246 / 0.2);
|
|
319
715
|
--dialog-spinner-arc: var(--dialog-primary);
|
|
320
716
|
|
|
717
|
+
/* Form */
|
|
718
|
+
--dialog-form-width: 500px;
|
|
719
|
+
--dialog-form-max-height: 60vh;
|
|
720
|
+
--dialog-form-gap: 16px;
|
|
721
|
+
--dialog-form-columns: 1;
|
|
722
|
+
--dialog-form-label-color: #374151;
|
|
723
|
+
--dialog-form-label-size: 13px;
|
|
724
|
+
--dialog-form-label-weight: 500;
|
|
725
|
+
--dialog-form-input-bg: #fff;
|
|
726
|
+
--dialog-form-input-border: #d1d5db;
|
|
727
|
+
--dialog-form-input-border-focus: var(--dialog-primary);
|
|
728
|
+
--dialog-form-input-radius: 6px;
|
|
729
|
+
--dialog-form-input-padding: 8px 12px;
|
|
730
|
+
--dialog-form-input-font-size: 14px;
|
|
731
|
+
--dialog-form-error-color: var(--dialog-error);
|
|
732
|
+
--dialog-form-hint-color: #9ca3af;
|
|
733
|
+
--dialog-form-required-color: var(--dialog-error);
|
|
734
|
+
|
|
321
735
|
display: contents;
|
|
322
736
|
font-family: var(--dialog-font-family);
|
|
323
737
|
color: var(--dialog-text-color);
|
|
@@ -469,8 +883,6 @@ var overlayStyles = css`
|
|
|
469
883
|
}
|
|
470
884
|
}
|
|
471
885
|
|
|
472
|
-
/* spin と spinner-enter は同じ transform を書き換えるため衝突する。
|
|
473
|
-
ラッパーでスケール/フェードを担い、.spinner は回転専用にする。 */
|
|
474
886
|
.spinner-wrap {
|
|
475
887
|
font-size: var(--dialog-spinner-size);
|
|
476
888
|
width: 1em;
|
|
@@ -953,6 +1365,204 @@ var overlayStyles = css`
|
|
|
953
1365
|
background-color: #e5e7eb;
|
|
954
1366
|
transition: background-color 400ms ease;
|
|
955
1367
|
}
|
|
1368
|
+
|
|
1369
|
+
/* ─── Form ─── */
|
|
1370
|
+
|
|
1371
|
+
@media (min-width: 640px) {
|
|
1372
|
+
.card[data-type='form'] {
|
|
1373
|
+
width: var(--dialog-form-width);
|
|
1374
|
+
}
|
|
1375
|
+
}
|
|
1376
|
+
|
|
1377
|
+
.form-scroll-container {
|
|
1378
|
+
max-height: var(--dialog-form-max-height);
|
|
1379
|
+
overflow-y: auto;
|
|
1380
|
+
width: 100%;
|
|
1381
|
+
padding: 4px 0;
|
|
1382
|
+
}
|
|
1383
|
+
|
|
1384
|
+
.form-grid {
|
|
1385
|
+
display: grid;
|
|
1386
|
+
grid-template-columns: repeat(var(--dialog-form-columns, 1), 1fr);
|
|
1387
|
+
gap: var(--dialog-form-gap);
|
|
1388
|
+
width: 100%;
|
|
1389
|
+
}
|
|
1390
|
+
|
|
1391
|
+
@media (max-width: 639px) {
|
|
1392
|
+
.form-grid {
|
|
1393
|
+
grid-template-columns: 1fr !important;
|
|
1394
|
+
}
|
|
1395
|
+
}
|
|
1396
|
+
|
|
1397
|
+
.form-field {
|
|
1398
|
+
display: flex;
|
|
1399
|
+
flex-direction: column;
|
|
1400
|
+
gap: 4px;
|
|
1401
|
+
text-align: left;
|
|
1402
|
+
}
|
|
1403
|
+
|
|
1404
|
+
.form-field[data-type='checkbox'] {
|
|
1405
|
+
grid-column: 1 / -1;
|
|
1406
|
+
}
|
|
1407
|
+
|
|
1408
|
+
.form-label {
|
|
1409
|
+
font-size: var(--dialog-form-label-size);
|
|
1410
|
+
font-weight: var(--dialog-form-label-weight);
|
|
1411
|
+
color: var(--dialog-form-label-color);
|
|
1412
|
+
}
|
|
1413
|
+
|
|
1414
|
+
.form-required {
|
|
1415
|
+
color: var(--dialog-form-required-color);
|
|
1416
|
+
margin-left: 2px;
|
|
1417
|
+
}
|
|
1418
|
+
|
|
1419
|
+
.form-input,
|
|
1420
|
+
.form-select {
|
|
1421
|
+
padding: var(--dialog-form-input-padding);
|
|
1422
|
+
font-size: var(--dialog-form-input-font-size);
|
|
1423
|
+
font-family: inherit;
|
|
1424
|
+
background: var(--dialog-form-input-bg);
|
|
1425
|
+
border: 1px solid var(--dialog-form-input-border);
|
|
1426
|
+
border-radius: var(--dialog-form-input-radius);
|
|
1427
|
+
color: var(--dialog-text-color);
|
|
1428
|
+
outline: none;
|
|
1429
|
+
transition:
|
|
1430
|
+
border-color 150ms ease,
|
|
1431
|
+
box-shadow 150ms ease;
|
|
1432
|
+
width: 100%;
|
|
1433
|
+
box-sizing: border-box;
|
|
1434
|
+
}
|
|
1435
|
+
|
|
1436
|
+
.form-input:focus,
|
|
1437
|
+
.form-select:focus {
|
|
1438
|
+
border-color: var(--dialog-form-input-border-focus);
|
|
1439
|
+
box-shadow: 0 0 0 3px rgb(59 130 246 / 0.1);
|
|
1440
|
+
}
|
|
1441
|
+
|
|
1442
|
+
.form-field[data-error] .form-input,
|
|
1443
|
+
.form-field[data-error] .form-select {
|
|
1444
|
+
border-color: var(--dialog-form-error-color);
|
|
1445
|
+
}
|
|
1446
|
+
|
|
1447
|
+
.form-field[data-error] .form-input:focus,
|
|
1448
|
+
.form-field[data-error] .form-select:focus {
|
|
1449
|
+
box-shadow: 0 0 0 3px rgb(239 68 68 / 0.1);
|
|
1450
|
+
}
|
|
1451
|
+
|
|
1452
|
+
.form-error {
|
|
1453
|
+
font-size: 12px;
|
|
1454
|
+
color: var(--dialog-form-error-color);
|
|
1455
|
+
min-height: 1em;
|
|
1456
|
+
}
|
|
1457
|
+
|
|
1458
|
+
.form-hint {
|
|
1459
|
+
font-size: 12px;
|
|
1460
|
+
color: var(--dialog-form-hint-color);
|
|
1461
|
+
}
|
|
1462
|
+
|
|
1463
|
+
.form-checkbox {
|
|
1464
|
+
width: 18px;
|
|
1465
|
+
height: 18px;
|
|
1466
|
+
accent-color: var(--dialog-primary);
|
|
1467
|
+
cursor: pointer;
|
|
1468
|
+
flex-shrink: 0;
|
|
1469
|
+
}
|
|
1470
|
+
|
|
1471
|
+
.form-checkbox-label {
|
|
1472
|
+
display: flex;
|
|
1473
|
+
align-items: center;
|
|
1474
|
+
gap: 8px;
|
|
1475
|
+
cursor: pointer;
|
|
1476
|
+
font-size: var(--dialog-form-input-font-size);
|
|
1477
|
+
color: var(--dialog-form-label-color);
|
|
1478
|
+
}
|
|
1479
|
+
|
|
1480
|
+
.form-checkbox-text {
|
|
1481
|
+
font-size: var(--dialog-form-label-size);
|
|
1482
|
+
font-weight: var(--dialog-form-label-weight);
|
|
1483
|
+
color: var(--dialog-form-label-color);
|
|
1484
|
+
}
|
|
1485
|
+
|
|
1486
|
+
.form-group {
|
|
1487
|
+
border: 1px solid var(--dialog-card-border);
|
|
1488
|
+
border-radius: var(--dialog-form-input-radius);
|
|
1489
|
+
padding: 16px;
|
|
1490
|
+
margin: 0 0 8px;
|
|
1491
|
+
width: 100%;
|
|
1492
|
+
box-sizing: border-box;
|
|
1493
|
+
}
|
|
1494
|
+
|
|
1495
|
+
.form-group-label {
|
|
1496
|
+
font-size: var(--dialog-form-label-size);
|
|
1497
|
+
font-weight: 600;
|
|
1498
|
+
color: var(--dialog-form-label-color);
|
|
1499
|
+
padding: 0 4px;
|
|
1500
|
+
}
|
|
1501
|
+
|
|
1502
|
+
/* ─── Step Form ─── */
|
|
1503
|
+
|
|
1504
|
+
@media (min-width: 640px) {
|
|
1505
|
+
.card[data-type='step-form'] {
|
|
1506
|
+
width: var(--dialog-form-width);
|
|
1507
|
+
}
|
|
1508
|
+
}
|
|
1509
|
+
|
|
1510
|
+
.step-form-counter {
|
|
1511
|
+
font-size: 12px;
|
|
1512
|
+
color: var(--dialog-form-hint-color);
|
|
1513
|
+
text-align: center;
|
|
1514
|
+
margin: 0 0 4px;
|
|
1515
|
+
}
|
|
1516
|
+
|
|
1517
|
+
.actions-step-form {
|
|
1518
|
+
display: flex;
|
|
1519
|
+
flex-direction: row;
|
|
1520
|
+
justify-content: space-between;
|
|
1521
|
+
align-items: center;
|
|
1522
|
+
gap: 8px;
|
|
1523
|
+
margin-top: 20px;
|
|
1524
|
+
width: 100%;
|
|
1525
|
+
}
|
|
1526
|
+
|
|
1527
|
+
.step-form-nav {
|
|
1528
|
+
display: flex;
|
|
1529
|
+
flex-direction: row;
|
|
1530
|
+
gap: 8px;
|
|
1531
|
+
align-items: center;
|
|
1532
|
+
}
|
|
1533
|
+
|
|
1534
|
+
.btn-prev {
|
|
1535
|
+
padding: var(--dialog-btn-padding);
|
|
1536
|
+
font-size: var(--dialog-btn-font-size);
|
|
1537
|
+
font-family: inherit;
|
|
1538
|
+
font-weight: 500;
|
|
1539
|
+
border-radius: var(--dialog-btn-radius);
|
|
1540
|
+
cursor: pointer;
|
|
1541
|
+
border: 1px solid var(--dialog-form-input-border);
|
|
1542
|
+
background: transparent;
|
|
1543
|
+
color: var(--dialog-text-color);
|
|
1544
|
+
transition: background-color 120ms ease, border-color 120ms ease;
|
|
1545
|
+
}
|
|
1546
|
+
|
|
1547
|
+
.btn-prev:hover {
|
|
1548
|
+
background: #f9fafb;
|
|
1549
|
+
border-color: #9ca3af;
|
|
1550
|
+
}
|
|
1551
|
+
|
|
1552
|
+
.btn-prev:active {
|
|
1553
|
+
transform: scale(0.98);
|
|
1554
|
+
}
|
|
1555
|
+
|
|
1556
|
+
@media (max-width: 639px) {
|
|
1557
|
+
.actions-step-form {
|
|
1558
|
+
flex-direction: column-reverse;
|
|
1559
|
+
}
|
|
1560
|
+
|
|
1561
|
+
.step-form-nav {
|
|
1562
|
+
width: 100%;
|
|
1563
|
+
justify-content: flex-end;
|
|
1564
|
+
}
|
|
1565
|
+
}
|
|
956
1566
|
`;
|
|
957
1567
|
|
|
958
1568
|
// src/overlay-dialog.ts
|
|
@@ -976,6 +1586,7 @@ var OverlayDialog = class extends LitElement {
|
|
|
976
1586
|
this._unsubscribe = this.controller.subscribe((s) => {
|
|
977
1587
|
const wasOpen = this._state.open;
|
|
978
1588
|
const prevDialogType = this._state.dialogType;
|
|
1589
|
+
const prevStepIndex = this._state.stepFormCurrentIndex;
|
|
979
1590
|
if (s.open && !wasOpen) {
|
|
980
1591
|
this._isClosing = false;
|
|
981
1592
|
clearTimeout(this._closeTimer);
|
|
@@ -990,6 +1601,8 @@ var OverlayDialog = class extends LitElement {
|
|
|
990
1601
|
}
|
|
991
1602
|
if (s.open && s.dialogType !== prevDialogType) {
|
|
992
1603
|
this._bodyKey++;
|
|
1604
|
+
} else if (s.open && s.dialogType === "step-form" && s.stepFormCurrentIndex !== prevStepIndex) {
|
|
1605
|
+
this._bodyKey++;
|
|
993
1606
|
}
|
|
994
1607
|
this._state = s;
|
|
995
1608
|
this._syncBodyScroll(s.open);
|
|
@@ -1219,6 +1832,187 @@ var OverlayDialog = class extends LitElement {
|
|
|
1219
1832
|
</ul>
|
|
1220
1833
|
`;
|
|
1221
1834
|
}
|
|
1835
|
+
// ─── Form Helpers ────────────────────────────────────────
|
|
1836
|
+
_createFormContext() {
|
|
1837
|
+
const s = this._state;
|
|
1838
|
+
return {
|
|
1839
|
+
getValue: (k) => s.formValues[k],
|
|
1840
|
+
getError: (k) => s.formErrors[k] ?? "",
|
|
1841
|
+
getTouched: (k) => !!s.formTouched[k],
|
|
1842
|
+
onUpdate: (k, v) => this.controller.updateFormField(k, v),
|
|
1843
|
+
onBlur: (k) => this.controller.touchFormField(k)
|
|
1844
|
+
};
|
|
1845
|
+
}
|
|
1846
|
+
_createStepFormContext() {
|
|
1847
|
+
const s = this._state;
|
|
1848
|
+
const step = s.stepFormSteps[s.stepFormCurrentIndex];
|
|
1849
|
+
return {
|
|
1850
|
+
getValue: (k) => step?.values[k],
|
|
1851
|
+
getError: (k) => step?.errors[k] ?? "",
|
|
1852
|
+
getTouched: (k) => !!step?.touched[k],
|
|
1853
|
+
onUpdate: (k, v) => this.controller.updateStepFormField(k, v),
|
|
1854
|
+
onBlur: (k) => this.controller.touchStepFormField(k)
|
|
1855
|
+
};
|
|
1856
|
+
}
|
|
1857
|
+
_getOrderedFields(fields, layout) {
|
|
1858
|
+
const order = layout.fieldOrder;
|
|
1859
|
+
if (!order?.length) return fields;
|
|
1860
|
+
const fieldMap = new Map(fields.map((f) => [f.key, f]));
|
|
1861
|
+
const ordered = [];
|
|
1862
|
+
for (const key of order) {
|
|
1863
|
+
const f = fieldMap.get(key);
|
|
1864
|
+
if (f) {
|
|
1865
|
+
ordered.push(f);
|
|
1866
|
+
fieldMap.delete(key);
|
|
1867
|
+
}
|
|
1868
|
+
}
|
|
1869
|
+
for (const f of fieldMap.values()) {
|
|
1870
|
+
ordered.push(f);
|
|
1871
|
+
}
|
|
1872
|
+
return ordered;
|
|
1873
|
+
}
|
|
1874
|
+
_renderFormGrid(fields, columns, gap, ctx) {
|
|
1875
|
+
return html`
|
|
1876
|
+
<div class="form-grid" style="--dialog-form-columns:${columns}; gap:${gap}">
|
|
1877
|
+
${fields.map((f) => this._renderFormField(f, ctx))}
|
|
1878
|
+
</div>
|
|
1879
|
+
`;
|
|
1880
|
+
}
|
|
1881
|
+
_renderGroupedForm(allFields, groups, layout, ctx) {
|
|
1882
|
+
const fieldMap = new Map(allFields.map((f) => [f.key, f]));
|
|
1883
|
+
const usedKeys = /* @__PURE__ */ new Set();
|
|
1884
|
+
const gap = layout.gap ?? "16px";
|
|
1885
|
+
const groupFragments = groups.map((group) => {
|
|
1886
|
+
const groupFields = [];
|
|
1887
|
+
for (const key of group.fields) {
|
|
1888
|
+
const f = fieldMap.get(key);
|
|
1889
|
+
if (f) {
|
|
1890
|
+
groupFields.push(f);
|
|
1891
|
+
usedKeys.add(key);
|
|
1892
|
+
}
|
|
1893
|
+
}
|
|
1894
|
+
if (!groupFields.length) return nothing;
|
|
1895
|
+
const cols = group.columns ?? layout.columns ?? 1;
|
|
1896
|
+
return html`
|
|
1897
|
+
<fieldset class="form-group">
|
|
1898
|
+
${group.label ? html`<legend class="form-group-label">${group.label}</legend>` : nothing}
|
|
1899
|
+
${this._renderFormGrid(groupFields, cols, gap, ctx)}
|
|
1900
|
+
</fieldset>
|
|
1901
|
+
`;
|
|
1902
|
+
});
|
|
1903
|
+
const remaining = allFields.filter((f) => !usedKeys.has(f.key));
|
|
1904
|
+
return html`
|
|
1905
|
+
${groupFragments}
|
|
1906
|
+
${remaining.length ? this._renderFormGrid(remaining, layout.columns ?? 1, gap, ctx) : nothing}
|
|
1907
|
+
`;
|
|
1908
|
+
}
|
|
1909
|
+
_renderForm(fields, layout, ctx) {
|
|
1910
|
+
const ordered = this._getOrderedFields(fields, layout);
|
|
1911
|
+
const gap = layout.gap ?? "16px";
|
|
1912
|
+
if (layout.groups?.length) {
|
|
1913
|
+
return this._renderGroupedForm(ordered, layout.groups, layout, ctx);
|
|
1914
|
+
}
|
|
1915
|
+
return this._renderFormGrid(ordered, layout.columns ?? 1, gap, ctx);
|
|
1916
|
+
}
|
|
1917
|
+
_renderFormField(field, ctx) {
|
|
1918
|
+
const value = ctx.getValue(field.key);
|
|
1919
|
+
const error = ctx.getError(field.key);
|
|
1920
|
+
const touched = ctx.getTouched(field.key);
|
|
1921
|
+
const showError = touched && !!error;
|
|
1922
|
+
if (field.inputType === "checkbox") {
|
|
1923
|
+
return html`
|
|
1924
|
+
<div class="form-field" data-type="checkbox" ?data-error=${showError}>
|
|
1925
|
+
<label class="form-checkbox-label">
|
|
1926
|
+
<input
|
|
1927
|
+
type="checkbox"
|
|
1928
|
+
class="form-checkbox"
|
|
1929
|
+
.checked=${!!value}
|
|
1930
|
+
@change=${(e) => ctx.onUpdate(field.key, e.target.checked)}
|
|
1931
|
+
@blur=${() => ctx.onBlur(field.key)}
|
|
1932
|
+
/>
|
|
1933
|
+
<span class="form-checkbox-text">
|
|
1934
|
+
${field.label}
|
|
1935
|
+
${field.required ? html`<span class="form-required">*</span>` : nothing}
|
|
1936
|
+
</span>
|
|
1937
|
+
</label>
|
|
1938
|
+
${showError ? html`<span class="form-error">${error}</span>` : nothing}
|
|
1939
|
+
</div>
|
|
1940
|
+
`;
|
|
1941
|
+
}
|
|
1942
|
+
return html`
|
|
1943
|
+
<div class="form-field" data-type=${field.inputType} ?data-error=${showError}>
|
|
1944
|
+
<label class="form-label" for="form-${field.key}">
|
|
1945
|
+
${field.label} ${field.required ? html`<span class="form-required">*</span>` : nothing}
|
|
1946
|
+
</label>
|
|
1947
|
+
${field.description ? html`<span class="form-hint">${field.description}</span>` : nothing}
|
|
1948
|
+
${this._renderFormInput(field, value, ctx)}
|
|
1949
|
+
${showError ? html`<span class="form-error">${error}</span>` : nothing}
|
|
1950
|
+
</div>
|
|
1951
|
+
`;
|
|
1952
|
+
}
|
|
1953
|
+
_renderFormInput(field, value, ctx) {
|
|
1954
|
+
switch (field.inputType) {
|
|
1955
|
+
case "select":
|
|
1956
|
+
return html`
|
|
1957
|
+
<select
|
|
1958
|
+
class="form-select"
|
|
1959
|
+
id="form-${field.key}"
|
|
1960
|
+
@change=${(e) => ctx.onUpdate(field.key, e.target.value)}
|
|
1961
|
+
@blur=${() => ctx.onBlur(field.key)}
|
|
1962
|
+
>
|
|
1963
|
+
<option value="" ?selected=${!value}>選択してください</option>
|
|
1964
|
+
${field.options.map(
|
|
1965
|
+
(opt) => html`<option value=${opt} ?selected=${value === opt}>${opt}</option>`
|
|
1966
|
+
)}
|
|
1967
|
+
</select>
|
|
1968
|
+
`;
|
|
1969
|
+
case "number":
|
|
1970
|
+
return html`
|
|
1971
|
+
<input
|
|
1972
|
+
type="number"
|
|
1973
|
+
class="form-input"
|
|
1974
|
+
id="form-${field.key}"
|
|
1975
|
+
.value=${value != null ? String(value) : ""}
|
|
1976
|
+
min=${field.min ?? nothing}
|
|
1977
|
+
max=${field.max ?? nothing}
|
|
1978
|
+
placeholder=${field.placeholder || nothing}
|
|
1979
|
+
@input=${(e) => {
|
|
1980
|
+
const v = e.target.valueAsNumber;
|
|
1981
|
+
ctx.onUpdate(field.key, Number.isNaN(v) ? void 0 : v);
|
|
1982
|
+
}}
|
|
1983
|
+
@blur=${() => ctx.onBlur(field.key)}
|
|
1984
|
+
/>
|
|
1985
|
+
`;
|
|
1986
|
+
case "date":
|
|
1987
|
+
return html`
|
|
1988
|
+
<input
|
|
1989
|
+
type="date"
|
|
1990
|
+
class="form-input"
|
|
1991
|
+
id="form-${field.key}"
|
|
1992
|
+
.value=${value != null ? String(value) : ""}
|
|
1993
|
+
@input=${(e) => {
|
|
1994
|
+
const str = e.target.value;
|
|
1995
|
+
ctx.onUpdate(field.key, str || void 0);
|
|
1996
|
+
}}
|
|
1997
|
+
@blur=${() => ctx.onBlur(field.key)}
|
|
1998
|
+
/>
|
|
1999
|
+
`;
|
|
2000
|
+
default:
|
|
2001
|
+
return html`
|
|
2002
|
+
<input
|
|
2003
|
+
type=${field.inputType}
|
|
2004
|
+
class="form-input"
|
|
2005
|
+
id="form-${field.key}"
|
|
2006
|
+
.value=${value ?? ""}
|
|
2007
|
+
minlength=${field.minLength ?? nothing}
|
|
2008
|
+
maxlength=${field.maxLength ?? nothing}
|
|
2009
|
+
placeholder=${field.placeholder || nothing}
|
|
2010
|
+
@input=${(e) => ctx.onUpdate(field.key, e.target.value)}
|
|
2011
|
+
@blur=${() => ctx.onBlur(field.key)}
|
|
2012
|
+
/>
|
|
2013
|
+
`;
|
|
2014
|
+
}
|
|
2015
|
+
}
|
|
1222
2016
|
_renderButtons() {
|
|
1223
2017
|
const s = this._state;
|
|
1224
2018
|
if (!s.showConfirmButton && !s.showCancelButton) return nothing;
|
|
@@ -1233,6 +2027,39 @@ var OverlayDialog = class extends LitElement {
|
|
|
1233
2027
|
</div>
|
|
1234
2028
|
`;
|
|
1235
2029
|
}
|
|
2030
|
+
// ─── Step Form Helpers ───────────────────────────────────
|
|
2031
|
+
_renderStepFormButtons() {
|
|
2032
|
+
const s = this._state;
|
|
2033
|
+
const isFirst = s.stepFormCurrentIndex === 0;
|
|
2034
|
+
const isLast = s.stepFormCurrentIndex === s.stepFormSteps.length - 1;
|
|
2035
|
+
const submitText = isLast ? s.stepFormSubmitText : s.stepFormNextText;
|
|
2036
|
+
return html`
|
|
2037
|
+
<div class="actions actions-step-form">
|
|
2038
|
+
<button class="btn btn-cancel" @click=${() => this.controller.onCancel()}>
|
|
2039
|
+
${s.cancelButtonText}
|
|
2040
|
+
</button>
|
|
2041
|
+
<div class="step-form-nav">
|
|
2042
|
+
${isFirst ? nothing : html`
|
|
2043
|
+
<button class="btn btn-prev" @click=${() => this.controller.onStepPrev()}>
|
|
2044
|
+
${s.stepFormPrevText}
|
|
2045
|
+
</button>
|
|
2046
|
+
`}
|
|
2047
|
+
<button class="btn btn-confirm" @click=${() => this.controller.onStepNext()}>
|
|
2048
|
+
${submitText}
|
|
2049
|
+
</button>
|
|
2050
|
+
</div>
|
|
2051
|
+
</div>
|
|
2052
|
+
`;
|
|
2053
|
+
}
|
|
2054
|
+
_deriveStepItems() {
|
|
2055
|
+
const s = this._state;
|
|
2056
|
+
return s.stepFormSteps.map((st, i) => {
|
|
2057
|
+
let status = "pending";
|
|
2058
|
+
if (i < s.stepFormCurrentIndex) status = "done";
|
|
2059
|
+
else if (i === s.stepFormCurrentIndex) status = "active";
|
|
2060
|
+
return { key: st.key, label: st.label, status };
|
|
2061
|
+
});
|
|
2062
|
+
}
|
|
1236
2063
|
_renderBody() {
|
|
1237
2064
|
const s = this._state;
|
|
1238
2065
|
switch (s.dialogType) {
|
|
@@ -1259,16 +2086,47 @@ var OverlayDialog = class extends LitElement {
|
|
|
1259
2086
|
${s.label ? html`<p class="label">${s.label}</p>` : nothing}
|
|
1260
2087
|
${this._renderStepsList(s.steps)}
|
|
1261
2088
|
`;
|
|
2089
|
+
case "form": {
|
|
2090
|
+
const ctx = this._createFormContext();
|
|
2091
|
+
return html`
|
|
2092
|
+
${s.title ? html`<p class="label">${s.title}</p>` : nothing}
|
|
2093
|
+
${s.description ? html`<p class="description">${s.description}</p>` : nothing}
|
|
2094
|
+
<div class="form-scroll-container">
|
|
2095
|
+
${this._renderForm(s.formFields, s.formLayout, ctx)}
|
|
2096
|
+
</div>
|
|
2097
|
+
${this._renderButtons()}
|
|
2098
|
+
`;
|
|
2099
|
+
}
|
|
2100
|
+
case "step-form": {
|
|
2101
|
+
const stepItems = this._deriveStepItems();
|
|
2102
|
+
const currentStep = s.stepFormSteps[s.stepFormCurrentIndex];
|
|
2103
|
+
if (!currentStep) return html`${nothing}`;
|
|
2104
|
+
const ctx = this._createStepFormContext();
|
|
2105
|
+
const stepCount = s.stepFormSteps.length;
|
|
2106
|
+
const counterText = `${s.stepFormCurrentIndex + 1} / ${stepCount}`;
|
|
2107
|
+
return html`
|
|
2108
|
+
${this._renderStepsHeader(stepItems)}
|
|
2109
|
+
<p class="step-form-counter">${counterText}</p>
|
|
2110
|
+
<p class="label">${currentStep.label}</p>
|
|
2111
|
+
${currentStep.description ? html`<p class="description">${currentStep.description}</p>` : nothing}
|
|
2112
|
+
${currentStep.fields.length ? html`
|
|
2113
|
+
<div class="form-scroll-container">
|
|
2114
|
+
${this._renderForm(currentStep.fields, currentStep.layout, ctx)}
|
|
2115
|
+
</div>
|
|
2116
|
+
` : nothing}
|
|
2117
|
+
${this._renderStepFormButtons()}
|
|
2118
|
+
`;
|
|
2119
|
+
}
|
|
1262
2120
|
default:
|
|
1263
2121
|
return html`${nothing}`;
|
|
1264
2122
|
}
|
|
1265
2123
|
}
|
|
1266
2124
|
render() {
|
|
1267
2125
|
const s = this._state;
|
|
1268
|
-
const showHeaderTitle = s.title && s.dialogType !== "alert" && s.dialogType !== "confirm";
|
|
2126
|
+
const showHeaderTitle = s.title && s.dialogType !== "alert" && s.dialogType !== "confirm" && s.dialogType !== "form" && s.dialogType !== "step-form";
|
|
1269
2127
|
return html`
|
|
1270
2128
|
<div class="backdrop" ?data-open=${s.open} @click=${this._onBackdropClick}>
|
|
1271
|
-
<div class="card" ?data-closing=${this._isClosing}>
|
|
2129
|
+
<div class="card" data-type=${s.dialogType} ?data-closing=${this._isClosing}>
|
|
1272
2130
|
${showHeaderTitle ? html`<p class="dialog-title">${s.title}</p>` : nothing}
|
|
1273
2131
|
<div class="card-body">
|
|
1274
2132
|
${keyed(this._bodyKey, html`<div class="body-inner">${this._renderBody()}</div>`)}
|
|
@@ -1324,6 +2182,28 @@ var DialogSingleton = class {
|
|
|
1324
2182
|
__privateMethod(this, _DialogSingleton_instances, ensureElement_fn).call(this);
|
|
1325
2183
|
return __privateGet(this, _controller).confirm(optionsOrLabel);
|
|
1326
2184
|
}
|
|
2185
|
+
// ─── Form ──────────────────────────────────────────────────
|
|
2186
|
+
form(schema, options) {
|
|
2187
|
+
__privateMethod(this, _DialogSingleton_instances, ensureElement_fn).call(this);
|
|
2188
|
+
return __privateGet(this, _controller).form(schema, options);
|
|
2189
|
+
}
|
|
2190
|
+
// ─── Step Form ─────────────────────────────────────────────
|
|
2191
|
+
showStepForm(steps, options) {
|
|
2192
|
+
__privateMethod(this, _DialogSingleton_instances, ensureElement_fn).call(this);
|
|
2193
|
+
return __privateGet(this, _controller).showStepForm(steps, options);
|
|
2194
|
+
}
|
|
2195
|
+
onStepNext() {
|
|
2196
|
+
__privateGet(this, _controller).onStepNext();
|
|
2197
|
+
}
|
|
2198
|
+
onStepPrev() {
|
|
2199
|
+
__privateGet(this, _controller).onStepPrev();
|
|
2200
|
+
}
|
|
2201
|
+
updateStepFormField(fieldKey, value) {
|
|
2202
|
+
__privateGet(this, _controller).updateStepFormField(fieldKey, value);
|
|
2203
|
+
}
|
|
2204
|
+
touchStepFormField(fieldKey) {
|
|
2205
|
+
__privateGet(this, _controller).touchStepFormField(fieldKey);
|
|
2206
|
+
}
|
|
1327
2207
|
// ─── Loading helpers ─────────────────────────────────────
|
|
1328
2208
|
showLoading(label) {
|
|
1329
2209
|
__privateMethod(this, _DialogSingleton_instances, ensureElement_fn).call(this);
|