@letar/forms 1.0.0 → 1.0.3
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/CHANGELOG.md +34 -0
- package/README.md +79 -4
- package/{chunk-G3HYXHCZ.js → chunk-4V6WBJ76.js} +14 -14
- package/chunk-4V6WBJ76.js.map +1 -0
- package/{chunk-GIBNEYK3.js → chunk-7FEQFDJ7.js} +5 -4
- package/chunk-7FEQFDJ7.js.map +1 -0
- package/i18n.js +1 -1
- package/index.js +454 -290
- package/index.js.map +1 -1
- package/offline.js +1 -1
- package/package.json +7 -2
- package/chunk-G3HYXHCZ.js.map +0 -1
- package/chunk-GIBNEYK3.js.map +0 -1
package/index.js
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import { FormSyncStatus, FormOfflineIndicator, useOfflineForm } from './chunk-
|
|
2
|
-
export { FormOfflineIndicator, FormSyncStatus, useOfflineForm, useOfflineStatus, useSyncQueue } from './chunk-
|
|
3
|
-
import { useFormI18n, getLocalizedValue, useLocalizedOptions } from './chunk-
|
|
4
|
-
export { FormI18nProvider, getLocalizedValue, useFormI18n, useLocalizedOptions } from './chunk-
|
|
1
|
+
import { FormSyncStatus, FormOfflineIndicator, useOfflineForm } from './chunk-4V6WBJ76.js';
|
|
2
|
+
export { FormOfflineIndicator, FormSyncStatus, useOfflineForm, useOfflineStatus, useSyncQueue } from './chunk-4V6WBJ76.js';
|
|
3
|
+
import { useFormI18n, getLocalizedValue, useLocalizedOptions } from './chunk-7FEQFDJ7.js';
|
|
4
|
+
export { FormI18nProvider, getLocalizedValue, useFormI18n, useLocalizedOptions } from './chunk-7FEQFDJ7.js';
|
|
5
5
|
import { createFormHookContexts, createFormHook } from '@tanstack/react-form';
|
|
6
6
|
import { createContext, forwardRef, memo, useMemo, useCallback, useContext, Fragment, useState, useRef, useEffect, Children, isValidElement, useSyncExternalStore, lazy, Suspense } from 'react';
|
|
7
7
|
import { jsxs, jsx, Fragment as Fragment$1 } from 'react/jsx-runtime';
|
|
8
|
-
import { Field, Stack, Box, Text, HStack, Button, Input, IconButton, Steps, ButtonGroup, VStack, Alert, List, FileUpload, Icon, parseColor, ColorPicker, Portal, PinInput, Spinner, Group, TagsInput, SegmentGroup, RadioCard, RadioGroup, Listbox, Combobox, useFilter, createListCollection, NativeSelect, Select, Switch, Fieldset, CheckboxGroup, Flex, CheckboxCard, Checkbox, NumberInput, Menu, RatingGroup, Slider, For, Editable, Progress, InputGroup, Textarea, Tooltip, Circle, useFileUploadContext, Float, Popover, Center, Image, Dialog, CloseButton, Skeleton } from '@chakra-ui/react';
|
|
8
|
+
import { Field, Stack, Box, Text, HStack, Button, Input, IconButton, Steps, ButtonGroup, VStack, Heading, Alert, List, FileUpload, Icon, parseColor, ColorPicker, Portal, PinInput, Spinner, Group, TagsInput, SegmentGroup, RadioCard, RadioGroup, Listbox, Combobox, useFilter, createListCollection, NativeSelect, Select, Switch, Fieldset, CheckboxGroup, Flex, CheckboxCard, Checkbox, NumberInput, Menu, RatingGroup, Slider, For, Editable, Progress, InputGroup, Textarea, Tooltip, Circle, useFileUploadContext, Float, Popover, Center, Image, Dialog, CloseButton, Skeleton } from '@chakra-ui/react';
|
|
9
9
|
import { useRouter } from 'next/navigation';
|
|
10
10
|
import { LuCheck, LuUpload, LuCalendar, LuChevronDown, LuEyeOff, LuEye, LuX, LuCircleHelp, LuFile, LuUnlink, LuLink, LuImage, LuRedo, LuUndo, LuQuote, LuListOrdered, LuList, LuHeading3, LuHeading2, LuHeading1, LuCode, LuStrikethrough, LuUnderline, LuItalic, LuBold } from 'react-icons/lu';
|
|
11
11
|
import TiptapImage from '@tiptap/extension-image';
|
|
@@ -18,6 +18,9 @@ import { withMask } from 'use-mask-input';
|
|
|
18
18
|
import { useSensors, useSensor, PointerSensor, KeyboardSensor, DndContext, closestCenter } from '@dnd-kit/core';
|
|
19
19
|
import { sortableKeyboardCoordinates, SortableContext, verticalListSortingStrategy, useSortable } from '@dnd-kit/sortable';
|
|
20
20
|
import { CSS } from '@dnd-kit/utilities';
|
|
21
|
+
import JsonView from '@uiw/react-json-view';
|
|
22
|
+
import { githubDarkTheme } from '@uiw/react-json-view/githubDark';
|
|
23
|
+
import { githubLightTheme } from '@uiw/react-json-view/githubLight';
|
|
21
24
|
import { AnimatePresence, motion } from 'framer-motion';
|
|
22
25
|
import { z } from 'zod/v4';
|
|
23
26
|
|
|
@@ -27,31 +30,31 @@ function useTypedFormContext() {
|
|
|
27
30
|
return useMemo(
|
|
28
31
|
() => ({
|
|
29
32
|
/**
|
|
30
|
-
*
|
|
31
|
-
*
|
|
33
|
+
* Original form API from TanStack Form.
|
|
34
|
+
* Use form.store for useStore subscriptions.
|
|
32
35
|
*/
|
|
33
36
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
34
37
|
form: rawForm,
|
|
35
38
|
/**
|
|
36
|
-
*
|
|
37
|
-
*
|
|
39
|
+
* Typed setFieldValue.
|
|
40
|
+
* Use instead of form.setFieldValue for proper typing.
|
|
38
41
|
*/
|
|
39
42
|
setFieldValue: (name, value) => {
|
|
40
43
|
rawForm.setFieldValue(name, value);
|
|
41
44
|
},
|
|
42
45
|
/**
|
|
43
|
-
*
|
|
44
|
-
*
|
|
46
|
+
* Typed selector for values.
|
|
47
|
+
* Use inside form.Subscribe: `selector={(s) => values(s)}`
|
|
45
48
|
*/
|
|
46
49
|
values: (state) => state.values,
|
|
47
50
|
/**
|
|
48
|
-
*
|
|
49
|
-
*
|
|
51
|
+
* Get current form values (snapshot).
|
|
52
|
+
* Note: this is not reactive! For reactive access use form.Subscribe.
|
|
50
53
|
*/
|
|
51
54
|
getValues: () => rawForm.state.values,
|
|
52
55
|
/**
|
|
53
|
-
*
|
|
54
|
-
*
|
|
56
|
+
* Subscribe to a specific field.
|
|
57
|
+
* Returns a selector for use in form.Subscribe.
|
|
55
58
|
*/
|
|
56
59
|
field: (name) => (state) => state.values[name]
|
|
57
60
|
}),
|
|
@@ -199,10 +202,10 @@ function useDeclarativeFormOptional() {
|
|
|
199
202
|
}
|
|
200
203
|
function DirtyGuard({
|
|
201
204
|
message = "You have unsaved changes. Are you sure you want to leave?",
|
|
202
|
-
dialogTitle = "
|
|
203
|
-
dialogDescription = "
|
|
204
|
-
confirmText = "
|
|
205
|
-
cancelText = "
|
|
205
|
+
dialogTitle = "Unsaved changes",
|
|
206
|
+
dialogDescription = "You have unsaved changes. Are you sure you want to leave this page?",
|
|
207
|
+
confirmText = "Leave",
|
|
208
|
+
cancelText = "Stay",
|
|
206
209
|
enabled = true,
|
|
207
210
|
onBlock
|
|
208
211
|
}) {
|
|
@@ -406,7 +409,7 @@ function FieldTooltip({ title, description, example, impact }) {
|
|
|
406
409
|
title && /* @__PURE__ */ jsx(Text, { fontWeight: "semibold", fontSize: "sm", children: title }),
|
|
407
410
|
/* @__PURE__ */ jsx(Text, { fontSize: "sm", children: description }),
|
|
408
411
|
example && /* @__PURE__ */ jsxs(Box, { bg: "bg.emphasized", px: 2, py: 1, borderRadius: "md", w: "full", children: [
|
|
409
|
-
/* @__PURE__ */ jsx(Text, { fontSize: "xs", color: "fg.muted", children: "
|
|
412
|
+
/* @__PURE__ */ jsx(Text, { fontSize: "xs", color: "fg.muted", children: "Example:" }),
|
|
410
413
|
/* @__PURE__ */ jsxs(Text, { fontSize: "sm", fontStyle: "italic", children: [
|
|
411
414
|
'"',
|
|
412
415
|
example,
|
|
@@ -498,144 +501,176 @@ function getFieldErrors(field) {
|
|
|
498
501
|
}
|
|
499
502
|
|
|
500
503
|
// src/lib/declarative/constraint-hints.ts
|
|
501
|
-
|
|
504
|
+
var EN_TRANSLATIONS = {
|
|
505
|
+
string_exact: "Exactly {n} {chars}",
|
|
506
|
+
string_range: "From {min} to {max} characters",
|
|
507
|
+
string_max: "Maximum {n} {chars}",
|
|
508
|
+
string_min: "Minimum {n} {chars}",
|
|
509
|
+
number_range: "From {min} to {max}{suffix}",
|
|
510
|
+
number_max: "Maximum {max}{suffix}",
|
|
511
|
+
number_min: "Minimum {min}{suffix}",
|
|
512
|
+
number_integer: "Integer",
|
|
513
|
+
number_integer_suffix: " (integer)",
|
|
514
|
+
date_range: "From {min} to {max}",
|
|
515
|
+
date_after: "Not before {min}",
|
|
516
|
+
date_before: "Not after {max}",
|
|
517
|
+
array_exact: "Exactly {n} {items}",
|
|
518
|
+
array_range: "From {min} to {max} items",
|
|
519
|
+
array_max: "Maximum {n} {items}",
|
|
520
|
+
array_min: "Minimum {n} {items}"
|
|
521
|
+
};
|
|
522
|
+
var RU_TRANSLATIONS = {
|
|
523
|
+
string_exact: "\u0420\u043E\u0432\u043D\u043E {n} {chars}",
|
|
524
|
+
string_range: "\u041E\u0442 {min} \u0434\u043E {max} \u0441\u0438\u043C\u0432\u043E\u043B\u043E\u0432",
|
|
525
|
+
string_max: "\u041C\u0430\u043A\u0441\u0438\u043C\u0443\u043C {n} {chars}",
|
|
526
|
+
string_min: "\u041C\u0438\u043D\u0438\u043C\u0443\u043C {n} {chars}",
|
|
527
|
+
number_range: "\u041E\u0442 {min} \u0434\u043E {max}{suffix}",
|
|
528
|
+
number_max: "\u041C\u0430\u043A\u0441\u0438\u043C\u0443\u043C {max}{suffix}",
|
|
529
|
+
number_min: "\u041C\u0438\u043D\u0438\u043C\u0443\u043C {min}{suffix}",
|
|
530
|
+
number_integer: "\u0426\u0435\u043B\u043E\u0435 \u0447\u0438\u0441\u043B\u043E",
|
|
531
|
+
number_integer_suffix: " (\u0446\u0435\u043B\u043E\u0435)",
|
|
532
|
+
date_range: "\u0421 {min} \u043F\u043E {max}",
|
|
533
|
+
date_after: "\u041D\u0435 \u0440\u0430\u043D\u0435\u0435 {min}",
|
|
534
|
+
date_before: "\u041D\u0435 \u043F\u043E\u0437\u0434\u043D\u0435\u0435 {max}",
|
|
535
|
+
array_exact: "\u0420\u043E\u0432\u043D\u043E {n} {items}",
|
|
536
|
+
array_range: "\u041E\u0442 {min} \u0434\u043E {max} \u044D\u043B\u0435\u043C\u0435\u043D\u0442\u043E\u0432",
|
|
537
|
+
array_max: "\u041C\u0430\u043A\u0441\u0438\u043C\u0443\u043C {n} {items}",
|
|
538
|
+
array_min: "\u041C\u0438\u043D\u0438\u043C\u0443\u043C {n} {items}"
|
|
539
|
+
};
|
|
540
|
+
var BUILTIN_TRANSLATIONS = {
|
|
541
|
+
en: EN_TRANSLATIONS,
|
|
542
|
+
ru: RU_TRANSLATIONS
|
|
543
|
+
};
|
|
544
|
+
var CHAR_PLURALS = {
|
|
545
|
+
en: { one: "character", other: "characters" },
|
|
546
|
+
ru: { one: "\u0441\u0438\u043C\u0432\u043E\u043B", few: "\u0441\u0438\u043C\u0432\u043E\u043B\u0430", many: "\u0441\u0438\u043C\u0432\u043E\u043B\u043E\u0432", other: "\u0441\u0438\u043C\u0432\u043E\u043B\u043E\u0432" }
|
|
547
|
+
};
|
|
548
|
+
var ITEM_PLURALS = {
|
|
549
|
+
en: { one: "item", other: "items" },
|
|
550
|
+
ru: { one: "\u044D\u043B\u0435\u043C\u0435\u043D\u0442", few: "\u044D\u043B\u0435\u043C\u0435\u043D\u0442\u0430", many: "\u044D\u043B\u0435\u043C\u0435\u043D\u0442\u043E\u0432", other: "\u044D\u043B\u0435\u043C\u0435\u043D\u0442\u043E\u0432" }
|
|
551
|
+
};
|
|
552
|
+
function pluralizeWord(n, locale, plurals) {
|
|
553
|
+
const lang = locale.split("-")[0];
|
|
554
|
+
const forms = plurals[lang] ?? plurals.en;
|
|
555
|
+
const rule = new Intl.PluralRules(locale).select(n);
|
|
556
|
+
return forms[rule] ?? forms.other;
|
|
557
|
+
}
|
|
558
|
+
function formatNumber(n, locale) {
|
|
559
|
+
if (Number.isInteger(n)) {
|
|
560
|
+
return new Intl.NumberFormat(locale).format(n);
|
|
561
|
+
}
|
|
562
|
+
return new Intl.NumberFormat(locale, { maximumFractionDigits: 2 }).format(n);
|
|
563
|
+
}
|
|
564
|
+
function formatDate(dateStr, locale) {
|
|
565
|
+
try {
|
|
566
|
+
const date = new Date(dateStr);
|
|
567
|
+
return new Intl.DateTimeFormat(locale, {
|
|
568
|
+
day: "numeric",
|
|
569
|
+
month: "long",
|
|
570
|
+
year: "numeric"
|
|
571
|
+
}).format(date);
|
|
572
|
+
} catch {
|
|
573
|
+
return dateStr;
|
|
574
|
+
}
|
|
575
|
+
}
|
|
576
|
+
function template(str, vars) {
|
|
577
|
+
return str.replace(/\{(\w+)\}/g, (_, key) => String(vars[key] ?? ""));
|
|
578
|
+
}
|
|
579
|
+
function getTranslations(locale, custom) {
|
|
580
|
+
const lang = locale.split("-")[0];
|
|
581
|
+
const base = BUILTIN_TRANSLATIONS[lang] ?? BUILTIN_TRANSLATIONS[locale] ?? EN_TRANSLATIONS;
|
|
582
|
+
return base;
|
|
583
|
+
}
|
|
584
|
+
function generateConstraintHint(constraints, locale = "en", customTranslations) {
|
|
502
585
|
if (!constraints) {
|
|
503
586
|
return void 0;
|
|
504
587
|
}
|
|
588
|
+
const t = getTranslations(locale);
|
|
505
589
|
switch (constraints.schemaType) {
|
|
506
590
|
case "string":
|
|
507
|
-
return generateStringHint(constraints.string);
|
|
591
|
+
return generateStringHint(constraints.string, locale, t);
|
|
508
592
|
case "number":
|
|
509
|
-
return generateNumberHint(constraints.number);
|
|
593
|
+
return generateNumberHint(constraints.number, locale, t);
|
|
510
594
|
case "date":
|
|
511
|
-
return generateDateHint(constraints.date);
|
|
595
|
+
return generateDateHint(constraints.date, locale, t);
|
|
512
596
|
case "array":
|
|
513
|
-
return generateArrayHint(constraints.array);
|
|
597
|
+
return generateArrayHint(constraints.array, locale, t);
|
|
514
598
|
default:
|
|
515
599
|
return void 0;
|
|
516
600
|
}
|
|
517
601
|
}
|
|
518
|
-
function generateStringHint(constraints) {
|
|
519
|
-
if (!constraints)
|
|
520
|
-
return void 0;
|
|
521
|
-
}
|
|
602
|
+
function generateStringHint(constraints, locale, t) {
|
|
603
|
+
if (!constraints) return void 0;
|
|
522
604
|
const { minLength, maxLength, inputType } = constraints;
|
|
523
|
-
if (inputType === "email") {
|
|
605
|
+
if (inputType === "email" || inputType === "url") {
|
|
524
606
|
if (maxLength) {
|
|
525
|
-
return
|
|
526
|
-
}
|
|
527
|
-
return void 0;
|
|
528
|
-
}
|
|
529
|
-
if (inputType === "url") {
|
|
530
|
-
if (maxLength) {
|
|
531
|
-
return `\u041C\u0430\u043A\u0441\u0438\u043C\u0443\u043C ${maxLength} \u0441\u0438\u043C\u0432\u043E\u043B\u043E\u0432`;
|
|
607
|
+
return template(t.string_max, { n: maxLength, chars: pluralizeWord(maxLength, locale, CHAR_PLURALS) });
|
|
532
608
|
}
|
|
533
609
|
return void 0;
|
|
534
610
|
}
|
|
535
611
|
if (minLength !== void 0 && maxLength !== void 0) {
|
|
536
612
|
if (minLength === maxLength) {
|
|
537
|
-
return
|
|
613
|
+
return template(t.string_exact, { n: minLength, chars: pluralizeWord(minLength, locale, CHAR_PLURALS) });
|
|
538
614
|
}
|
|
539
|
-
return
|
|
615
|
+
return template(t.string_range, { min: minLength, max: maxLength });
|
|
540
616
|
}
|
|
541
617
|
if (maxLength !== void 0) {
|
|
542
|
-
return
|
|
618
|
+
return template(t.string_max, { n: maxLength, chars: pluralizeWord(maxLength, locale, CHAR_PLURALS) });
|
|
543
619
|
}
|
|
544
620
|
if (minLength !== void 0) {
|
|
545
|
-
return
|
|
621
|
+
return template(t.string_min, { n: minLength, chars: pluralizeWord(minLength, locale, CHAR_PLURALS) });
|
|
546
622
|
}
|
|
547
623
|
return void 0;
|
|
548
624
|
}
|
|
549
|
-
function generateNumberHint(constraints) {
|
|
550
|
-
if (!constraints)
|
|
551
|
-
return void 0;
|
|
552
|
-
}
|
|
625
|
+
function generateNumberHint(constraints, locale, t) {
|
|
626
|
+
if (!constraints) return void 0;
|
|
553
627
|
const { min, max, isInteger } = constraints;
|
|
628
|
+
const suffix = isInteger ? t.number_integer_suffix : "";
|
|
554
629
|
if (min !== void 0 && max !== void 0) {
|
|
555
|
-
|
|
556
|
-
return `\u041E\u0442 ${formatNumber(min)} \u0434\u043E ${formatNumber(max)}${suffix}`;
|
|
630
|
+
return template(t.number_range, { min: formatNumber(min, locale), max: formatNumber(max, locale), suffix });
|
|
557
631
|
}
|
|
558
632
|
if (max !== void 0) {
|
|
559
|
-
|
|
560
|
-
return `\u041C\u0430\u043A\u0441\u0438\u043C\u0443\u043C ${formatNumber(max)}${suffix}`;
|
|
633
|
+
return template(t.number_max, { max: formatNumber(max, locale), suffix });
|
|
561
634
|
}
|
|
562
635
|
if (min !== void 0) {
|
|
563
|
-
|
|
564
|
-
return `\u041C\u0438\u043D\u0438\u043C\u0443\u043C ${formatNumber(min)}${suffix}`;
|
|
636
|
+
return template(t.number_min, { min: formatNumber(min, locale), suffix });
|
|
565
637
|
}
|
|
566
638
|
if (isInteger) {
|
|
567
|
-
return
|
|
639
|
+
return t.number_integer;
|
|
568
640
|
}
|
|
569
641
|
return void 0;
|
|
570
642
|
}
|
|
571
|
-
function generateDateHint(constraints) {
|
|
572
|
-
if (!constraints)
|
|
573
|
-
return void 0;
|
|
574
|
-
}
|
|
643
|
+
function generateDateHint(constraints, locale, t) {
|
|
644
|
+
if (!constraints) return void 0;
|
|
575
645
|
const { min, max } = constraints;
|
|
576
646
|
if (min && max) {
|
|
577
|
-
return
|
|
647
|
+
return template(t.date_range, { min: formatDate(min, locale), max: formatDate(max, locale) });
|
|
578
648
|
}
|
|
579
649
|
if (min) {
|
|
580
|
-
return
|
|
650
|
+
return template(t.date_after, { min: formatDate(min, locale) });
|
|
581
651
|
}
|
|
582
652
|
if (max) {
|
|
583
|
-
return
|
|
653
|
+
return template(t.date_before, { max: formatDate(max, locale) });
|
|
584
654
|
}
|
|
585
655
|
return void 0;
|
|
586
656
|
}
|
|
587
|
-
function generateArrayHint(constraints) {
|
|
588
|
-
if (!constraints)
|
|
589
|
-
return void 0;
|
|
590
|
-
}
|
|
657
|
+
function generateArrayHint(constraints, locale, t) {
|
|
658
|
+
if (!constraints) return void 0;
|
|
591
659
|
const { minItems, maxItems } = constraints;
|
|
592
660
|
if (minItems !== void 0 && maxItems !== void 0) {
|
|
593
661
|
if (minItems === maxItems) {
|
|
594
|
-
return
|
|
662
|
+
return template(t.array_exact, { n: minItems, items: pluralizeWord(minItems, locale, ITEM_PLURALS) });
|
|
595
663
|
}
|
|
596
|
-
return
|
|
664
|
+
return template(t.array_range, { min: minItems, max: maxItems });
|
|
597
665
|
}
|
|
598
666
|
if (maxItems !== void 0) {
|
|
599
|
-
return
|
|
667
|
+
return template(t.array_max, { n: maxItems, items: pluralizeWord(maxItems, locale, ITEM_PLURALS) });
|
|
600
668
|
}
|
|
601
669
|
if (minItems !== void 0) {
|
|
602
|
-
return
|
|
670
|
+
return template(t.array_min, { n: minItems, items: pluralizeWord(minItems, locale, ITEM_PLURALS) });
|
|
603
671
|
}
|
|
604
672
|
return void 0;
|
|
605
673
|
}
|
|
606
|
-
function pluralize(n, one, few, many) {
|
|
607
|
-
const abs = Math.abs(n);
|
|
608
|
-
const mod10 = abs % 10;
|
|
609
|
-
const mod100 = abs % 100;
|
|
610
|
-
if (mod100 >= 11 && mod100 <= 19) {
|
|
611
|
-
return many;
|
|
612
|
-
}
|
|
613
|
-
if (mod10 === 1) {
|
|
614
|
-
return one;
|
|
615
|
-
}
|
|
616
|
-
if (mod10 >= 2 && mod10 <= 4) {
|
|
617
|
-
return few;
|
|
618
|
-
}
|
|
619
|
-
return many;
|
|
620
|
-
}
|
|
621
|
-
function formatNumber(n) {
|
|
622
|
-
if (Number.isInteger(n)) {
|
|
623
|
-
return n.toLocaleString("ru-RU");
|
|
624
|
-
}
|
|
625
|
-
return n.toLocaleString("ru-RU", { maximumFractionDigits: 2 });
|
|
626
|
-
}
|
|
627
|
-
function formatDate(dateStr) {
|
|
628
|
-
try {
|
|
629
|
-
const date = new Date(dateStr);
|
|
630
|
-
return date.toLocaleDateString("ru-RU", {
|
|
631
|
-
day: "numeric",
|
|
632
|
-
month: "long",
|
|
633
|
-
year: "numeric"
|
|
634
|
-
});
|
|
635
|
-
} catch {
|
|
636
|
-
return dateStr;
|
|
637
|
-
}
|
|
638
|
-
}
|
|
639
674
|
|
|
640
675
|
// src/lib/declarative/zod-utils.ts
|
|
641
676
|
function unwrapSchema(schema) {
|
|
@@ -928,7 +963,7 @@ function getSchemaAtPath2(schema, path) {
|
|
|
928
963
|
current = unwrapToBaseSchema(current);
|
|
929
964
|
const finalUnwrap = unwrapSchemaWithRequired(current);
|
|
930
965
|
return {
|
|
931
|
-
// Возвращаем схему ДО unwrap — на ней
|
|
966
|
+
// Возвращаем схему ДО unwrap — на ней can быть мета (.default().meta())
|
|
932
967
|
schema: current,
|
|
933
968
|
required: isRequired2 && finalUnwrap.required
|
|
934
969
|
};
|
|
@@ -976,7 +1011,7 @@ function useResolvedFieldProps(name, props) {
|
|
|
976
1011
|
const resolvedTitle = getLocalizedValue(i18n, i18nKey, "title", meta?.title);
|
|
977
1012
|
const resolvedPlaceholder = getLocalizedValue(i18n, i18nKey, "placeholder", meta?.placeholder);
|
|
978
1013
|
const resolvedDescription = getLocalizedValue(i18n, i18nKey, "description", meta?.description);
|
|
979
|
-
const autoHint = generateConstraintHint(constraints);
|
|
1014
|
+
const autoHint = generateConstraintHint(constraints, i18n?.locale ?? "en");
|
|
980
1015
|
const helperText = props.helperText ?? resolvedDescription ?? autoHint;
|
|
981
1016
|
const localizedOptions = useLocalizedOptions(meta?.options);
|
|
982
1017
|
return {
|
|
@@ -993,9 +1028,9 @@ function useResolvedFieldProps(name, props) {
|
|
|
993
1028
|
// Form-level + local props (local wins)
|
|
994
1029
|
disabled: props.disabled ?? formDisabled,
|
|
995
1030
|
readOnly: props.readOnly ?? formReadOnly,
|
|
996
|
-
// Constraints
|
|
1031
|
+
// Constraints for additional component configuration
|
|
997
1032
|
constraints,
|
|
998
|
-
// Options
|
|
1033
|
+
// Options with i18n translations
|
|
999
1034
|
options: localizedOptions
|
|
1000
1035
|
};
|
|
1001
1036
|
}
|
|
@@ -1173,7 +1208,7 @@ var FieldEditable = createField({
|
|
|
1173
1208
|
onValueChange: (details) => field.handleChange(details.value),
|
|
1174
1209
|
disabled: resolved.disabled,
|
|
1175
1210
|
readOnly: resolved.readOnly,
|
|
1176
|
-
placeholder: resolved.placeholder ?? "
|
|
1211
|
+
placeholder: resolved.placeholder ?? "Click to edit",
|
|
1177
1212
|
activationMode,
|
|
1178
1213
|
submitMode: submitOnBlur ? "blur" : "enter",
|
|
1179
1214
|
children: [
|
|
@@ -1221,7 +1256,7 @@ var FieldPassword = createField({
|
|
|
1221
1256
|
size: "sm",
|
|
1222
1257
|
variant: "ghost",
|
|
1223
1258
|
height: "calc(100% - {spacing.2})",
|
|
1224
|
-
"aria-label": "
|
|
1259
|
+
"aria-label": "Toggle password visibility",
|
|
1225
1260
|
disabled: resolved.disabled,
|
|
1226
1261
|
onPointerDown: (e) => {
|
|
1227
1262
|
if (resolved.disabled) {
|
|
@@ -1254,11 +1289,11 @@ var FieldPassword = createField({
|
|
|
1254
1289
|
});
|
|
1255
1290
|
var DEFAULT_REQUIREMENTS = ["minLength:8", "uppercase", "lowercase", "number", "special"];
|
|
1256
1291
|
var REQUIREMENT_LABELS = {
|
|
1257
|
-
"minLength:8": "
|
|
1258
|
-
uppercase: "
|
|
1259
|
-
lowercase: "
|
|
1260
|
-
number: "
|
|
1261
|
-
special: "
|
|
1292
|
+
"minLength:8": "Minimum 8 characters",
|
|
1293
|
+
uppercase: "At least one uppercase letter",
|
|
1294
|
+
lowercase: "At least one lowercase letter",
|
|
1295
|
+
number: "At least one digit",
|
|
1296
|
+
special: "At least one special character (!@#$%^&*)"
|
|
1262
1297
|
};
|
|
1263
1298
|
function checkRequirement(password, requirement) {
|
|
1264
1299
|
switch (requirement) {
|
|
@@ -1285,15 +1320,15 @@ function calculateStrength(password, requirements) {
|
|
|
1285
1320
|
}
|
|
1286
1321
|
function getStrengthInfo(strength) {
|
|
1287
1322
|
if (strength < 25) {
|
|
1288
|
-
return { label: "
|
|
1323
|
+
return { label: "Weak", colorPalette: "red" };
|
|
1289
1324
|
}
|
|
1290
1325
|
if (strength < 50) {
|
|
1291
|
-
return { label: "
|
|
1326
|
+
return { label: "Medium", colorPalette: "orange" };
|
|
1292
1327
|
}
|
|
1293
1328
|
if (strength < 75) {
|
|
1294
|
-
return { label: "
|
|
1329
|
+
return { label: "Good", colorPalette: "yellow" };
|
|
1295
1330
|
}
|
|
1296
|
-
return { label: "
|
|
1331
|
+
return { label: "Strong", colorPalette: "green" };
|
|
1297
1332
|
}
|
|
1298
1333
|
var FieldPasswordStrength = createField({
|
|
1299
1334
|
displayName: "FieldPasswordStrength",
|
|
@@ -1325,7 +1360,7 @@ var FieldPasswordStrength = createField({
|
|
|
1325
1360
|
value,
|
|
1326
1361
|
onChange: (e) => field.handleChange(e.target.value),
|
|
1327
1362
|
onBlur: field.handleBlur,
|
|
1328
|
-
placeholder: resolved.placeholder ?? "
|
|
1363
|
+
placeholder: resolved.placeholder ?? "Enter password",
|
|
1329
1364
|
"data-field-name": fullPath,
|
|
1330
1365
|
flex: 1
|
|
1331
1366
|
}
|
|
@@ -1333,7 +1368,7 @@ var FieldPasswordStrength = createField({
|
|
|
1333
1368
|
/* @__PURE__ */ jsx(
|
|
1334
1369
|
IconButton,
|
|
1335
1370
|
{
|
|
1336
|
-
"aria-label": visible ? "
|
|
1371
|
+
"aria-label": visible ? "Hide password" : "Show password",
|
|
1337
1372
|
onClick: toggle,
|
|
1338
1373
|
variant: "ghost",
|
|
1339
1374
|
size: "sm",
|
|
@@ -1343,7 +1378,7 @@ var FieldPasswordStrength = createField({
|
|
|
1343
1378
|
] }),
|
|
1344
1379
|
value && /* @__PURE__ */ jsxs(Box, { children: [
|
|
1345
1380
|
/* @__PURE__ */ jsxs(HStack, { justify: "space-between", mb: 1, children: [
|
|
1346
|
-
/* @__PURE__ */ jsx(Text, { fontSize: "xs", color: "fg.muted", children: "
|
|
1381
|
+
/* @__PURE__ */ jsx(Text, { fontSize: "xs", color: "fg.muted", children: "Strength" }),
|
|
1347
1382
|
/* @__PURE__ */ jsx(Text, { fontSize: "xs", fontWeight: "medium", color: `${colorPalette}.600`, children: strengthLabel })
|
|
1348
1383
|
] }),
|
|
1349
1384
|
/* @__PURE__ */ jsx(Progress.Root, { value: strength, colorPalette, size: "xs", children: /* @__PURE__ */ jsx(Progress.Track, { children: /* @__PURE__ */ jsx(Progress.Range, {}) }) })
|
|
@@ -1374,13 +1409,13 @@ function ImagePopover({ editor, config, disabled }) {
|
|
|
1374
1409
|
const handleUpload = useCallback(
|
|
1375
1410
|
async (file) => {
|
|
1376
1411
|
if (!file.type.startsWith("image/")) {
|
|
1377
|
-
setErrorMessage("
|
|
1412
|
+
setErrorMessage("File must be an image");
|
|
1378
1413
|
setUploadState("error");
|
|
1379
1414
|
return;
|
|
1380
1415
|
}
|
|
1381
1416
|
if (file.size > maxSize) {
|
|
1382
1417
|
const maxSizeMB = (maxSize / 1024 / 1024).toFixed(0);
|
|
1383
|
-
setErrorMessage(
|
|
1418
|
+
setErrorMessage(`Size file\u0430 \u043D\u0435 must \u043F\u0440\u0435\u0432\u044B\u0448\u0430\u0442\u044C ${maxSizeMB}MB`);
|
|
1384
1419
|
setUploadState("error");
|
|
1385
1420
|
return;
|
|
1386
1421
|
}
|
|
@@ -1400,17 +1435,17 @@ function ImagePopover({ editor, config, disabled }) {
|
|
|
1400
1435
|
});
|
|
1401
1436
|
const result = await response.json();
|
|
1402
1437
|
if (!response.ok) {
|
|
1403
|
-
throw new Error(result.error || "
|
|
1438
|
+
throw new Error(result.error || "Upload error");
|
|
1404
1439
|
}
|
|
1405
1440
|
if (result.url) {
|
|
1406
1441
|
;
|
|
1407
1442
|
editor.chain().focus().setImage({ src: result.url }).run();
|
|
1408
1443
|
handleClose();
|
|
1409
1444
|
} else {
|
|
1410
|
-
throw new Error("URL
|
|
1445
|
+
throw new Error("Image URL not received");
|
|
1411
1446
|
}
|
|
1412
1447
|
} catch (err) {
|
|
1413
|
-
setErrorMessage(err instanceof Error ? err.message : "
|
|
1448
|
+
setErrorMessage(err instanceof Error ? err.message : "Upload error");
|
|
1414
1449
|
setUploadState("error");
|
|
1415
1450
|
} finally {
|
|
1416
1451
|
if (preview) {
|
|
@@ -1457,7 +1492,7 @@ function ImagePopover({ editor, config, disabled }) {
|
|
|
1457
1492
|
/* @__PURE__ */ jsx(Popover.Trigger, { asChild: true, children: /* @__PURE__ */ jsx(
|
|
1458
1493
|
IconButton,
|
|
1459
1494
|
{
|
|
1460
|
-
"aria-label": "
|
|
1495
|
+
"aria-label": "Insert image",
|
|
1461
1496
|
size: "sm",
|
|
1462
1497
|
variant: "ghost",
|
|
1463
1498
|
onClick: () => setIsOpen(true),
|
|
@@ -1493,13 +1528,13 @@ function ImagePopover({ editor, config, disabled }) {
|
|
|
1493
1528
|
onClick: () => fileInputRef.current?.click(),
|
|
1494
1529
|
children: /* @__PURE__ */ jsx(Center, { children: /* @__PURE__ */ jsxs(VStack, { gap: 2, children: [
|
|
1495
1530
|
/* @__PURE__ */ jsx(Icon, { fontSize: "2xl", color: "fg.muted", children: /* @__PURE__ */ jsx(LuUpload, {}) }),
|
|
1496
|
-
/* @__PURE__ */ jsx(Text, { fontSize: "sm", fontWeight: "medium", textAlign: "center", children: "
|
|
1497
|
-
/* @__PURE__ */ jsx(Text, { fontSize: "xs", color: "fg.muted", children: "
|
|
1531
|
+
/* @__PURE__ */ jsx(Text, { fontSize: "sm", fontWeight: "medium", textAlign: "center", children: "Drag image here" }),
|
|
1532
|
+
/* @__PURE__ */ jsx(Text, { fontSize: "xs", color: "fg.muted", children: "or click to select" })
|
|
1498
1533
|
] }) })
|
|
1499
1534
|
}
|
|
1500
1535
|
),
|
|
1501
1536
|
/* @__PURE__ */ jsxs(Text, { fontSize: "xs", color: "fg.muted", textAlign: "center", children: [
|
|
1502
|
-
"PNG, JPG, WEBP
|
|
1537
|
+
"PNG, JPG, WEBP up to ",
|
|
1503
1538
|
(maxSize / 1024 / 1024).toFixed(0),
|
|
1504
1539
|
"MB"
|
|
1505
1540
|
] }),
|
|
@@ -1513,24 +1548,24 @@ function ImagePopover({ editor, config, disabled }) {
|
|
|
1513
1548
|
style: { display: "none" }
|
|
1514
1549
|
}
|
|
1515
1550
|
),
|
|
1516
|
-
/* @__PURE__ */ jsx(HStack, { justify: "flex-end", children: /* @__PURE__ */ jsx(Button, { size: "sm", variant: "ghost", onClick: handleClose, children: "
|
|
1551
|
+
/* @__PURE__ */ jsx(HStack, { justify: "flex-end", children: /* @__PURE__ */ jsx(Button, { size: "sm", variant: "ghost", onClick: handleClose, children: "Cancel" }) })
|
|
1517
1552
|
] }),
|
|
1518
1553
|
uploadState === "uploading" && /* @__PURE__ */ jsxs(VStack, { gap: 3, align: "stretch", children: [
|
|
1519
|
-
previewUrl && /* @__PURE__ */ jsx(Box, { borderRadius: "md", overflow: "hidden", bg: "bg.subtle", children: /* @__PURE__ */ jsx(Image, { src: previewUrl, alt: "
|
|
1554
|
+
previewUrl && /* @__PURE__ */ jsx(Box, { borderRadius: "md", overflow: "hidden", bg: "bg.subtle", children: /* @__PURE__ */ jsx(Image, { src: previewUrl, alt: "Preview", maxH: "150px", w: "100%", objectFit: "contain" }) }),
|
|
1520
1555
|
/* @__PURE__ */ jsx(Center, { py: 2, children: /* @__PURE__ */ jsxs(HStack, { gap: 2, children: [
|
|
1521
1556
|
/* @__PURE__ */ jsx(Spinner, { size: "sm", color: "colorPalette.500" }),
|
|
1522
|
-
/* @__PURE__ */ jsx(Text, { fontSize: "sm", color: "fg.muted", children: "
|
|
1557
|
+
/* @__PURE__ */ jsx(Text, { fontSize: "sm", color: "fg.muted", children: "Loading..." })
|
|
1523
1558
|
] }) })
|
|
1524
1559
|
] }),
|
|
1525
1560
|
uploadState === "error" && /* @__PURE__ */ jsxs(VStack, { gap: 3, align: "stretch", children: [
|
|
1526
1561
|
previewUrl && /* @__PURE__ */ jsxs(Box, { borderRadius: "md", overflow: "hidden", bg: "bg.subtle", position: "relative", children: [
|
|
1527
|
-
/* @__PURE__ */ jsx(Image, { src: previewUrl, alt: "
|
|
1562
|
+
/* @__PURE__ */ jsx(Image, { src: previewUrl, alt: "Preview", maxH: "150px", w: "100%", objectFit: "contain", opacity: 0.5 }),
|
|
1528
1563
|
/* @__PURE__ */ jsx(Center, { position: "absolute", inset: 0, bg: "blackAlpha.500", borderRadius: "md", children: /* @__PURE__ */ jsx(Icon, { color: "red.400", fontSize: "2xl", children: /* @__PURE__ */ jsx(LuX, {}) }) })
|
|
1529
1564
|
] }),
|
|
1530
1565
|
/* @__PURE__ */ jsx(Text, { fontSize: "sm", color: "red.400", textAlign: "center", children: errorMessage }),
|
|
1531
1566
|
/* @__PURE__ */ jsxs(HStack, { justify: "center", gap: 2, children: [
|
|
1532
|
-
/* @__PURE__ */ jsx(Button, { size: "sm", variant: "ghost", onClick: handleClose, children: "
|
|
1533
|
-
/* @__PURE__ */ jsx(Button, { size: "sm", colorPalette: "brand", onClick: handleRetry, children: "
|
|
1567
|
+
/* @__PURE__ */ jsx(Button, { size: "sm", variant: "ghost", onClick: handleClose, children: "Cancel" }),
|
|
1568
|
+
/* @__PURE__ */ jsx(Button, { size: "sm", colorPalette: "brand", onClick: handleRetry, children: "Try again" })
|
|
1534
1569
|
] })
|
|
1535
1570
|
] })
|
|
1536
1571
|
] })
|
|
@@ -1579,7 +1614,7 @@ function LinkPopover({ editor, disabled }) {
|
|
|
1579
1614
|
/* @__PURE__ */ jsx(Popover.Trigger, { asChild: true, children: /* @__PURE__ */ jsx(
|
|
1580
1615
|
IconButton,
|
|
1581
1616
|
{
|
|
1582
|
-
"aria-label": isActive ? "
|
|
1617
|
+
"aria-label": isActive ? "Remove \u0441\u0441\u044B\u043B\u043A\u0443" : "Add \u0441\u0441\u044B\u043B\u043A\u0443",
|
|
1583
1618
|
size: "sm",
|
|
1584
1619
|
variant: isActive ? "solid" : "ghost",
|
|
1585
1620
|
colorPalette: isActive ? "brand" : void 0,
|
|
@@ -1603,9 +1638,9 @@ function LinkPopover({ editor, disabled }) {
|
|
|
1603
1638
|
}
|
|
1604
1639
|
) }),
|
|
1605
1640
|
/* @__PURE__ */ jsxs(HStack, { gap: 2, justify: "flex-end", children: [
|
|
1606
|
-
editor.isActive("link") && /* @__PURE__ */ jsx(Button, { size: "sm", variant: "ghost", colorPalette: "red", onClick: handleRemove, children: "
|
|
1607
|
-
/* @__PURE__ */ jsx(Button, { size: "sm", variant: "ghost", onClick: handleClose, children: "
|
|
1608
|
-
/* @__PURE__ */ jsx(Button, { size: "sm", colorPalette: "brand", onClick: handleSubmit, disabled: !url.trim(), children: "
|
|
1641
|
+
editor.isActive("link") && /* @__PURE__ */ jsx(Button, { size: "sm", variant: "ghost", colorPalette: "red", onClick: handleRemove, children: "Remove" }),
|
|
1642
|
+
/* @__PURE__ */ jsx(Button, { size: "sm", variant: "ghost", onClick: handleClose, children: "Cancel" }),
|
|
1643
|
+
/* @__PURE__ */ jsx(Button, { size: "sm", colorPalette: "brand", onClick: handleSubmit, disabled: !url.trim(), children: "Apply" })
|
|
1609
1644
|
] })
|
|
1610
1645
|
] }) })
|
|
1611
1646
|
] }) }) })
|
|
@@ -1630,13 +1665,13 @@ var DEFAULT_TOOLBAR_BUTTONS = [
|
|
|
1630
1665
|
var TOOLBAR_CONFIG = {
|
|
1631
1666
|
bold: {
|
|
1632
1667
|
icon: /* @__PURE__ */ jsx(LuBold, {}),
|
|
1633
|
-
label: "
|
|
1668
|
+
label: "Bold",
|
|
1634
1669
|
action: (editor) => editor?.chain().focus().toggleBold().run(),
|
|
1635
1670
|
isActive: (editor) => editor?.isActive("bold") ?? false
|
|
1636
1671
|
},
|
|
1637
1672
|
italic: {
|
|
1638
1673
|
icon: /* @__PURE__ */ jsx(LuItalic, {}),
|
|
1639
|
-
label: "
|
|
1674
|
+
label: "Italic",
|
|
1640
1675
|
action: (editor) => editor?.chain().focus().toggleItalic().run(),
|
|
1641
1676
|
isActive: (editor) => editor?.isActive("italic") ?? false
|
|
1642
1677
|
},
|
|
@@ -1648,7 +1683,7 @@ var TOOLBAR_CONFIG = {
|
|
|
1648
1683
|
},
|
|
1649
1684
|
strike: {
|
|
1650
1685
|
icon: /* @__PURE__ */ jsx(LuStrikethrough, {}),
|
|
1651
|
-
label: "
|
|
1686
|
+
label: "Strikethrough",
|
|
1652
1687
|
action: (editor) => editor?.chain().focus().toggleStrike().run(),
|
|
1653
1688
|
isActive: (editor) => editor?.isActive("strike") ?? false
|
|
1654
1689
|
},
|
|
@@ -1678,19 +1713,19 @@ var TOOLBAR_CONFIG = {
|
|
|
1678
1713
|
},
|
|
1679
1714
|
bulletList: {
|
|
1680
1715
|
icon: /* @__PURE__ */ jsx(LuList, {}),
|
|
1681
|
-
label: "
|
|
1716
|
+
label: "Bullet list",
|
|
1682
1717
|
action: (editor) => editor?.chain().focus().toggleBulletList().run(),
|
|
1683
1718
|
isActive: (editor) => editor?.isActive("bulletList") ?? false
|
|
1684
1719
|
},
|
|
1685
1720
|
orderedList: {
|
|
1686
1721
|
icon: /* @__PURE__ */ jsx(LuListOrdered, {}),
|
|
1687
|
-
label: "
|
|
1722
|
+
label: "Ordered list",
|
|
1688
1723
|
action: (editor) => editor?.chain().focus().toggleOrderedList().run(),
|
|
1689
1724
|
isActive: (editor) => editor?.isActive("orderedList") ?? false
|
|
1690
1725
|
},
|
|
1691
1726
|
blockquote: {
|
|
1692
1727
|
icon: /* @__PURE__ */ jsx(LuQuote, {}),
|
|
1693
|
-
label: "
|
|
1728
|
+
label: "Quote",
|
|
1694
1729
|
action: (editor) => editor?.chain().focus().toggleBlockquote().run(),
|
|
1695
1730
|
isActive: (editor) => editor?.isActive("blockquote") ?? false
|
|
1696
1731
|
},
|
|
@@ -1711,18 +1746,18 @@ var TOOLBAR_CONFIG = {
|
|
|
1711
1746
|
},
|
|
1712
1747
|
undo: {
|
|
1713
1748
|
icon: /* @__PURE__ */ jsx(LuUndo, {}),
|
|
1714
|
-
label: "
|
|
1749
|
+
label: "Undo",
|
|
1715
1750
|
action: (editor) => editor?.chain().focus().undo().run()
|
|
1716
1751
|
},
|
|
1717
1752
|
redo: {
|
|
1718
1753
|
icon: /* @__PURE__ */ jsx(LuRedo, {}),
|
|
1719
|
-
label: "
|
|
1754
|
+
label: "Redo",
|
|
1720
1755
|
action: (editor) => editor?.chain().focus().redo().run()
|
|
1721
1756
|
},
|
|
1722
|
-
// Кнопка image
|
|
1757
|
+
// Кнопка image processesся отдельно через ImagePopover (аналогично link)
|
|
1723
1758
|
image: {
|
|
1724
1759
|
icon: /* @__PURE__ */ jsx(LuImage, {}),
|
|
1725
|
-
label: "
|
|
1760
|
+
label: "Insert image",
|
|
1726
1761
|
action: () => {
|
|
1727
1762
|
}
|
|
1728
1763
|
}
|
|
@@ -1826,9 +1861,9 @@ function RichTextEditor({
|
|
|
1826
1861
|
}
|
|
1827
1862
|
}),
|
|
1828
1863
|
Placeholder.configure({
|
|
1829
|
-
placeholder: placeholder ?? "
|
|
1864
|
+
placeholder: placeholder ?? "Start typing..."
|
|
1830
1865
|
}),
|
|
1831
|
-
//
|
|
1866
|
+
// Add Image extension only if imageUpload is configured
|
|
1832
1867
|
...imageUpload ? [
|
|
1833
1868
|
TiptapImage.configure({
|
|
1834
1869
|
inline: false,
|
|
@@ -1843,7 +1878,7 @@ function RichTextEditor({
|
|
|
1843
1878
|
}, [placeholder, imageUpload]);
|
|
1844
1879
|
const editor = useEditor({
|
|
1845
1880
|
// Cast needed: minor @tiptap/core version drift (e.g. 3.20.0 vs 3.20.1) causes nominal type mismatch
|
|
1846
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any --
|
|
1881
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- @tiptap/core version incompatibility
|
|
1847
1882
|
extensions,
|
|
1848
1883
|
content: outputFormat === "json" && value ? safeParseJSON(value) : value || "",
|
|
1849
1884
|
editable: !disabled && !readOnly,
|
|
@@ -2421,27 +2456,27 @@ function getPresetRange(preset) {
|
|
|
2421
2456
|
function getPresetLabel(preset) {
|
|
2422
2457
|
switch (preset) {
|
|
2423
2458
|
case "today":
|
|
2424
|
-
return "
|
|
2459
|
+
return "Today";
|
|
2425
2460
|
case "yesterday":
|
|
2426
|
-
return "
|
|
2461
|
+
return "Yesterday";
|
|
2427
2462
|
case "thisWeek":
|
|
2428
|
-
return "
|
|
2463
|
+
return "This week";
|
|
2429
2464
|
case "lastWeek":
|
|
2430
|
-
return "
|
|
2465
|
+
return "Last week";
|
|
2431
2466
|
case "thisMonth":
|
|
2432
|
-
return "
|
|
2467
|
+
return "This month";
|
|
2433
2468
|
case "lastMonth":
|
|
2434
|
-
return "
|
|
2469
|
+
return "Last month";
|
|
2435
2470
|
case "thisYear":
|
|
2436
|
-
return "
|
|
2471
|
+
return "This year";
|
|
2437
2472
|
}
|
|
2438
2473
|
}
|
|
2439
2474
|
var FieldDateRange = createField({
|
|
2440
2475
|
displayName: "FieldDateRange",
|
|
2441
2476
|
render: ({ field, fullPath, resolved, hasError, errorMessage, componentProps }) => {
|
|
2442
2477
|
const {
|
|
2443
|
-
startLabel = "
|
|
2444
|
-
endLabel = "
|
|
2478
|
+
startLabel = "Start",
|
|
2479
|
+
endLabel = "End",
|
|
2445
2480
|
startPlaceholder,
|
|
2446
2481
|
endPlaceholder,
|
|
2447
2482
|
min,
|
|
@@ -2510,7 +2545,7 @@ var FieldDateRange = createField({
|
|
|
2510
2545
|
presets && presets.length > 0 && !resolved.readOnly && /* @__PURE__ */ jsxs(Menu.Root, { children: [
|
|
2511
2546
|
/* @__PURE__ */ jsx(Menu.Trigger, { asChild: true, children: /* @__PURE__ */ jsxs(Button, { variant: "outline", size, disabled: resolved.disabled, children: [
|
|
2512
2547
|
/* @__PURE__ */ jsx(LuCalendar, {}),
|
|
2513
|
-
"
|
|
2548
|
+
"Presets",
|
|
2514
2549
|
/* @__PURE__ */ jsx(LuChevronDown, {})
|
|
2515
2550
|
] }) }),
|
|
2516
2551
|
/* @__PURE__ */ jsx(Portal, { children: /* @__PURE__ */ jsx(Menu.Positioner, { children: /* @__PURE__ */ jsx(Menu.Content, { children: presets.map((preset) => /* @__PURE__ */ jsx(Menu.Item, { value: preset, onClick: () => handlePreset(preset), children: getPresetLabel(preset) }, preset)) }) }) })
|
|
@@ -2659,7 +2694,7 @@ var FieldDuration = createField({
|
|
|
2659
2694
|
/* @__PURE__ */ jsx(NumberInput.IncrementTrigger, {}),
|
|
2660
2695
|
/* @__PURE__ */ jsx(NumberInput.DecrementTrigger, {})
|
|
2661
2696
|
] }),
|
|
2662
|
-
/* @__PURE__ */ jsx(NumberInput.Input, { placeholder: resolved.placeholder ?? "
|
|
2697
|
+
/* @__PURE__ */ jsx(NumberInput.Input, { placeholder: resolved.placeholder ?? "min", "data-field-name": fullPath })
|
|
2663
2698
|
]
|
|
2664
2699
|
}
|
|
2665
2700
|
),
|
|
@@ -2735,13 +2770,13 @@ var FieldDuration = createField({
|
|
|
2735
2770
|
});
|
|
2736
2771
|
var DAYS_OF_WEEK = ["monday", "tuesday", "wednesday", "thursday", "friday", "saturday", "sunday"];
|
|
2737
2772
|
var DEFAULT_DAY_NAMES = {
|
|
2738
|
-
monday: "
|
|
2739
|
-
tuesday: "
|
|
2740
|
-
wednesday: "
|
|
2741
|
-
thursday: "
|
|
2742
|
-
friday: "
|
|
2743
|
-
saturday: "
|
|
2744
|
-
sunday: "
|
|
2773
|
+
monday: "Monday",
|
|
2774
|
+
tuesday: "Tuesday",
|
|
2775
|
+
wednesday: "Wednesday",
|
|
2776
|
+
thursday: "Thursday",
|
|
2777
|
+
friday: "Friday",
|
|
2778
|
+
saturday: "Saturday",
|
|
2779
|
+
sunday: "Sunday"
|
|
2745
2780
|
};
|
|
2746
2781
|
var DEFAULT_WORKING_HOURS = {
|
|
2747
2782
|
monday: { open: "09:00", close: "18:00" },
|
|
@@ -2753,15 +2788,15 @@ var DEFAULT_WORKING_HOURS = {
|
|
|
2753
2788
|
sunday: null
|
|
2754
2789
|
};
|
|
2755
2790
|
var SWITCH_STYLES = {
|
|
2756
|
-
/**
|
|
2791
|
+
/** Switch track width */
|
|
2757
2792
|
trackWidth: "36px",
|
|
2758
|
-
/**
|
|
2793
|
+
/** Switch track height */
|
|
2759
2794
|
trackHeight: "20px",
|
|
2760
|
-
/**
|
|
2795
|
+
/** Round indicator (thumb) size */
|
|
2761
2796
|
thumbSize: "16px",
|
|
2762
|
-
/**
|
|
2797
|
+
/** Thumb offset from edge (2px each side for centering in 20px track) */
|
|
2763
2798
|
thumbOffset: "2px",
|
|
2764
|
-
/**
|
|
2799
|
+
/** Thumb position in enabled state (trackWidth - thumbSize - thumbOffset = 36 - 16 - 2 = 18) */
|
|
2765
2800
|
thumbEnabledLeft: "18px"
|
|
2766
2801
|
};
|
|
2767
2802
|
function isValidTimeRange(open, close) {
|
|
@@ -2851,11 +2886,11 @@ var ScheduleContent = memo(function ScheduleContent2({
|
|
|
2851
2886
|
/* @__PURE__ */ jsx(FieldLabel, { label: resolvedLabel, tooltip: resolvedTooltip, required: resolvedRequired }),
|
|
2852
2887
|
/* @__PURE__ */ jsxs(Stack, { gap: 3, children: [
|
|
2853
2888
|
invalidDays.length > 0 && /* @__PURE__ */ jsx(Box, { p: 3, bg: "red.50", borderWidth: "1px", borderColor: "red.200", borderRadius: "md", children: /* @__PURE__ */ jsxs(Text, { color: "red.600", fontSize: "sm", fontWeight: "medium", children: [
|
|
2854
|
-
"
|
|
2889
|
+
"End time must be after start time: ",
|
|
2855
2890
|
invalidDays.map((d) => mergedDayNames[d]).join(", ")
|
|
2856
2891
|
] }) }),
|
|
2857
2892
|
showCopyToWeekdays && days.includes("monday") && /* @__PURE__ */ jsxs(HStack, { gap: 2, flexWrap: "wrap", children: [
|
|
2858
|
-
/* @__PURE__ */ jsx(Text, { fontSize: "sm", color: "fg.muted", children: "
|
|
2893
|
+
/* @__PURE__ */ jsx(Text, { fontSize: "sm", color: "fg.muted", children: "Quick actions:" }),
|
|
2859
2894
|
/* @__PURE__ */ jsx(
|
|
2860
2895
|
Button,
|
|
2861
2896
|
{
|
|
@@ -2988,8 +3023,8 @@ function FieldSchedule({
|
|
|
2988
3023
|
defaultSchedule = DEFAULT_WORKING_HOURS,
|
|
2989
3024
|
days = DAYS_OF_WEEK,
|
|
2990
3025
|
showCopyToWeekdays = true,
|
|
2991
|
-
offLabel = "
|
|
2992
|
-
copyToWeekdaysLabel = "
|
|
3026
|
+
offLabel = "Day off",
|
|
3027
|
+
copyToWeekdaysLabel = "Copy Mon to weekdays",
|
|
2993
3028
|
defaultOpenTime = "09:00",
|
|
2994
3029
|
defaultCloseTime = "18:00"
|
|
2995
3030
|
}) {
|
|
@@ -3196,19 +3231,19 @@ var FieldAutocomplete = createField({
|
|
|
3196
3231
|
children: [
|
|
3197
3232
|
resolved.label && /* @__PURE__ */ jsx(Combobox.Label, { children: /* @__PURE__ */ jsx(SelectionFieldLabel, { label: resolved.label, tooltip: resolved.tooltip, required: resolved.required }) }),
|
|
3198
3233
|
/* @__PURE__ */ jsxs(Combobox.Control, { children: [
|
|
3199
|
-
/* @__PURE__ */ jsx(Combobox.Input, { placeholder: resolved.placeholder ?? "
|
|
3234
|
+
/* @__PURE__ */ jsx(Combobox.Input, { placeholder: resolved.placeholder ?? "Start typing..." }),
|
|
3200
3235
|
/* @__PURE__ */ jsxs(Combobox.IndicatorGroup, { children: [
|
|
3201
3236
|
fieldState.isLoading && /* @__PURE__ */ jsx(Spinner, { size: "xs" }),
|
|
3202
3237
|
/* @__PURE__ */ jsx(Combobox.Trigger, {})
|
|
3203
3238
|
] })
|
|
3204
3239
|
] }),
|
|
3205
3240
|
/* @__PURE__ */ jsx(Portal, { children: /* @__PURE__ */ jsx(Combobox.Positioner, { children: /* @__PURE__ */ jsxs(Combobox.Content, { children: [
|
|
3206
|
-
fieldState.isLoading && fieldState.suggestions.length === 0 && /* @__PURE__ */ jsx(Combobox.Empty, { children: componentProps.loadingMessage ?? "
|
|
3207
|
-
!fieldState.isLoading && fieldState.suggestions.length === 0 && fieldState.inputValue.length >= minChars && /* @__PURE__ */ jsx(Combobox.Empty, { children: componentProps.emptyMessage ?? "
|
|
3241
|
+
fieldState.isLoading && fieldState.suggestions.length === 0 && /* @__PURE__ */ jsx(Combobox.Empty, { children: componentProps.loadingMessage ?? "Loading..." }),
|
|
3242
|
+
!fieldState.isLoading && fieldState.suggestions.length === 0 && fieldState.inputValue.length >= minChars && /* @__PURE__ */ jsx(Combobox.Empty, { children: componentProps.emptyMessage ?? "No suggestions" }),
|
|
3208
3243
|
!fieldState.isLoading && fieldState.suggestions.length === 0 && fieldState.inputValue.length < minChars && fieldState.inputValue.length > 0 && /* @__PURE__ */ jsxs(Combobox.Empty, { children: [
|
|
3209
|
-
"
|
|
3244
|
+
"Enter at least ",
|
|
3210
3245
|
minChars,
|
|
3211
|
-
"
|
|
3246
|
+
" characters"
|
|
3212
3247
|
] }),
|
|
3213
3248
|
fieldState.suggestions.map((item) => /* @__PURE__ */ jsxs(Combobox.Item, { item, children: [
|
|
3214
3249
|
/* @__PURE__ */ jsx(Combobox.ItemText, { children: item.label }),
|
|
@@ -3358,7 +3393,7 @@ var FieldCombobox = createField({
|
|
|
3358
3393
|
children: [
|
|
3359
3394
|
resolved.label && /* @__PURE__ */ jsx(Combobox.Label, { children: /* @__PURE__ */ jsx(SelectionFieldLabel, { label: resolved.label, tooltip: resolved.tooltip, required: resolved.required }) }),
|
|
3360
3395
|
/* @__PURE__ */ jsxs(Combobox.Control, { children: [
|
|
3361
|
-
/* @__PURE__ */ jsx(Combobox.Input, { placeholder: resolved.placeholder ?? "
|
|
3396
|
+
/* @__PURE__ */ jsx(Combobox.Input, { placeholder: resolved.placeholder ?? "Search..." }),
|
|
3362
3397
|
/* @__PURE__ */ jsxs(Combobox.IndicatorGroup, { children: [
|
|
3363
3398
|
fieldState.isLoading && /* @__PURE__ */ jsx(Spinner, { size: "xs" }),
|
|
3364
3399
|
fieldState.resolvedClearable && /* @__PURE__ */ jsx(Combobox.ClearTrigger, {}),
|
|
@@ -3366,12 +3401,12 @@ var FieldCombobox = createField({
|
|
|
3366
3401
|
] })
|
|
3367
3402
|
] }),
|
|
3368
3403
|
/* @__PURE__ */ jsx(Portal, { children: /* @__PURE__ */ jsx(Combobox.Positioner, { children: /* @__PURE__ */ jsxs(Combobox.Content, { children: [
|
|
3369
|
-
fieldState.isLoading && fieldState.options.length === 0 && /* @__PURE__ */ jsx(Combobox.Empty, { children: componentProps.loadingMessage ?? "
|
|
3370
|
-
!fieldState.isLoading && fieldState.options.length === 0 && fieldState.inputValue.length >= minChars && /* @__PURE__ */ jsx(Combobox.Empty, { children: componentProps.emptyMessage ?? "
|
|
3404
|
+
fieldState.isLoading && fieldState.options.length === 0 && /* @__PURE__ */ jsx(Combobox.Empty, { children: componentProps.loadingMessage ?? "Loading..." }),
|
|
3405
|
+
!fieldState.isLoading && fieldState.options.length === 0 && fieldState.inputValue.length >= minChars && /* @__PURE__ */ jsx(Combobox.Empty, { children: componentProps.emptyMessage ?? "Nothing found" }),
|
|
3371
3406
|
!fieldState.isLoading && fieldState.options.length === 0 && fieldState.inputValue.length < minChars && fieldState.inputValue.length > 0 && /* @__PURE__ */ jsxs(Combobox.Empty, { children: [
|
|
3372
|
-
"
|
|
3407
|
+
"Enter at least ",
|
|
3373
3408
|
minChars,
|
|
3374
|
-
"
|
|
3409
|
+
" characters"
|
|
3375
3410
|
] }),
|
|
3376
3411
|
fieldState.groups ? Array.from(fieldState.groups.entries()).map(([groupName, groupOptions]) => /* @__PURE__ */ jsxs(Combobox.ItemGroup, { children: [
|
|
3377
3412
|
groupName && /* @__PURE__ */ jsx(Combobox.ItemGroupLabel, { children: groupName }),
|
|
@@ -3380,7 +3415,7 @@ var FieldCombobox = createField({
|
|
|
3380
3415
|
/* @__PURE__ */ jsx(Combobox.ItemIndicator, {})
|
|
3381
3416
|
] }, opt.value))
|
|
3382
3417
|
] }, groupName)) : (
|
|
3383
|
-
/*
|
|
3418
|
+
/* Flat options */
|
|
3384
3419
|
fieldState.options.map((opt) => /* @__PURE__ */ jsxs(Combobox.Item, { item: opt, children: [
|
|
3385
3420
|
/* @__PURE__ */ jsx(Combobox.ItemText, { children: getOptionLabel(opt) }),
|
|
3386
3421
|
/* @__PURE__ */ jsx(Combobox.ItemIndicator, {})
|
|
@@ -3433,7 +3468,7 @@ var FieldListbox = createField({
|
|
|
3433
3468
|
children: [
|
|
3434
3469
|
resolved.label && /* @__PURE__ */ jsx(Listbox.Label, { fontSize: componentProps.size ?? "md", children: /* @__PURE__ */ jsx(SelectionFieldLabel, { label: resolved.label, tooltip: resolved.tooltip, required: resolved.required }) }),
|
|
3435
3470
|
/* @__PURE__ */ jsx(Listbox.Content, { maxH: componentProps.maxHeight, children: fieldState.groups ? (
|
|
3436
|
-
/*
|
|
3471
|
+
/* Grouped options */
|
|
3437
3472
|
Array.from(fieldState.groups.entries()).map(([groupName, groupOptions]) => /* @__PURE__ */ jsxs(Listbox.ItemGroup, { children: [
|
|
3438
3473
|
groupName && /* @__PURE__ */ jsx(Listbox.ItemGroupLabel, { children: groupName }),
|
|
3439
3474
|
groupOptions.map((opt) => /* @__PURE__ */ jsxs(Listbox.Item, { item: opt, children: [
|
|
@@ -3442,7 +3477,7 @@ var FieldListbox = createField({
|
|
|
3442
3477
|
] }, opt.value))
|
|
3443
3478
|
] }, groupName))
|
|
3444
3479
|
) : (
|
|
3445
|
-
/*
|
|
3480
|
+
/* Flat options */
|
|
3446
3481
|
componentProps.options.map((opt) => /* @__PURE__ */ jsxs(Listbox.Item, { item: opt, children: [
|
|
3447
3482
|
/* @__PURE__ */ jsx(Listbox.ItemText, { children: getOptionLabel(opt) }),
|
|
3448
3483
|
/* @__PURE__ */ jsx(Listbox.ItemIndicator, {})
|
|
@@ -3574,6 +3609,10 @@ var FieldRadioGroup = createField({
|
|
|
3574
3609
|
disabled: resolved.disabled,
|
|
3575
3610
|
readOnly: resolved.readOnly,
|
|
3576
3611
|
"data-field-name": fullPath,
|
|
3612
|
+
display: "flex",
|
|
3613
|
+
flexDirection: componentProps.orientation === "horizontal" ? "row" : "column",
|
|
3614
|
+
gap: componentProps.orientation === "horizontal" ? 4 : 2,
|
|
3615
|
+
flexWrap: "wrap",
|
|
3577
3616
|
children: componentProps.options.map((opt) => /* @__PURE__ */ jsxs(RadioGroup.Item, { value: opt.value, disabled: opt.disabled, children: [
|
|
3578
3617
|
/* @__PURE__ */ jsx(RadioGroup.ItemHiddenInput, { onBlur: field.handleBlur }),
|
|
3579
3618
|
/* @__PURE__ */ jsx(RadioGroup.ItemIndicator, {}),
|
|
@@ -3751,10 +3790,61 @@ var FieldTags = createField({
|
|
|
3751
3790
|
);
|
|
3752
3791
|
}
|
|
3753
3792
|
});
|
|
3793
|
+
|
|
3794
|
+
// src/lib/declarative/form-fields/specialized/providers/dadata.ts
|
|
3795
|
+
var DADATA_URL = "https://suggestions.dadata.ru/suggestions/api/4_1/rs/suggest/address";
|
|
3796
|
+
function createDaDataProvider(config) {
|
|
3797
|
+
const { token, baseUrl = DADATA_URL } = config;
|
|
3798
|
+
return {
|
|
3799
|
+
async getSuggestions(query, options) {
|
|
3800
|
+
const body = {
|
|
3801
|
+
query,
|
|
3802
|
+
count: options?.count ?? 10
|
|
3803
|
+
};
|
|
3804
|
+
if (options?.bounds) {
|
|
3805
|
+
if (options.bounds.from) body.from_bound = { value: options.bounds.from };
|
|
3806
|
+
if (options.bounds.to) body.to_bound = { value: options.bounds.to };
|
|
3807
|
+
}
|
|
3808
|
+
if (options?.filters) {
|
|
3809
|
+
body.locations = [options.filters];
|
|
3810
|
+
}
|
|
3811
|
+
const response = await fetch(baseUrl, {
|
|
3812
|
+
method: "POST",
|
|
3813
|
+
headers: {
|
|
3814
|
+
"Content-Type": "application/json",
|
|
3815
|
+
Accept: "application/json",
|
|
3816
|
+
Authorization: `Token ${token}`
|
|
3817
|
+
},
|
|
3818
|
+
body: JSON.stringify(body)
|
|
3819
|
+
});
|
|
3820
|
+
if (!response.ok) {
|
|
3821
|
+
return [];
|
|
3822
|
+
}
|
|
3823
|
+
const data = await response.json();
|
|
3824
|
+
const suggestions = data.suggestions ?? [];
|
|
3825
|
+
return suggestions.map(
|
|
3826
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
3827
|
+
(s) => ({
|
|
3828
|
+
label: s.value,
|
|
3829
|
+
value: s.value,
|
|
3830
|
+
data: s.data
|
|
3831
|
+
})
|
|
3832
|
+
);
|
|
3833
|
+
}
|
|
3834
|
+
};
|
|
3835
|
+
}
|
|
3836
|
+
function useAddressProvider(propProvider, token) {
|
|
3837
|
+
const formContext2 = useDeclarativeFormOptional();
|
|
3838
|
+
if (propProvider) return propProvider;
|
|
3839
|
+
if (formContext2?.addressProvider) return formContext2.addressProvider;
|
|
3840
|
+
if (token) return createDaDataProvider({ token });
|
|
3841
|
+
return null;
|
|
3842
|
+
}
|
|
3754
3843
|
var FieldAddress = createField({
|
|
3755
3844
|
displayName: "FieldAddress",
|
|
3756
3845
|
useFieldState: (props) => {
|
|
3757
|
-
const { token, minChars = 3, debounceMs = 300, locations } = props;
|
|
3846
|
+
const { provider: propProvider, token, minChars = 3, debounceMs = 300, locations } = props;
|
|
3847
|
+
const provider = useAddressProvider(propProvider, token);
|
|
3758
3848
|
const [inputValue, setInputValue] = useState("");
|
|
3759
3849
|
const [suggestions, setSuggestions] = useState([]);
|
|
3760
3850
|
const [isLoading, setIsLoading] = useState(false);
|
|
@@ -3765,38 +3855,26 @@ var FieldAddress = createField({
|
|
|
3765
3855
|
const debouncedQuery = useDebounce(inputValue, debounceMs);
|
|
3766
3856
|
const fetchSuggestions = useCallback(
|
|
3767
3857
|
async (query) => {
|
|
3768
|
-
if (query.length < minChars) {
|
|
3858
|
+
if (query.length < minChars || !provider) {
|
|
3769
3859
|
setSuggestions([]);
|
|
3770
3860
|
return;
|
|
3771
3861
|
}
|
|
3772
3862
|
setIsLoading(true);
|
|
3773
3863
|
try {
|
|
3774
|
-
const
|
|
3775
|
-
|
|
3776
|
-
|
|
3777
|
-
"Content-Type": "application/json",
|
|
3778
|
-
Accept: "application/json",
|
|
3779
|
-
Authorization: `Token ${token}`
|
|
3780
|
-
},
|
|
3781
|
-
body: JSON.stringify({
|
|
3782
|
-
query,
|
|
3783
|
-
count: 10,
|
|
3784
|
-
locations
|
|
3785
|
-
})
|
|
3864
|
+
const results = await provider.getSuggestions(query, {
|
|
3865
|
+
count: 10,
|
|
3866
|
+
filters: locations ? Object.assign({}, ...locations) : void 0
|
|
3786
3867
|
});
|
|
3787
|
-
|
|
3788
|
-
|
|
3789
|
-
setSuggestions(data.suggestions || []);
|
|
3790
|
-
setIsOpen(true);
|
|
3791
|
-
}
|
|
3868
|
+
setSuggestions(results);
|
|
3869
|
+
setIsOpen(true);
|
|
3792
3870
|
} catch (error) {
|
|
3793
|
-
console.error("
|
|
3871
|
+
console.error("Error loading address suggestions:", error);
|
|
3794
3872
|
setSuggestions([]);
|
|
3795
3873
|
} finally {
|
|
3796
3874
|
setIsLoading(false);
|
|
3797
3875
|
}
|
|
3798
3876
|
},
|
|
3799
|
-
[
|
|
3877
|
+
[provider, minChars, locations]
|
|
3800
3878
|
);
|
|
3801
3879
|
useEffect(() => {
|
|
3802
3880
|
if (debouncedQuery) {
|
|
@@ -3918,7 +3996,7 @@ var FieldAddress = createField({
|
|
|
3918
3996
|
},
|
|
3919
3997
|
onBlur: field.handleBlur,
|
|
3920
3998
|
onKeyDown: handleKeyDown,
|
|
3921
|
-
placeholder: resolved.placeholder ?? "
|
|
3999
|
+
placeholder: resolved.placeholder ?? "Start typing address...",
|
|
3922
4000
|
"data-field-name": fullPath
|
|
3923
4001
|
}
|
|
3924
4002
|
),
|
|
@@ -3946,7 +4024,7 @@ var FieldAddress = createField({
|
|
|
3946
4024
|
_hover: { bg: "bg.muted" },
|
|
3947
4025
|
onClick: () => handleSelect(suggestion),
|
|
3948
4026
|
onMouseEnter: () => setHighlightedIndex(index),
|
|
3949
|
-
children: /* @__PURE__ */ jsx(Text, { fontSize: "sm", children: suggestion.
|
|
4027
|
+
children: /* @__PURE__ */ jsx(Text, { fontSize: "sm", children: suggestion.label })
|
|
3950
4028
|
},
|
|
3951
4029
|
suggestion.value + index
|
|
3952
4030
|
))
|
|
@@ -4074,11 +4152,11 @@ var FieldFileUpload = createField({
|
|
|
4074
4152
|
variant = "button",
|
|
4075
4153
|
showSize = false,
|
|
4076
4154
|
clearable = true,
|
|
4077
|
-
dropzoneLabel = "
|
|
4155
|
+
dropzoneLabel = "Drag and drop files here",
|
|
4078
4156
|
dropzoneDescription,
|
|
4079
|
-
buttonText = "
|
|
4157
|
+
buttonText = "Upload file"
|
|
4080
4158
|
} = componentProps;
|
|
4081
|
-
const placeholder = resolved.placeholder ?? "
|
|
4159
|
+
const placeholder = resolved.placeholder ?? "Select file(s)";
|
|
4082
4160
|
const normalizedAccept = accept ? typeof accept === "string" ? accept.split(",").map((s) => s.trim()) : accept : void 0;
|
|
4083
4161
|
const isImageUpload = normalizedAccept?.some((type) => type.startsWith("image/") || type === "image/*");
|
|
4084
4162
|
return /* @__PURE__ */ jsxs(Field.Root, { invalid: hasError, required: resolved.required, disabled: resolved.disabled, children: [
|
|
@@ -4120,7 +4198,7 @@ var FieldFileUpload = createField({
|
|
|
4120
4198
|
if (acceptedFiles.length > 1) {
|
|
4121
4199
|
return /* @__PURE__ */ jsxs("span", { children: [
|
|
4122
4200
|
acceptedFiles.length,
|
|
4123
|
-
"
|
|
4201
|
+
" files"
|
|
4124
4202
|
] });
|
|
4125
4203
|
}
|
|
4126
4204
|
return /* @__PURE__ */ jsx(Text, { color: "fg.subtle", children: placeholder });
|
|
@@ -4194,9 +4272,9 @@ var FieldOTPInput = createField({
|
|
|
4194
4272
|
}
|
|
4195
4273
|
),
|
|
4196
4274
|
onResend && /* @__PURE__ */ jsx(HStack, { mt: 3, justify: "center", children: countdown > 0 ? /* @__PURE__ */ jsxs(Text, { fontSize: "sm", color: "fg.muted", children: [
|
|
4197
|
-
"
|
|
4275
|
+
"Redo in ",
|
|
4198
4276
|
formatCountdown(countdown)
|
|
4199
|
-
] }) : /* @__PURE__ */ jsx(Button, { variant: "ghost", size: "sm", onClick: handleResend, disabled: isResending, loading: isResending, children: "
|
|
4277
|
+
] }) : /* @__PURE__ */ jsx(Button, { variant: "ghost", size: "sm", onClick: handleResend, disabled: isResending, loading: isResending, children: "Submit again" }) })
|
|
4200
4278
|
] }) });
|
|
4201
4279
|
}
|
|
4202
4280
|
});
|
|
@@ -4702,7 +4780,7 @@ function renderFieldByType(type, props) {
|
|
|
4702
4780
|
const selectOptions = resolveSelectOptions(fieldProps, relationOptions, enumValues);
|
|
4703
4781
|
const nativeSelectOptions = resolveNativeSelectOptions(fieldProps, relationOptions, enumValues);
|
|
4704
4782
|
switch (type) {
|
|
4705
|
-
//
|
|
4783
|
+
// Text fields
|
|
4706
4784
|
case "string":
|
|
4707
4785
|
return /* @__PURE__ */ jsx(
|
|
4708
4786
|
FieldString,
|
|
@@ -4726,7 +4804,7 @@ function renderFieldByType(type, props) {
|
|
|
4726
4804
|
return /* @__PURE__ */ jsx(FieldEditable, { ...baseProps, ...fieldProps }, name);
|
|
4727
4805
|
case "richText":
|
|
4728
4806
|
return /* @__PURE__ */ jsx(FieldRichText, { ...baseProps, ...fieldProps }, name);
|
|
4729
|
-
//
|
|
4807
|
+
// Number fields
|
|
4730
4808
|
case "number":
|
|
4731
4809
|
return /* @__PURE__ */ jsx(
|
|
4732
4810
|
FieldNumber,
|
|
@@ -4769,7 +4847,7 @@ function renderFieldByType(type, props) {
|
|
|
4769
4847
|
return /* @__PURE__ */ jsx(FieldCurrency, { ...baseProps, ...fieldProps }, name);
|
|
4770
4848
|
case "percentage":
|
|
4771
4849
|
return /* @__PURE__ */ jsx(FieldPercentage, { ...baseProps, ...fieldProps }, name);
|
|
4772
|
-
//
|
|
4850
|
+
// Date and time
|
|
4773
4851
|
case "date":
|
|
4774
4852
|
return /* @__PURE__ */ jsx(
|
|
4775
4853
|
FieldDate,
|
|
@@ -4791,13 +4869,13 @@ function renderFieldByType(type, props) {
|
|
|
4791
4869
|
return /* @__PURE__ */ jsx(FieldDuration, { ...baseProps, ...fieldProps }, name);
|
|
4792
4870
|
case "schedule":
|
|
4793
4871
|
return /* @__PURE__ */ jsx(FieldSchedule, { ...baseProps, ...fieldProps }, name);
|
|
4794
|
-
//
|
|
4872
|
+
// Boolean fields
|
|
4795
4873
|
case "checkbox":
|
|
4796
4874
|
return /* @__PURE__ */ jsx(FieldCheckbox, { ...baseProps, ...fieldProps }, name);
|
|
4797
4875
|
case "switch":
|
|
4798
4876
|
return /* @__PURE__ */ jsx(FieldSwitch, { ...baseProps, ...fieldProps }, name);
|
|
4799
|
-
//
|
|
4800
|
-
// Options
|
|
4877
|
+
// Selection from list
|
|
4878
|
+
// Options resolved with priority: fieldProps.options > relationOptions > enumValues
|
|
4801
4879
|
case "select":
|
|
4802
4880
|
return /* @__PURE__ */ jsx(FieldSelect, { ...baseProps, options: selectOptions ?? [], ...fieldProps }, name);
|
|
4803
4881
|
case "nativeSelect":
|
|
@@ -4818,7 +4896,7 @@ function renderFieldByType(type, props) {
|
|
|
4818
4896
|
return /* @__PURE__ */ jsx(FieldCheckboxCard, { ...baseProps, options: selectOptions ?? [], ...fieldProps }, name);
|
|
4819
4897
|
case "tags":
|
|
4820
4898
|
return /* @__PURE__ */ jsx(FieldTags, { ...baseProps, ...fieldProps }, name);
|
|
4821
|
-
//
|
|
4899
|
+
// Specialized fields
|
|
4822
4900
|
case "phone":
|
|
4823
4901
|
return /* @__PURE__ */ jsx(FieldPhone, { ...baseProps, ...fieldProps }, name);
|
|
4824
4902
|
case "address": {
|
|
@@ -5169,7 +5247,7 @@ function analyzeArrayElement(elementSchema, parentPath, ctx) {
|
|
|
5169
5247
|
ui: getUIMeta2(elementSchema),
|
|
5170
5248
|
required: isRequired(elementSchema),
|
|
5171
5249
|
constraints: {}
|
|
5172
|
-
// Constraints
|
|
5250
|
+
// Constraints for elements are determined separately
|
|
5173
5251
|
};
|
|
5174
5252
|
if (zodType === "object" && unwrapped._zod?.def?.shape) {
|
|
5175
5253
|
const children = traverseSchemaShape(unwrapped._zod.def.shape, path, { ...ctx, depth: ctx.depth + 1 });
|
|
@@ -5257,11 +5335,11 @@ function renderField(field, recursive, fieldWrapper) {
|
|
|
5257
5335
|
emptyContent: /* @__PURE__ */ jsx(EmptyArrayContent, { label: ui?.title ?? name }),
|
|
5258
5336
|
wrapper: ({ children }) => /* @__PURE__ */ jsxs(VStack, { align: "stretch", gap: 2, children: [
|
|
5259
5337
|
children,
|
|
5260
|
-
/* @__PURE__ */ jsx(ListButtonAdd, { defaultValue: createDefaultValue(elementChildren), children: "
|
|
5338
|
+
/* @__PURE__ */ jsx(ListButtonAdd, { defaultValue: createDefaultValue(elementChildren), children: "Add" })
|
|
5261
5339
|
] }),
|
|
5262
5340
|
children: /* @__PURE__ */ jsxs(VStack, { align: "stretch", gap: 2, p: 2, borderWidth: 1, borderRadius: "md", children: [
|
|
5263
5341
|
elementChildren.map((child) => renderField(child, recursive, fieldWrapper)),
|
|
5264
|
-
/* @__PURE__ */ jsx(ListButtonRemove, { children: "
|
|
5342
|
+
/* @__PURE__ */ jsx(ListButtonRemove, { children: "Remove" })
|
|
5265
5343
|
] })
|
|
5266
5344
|
},
|
|
5267
5345
|
name
|
|
@@ -5280,7 +5358,7 @@ function renderField(field, recursive, fieldWrapper) {
|
|
|
5280
5358
|
}
|
|
5281
5359
|
function EmptyArrayContent({ label }) {
|
|
5282
5360
|
return /* @__PURE__ */ jsxs(VStack, { py: 4, color: "fg.muted", children: [
|
|
5283
|
-
'
|
|
5361
|
+
'No items in "',
|
|
5284
5362
|
label,
|
|
5285
5363
|
'"'
|
|
5286
5364
|
] });
|
|
@@ -5320,7 +5398,7 @@ function createDefaultValue(children) {
|
|
|
5320
5398
|
function FormAutoFields({ include, exclude, recursive = true, fieldWrapper }) {
|
|
5321
5399
|
const { schema } = useDeclarativeForm();
|
|
5322
5400
|
if (!schema) {
|
|
5323
|
-
throw new Error("Form.AutoFields
|
|
5401
|
+
throw new Error("Form.AutoFields requires schema prop on Form component");
|
|
5324
5402
|
}
|
|
5325
5403
|
const allFields = traverseSchema(schema);
|
|
5326
5404
|
const fields = filterFields(allFields, { include, exclude });
|
|
@@ -5405,7 +5483,7 @@ function CascadingSelectContent({
|
|
|
5405
5483
|
const newOptions = Array.isArray(result) ? result : result.options;
|
|
5406
5484
|
setOptions(newOptions);
|
|
5407
5485
|
} catch (error) {
|
|
5408
|
-
console.error("
|
|
5486
|
+
console.error("Error loading cascading select options:", error);
|
|
5409
5487
|
setOptions([]);
|
|
5410
5488
|
} finally {
|
|
5411
5489
|
setIsLoading(false);
|
|
@@ -5534,11 +5612,20 @@ function FieldCascadingSelect(props) {
|
|
|
5534
5612
|
) });
|
|
5535
5613
|
}
|
|
5536
5614
|
FieldCascadingSelect.displayName = "FieldCascadingSelect";
|
|
5615
|
+
function useCityProvider(propProvider, token) {
|
|
5616
|
+
const formContext2 = useDeclarativeFormOptional();
|
|
5617
|
+
if (propProvider) return propProvider;
|
|
5618
|
+
if (formContext2?.addressProvider) return formContext2.addressProvider;
|
|
5619
|
+
if (token) return createDaDataProvider({ token });
|
|
5620
|
+
const envKey = typeof window !== "undefined" ? process.env.NEXT_PUBLIC_DADATA_API_KEY : "";
|
|
5621
|
+
if (envKey) return createDaDataProvider({ token: envKey });
|
|
5622
|
+
return null;
|
|
5623
|
+
}
|
|
5537
5624
|
var FieldCity = createField({
|
|
5538
5625
|
displayName: "FieldCity",
|
|
5539
5626
|
useFieldState: (props) => {
|
|
5540
|
-
const { token, minChars = 2, debounceMs = 300 } = props;
|
|
5541
|
-
const
|
|
5627
|
+
const { provider: propProvider, token, minChars = 2, debounceMs = 300 } = props;
|
|
5628
|
+
const provider = useCityProvider(propProvider, token);
|
|
5542
5629
|
const [inputValue, setInputValue] = useState("");
|
|
5543
5630
|
const [suggestions, setSuggestions] = useState([]);
|
|
5544
5631
|
const [isLoading, setIsLoading] = useState(false);
|
|
@@ -5550,39 +5637,26 @@ var FieldCity = createField({
|
|
|
5550
5637
|
const initializedRef = useRef(false);
|
|
5551
5638
|
const fetchSuggestions = useCallback(
|
|
5552
5639
|
async (query) => {
|
|
5553
|
-
if (query.length < minChars || !
|
|
5640
|
+
if (query.length < minChars || !provider) {
|
|
5554
5641
|
setSuggestions([]);
|
|
5555
5642
|
return;
|
|
5556
5643
|
}
|
|
5557
5644
|
setIsLoading(true);
|
|
5558
5645
|
try {
|
|
5559
|
-
const
|
|
5560
|
-
|
|
5561
|
-
|
|
5562
|
-
"Content-Type": "application/json",
|
|
5563
|
-
Accept: "application/json",
|
|
5564
|
-
Authorization: `Token ${apiKey}`
|
|
5565
|
-
},
|
|
5566
|
-
body: JSON.stringify({
|
|
5567
|
-
query,
|
|
5568
|
-
count: 7,
|
|
5569
|
-
from_bound: { value: "city" },
|
|
5570
|
-
to_bound: { value: "settlement" }
|
|
5571
|
-
})
|
|
5646
|
+
const results = await provider.getSuggestions(query, {
|
|
5647
|
+
count: 7,
|
|
5648
|
+
bounds: { from: "city", to: "settlement" }
|
|
5572
5649
|
});
|
|
5573
|
-
|
|
5574
|
-
|
|
5575
|
-
setSuggestions(data.suggestions || []);
|
|
5576
|
-
setIsOpen(data.suggestions?.length > 0);
|
|
5577
|
-
}
|
|
5650
|
+
setSuggestions(results);
|
|
5651
|
+
setIsOpen(results.length > 0);
|
|
5578
5652
|
} catch (error) {
|
|
5579
|
-
console.error("
|
|
5653
|
+
console.error("Error loading city suggestions:", error);
|
|
5580
5654
|
setSuggestions([]);
|
|
5581
5655
|
} finally {
|
|
5582
5656
|
setIsLoading(false);
|
|
5583
5657
|
}
|
|
5584
5658
|
},
|
|
5585
|
-
[
|
|
5659
|
+
[provider, minChars]
|
|
5586
5660
|
);
|
|
5587
5661
|
useEffect(() => {
|
|
5588
5662
|
if (justSelectedRef.current) {
|
|
@@ -5642,7 +5716,7 @@ var FieldCity = createField({
|
|
|
5642
5716
|
setInputValue(fieldValue);
|
|
5643
5717
|
}
|
|
5644
5718
|
const handleSelect = (suggestion) => {
|
|
5645
|
-
const cityName = suggestion.data
|
|
5719
|
+
const cityName = suggestion.data?.city || suggestion.data?.settlement || suggestion.value;
|
|
5646
5720
|
justSelectedRef.current = true;
|
|
5647
5721
|
setInputValue(cityName);
|
|
5648
5722
|
setIsOpen(false);
|
|
@@ -5699,9 +5773,14 @@ var FieldCity = createField({
|
|
|
5699
5773
|
setIsOpen(true);
|
|
5700
5774
|
}
|
|
5701
5775
|
},
|
|
5702
|
-
onBlur:
|
|
5776
|
+
onBlur: () => {
|
|
5777
|
+
if (inputValue && inputValue !== field.state.value) {
|
|
5778
|
+
field.handleChange(inputValue);
|
|
5779
|
+
}
|
|
5780
|
+
field.handleBlur();
|
|
5781
|
+
},
|
|
5703
5782
|
onKeyDown: handleKeyDown,
|
|
5704
|
-
placeholder: resolved.placeholder ?? "
|
|
5783
|
+
placeholder: resolved.placeholder ?? "Enter city",
|
|
5705
5784
|
"data-field-name": fullPath
|
|
5706
5785
|
}
|
|
5707
5786
|
),
|
|
@@ -5730,9 +5809,9 @@ var FieldCity = createField({
|
|
|
5730
5809
|
_hover: { bg: "bg.muted" },
|
|
5731
5810
|
onClick: () => handleSelect(suggestion),
|
|
5732
5811
|
onMouseEnter: () => setHighlightedIndex(index),
|
|
5733
|
-
children: /* @__PURE__ */ jsx(Text, { fontSize: "sm", children: suggestion.
|
|
5812
|
+
children: /* @__PURE__ */ jsx(Text, { fontSize: "sm", children: suggestion.label })
|
|
5734
5813
|
},
|
|
5735
|
-
`${suggestion.
|
|
5814
|
+
`${suggestion.value}-${index}`
|
|
5736
5815
|
))
|
|
5737
5816
|
}
|
|
5738
5817
|
)
|
|
@@ -5743,6 +5822,61 @@ var FieldCity = createField({
|
|
|
5743
5822
|
);
|
|
5744
5823
|
}
|
|
5745
5824
|
});
|
|
5825
|
+
function useIsDarkMode() {
|
|
5826
|
+
const [isDark, setIsDark] = useState(false);
|
|
5827
|
+
useEffect(() => {
|
|
5828
|
+
const check = () => {
|
|
5829
|
+
const html = document.documentElement;
|
|
5830
|
+
const isDarkNow = html.classList.contains("dark") || html.getAttribute("data-theme") === "dark" || html.style.colorScheme === "dark";
|
|
5831
|
+
setIsDark(isDarkNow);
|
|
5832
|
+
};
|
|
5833
|
+
check();
|
|
5834
|
+
const observer = new MutationObserver(check);
|
|
5835
|
+
observer.observe(document.documentElement, {
|
|
5836
|
+
attributes: true,
|
|
5837
|
+
attributeFilter: ["class", "data-theme", "style"]
|
|
5838
|
+
});
|
|
5839
|
+
return () => observer.disconnect();
|
|
5840
|
+
}, []);
|
|
5841
|
+
return isDark;
|
|
5842
|
+
}
|
|
5843
|
+
function FormDebugValues({
|
|
5844
|
+
title = "Form Values",
|
|
5845
|
+
collapsed = 2,
|
|
5846
|
+
showInProduction = false
|
|
5847
|
+
}) {
|
|
5848
|
+
const { form } = useDeclarativeForm();
|
|
5849
|
+
const isDark = useIsDarkMode();
|
|
5850
|
+
if (process.env.NODE_ENV === "production" && !showInProduction) {
|
|
5851
|
+
return null;
|
|
5852
|
+
}
|
|
5853
|
+
const jsonTheme = isDark ? githubDarkTheme : githubLightTheme;
|
|
5854
|
+
return /* @__PURE__ */ jsx(form.Subscribe, { selector: (state) => state.values, children: (values) => /* @__PURE__ */ jsxs(
|
|
5855
|
+
Box,
|
|
5856
|
+
{
|
|
5857
|
+
borderWidth: "1px",
|
|
5858
|
+
borderColor: "border.muted",
|
|
5859
|
+
borderRadius: "md",
|
|
5860
|
+
p: 3,
|
|
5861
|
+
mt: 4,
|
|
5862
|
+
fontSize: "sm",
|
|
5863
|
+
fontFamily: "mono",
|
|
5864
|
+
bg: "bg.subtle",
|
|
5865
|
+
children: [
|
|
5866
|
+
title && /* @__PURE__ */ jsx(Heading, { size: "xs", mb: 2, color: "fg.muted", children: title }),
|
|
5867
|
+
/* @__PURE__ */ jsx(
|
|
5868
|
+
JsonView,
|
|
5869
|
+
{
|
|
5870
|
+
value: values,
|
|
5871
|
+
collapsed,
|
|
5872
|
+
displayDataTypes: false,
|
|
5873
|
+
style: { ...jsonTheme, backgroundColor: "transparent" }
|
|
5874
|
+
}
|
|
5875
|
+
)
|
|
5876
|
+
]
|
|
5877
|
+
}
|
|
5878
|
+
) });
|
|
5879
|
+
}
|
|
5746
5880
|
|
|
5747
5881
|
// src/lib/declarative/form-root/form-validators.ts
|
|
5748
5882
|
function buildValidators(schema, validateOn) {
|
|
@@ -5964,7 +6098,7 @@ function useFormFeatures({
|
|
|
5964
6098
|
}
|
|
5965
6099
|
return { success: true };
|
|
5966
6100
|
} catch (error) {
|
|
5967
|
-
return { success: false, error: error instanceof Error ? error.message : "
|
|
6101
|
+
return { success: false, error: error instanceof Error ? error.message : "Error \u043E\u0442\u043F\u0440\u0430\u0432\u043A\u0438" };
|
|
5968
6102
|
}
|
|
5969
6103
|
},
|
|
5970
6104
|
[onlineSubmit, isPersistenceEnabled, persistenceResult]
|
|
@@ -6053,7 +6187,9 @@ function FormSimple({
|
|
|
6053
6187
|
validateOn,
|
|
6054
6188
|
disabled,
|
|
6055
6189
|
readOnly,
|
|
6190
|
+
debug,
|
|
6056
6191
|
middleware,
|
|
6192
|
+
addressProvider,
|
|
6057
6193
|
children
|
|
6058
6194
|
}) {
|
|
6059
6195
|
const features = useFormFeatures({
|
|
@@ -6110,13 +6246,14 @@ function FormSimple({
|
|
|
6110
6246
|
schema,
|
|
6111
6247
|
offlineState: features.offlineState,
|
|
6112
6248
|
disabled,
|
|
6113
|
-
readOnly
|
|
6249
|
+
readOnly,
|
|
6250
|
+
addressProvider
|
|
6114
6251
|
}),
|
|
6115
|
-
[form, schema, features.offlineState, disabled, readOnly]
|
|
6252
|
+
[form, schema, features.offlineState, disabled, readOnly, addressProvider]
|
|
6116
6253
|
);
|
|
6117
6254
|
return /* @__PURE__ */ jsxs(DeclarativeFormContext.Provider, { value: contextValue, children: [
|
|
6118
6255
|
features.isPersistenceEnabled && /* @__PURE__ */ jsx(features.persistenceResult.RestoreDialog, {}),
|
|
6119
|
-
/* @__PURE__ */
|
|
6256
|
+
/* @__PURE__ */ jsxs(
|
|
6120
6257
|
"form",
|
|
6121
6258
|
{
|
|
6122
6259
|
onSubmit: (e) => {
|
|
@@ -6124,7 +6261,10 @@ function FormSimple({
|
|
|
6124
6261
|
e.stopPropagation();
|
|
6125
6262
|
form.handleSubmit();
|
|
6126
6263
|
},
|
|
6127
|
-
children
|
|
6264
|
+
children: [
|
|
6265
|
+
children,
|
|
6266
|
+
debug && /* @__PURE__ */ jsx(FormDebugValues, { showInProduction: debug === "force" })
|
|
6267
|
+
]
|
|
6128
6268
|
}
|
|
6129
6269
|
)
|
|
6130
6270
|
] });
|
|
@@ -6183,7 +6323,7 @@ function useFormApi(config) {
|
|
|
6183
6323
|
);
|
|
6184
6324
|
}
|
|
6185
6325
|
function FormLoadingState() {
|
|
6186
|
-
return /* @__PURE__ */ jsx("div", { style: { opacity: 0.5, padding: "1rem" }, children: /* @__PURE__ */ jsx("p", { children: "
|
|
6326
|
+
return /* @__PURE__ */ jsx("div", { style: { opacity: 0.5, padding: "1rem" }, children: /* @__PURE__ */ jsx("p", { children: "Loading form data..." }) });
|
|
6187
6327
|
}
|
|
6188
6328
|
function FormWithApi({
|
|
6189
6329
|
api,
|
|
@@ -6195,7 +6335,9 @@ function FormWithApi({
|
|
|
6195
6335
|
validateOn,
|
|
6196
6336
|
disabled,
|
|
6197
6337
|
readOnly,
|
|
6338
|
+
debug,
|
|
6198
6339
|
middleware,
|
|
6340
|
+
addressProvider,
|
|
6199
6341
|
children
|
|
6200
6342
|
}) {
|
|
6201
6343
|
const formApi = useFormApi(api);
|
|
@@ -6253,7 +6395,7 @@ function FormWithApi({
|
|
|
6253
6395
|
const contextValue = {
|
|
6254
6396
|
form,
|
|
6255
6397
|
schema,
|
|
6256
|
-
//
|
|
6398
|
+
// Export API state for components that need it
|
|
6257
6399
|
apiState: {
|
|
6258
6400
|
isEditMode: formApi.isEditMode,
|
|
6259
6401
|
isLoading: formApi.isLoading,
|
|
@@ -6263,14 +6405,15 @@ function FormWithApi({
|
|
|
6263
6405
|
},
|
|
6264
6406
|
offlineState: features.offlineState,
|
|
6265
6407
|
disabled,
|
|
6266
|
-
readOnly
|
|
6408
|
+
readOnly,
|
|
6409
|
+
addressProvider
|
|
6267
6410
|
};
|
|
6268
6411
|
if (formApi.isLoading) {
|
|
6269
6412
|
return /* @__PURE__ */ jsx(FormLoadingState, {});
|
|
6270
6413
|
}
|
|
6271
6414
|
return /* @__PURE__ */ jsxs(DeclarativeFormContext.Provider, { value: contextValue, children: [
|
|
6272
6415
|
features.isPersistenceEnabled && /* @__PURE__ */ jsx(features.persistenceResult.RestoreDialog, {}),
|
|
6273
|
-
/* @__PURE__ */
|
|
6416
|
+
/* @__PURE__ */ jsxs(
|
|
6274
6417
|
"form",
|
|
6275
6418
|
{
|
|
6276
6419
|
onSubmit: (e) => {
|
|
@@ -6278,7 +6421,10 @@ function FormWithApi({
|
|
|
6278
6421
|
e.stopPropagation();
|
|
6279
6422
|
form.handleSubmit();
|
|
6280
6423
|
},
|
|
6281
|
-
children
|
|
6424
|
+
children: [
|
|
6425
|
+
children,
|
|
6426
|
+
debug && /* @__PURE__ */ jsx(FormDebugValues, { showInProduction: debug === "force" })
|
|
6427
|
+
]
|
|
6282
6428
|
}
|
|
6283
6429
|
)
|
|
6284
6430
|
] }, dataLoaded ? "loaded" : "initial");
|
|
@@ -6293,6 +6439,7 @@ function FormRoot({
|
|
|
6293
6439
|
validateOn,
|
|
6294
6440
|
disabled,
|
|
6295
6441
|
readOnly,
|
|
6442
|
+
debug,
|
|
6296
6443
|
children
|
|
6297
6444
|
}) {
|
|
6298
6445
|
if (api) {
|
|
@@ -6308,6 +6455,7 @@ function FormRoot({
|
|
|
6308
6455
|
validateOn,
|
|
6309
6456
|
disabled,
|
|
6310
6457
|
readOnly,
|
|
6458
|
+
debug,
|
|
6311
6459
|
children
|
|
6312
6460
|
}
|
|
6313
6461
|
);
|
|
@@ -6328,6 +6476,7 @@ function FormRoot({
|
|
|
6328
6476
|
validateOn,
|
|
6329
6477
|
disabled,
|
|
6330
6478
|
readOnly,
|
|
6479
|
+
debug,
|
|
6331
6480
|
children
|
|
6332
6481
|
}
|
|
6333
6482
|
);
|
|
@@ -6405,7 +6554,7 @@ function FormBuilder({
|
|
|
6405
6554
|
middleware,
|
|
6406
6555
|
disabled,
|
|
6407
6556
|
readOnly,
|
|
6408
|
-
submitLabel = "
|
|
6557
|
+
submitLabel = "Save",
|
|
6409
6558
|
children
|
|
6410
6559
|
}) {
|
|
6411
6560
|
return /* @__PURE__ */ jsxs(
|
|
@@ -6461,13 +6610,13 @@ function extractAllErrors(errors) {
|
|
|
6461
6610
|
return messages;
|
|
6462
6611
|
}
|
|
6463
6612
|
function FormErrors({
|
|
6464
|
-
title = "
|
|
6613
|
+
title = "Please fix the following errors:",
|
|
6465
6614
|
showBeforeSubmit = false
|
|
6466
6615
|
}) {
|
|
6467
6616
|
const { form, apiState } = useDeclarativeForm();
|
|
6468
6617
|
const serverError = apiState?.mutationError;
|
|
6469
6618
|
const errorInfo = serverError && "info" in serverError ? serverError.info : null;
|
|
6470
|
-
const serverErrorMessage = serverError ? serverError.message || errorInfo?.message || "
|
|
6619
|
+
const serverErrorMessage = serverError ? serverError.message || errorInfo?.message || "Server error" : null;
|
|
6471
6620
|
return /* @__PURE__ */ jsx(
|
|
6472
6621
|
form.Subscribe,
|
|
6473
6622
|
{
|
|
@@ -6500,14 +6649,15 @@ function FormFromSchema({
|
|
|
6500
6649
|
schema,
|
|
6501
6650
|
initialValue,
|
|
6502
6651
|
onSubmit,
|
|
6503
|
-
submitLabel = "
|
|
6652
|
+
submitLabel = "Save",
|
|
6504
6653
|
showReset = false,
|
|
6505
|
-
resetLabel = "
|
|
6654
|
+
resetLabel = "Reset",
|
|
6506
6655
|
exclude,
|
|
6507
6656
|
validateOn,
|
|
6508
6657
|
middleware,
|
|
6509
6658
|
disabled,
|
|
6510
6659
|
readOnly,
|
|
6660
|
+
debug,
|
|
6511
6661
|
persistence,
|
|
6512
6662
|
offline,
|
|
6513
6663
|
beforeButtons,
|
|
@@ -6524,6 +6674,7 @@ function FormFromSchema({
|
|
|
6524
6674
|
middleware,
|
|
6525
6675
|
disabled,
|
|
6526
6676
|
readOnly,
|
|
6677
|
+
debug,
|
|
6527
6678
|
persistence,
|
|
6528
6679
|
offline,
|
|
6529
6680
|
children: /* @__PURE__ */ jsxs(VStack, { align: "stretch", gap, children: [
|
|
@@ -6856,7 +7007,7 @@ function FormSteps({
|
|
|
6856
7007
|
() => ({
|
|
6857
7008
|
currentStep,
|
|
6858
7009
|
stepCount,
|
|
6859
|
-
//
|
|
7010
|
+
// Getter for steps — returns current value via ref
|
|
6860
7011
|
get steps() {
|
|
6861
7012
|
return sortedStepsRef.current;
|
|
6862
7013
|
},
|
|
@@ -6891,8 +7042,8 @@ function FormSteps({
|
|
|
6891
7042
|
},
|
|
6892
7043
|
clearStepPersistence: clearPersistence
|
|
6893
7044
|
}),
|
|
6894
|
-
//
|
|
6895
|
-
//
|
|
7045
|
+
// IMPORTANT: sortedSteps, hiddenFields, onStepComplete NOT in deps —
|
|
7046
|
+
// accessed via refs/getters, prevents infinite loop
|
|
6896
7047
|
[
|
|
6897
7048
|
currentStep,
|
|
6898
7049
|
stepCount,
|
|
@@ -7168,7 +7319,7 @@ function FormStepsStep({
|
|
|
7168
7319
|
if (!when) {
|
|
7169
7320
|
return;
|
|
7170
7321
|
}
|
|
7171
|
-
const
|
|
7322
|
+
const subscription = form.store.subscribe(() => {
|
|
7172
7323
|
const fieldValue = getNestedValue(form.state.values, when.field);
|
|
7173
7324
|
const newIsVisible = evaluateWhenCondition(when, fieldValue);
|
|
7174
7325
|
if (newIsVisible !== wasVisibleRef.current) {
|
|
@@ -7176,7 +7327,7 @@ function FormStepsStep({
|
|
|
7176
7327
|
setIsVisible(newIsVisible);
|
|
7177
7328
|
}
|
|
7178
7329
|
});
|
|
7179
|
-
return unsubscribe;
|
|
7330
|
+
return () => subscription.unsubscribe();
|
|
7180
7331
|
}, [form, when]);
|
|
7181
7332
|
const stepsRef = useRef(steps);
|
|
7182
7333
|
stepsRef.current = steps;
|
|
@@ -7216,8 +7367,8 @@ function FormStepsStep({
|
|
|
7216
7367
|
const fieldNamesRef = useRef([]);
|
|
7217
7368
|
const currentFieldNames = useMemo(
|
|
7218
7369
|
() => extractFieldNames(children, fieldExtractionPath),
|
|
7219
|
-
//
|
|
7220
|
-
// children
|
|
7370
|
+
// Use segment path as proxy to determine when structure may change
|
|
7371
|
+
// children NOT included — they change every render
|
|
7221
7372
|
[fieldExtractionPath]
|
|
7222
7373
|
);
|
|
7223
7374
|
const fieldNamesChanged = currentFieldNames.length !== fieldNamesRef.current.length || currentFieldNames.some((name, i) => name !== fieldNamesRef.current[i]);
|
|
@@ -7243,17 +7394,17 @@ function FormStepsStep({
|
|
|
7243
7394
|
const index = indexRef.current;
|
|
7244
7395
|
const slideVariants = useMemo(
|
|
7245
7396
|
() => ({
|
|
7246
|
-
//
|
|
7397
|
+
// Initial state: element appears from the appropriate side
|
|
7247
7398
|
initial: {
|
|
7248
7399
|
opacity: 0,
|
|
7249
7400
|
x: direction === "forward" ? SLIDE_OFFSET : -SLIDE_OFFSET
|
|
7250
7401
|
},
|
|
7251
|
-
//
|
|
7402
|
+
// Final state: element in place
|
|
7252
7403
|
animate: {
|
|
7253
7404
|
opacity: 1,
|
|
7254
7405
|
x: 0
|
|
7255
7406
|
},
|
|
7256
|
-
//
|
|
7407
|
+
// Exit state: element leaves to the opposite side
|
|
7257
7408
|
exit: {
|
|
7258
7409
|
opacity: 0,
|
|
7259
7410
|
x: direction === "forward" ? -SLIDE_OFFSET : SLIDE_OFFSET
|
|
@@ -7422,7 +7573,8 @@ function createForm(options = {}) {
|
|
|
7422
7573
|
extraListboxes = {},
|
|
7423
7574
|
lazySelects = {},
|
|
7424
7575
|
lazyComboboxes = {},
|
|
7425
|
-
lazyListboxes = {}
|
|
7576
|
+
lazyListboxes = {},
|
|
7577
|
+
addressProvider
|
|
7426
7578
|
} = options;
|
|
7427
7579
|
const lazySelectComponents = createLazyComponents(lazySelects);
|
|
7428
7580
|
const lazyComboboxComponents = createLazyComponents(lazyComboboxes);
|
|
@@ -7450,7 +7602,8 @@ function createForm(options = {}) {
|
|
|
7450
7602
|
const ExtendedForm = Object.assign(
|
|
7451
7603
|
// Root component
|
|
7452
7604
|
function ExtendedFormRoot(props) {
|
|
7453
|
-
|
|
7605
|
+
const mergedProps = addressProvider && !props.addressProvider ? { ...props, addressProvider } : props;
|
|
7606
|
+
return Form2(mergedProps);
|
|
7454
7607
|
},
|
|
7455
7608
|
{
|
|
7456
7609
|
Group: Form2.Group,
|
|
@@ -7460,6 +7613,7 @@ function createForm(options = {}) {
|
|
|
7460
7613
|
Combobox: ExtendedCombobox,
|
|
7461
7614
|
Listbox: ExtendedListbox,
|
|
7462
7615
|
Errors: Form2.Errors,
|
|
7616
|
+
DebugValues: Form2.DebugValues,
|
|
7463
7617
|
DirtyGuard: Form2.DirtyGuard,
|
|
7464
7618
|
When: Form2.When,
|
|
7465
7619
|
Steps: Form2.Steps,
|
|
@@ -7489,7 +7643,16 @@ function useFieldActions(fieldName) {
|
|
|
7489
7643
|
},
|
|
7490
7644
|
[fullPath]
|
|
7491
7645
|
);
|
|
7492
|
-
const subscribe = useCallback(
|
|
7646
|
+
const subscribe = useCallback(
|
|
7647
|
+
(callback) => {
|
|
7648
|
+
const subscription = form.store.subscribe(callback);
|
|
7649
|
+
if (typeof subscription === "function") {
|
|
7650
|
+
return subscription;
|
|
7651
|
+
}
|
|
7652
|
+
return () => subscription.unsubscribe();
|
|
7653
|
+
},
|
|
7654
|
+
[form]
|
|
7655
|
+
);
|
|
7493
7656
|
const getValueSnapshot = useCallback(
|
|
7494
7657
|
() => getNestedValue2(form.state.values),
|
|
7495
7658
|
[form, getNestedValue2]
|
|
@@ -7635,12 +7798,12 @@ var commonMeta = {
|
|
|
7635
7798
|
fieldProps: { disabled: true }
|
|
7636
7799
|
},
|
|
7637
7800
|
createdAt: {
|
|
7638
|
-
title: "
|
|
7801
|
+
title: "Created",
|
|
7639
7802
|
fieldType: "date",
|
|
7640
7803
|
fieldProps: { readOnly: true }
|
|
7641
7804
|
},
|
|
7642
7805
|
updatedAt: {
|
|
7643
|
-
title: "
|
|
7806
|
+
title: "Updated",
|
|
7644
7807
|
fieldType: "date",
|
|
7645
7808
|
fieldProps: { readOnly: true }
|
|
7646
7809
|
}
|
|
@@ -7802,6 +7965,7 @@ var Form2 = Object.assign(Form, {
|
|
|
7802
7965
|
Field: FormField2,
|
|
7803
7966
|
Button: FormButton,
|
|
7804
7967
|
Errors: FormErrors,
|
|
7968
|
+
DebugValues: FormDebugValues,
|
|
7805
7969
|
DirtyGuard,
|
|
7806
7970
|
When: FormWhen,
|
|
7807
7971
|
Steps: FormSteps2,
|