@resistdesign/voltra 3.0.0-alpha.26 → 3.0.0-alpha.28
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +8 -0
- package/api/index.js +6 -383
- package/app/index.js +10 -1188
- package/app/utils/History.d.ts +17 -0
- package/app/utils/Route.d.ts +22 -0
- package/build/index.js +2 -12
- package/common/index.js +7 -384
- package/iac/index.js +2 -258
- package/iac/packs/index.js +2 -254
- package/native/index.d.ts +4 -0
- package/native/index.js +63 -705
- package/native/testing/react-native.d.ts +28 -0
- package/native/utils/History.d.ts +1 -12
- package/native/utils/Route.d.ts +34 -1
- package/package.json +1 -1
- package/web/index.js +6 -539
package/native/index.js
CHANGED
|
@@ -1,115 +1,13 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
import {
|
|
1
|
+
import { createHistoryBackHandler, buildHistoryPath, parseHistoryPath, createMemoryHistory, Route, buildRoutePath, computeTrackPixels } from '../chunk-G5CLUK4Y.js';
|
|
2
|
+
export { buildHistoryPath, createHistoryBackHandler, createMemoryHistory, parseHistoryPath, useRouteContext } from '../chunk-G5CLUK4Y.js';
|
|
3
|
+
import { createFormRenderer, AutoFormView, AutoForm, parseTemplate, validateAreas, computeAreaBounds } from '../chunk-WELZGQDJ.js';
|
|
4
|
+
import '../chunk-IWRHGGGH.js';
|
|
5
|
+
import { getPathArray } from '../chunk-GYWRAW3Y.js';
|
|
6
|
+
import '../chunk-I2KLQ2HA.js';
|
|
7
|
+
import { createElement, useMemo } from 'react';
|
|
8
|
+
import { Text, View, Platform, Switch, TextInput, Pressable, BackHandler } from 'react-native';
|
|
9
|
+
import { jsx } from 'react/jsx-runtime';
|
|
4
10
|
|
|
5
|
-
// src/native/forms/suite.ts
|
|
6
|
-
|
|
7
|
-
// src/app/forms/core/resolveSuite.ts
|
|
8
|
-
var fieldKinds = [
|
|
9
|
-
"string",
|
|
10
|
-
"number",
|
|
11
|
-
"boolean",
|
|
12
|
-
"enum_select",
|
|
13
|
-
"array",
|
|
14
|
-
"relation_single",
|
|
15
|
-
"relation_array",
|
|
16
|
-
"custom_single",
|
|
17
|
-
"custom_array"
|
|
18
|
-
];
|
|
19
|
-
var getMissingKinds = (renderers) => {
|
|
20
|
-
return fieldKinds.filter((kind) => !renderers[kind]);
|
|
21
|
-
};
|
|
22
|
-
var resolveSuite = (overrides, fallback) => {
|
|
23
|
-
const mergedRenderers = {
|
|
24
|
-
...fallback.renderers ?? {},
|
|
25
|
-
...overrides?.renderers ?? {}
|
|
26
|
-
};
|
|
27
|
-
const missingKinds = getMissingKinds(mergedRenderers);
|
|
28
|
-
if (missingKinds.length) {
|
|
29
|
-
throw new Error(
|
|
30
|
-
`Missing renderers for field kinds: ${missingKinds.join(", ")}`
|
|
31
|
-
);
|
|
32
|
-
}
|
|
33
|
-
const mergedPrimitives = {
|
|
34
|
-
...fallback.primitives ?? {},
|
|
35
|
-
...overrides?.primitives ?? {}
|
|
36
|
-
};
|
|
37
|
-
return {
|
|
38
|
-
renderers: mergedRenderers,
|
|
39
|
-
primitives: Object.keys(mergedPrimitives).length ? mergedPrimitives : void 0
|
|
40
|
-
};
|
|
41
|
-
};
|
|
42
|
-
|
|
43
|
-
// src/app/forms/core/getFieldKind.ts
|
|
44
|
-
var hasSelectableValues = (field) => {
|
|
45
|
-
const possibleValues = field.possibleValues ?? [];
|
|
46
|
-
return possibleValues.some(
|
|
47
|
-
(value) => typeof value === "string" || typeof value === "number"
|
|
48
|
-
);
|
|
49
|
-
};
|
|
50
|
-
var getFieldKind = (field) => {
|
|
51
|
-
if (field.typeReference) {
|
|
52
|
-
return field.array ? "relation_array" : "relation_single";
|
|
53
|
-
}
|
|
54
|
-
if (field.tags?.customType) {
|
|
55
|
-
return field.array ? "custom_array" : "custom_single";
|
|
56
|
-
}
|
|
57
|
-
if (field.array) {
|
|
58
|
-
return "array";
|
|
59
|
-
}
|
|
60
|
-
if (hasSelectableValues(field)) {
|
|
61
|
-
return "enum_select";
|
|
62
|
-
}
|
|
63
|
-
if (field.type === "boolean") {
|
|
64
|
-
return "boolean";
|
|
65
|
-
}
|
|
66
|
-
if (field.type === "number") {
|
|
67
|
-
return "number";
|
|
68
|
-
}
|
|
69
|
-
return "string";
|
|
70
|
-
};
|
|
71
|
-
|
|
72
|
-
// src/app/forms/core/createAutoField.ts
|
|
73
|
-
var createAutoField = (suite) => {
|
|
74
|
-
const renderField = (props) => {
|
|
75
|
-
const { field, fieldKey, value, onChange, error, disabled } = props;
|
|
76
|
-
const { tags } = field;
|
|
77
|
-
const context = {
|
|
78
|
-
field,
|
|
79
|
-
fieldKey,
|
|
80
|
-
label: tags?.label ?? fieldKey,
|
|
81
|
-
required: !field.optional,
|
|
82
|
-
disabled: !!disabled,
|
|
83
|
-
error,
|
|
84
|
-
value,
|
|
85
|
-
onChange,
|
|
86
|
-
constraints: tags?.constraints,
|
|
87
|
-
format: tags?.format,
|
|
88
|
-
possibleValues: field.possibleValues,
|
|
89
|
-
allowCustomSelection: tags?.allowCustomSelection,
|
|
90
|
-
customType: tags?.customType,
|
|
91
|
-
onRelationAction: props.onRelationAction,
|
|
92
|
-
onCustomTypeAction: props.onCustomTypeAction,
|
|
93
|
-
renderField
|
|
94
|
-
};
|
|
95
|
-
const kind = getFieldKind(field);
|
|
96
|
-
return suite.renderers[kind](context);
|
|
97
|
-
};
|
|
98
|
-
return renderField;
|
|
99
|
-
};
|
|
100
|
-
|
|
101
|
-
// src/app/forms/core/createFormRenderer.ts
|
|
102
|
-
var createFormRenderer = (options) => {
|
|
103
|
-
const resolvedSuite = resolveSuite(
|
|
104
|
-
options.suite,
|
|
105
|
-
options.fallbackSuite
|
|
106
|
-
);
|
|
107
|
-
const AutoField2 = createAutoField(resolvedSuite);
|
|
108
|
-
return {
|
|
109
|
-
AutoField: AutoField2,
|
|
110
|
-
suite: resolvedSuite
|
|
111
|
-
};
|
|
112
|
-
};
|
|
113
11
|
var FieldWrapper = (props) => {
|
|
114
12
|
return createElement(View, null, props.children);
|
|
115
13
|
};
|
|
@@ -489,209 +387,6 @@ var nativeSuite = {
|
|
|
489
387
|
var nativeAutoField = createFormRenderer({
|
|
490
388
|
fallbackSuite: nativeSuite
|
|
491
389
|
}).AutoField;
|
|
492
|
-
var getDeniedOperation = (deniedOperations, operation) => {
|
|
493
|
-
if (!deniedOperations) {
|
|
494
|
-
return false;
|
|
495
|
-
}
|
|
496
|
-
const denied = deniedOperations[operation];
|
|
497
|
-
if (typeof denied === "boolean") {
|
|
498
|
-
return denied;
|
|
499
|
-
}
|
|
500
|
-
return deniedOperations[operation.toLowerCase()] ?? false;
|
|
501
|
-
};
|
|
502
|
-
var buildInitialValues = (initialValues, typeInfo) => {
|
|
503
|
-
const values = { ...initialValues };
|
|
504
|
-
for (const [key, field] of Object.entries(typeInfo.fields ?? {})) {
|
|
505
|
-
if (values[key] !== void 0) {
|
|
506
|
-
continue;
|
|
507
|
-
}
|
|
508
|
-
const defaultValue = field.tags?.constraints?.defaultValue;
|
|
509
|
-
if (defaultValue !== void 0) {
|
|
510
|
-
let parsedDefaultValue = defaultValue;
|
|
511
|
-
try {
|
|
512
|
-
parsedDefaultValue = JSON.parse(defaultValue);
|
|
513
|
-
} catch (error) {
|
|
514
|
-
}
|
|
515
|
-
values[key] = parsedDefaultValue;
|
|
516
|
-
continue;
|
|
517
|
-
}
|
|
518
|
-
if (field.array && !field.typeReference && !field.optional) {
|
|
519
|
-
values[key] = [];
|
|
520
|
-
continue;
|
|
521
|
-
}
|
|
522
|
-
if (field.type === "boolean" && !field.optional) {
|
|
523
|
-
values[key] = false;
|
|
524
|
-
}
|
|
525
|
-
}
|
|
526
|
-
return values;
|
|
527
|
-
};
|
|
528
|
-
var useFormEngine = (initialValues = {}, typeInfo, options) => {
|
|
529
|
-
const operation = options?.operation ?? "CREATE" /* CREATE */;
|
|
530
|
-
const [values, setValues] = useState(
|
|
531
|
-
buildInitialValues(initialValues, typeInfo)
|
|
532
|
-
);
|
|
533
|
-
const [errors, setErrors] = useState({});
|
|
534
|
-
const setFieldValue = useCallback((path, value) => {
|
|
535
|
-
setValues((prev) => {
|
|
536
|
-
return {
|
|
537
|
-
...prev,
|
|
538
|
-
[path]: value
|
|
539
|
-
};
|
|
540
|
-
});
|
|
541
|
-
}, []);
|
|
542
|
-
const validate = useCallback(() => {
|
|
543
|
-
const newErrors = {};
|
|
544
|
-
for (const [key, field] of Object.entries(typeInfo.fields ?? {})) {
|
|
545
|
-
if (field.tags?.hidden) {
|
|
546
|
-
continue;
|
|
547
|
-
}
|
|
548
|
-
const val = values[key];
|
|
549
|
-
if (field.readonly && (val === void 0 || val === null || val === "")) {
|
|
550
|
-
continue;
|
|
551
|
-
}
|
|
552
|
-
const isMissing = val === void 0 || val === null || val === "" || field.array && (!Array.isArray(val) || val.length === 0);
|
|
553
|
-
if (!field.optional && isMissing) {
|
|
554
|
-
newErrors[key] = "This field is required";
|
|
555
|
-
continue;
|
|
556
|
-
}
|
|
557
|
-
if (isMissing) {
|
|
558
|
-
continue;
|
|
559
|
-
}
|
|
560
|
-
const constraints = field.tags?.constraints;
|
|
561
|
-
if (constraints?.pattern && typeof val === "string") {
|
|
562
|
-
const pattern = new RegExp(constraints.pattern);
|
|
563
|
-
if (!pattern.test(val)) {
|
|
564
|
-
newErrors[key] = "Value does not match required pattern";
|
|
565
|
-
continue;
|
|
566
|
-
}
|
|
567
|
-
}
|
|
568
|
-
if (field.type === "number" && typeof val === "number") {
|
|
569
|
-
if (constraints?.min !== void 0 && val < constraints.min) {
|
|
570
|
-
newErrors[key] = `Value must be at least ${constraints.min}`;
|
|
571
|
-
continue;
|
|
572
|
-
}
|
|
573
|
-
if (constraints?.max !== void 0 && val > constraints.max) {
|
|
574
|
-
newErrors[key] = `Value must be at most ${constraints.max}`;
|
|
575
|
-
continue;
|
|
576
|
-
}
|
|
577
|
-
}
|
|
578
|
-
}
|
|
579
|
-
setErrors(newErrors);
|
|
580
|
-
return Object.keys(newErrors).length === 0;
|
|
581
|
-
}, [typeInfo, values]);
|
|
582
|
-
const fields = useMemo(() => {
|
|
583
|
-
return Object.entries(typeInfo.fields ?? {}).map(([key, field]) => {
|
|
584
|
-
const { tags } = field;
|
|
585
|
-
const isPrimary = tags?.primaryField || typeInfo.primaryField === key;
|
|
586
|
-
return {
|
|
587
|
-
key,
|
|
588
|
-
field,
|
|
589
|
-
label: tags?.label ?? key,
|
|
590
|
-
required: !field.optional,
|
|
591
|
-
disabled: field.readonly || getDeniedOperation(typeInfo.tags?.deniedOperations, operation) || getDeniedOperation(tags?.deniedOperations, operation) || operation === "UPDATE" /* UPDATE */ && isPrimary,
|
|
592
|
-
hidden: !!tags?.hidden,
|
|
593
|
-
primary: isPrimary,
|
|
594
|
-
format: tags?.format,
|
|
595
|
-
constraints: tags?.constraints,
|
|
596
|
-
value: values[key],
|
|
597
|
-
onChange: (value) => setFieldValue(key, value),
|
|
598
|
-
error: errors[key]
|
|
599
|
-
};
|
|
600
|
-
});
|
|
601
|
-
}, [typeInfo, values, errors, setFieldValue, operation]);
|
|
602
|
-
return {
|
|
603
|
-
typeInfo,
|
|
604
|
-
typeTags: typeInfo.tags,
|
|
605
|
-
operation,
|
|
606
|
-
values,
|
|
607
|
-
errors,
|
|
608
|
-
fields,
|
|
609
|
-
setFieldValue,
|
|
610
|
-
validate,
|
|
611
|
-
setErrors
|
|
612
|
-
};
|
|
613
|
-
};
|
|
614
|
-
var fallbackFormRoot = ({
|
|
615
|
-
children,
|
|
616
|
-
onSubmit
|
|
617
|
-
}) => {
|
|
618
|
-
const handleSubmit = (event) => {
|
|
619
|
-
event.preventDefault();
|
|
620
|
-
onSubmit?.();
|
|
621
|
-
};
|
|
622
|
-
return /* @__PURE__ */ jsx("form", { onSubmit: handleSubmit, children });
|
|
623
|
-
};
|
|
624
|
-
var fallbackButton = ({
|
|
625
|
-
children,
|
|
626
|
-
disabled,
|
|
627
|
-
type,
|
|
628
|
-
onClick
|
|
629
|
-
}) => {
|
|
630
|
-
return /* @__PURE__ */ jsx("button", { type: type ?? "button", disabled, onClick, children });
|
|
631
|
-
};
|
|
632
|
-
var AutoFormView = ({
|
|
633
|
-
controller,
|
|
634
|
-
onSubmit,
|
|
635
|
-
renderer,
|
|
636
|
-
submitDisabled,
|
|
637
|
-
onRelationAction,
|
|
638
|
-
onCustomTypeAction
|
|
639
|
-
}) => {
|
|
640
|
-
const FormRoot2 = renderer.suite.primitives?.FormRoot ?? fallbackFormRoot;
|
|
641
|
-
const Button2 = renderer.suite.primitives?.Button ?? fallbackButton;
|
|
642
|
-
const AutoField2 = renderer.AutoField;
|
|
643
|
-
const submit = () => {
|
|
644
|
-
if (controller.validate()) {
|
|
645
|
-
onSubmit(controller.values);
|
|
646
|
-
}
|
|
647
|
-
};
|
|
648
|
-
return /* @__PURE__ */ jsx(FormRoot2, { onSubmit: submit, children: /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
649
|
-
controller.fields.filter((fieldController) => !fieldController.hidden).map((fieldController) => /* @__PURE__ */ jsx(
|
|
650
|
-
AutoField2,
|
|
651
|
-
{
|
|
652
|
-
field: fieldController.field,
|
|
653
|
-
fieldKey: fieldController.key,
|
|
654
|
-
value: fieldController.value,
|
|
655
|
-
onChange: fieldController.onChange,
|
|
656
|
-
error: fieldController.error,
|
|
657
|
-
onRelationAction,
|
|
658
|
-
disabled: fieldController.disabled,
|
|
659
|
-
onCustomTypeAction
|
|
660
|
-
},
|
|
661
|
-
fieldController.key
|
|
662
|
-
)),
|
|
663
|
-
/* @__PURE__ */ jsx(Button2, { type: "submit", onClick: submit, disabled: submitDisabled, children: /* @__PURE__ */ jsx(Fragment, { children: "Submit" }) })
|
|
664
|
-
] }) });
|
|
665
|
-
};
|
|
666
|
-
var AutoForm = ({
|
|
667
|
-
typeInfo,
|
|
668
|
-
onSubmit,
|
|
669
|
-
renderer,
|
|
670
|
-
initialValues,
|
|
671
|
-
onValuesChange,
|
|
672
|
-
onRelationAction,
|
|
673
|
-
onCustomTypeAction,
|
|
674
|
-
operation,
|
|
675
|
-
submitDisabled
|
|
676
|
-
}) => {
|
|
677
|
-
const controller = useFormEngine(initialValues, typeInfo, { operation });
|
|
678
|
-
useEffect(() => {
|
|
679
|
-
if (onValuesChange) {
|
|
680
|
-
onValuesChange(controller.values);
|
|
681
|
-
}
|
|
682
|
-
}, [controller.values, onValuesChange]);
|
|
683
|
-
return /* @__PURE__ */ jsx(
|
|
684
|
-
AutoFormView,
|
|
685
|
-
{
|
|
686
|
-
controller,
|
|
687
|
-
onSubmit,
|
|
688
|
-
renderer,
|
|
689
|
-
onRelationAction,
|
|
690
|
-
onCustomTypeAction,
|
|
691
|
-
submitDisabled
|
|
692
|
-
}
|
|
693
|
-
);
|
|
694
|
-
};
|
|
695
390
|
|
|
696
391
|
// src/native/forms/createNativeFormRenderer.ts
|
|
697
392
|
var createNativeFormRenderer = (options) => {
|
|
@@ -719,328 +414,6 @@ var AutoFormView2 = (props) => {
|
|
|
719
414
|
var AutoForm2 = (props) => {
|
|
720
415
|
return /* @__PURE__ */ jsx(AutoForm, { ...props, renderer: defaultNativeRenderer });
|
|
721
416
|
};
|
|
722
|
-
|
|
723
|
-
// src/app/utils/History.ts
|
|
724
|
-
var ensurePrefix = (value, prefix) => value ? value.startsWith(prefix) ? value : `${prefix}${value}` : "";
|
|
725
|
-
var parseHistoryPath = (inputPath) => {
|
|
726
|
-
const raw = String(inputPath ?? "").trim();
|
|
727
|
-
if (!raw) {
|
|
728
|
-
return { path: "/" };
|
|
729
|
-
}
|
|
730
|
-
try {
|
|
731
|
-
const absoluteUrl = new URL(raw);
|
|
732
|
-
return {
|
|
733
|
-
path: absoluteUrl.pathname || "/",
|
|
734
|
-
...absoluteUrl.search ? { search: absoluteUrl.search } : {},
|
|
735
|
-
...absoluteUrl.hash ? { hash: absoluteUrl.hash } : {}
|
|
736
|
-
};
|
|
737
|
-
} catch (error) {
|
|
738
|
-
let target = raw;
|
|
739
|
-
let hash = "";
|
|
740
|
-
let search = "";
|
|
741
|
-
const hashIndex = target.indexOf("#");
|
|
742
|
-
if (hashIndex >= 0) {
|
|
743
|
-
hash = target.slice(hashIndex);
|
|
744
|
-
target = target.slice(0, hashIndex);
|
|
745
|
-
}
|
|
746
|
-
const searchIndex = target.indexOf("?");
|
|
747
|
-
if (searchIndex >= 0) {
|
|
748
|
-
search = target.slice(searchIndex);
|
|
749
|
-
target = target.slice(0, searchIndex);
|
|
750
|
-
}
|
|
751
|
-
const path = target ? target.startsWith("/") ? target : `/${target}` : "/";
|
|
752
|
-
return {
|
|
753
|
-
path,
|
|
754
|
-
...search && search !== "?" ? { search } : {},
|
|
755
|
-
...hash && hash !== "#" ? { hash } : {}
|
|
756
|
-
};
|
|
757
|
-
}
|
|
758
|
-
};
|
|
759
|
-
var buildHistoryPath = ({
|
|
760
|
-
path,
|
|
761
|
-
search,
|
|
762
|
-
hash
|
|
763
|
-
}) => {
|
|
764
|
-
const normalizedPath = path ? path.startsWith("/") ? path : `/${path}` : "/";
|
|
765
|
-
const normalizedSearch = search ? ensurePrefix(search, "?") : "";
|
|
766
|
-
const normalizedHash = hash ? ensurePrefix(hash, "#") : "";
|
|
767
|
-
return `${normalizedPath}${normalizedSearch}${normalizedHash}`;
|
|
768
|
-
};
|
|
769
|
-
var getHistoryLocation = (inputPath, state, getNextKey, currentLocation, replaceSearch = false) => {
|
|
770
|
-
const parsed = parseHistoryPath(inputPath);
|
|
771
|
-
const nextSearch = typeof parsed.search === "undefined" ? replaceSearch ? void 0 : currentLocation?.search : parsed.search;
|
|
772
|
-
return {
|
|
773
|
-
path: parsed.path,
|
|
774
|
-
...typeof nextSearch !== "undefined" ? { search: nextSearch } : {},
|
|
775
|
-
...parsed.hash ? { hash: parsed.hash } : {},
|
|
776
|
-
...typeof state !== "undefined" ? { state } : {},
|
|
777
|
-
key: getNextKey()
|
|
778
|
-
};
|
|
779
|
-
};
|
|
780
|
-
var createMemoryHistory = (initialPath = "/") => {
|
|
781
|
-
let keyCounter = 0;
|
|
782
|
-
const getNextKey = () => `h${keyCounter++}`;
|
|
783
|
-
const listeners = /* @__PURE__ */ new Set();
|
|
784
|
-
const entries = [
|
|
785
|
-
{
|
|
786
|
-
location: getHistoryLocation(
|
|
787
|
-
initialPath,
|
|
788
|
-
void 0,
|
|
789
|
-
getNextKey,
|
|
790
|
-
void 0,
|
|
791
|
-
true
|
|
792
|
-
)
|
|
793
|
-
}
|
|
794
|
-
];
|
|
795
|
-
let currentIndex = 0;
|
|
796
|
-
const getCurrentLocation = () => entries[currentIndex].location;
|
|
797
|
-
const notify = () => {
|
|
798
|
-
const location = getCurrentLocation();
|
|
799
|
-
listeners.forEach((listener) => listener(location));
|
|
800
|
-
};
|
|
801
|
-
const push = (path, opts) => {
|
|
802
|
-
const location = getHistoryLocation(
|
|
803
|
-
path,
|
|
804
|
-
opts?.state,
|
|
805
|
-
getNextKey,
|
|
806
|
-
getCurrentLocation(),
|
|
807
|
-
opts?.replaceSearch === true
|
|
808
|
-
);
|
|
809
|
-
if (currentIndex < entries.length - 1) {
|
|
810
|
-
entries.splice(currentIndex + 1);
|
|
811
|
-
}
|
|
812
|
-
entries.push({ location });
|
|
813
|
-
currentIndex = entries.length - 1;
|
|
814
|
-
notify();
|
|
815
|
-
};
|
|
816
|
-
const replace = (path, opts) => {
|
|
817
|
-
const location = getHistoryLocation(
|
|
818
|
-
path,
|
|
819
|
-
opts?.state,
|
|
820
|
-
getNextKey,
|
|
821
|
-
getCurrentLocation(),
|
|
822
|
-
opts?.replaceSearch === true
|
|
823
|
-
);
|
|
824
|
-
entries[currentIndex] = { location };
|
|
825
|
-
notify();
|
|
826
|
-
};
|
|
827
|
-
const go = (delta) => {
|
|
828
|
-
if (!Number.isFinite(delta)) {
|
|
829
|
-
return;
|
|
830
|
-
}
|
|
831
|
-
const targetIndex = Math.max(
|
|
832
|
-
0,
|
|
833
|
-
Math.min(entries.length - 1, currentIndex + Math.trunc(delta))
|
|
834
|
-
);
|
|
835
|
-
if (targetIndex === currentIndex) {
|
|
836
|
-
return;
|
|
837
|
-
}
|
|
838
|
-
currentIndex = targetIndex;
|
|
839
|
-
notify();
|
|
840
|
-
};
|
|
841
|
-
return {
|
|
842
|
-
get location() {
|
|
843
|
-
return getCurrentLocation();
|
|
844
|
-
},
|
|
845
|
-
get length() {
|
|
846
|
-
return entries.length;
|
|
847
|
-
},
|
|
848
|
-
get index() {
|
|
849
|
-
return currentIndex;
|
|
850
|
-
},
|
|
851
|
-
push,
|
|
852
|
-
replace,
|
|
853
|
-
go,
|
|
854
|
-
back: () => go(-1),
|
|
855
|
-
forward: () => go(1),
|
|
856
|
-
listen: (listener) => {
|
|
857
|
-
listeners.add(listener);
|
|
858
|
-
return () => listeners.delete(listener);
|
|
859
|
-
}
|
|
860
|
-
};
|
|
861
|
-
};
|
|
862
|
-
|
|
863
|
-
// src/app/utils/easy-layout/computeAreaBounds.ts
|
|
864
|
-
var computeAreaBounds = (parsed) => {
|
|
865
|
-
const result = {};
|
|
866
|
-
for (let rowIndex = 0; rowIndex < parsed.areaGrid.length; rowIndex++) {
|
|
867
|
-
const row = parsed.areaGrid[rowIndex];
|
|
868
|
-
for (let colIndex = 0; colIndex < row.length; colIndex++) {
|
|
869
|
-
const name = row[colIndex];
|
|
870
|
-
if (!name || name === ".") {
|
|
871
|
-
continue;
|
|
872
|
-
}
|
|
873
|
-
const row1 = rowIndex + 1;
|
|
874
|
-
const col1 = colIndex + 1;
|
|
875
|
-
const existing = result[name];
|
|
876
|
-
if (!existing) {
|
|
877
|
-
result[name] = {
|
|
878
|
-
name,
|
|
879
|
-
rowStart: row1,
|
|
880
|
-
rowEnd: row1,
|
|
881
|
-
colStart: col1,
|
|
882
|
-
colEnd: col1
|
|
883
|
-
};
|
|
884
|
-
continue;
|
|
885
|
-
}
|
|
886
|
-
existing.rowStart = Math.min(existing.rowStart, row1);
|
|
887
|
-
existing.rowEnd = Math.max(existing.rowEnd, row1);
|
|
888
|
-
existing.colStart = Math.min(existing.colStart, col1);
|
|
889
|
-
existing.colEnd = Math.max(existing.colEnd, col1);
|
|
890
|
-
}
|
|
891
|
-
}
|
|
892
|
-
return result;
|
|
893
|
-
};
|
|
894
|
-
|
|
895
|
-
// src/app/utils/easy-layout/computeTracks.ts
|
|
896
|
-
var computeTrackPixels = ({
|
|
897
|
-
tracks,
|
|
898
|
-
totalPx,
|
|
899
|
-
gapPx = 0,
|
|
900
|
-
paddingPx = 0
|
|
901
|
-
}) => {
|
|
902
|
-
if (!tracks.length) {
|
|
903
|
-
return [];
|
|
904
|
-
}
|
|
905
|
-
const gapsPx = Math.max(0, tracks.length - 1) * Math.max(0, gapPx);
|
|
906
|
-
const usablePx = Math.max(0, totalPx - Math.max(0, paddingPx) * 2 - gapsPx);
|
|
907
|
-
let fixedPx = 0;
|
|
908
|
-
let frTotal = 0;
|
|
909
|
-
for (const track of tracks) {
|
|
910
|
-
if (track.kind === "px") {
|
|
911
|
-
fixedPx += track.value;
|
|
912
|
-
} else if (track.kind === "pct") {
|
|
913
|
-
fixedPx += usablePx * track.value / 100;
|
|
914
|
-
} else {
|
|
915
|
-
frTotal += track.value;
|
|
916
|
-
}
|
|
917
|
-
}
|
|
918
|
-
const remainderPx = Math.max(0, usablePx - fixedPx);
|
|
919
|
-
return tracks.map((track) => {
|
|
920
|
-
if (track.kind === "px") {
|
|
921
|
-
return track.value;
|
|
922
|
-
}
|
|
923
|
-
if (track.kind === "pct") {
|
|
924
|
-
return usablePx * track.value / 100;
|
|
925
|
-
}
|
|
926
|
-
if (frTotal <= 0) {
|
|
927
|
-
return 0;
|
|
928
|
-
}
|
|
929
|
-
return remainderPx * track.value / frTotal;
|
|
930
|
-
});
|
|
931
|
-
};
|
|
932
|
-
|
|
933
|
-
// src/app/utils/easy-layout/parseTemplate.ts
|
|
934
|
-
var parseTrackSpec = (token) => {
|
|
935
|
-
const trimmed = token.trim();
|
|
936
|
-
const numericMatch = trimmed.match(/^([0-9]*\.?[0-9]+)(fr|px|%)$/);
|
|
937
|
-
if (!numericMatch) {
|
|
938
|
-
throw new Error(
|
|
939
|
-
`Invalid track token "${trimmed}". Supported units are fr, px, and %.`
|
|
940
|
-
);
|
|
941
|
-
}
|
|
942
|
-
const value = Number(numericMatch[1]);
|
|
943
|
-
const suffix = numericMatch[2];
|
|
944
|
-
if (!Number.isFinite(value) || value < 0) {
|
|
945
|
-
throw new Error(`Track value must be a non-negative number. Received "${trimmed}".`);
|
|
946
|
-
}
|
|
947
|
-
if (suffix === "fr") {
|
|
948
|
-
return { kind: "fr", value };
|
|
949
|
-
}
|
|
950
|
-
if (suffix === "px") {
|
|
951
|
-
return { kind: "px", value };
|
|
952
|
-
}
|
|
953
|
-
return { kind: "pct", value };
|
|
954
|
-
};
|
|
955
|
-
var normalizeAreas = (areaPart) => {
|
|
956
|
-
return areaPart.trim().split(/\s+/g).map((token) => token.trim()).filter(Boolean);
|
|
957
|
-
};
|
|
958
|
-
var parseTemplate = (template = "") => {
|
|
959
|
-
const lines = template.split("\n").map((line) => line.trim()).filter(Boolean);
|
|
960
|
-
const areaGrid = [];
|
|
961
|
-
const rowTracks = [];
|
|
962
|
-
let colTracks = null;
|
|
963
|
-
for (const line of lines) {
|
|
964
|
-
if (line.startsWith("\\")) {
|
|
965
|
-
if (colTracks) {
|
|
966
|
-
throw new Error("Template can include only one column-track line.");
|
|
967
|
-
}
|
|
968
|
-
const colTokens = line.replace(/\\/g, " ").trim().split(/\s+/g).filter(Boolean);
|
|
969
|
-
colTracks = colTokens.map(parseTrackSpec);
|
|
970
|
-
continue;
|
|
971
|
-
}
|
|
972
|
-
const parts = line.split(",").map((part) => part.trim());
|
|
973
|
-
const areaPart = parts[0] || "";
|
|
974
|
-
if (!areaPart) {
|
|
975
|
-
continue;
|
|
976
|
-
}
|
|
977
|
-
if (parts.length > 2) {
|
|
978
|
-
throw new Error(
|
|
979
|
-
`Invalid row definition "${line}". Expected "<areas>, <row-track>".`
|
|
980
|
-
);
|
|
981
|
-
}
|
|
982
|
-
const areas = normalizeAreas(areaPart);
|
|
983
|
-
if (!areas.length) {
|
|
984
|
-
continue;
|
|
985
|
-
}
|
|
986
|
-
areaGrid.push(areas);
|
|
987
|
-
const rowTrack = parts[1];
|
|
988
|
-
if (rowTrack) {
|
|
989
|
-
rowTracks.push(parseTrackSpec(rowTrack));
|
|
990
|
-
}
|
|
991
|
-
}
|
|
992
|
-
if (!areaGrid.length) {
|
|
993
|
-
throw new Error("Template must include at least one area row.");
|
|
994
|
-
}
|
|
995
|
-
const expectedWidth = areaGrid[0].length;
|
|
996
|
-
for (let rowIndex = 0; rowIndex < areaGrid.length; rowIndex++) {
|
|
997
|
-
const width = areaGrid[rowIndex].length;
|
|
998
|
-
if (width !== expectedWidth) {
|
|
999
|
-
throw new Error(
|
|
1000
|
-
`All area rows must have the same width. Expected ${expectedWidth}, received ${width} at row ${rowIndex + 1}.`
|
|
1001
|
-
);
|
|
1002
|
-
}
|
|
1003
|
-
}
|
|
1004
|
-
if (colTracks && colTracks.length !== expectedWidth) {
|
|
1005
|
-
throw new Error(
|
|
1006
|
-
`Column track count must match area width. Expected ${expectedWidth}, received ${colTracks.length}.`
|
|
1007
|
-
);
|
|
1008
|
-
}
|
|
1009
|
-
const areaNames = Array.from(
|
|
1010
|
-
new Set(
|
|
1011
|
-
areaGrid.flat().map((name) => name.trim()).filter((name) => !!name && name !== ".")
|
|
1012
|
-
)
|
|
1013
|
-
);
|
|
1014
|
-
return {
|
|
1015
|
-
areaGrid,
|
|
1016
|
-
rowTracks,
|
|
1017
|
-
colTracks: colTracks || [],
|
|
1018
|
-
areaNames
|
|
1019
|
-
};
|
|
1020
|
-
};
|
|
1021
|
-
|
|
1022
|
-
// src/app/utils/easy-layout/validateAreas.ts
|
|
1023
|
-
var validateAreas = (parsed) => {
|
|
1024
|
-
const bounds = computeAreaBounds(parsed);
|
|
1025
|
-
for (const areaName of parsed.areaNames) {
|
|
1026
|
-
const bound = bounds[areaName];
|
|
1027
|
-
if (!bound) {
|
|
1028
|
-
continue;
|
|
1029
|
-
}
|
|
1030
|
-
for (let row = bound.rowStart; row <= bound.rowEnd; row++) {
|
|
1031
|
-
for (let col = bound.colStart; col <= bound.colEnd; col++) {
|
|
1032
|
-
const token = parsed.areaGrid[row - 1]?.[col - 1];
|
|
1033
|
-
if (token !== areaName) {
|
|
1034
|
-
throw new Error(
|
|
1035
|
-
`Area "${areaName}" must be a rectangle. Missing "${areaName}" at row ${row}, col ${col}.`
|
|
1036
|
-
);
|
|
1037
|
-
}
|
|
1038
|
-
}
|
|
1039
|
-
}
|
|
1040
|
-
}
|
|
1041
|
-
};
|
|
1042
|
-
|
|
1043
|
-
// src/native/utils/EasyLayout.tsx
|
|
1044
417
|
var roundTo = (value, decimals) => {
|
|
1045
418
|
const places = Number.isFinite(decimals) ? Math.max(0, decimals) : 3;
|
|
1046
419
|
const factor = Math.pow(10, places);
|
|
@@ -1252,74 +625,7 @@ var createNativeHistory = (options = {}) => {
|
|
|
1252
625
|
}
|
|
1253
626
|
};
|
|
1254
627
|
};
|
|
1255
|
-
var createNativeBackHandler = (history) =>
|
|
1256
|
-
return {
|
|
1257
|
-
/**
|
|
1258
|
-
* @returns True when back navigation was handled by history.
|
|
1259
|
-
*/
|
|
1260
|
-
handle: () => {
|
|
1261
|
-
if (history.index > 0) {
|
|
1262
|
-
history.back();
|
|
1263
|
-
return true;
|
|
1264
|
-
}
|
|
1265
|
-
return false;
|
|
1266
|
-
}
|
|
1267
|
-
};
|
|
1268
|
-
};
|
|
1269
|
-
|
|
1270
|
-
// src/common/Routing.ts
|
|
1271
|
-
var PATH_DELIMITER = "/";
|
|
1272
|
-
var getPotentialJSONValue = (value) => {
|
|
1273
|
-
try {
|
|
1274
|
-
return JSON.parse(value);
|
|
1275
|
-
} catch (error) {
|
|
1276
|
-
return value;
|
|
1277
|
-
}
|
|
1278
|
-
};
|
|
1279
|
-
var getPathArray = (path, delimiter = PATH_DELIMITER, filterEmptyOutput = false, filterEmptyInput = true, useJson = true, uriDecodeParts = true) => path.split(delimiter).filter(filterEmptyInput ? (p) => p !== "" : () => true).map(uriDecodeParts ? decodeURIComponent : (x) => x).map(useJson ? getPotentialJSONValue : (p) => p).filter(filterEmptyOutput ? (p) => p ?? false : () => true);
|
|
1280
|
-
var getPathString = (parts = [], delimiter = PATH_DELIMITER, filterEmptyInput = false, useJson = true, uriEncodeParts = false) => parts.filter(filterEmptyInput ? (p) => p ?? false : () => true).map(useJson ? (p) => JSON.stringify(p) : (x) => x).map(uriEncodeParts ? encodeURIComponent : (x) => x).join(delimiter);
|
|
1281
|
-
var buildQueryString = (query = {}) => {
|
|
1282
|
-
const parts = [];
|
|
1283
|
-
for (const [key, rawValue] of Object.entries(query)) {
|
|
1284
|
-
if (rawValue === void 0) {
|
|
1285
|
-
continue;
|
|
1286
|
-
}
|
|
1287
|
-
const values = Array.isArray(rawValue) ? rawValue : [rawValue];
|
|
1288
|
-
for (const value of values) {
|
|
1289
|
-
if (value === void 0) {
|
|
1290
|
-
continue;
|
|
1291
|
-
}
|
|
1292
|
-
const encodedKey = encodeURIComponent(key);
|
|
1293
|
-
const encodedValue = value === null ? "" : encodeURIComponent(String(value));
|
|
1294
|
-
parts.push(`${encodedKey}=${encodedValue}`);
|
|
1295
|
-
}
|
|
1296
|
-
}
|
|
1297
|
-
return parts.join("&");
|
|
1298
|
-
};
|
|
1299
|
-
var buildRoutePath = (segments, query) => {
|
|
1300
|
-
const normalizedSegments = segments.map((segment) => String(segment));
|
|
1301
|
-
const basePath = "/" + getPathString(normalizedSegments, "/", true, false, true);
|
|
1302
|
-
const queryString = query ? buildQueryString(query) : "";
|
|
1303
|
-
return queryString ? `${basePath}?${queryString}` : basePath;
|
|
1304
|
-
};
|
|
1305
|
-
var RouteContext = createContext({
|
|
1306
|
-
currentWindowPath: "",
|
|
1307
|
-
parentPath: "",
|
|
1308
|
-
params: {},
|
|
1309
|
-
isTopLevel: true
|
|
1310
|
-
});
|
|
1311
|
-
var {
|
|
1312
|
-
/**
|
|
1313
|
-
* @ignore
|
|
1314
|
-
*/
|
|
1315
|
-
Provider: RouteContextProvider,
|
|
1316
|
-
/**
|
|
1317
|
-
* @ignore
|
|
1318
|
-
*/
|
|
1319
|
-
Consumer: RouteContextConsumer
|
|
1320
|
-
} = RouteContext;
|
|
1321
|
-
|
|
1322
|
-
// src/native/utils/Route.ts
|
|
628
|
+
var createNativeBackHandler = (history) => createHistoryBackHandler(history);
|
|
1323
629
|
var createNavigationStateRouteAdapter = (options) => {
|
|
1324
630
|
const getPath = () => options.toPath(options.getState());
|
|
1325
631
|
return {
|
|
@@ -1331,6 +637,58 @@ var createNavigationStateRouteAdapter = (options) => {
|
|
|
1331
637
|
replace: options.replace ? (path) => options.replace?.(path) : void 0
|
|
1332
638
|
};
|
|
1333
639
|
};
|
|
640
|
+
var createNativeHardwareBackHandler = (adapter) => {
|
|
641
|
+
return () => {
|
|
642
|
+
if (adapter.canGoBack?.()) {
|
|
643
|
+
adapter.back?.();
|
|
644
|
+
return true;
|
|
645
|
+
}
|
|
646
|
+
return false;
|
|
647
|
+
};
|
|
648
|
+
};
|
|
649
|
+
var registerNativeHardwareBackHandler = (adapter, backHandler) => {
|
|
650
|
+
const listener = createNativeHardwareBackHandler(adapter);
|
|
651
|
+
const subscription = backHandler.addEventListener(
|
|
652
|
+
"hardwareBackPress",
|
|
653
|
+
listener
|
|
654
|
+
);
|
|
655
|
+
return () => {
|
|
656
|
+
if (typeof subscription?.remove === "function") {
|
|
657
|
+
subscription.remove();
|
|
658
|
+
return;
|
|
659
|
+
}
|
|
660
|
+
backHandler.removeEventListener?.("hardwareBackPress", listener);
|
|
661
|
+
};
|
|
662
|
+
};
|
|
663
|
+
var createNativeRouteBackIntegration = (backHandler) => {
|
|
664
|
+
return {
|
|
665
|
+
setup: (adapter) => registerNativeHardwareBackHandler(adapter, backHandler)
|
|
666
|
+
};
|
|
667
|
+
};
|
|
668
|
+
var Route2 = (props) => {
|
|
669
|
+
const hasMatcherProps = typeof props.path !== "undefined" || typeof props.exact !== "undefined" || typeof props.onParamsChange !== "undefined";
|
|
670
|
+
const nativeRuntime = {
|
|
671
|
+
platformOS: String(Platform?.OS ?? ""),
|
|
672
|
+
backHandler: BackHandler
|
|
673
|
+
};
|
|
674
|
+
const runtimeIntegration = (() => {
|
|
675
|
+
if (hasMatcherProps || nativeRuntime.platformOS === "web") {
|
|
676
|
+
return void 0;
|
|
677
|
+
}
|
|
678
|
+
const backHandler = nativeRuntime.backHandler;
|
|
679
|
+
if (!backHandler) {
|
|
680
|
+
return void 0;
|
|
681
|
+
}
|
|
682
|
+
return createNativeRouteBackIntegration(backHandler);
|
|
683
|
+
})();
|
|
684
|
+
return /* @__PURE__ */ jsx(
|
|
685
|
+
Route,
|
|
686
|
+
{
|
|
687
|
+
...props,
|
|
688
|
+
runtimeIntegration
|
|
689
|
+
}
|
|
690
|
+
);
|
|
691
|
+
};
|
|
1334
692
|
var expandPattern = (pattern, params = {}) => {
|
|
1335
693
|
const segments = getPathArray(pattern, "/", true, true, false, false);
|
|
1336
694
|
return segments.map((segment) => {
|
|
@@ -1356,4 +714,4 @@ var buildPathFromRouteChain = (routeChain, config, query) => {
|
|
|
1356
714
|
return buildRoutePath(segments, query);
|
|
1357
715
|
};
|
|
1358
716
|
|
|
1359
|
-
export { ArrayContainer, ArrayItemWrapper, AutoField, AutoForm2 as AutoForm, AutoFormView2 as AutoFormView, Button, ErrorMessage, FieldWrapper, NativeEasyLayoutView,
|
|
717
|
+
export { ArrayContainer, ArrayItemWrapper, AutoField, AutoForm2 as AutoForm, AutoFormView2 as AutoFormView, Button, ErrorMessage, FieldWrapper, NativeEasyLayoutView, Route2 as Route, buildPathFromRouteChain, createNativeBackHandler, createNativeFormRenderer, createNativeHardwareBackHandler, createNativeHistory, createNativeRouteBackIntegration, createNavigationStateRouteAdapter, makeNativeEasyLayout, mapNativeURLToPath, nativeAutoField, nativeSuite, registerNativeHardwareBackHandler, useNativeEasyLayout };
|