@resistdesign/voltra 3.0.0-alpha.26 → 3.0.0-alpha.27
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/app/index.js +90 -10
- package/app/utils/History.d.ts +17 -0
- package/app/utils/Route.d.ts +4 -0
- package/app/utils/UniversalRouteAdapter.d.ts +11 -0
- package/native/index.js +16 -15
- package/native/utils/History.d.ts +1 -12
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -218,6 +218,14 @@ How it works:
|
|
|
218
218
|
- Strategy is auto-selected:
|
|
219
219
|
- DOM + History API => browser history strategy.
|
|
220
220
|
- Otherwise => in-memory native strategy.
|
|
221
|
+
- Native strategy automatically wires Android hardware back to route history.
|
|
222
|
+
- If Voltra can go back (`history.index > 0`), it consumes the event and navigates back.
|
|
223
|
+
- If Voltra cannot go back, the event is not consumed so OS/native container behavior continues.
|
|
224
|
+
|
|
225
|
+
Optional back affordances:
|
|
226
|
+
|
|
227
|
+
- `adapter.back?.()` navigates backward when supported.
|
|
228
|
+
- `adapter.canGoBack?.()` reports whether back navigation is currently possible.
|
|
221
229
|
|
|
222
230
|
Escape hatches (root-only):
|
|
223
231
|
|
package/app/index.js
CHANGED
|
@@ -603,6 +603,20 @@ var computeTrackPixels = ({
|
|
|
603
603
|
};
|
|
604
604
|
|
|
605
605
|
// src/app/utils/History.ts
|
|
606
|
+
var createHistoryBackHandler = (history) => {
|
|
607
|
+
return {
|
|
608
|
+
/**
|
|
609
|
+
* @returns True when back navigation was handled by history.
|
|
610
|
+
*/
|
|
611
|
+
handle: () => {
|
|
612
|
+
if (history.index > 0) {
|
|
613
|
+
history.back();
|
|
614
|
+
return true;
|
|
615
|
+
}
|
|
616
|
+
return false;
|
|
617
|
+
}
|
|
618
|
+
};
|
|
619
|
+
};
|
|
606
620
|
var ensurePrefix = (value, prefix) => value ? value.startsWith(prefix) ? value : `${prefix}${value}` : "";
|
|
607
621
|
var parseHistoryPath = (inputPath) => {
|
|
608
622
|
const raw = String(inputPath ?? "").trim();
|
|
@@ -756,7 +770,9 @@ var createRouteAdapterFromHistory = (history) => {
|
|
|
756
770
|
},
|
|
757
771
|
replace: (path) => {
|
|
758
772
|
history.replace(path, { replaceSearch: true });
|
|
759
|
-
}
|
|
773
|
+
},
|
|
774
|
+
back: history.back,
|
|
775
|
+
canGoBack: () => history.index > 0
|
|
760
776
|
};
|
|
761
777
|
};
|
|
762
778
|
|
|
@@ -770,6 +786,37 @@ var getWindow = () => {
|
|
|
770
786
|
}
|
|
771
787
|
return void 0;
|
|
772
788
|
};
|
|
789
|
+
var getRuntimeRequire = () => {
|
|
790
|
+
const runtimeRequire = globalThis.__voltra_require__;
|
|
791
|
+
if (typeof runtimeRequire === "function") {
|
|
792
|
+
return runtimeRequire;
|
|
793
|
+
}
|
|
794
|
+
try {
|
|
795
|
+
return (0, eval)("require");
|
|
796
|
+
} catch (error) {
|
|
797
|
+
return void 0;
|
|
798
|
+
}
|
|
799
|
+
};
|
|
800
|
+
var tryGetReactNativeBackHandler = () => {
|
|
801
|
+
const runtimeRequire = getRuntimeRequire();
|
|
802
|
+
if (!runtimeRequire) {
|
|
803
|
+
return void 0;
|
|
804
|
+
}
|
|
805
|
+
try {
|
|
806
|
+
const reactNativeModule = runtimeRequire("react-native");
|
|
807
|
+
const platform = reactNativeModule?.Platform;
|
|
808
|
+
const backHandler = reactNativeModule?.BackHandler;
|
|
809
|
+
if (platform?.OS !== "android") {
|
|
810
|
+
return void 0;
|
|
811
|
+
}
|
|
812
|
+
if (typeof backHandler?.addEventListener !== "function") {
|
|
813
|
+
return void 0;
|
|
814
|
+
}
|
|
815
|
+
return backHandler;
|
|
816
|
+
} catch (error) {
|
|
817
|
+
return void 0;
|
|
818
|
+
}
|
|
819
|
+
};
|
|
773
820
|
var canUseBrowserHistory = () => {
|
|
774
821
|
const WINDOW = getWindow();
|
|
775
822
|
return Boolean(
|
|
@@ -823,7 +870,9 @@ var createBrowserRouteAdapter = () => {
|
|
|
823
870
|
}
|
|
824
871
|
WINDOW.history.replaceState({}, title, path);
|
|
825
872
|
notify();
|
|
826
|
-
}
|
|
873
|
+
},
|
|
874
|
+
back: () => WINDOW?.history?.back(),
|
|
875
|
+
canGoBack: () => (WINDOW?.history?.length ?? 0) > 1
|
|
827
876
|
};
|
|
828
877
|
};
|
|
829
878
|
var createNativeRouteAdapter = (initialPath = "/", ingress) => {
|
|
@@ -832,7 +881,8 @@ var createNativeRouteAdapter = (initialPath = "/", ingress) => {
|
|
|
832
881
|
const history = createMemoryHistory(initialPath);
|
|
833
882
|
const adapter = createRouteAdapterFromHistory(history);
|
|
834
883
|
let stopIngress;
|
|
835
|
-
let
|
|
884
|
+
let stopBackHandler;
|
|
885
|
+
let ingressStarted = false;
|
|
836
886
|
let subscribers = 0;
|
|
837
887
|
const applyPath = (path, mode) => {
|
|
838
888
|
const normalizedPath = parseHistoryPath(path).path;
|
|
@@ -846,10 +896,10 @@ var createNativeRouteAdapter = (initialPath = "/", ingress) => {
|
|
|
846
896
|
history.replace(normalizedPath, { replaceSearch: true });
|
|
847
897
|
};
|
|
848
898
|
const startIngress = async () => {
|
|
849
|
-
if (
|
|
899
|
+
if (ingressStarted || !ingress) {
|
|
850
900
|
return;
|
|
851
901
|
}
|
|
852
|
-
|
|
902
|
+
ingressStarted = true;
|
|
853
903
|
const startKey = history.location.key;
|
|
854
904
|
const startIndex = history.index;
|
|
855
905
|
if (ingress.subscribe) {
|
|
@@ -870,6 +920,31 @@ var createNativeRouteAdapter = (initialPath = "/", ingress) => {
|
|
|
870
920
|
}
|
|
871
921
|
}
|
|
872
922
|
};
|
|
923
|
+
const startBackHandler = () => {
|
|
924
|
+
if (stopBackHandler) {
|
|
925
|
+
return;
|
|
926
|
+
}
|
|
927
|
+
const reactNativeBackHandler = tryGetReactNativeBackHandler();
|
|
928
|
+
if (!reactNativeBackHandler) {
|
|
929
|
+
return;
|
|
930
|
+
}
|
|
931
|
+
const historyBackHandler = createHistoryBackHandler(history);
|
|
932
|
+
const handleHardwareBackPress = () => historyBackHandler.handle();
|
|
933
|
+
const subscription = reactNativeBackHandler.addEventListener(
|
|
934
|
+
"hardwareBackPress",
|
|
935
|
+
handleHardwareBackPress
|
|
936
|
+
);
|
|
937
|
+
stopBackHandler = () => {
|
|
938
|
+
if (typeof subscription?.remove === "function") {
|
|
939
|
+
subscription.remove();
|
|
940
|
+
return;
|
|
941
|
+
}
|
|
942
|
+
reactNativeBackHandler.removeEventListener?.(
|
|
943
|
+
"hardwareBackPress",
|
|
944
|
+
handleHardwareBackPress
|
|
945
|
+
);
|
|
946
|
+
};
|
|
947
|
+
};
|
|
873
948
|
return {
|
|
874
949
|
...adapter,
|
|
875
950
|
push: (path, title) => {
|
|
@@ -888,18 +963,23 @@ var createNativeRouteAdapter = (initialPath = "/", ingress) => {
|
|
|
888
963
|
subscribers += 1;
|
|
889
964
|
if (subscribers === 1) {
|
|
890
965
|
void startIngress();
|
|
966
|
+
startBackHandler();
|
|
891
967
|
}
|
|
892
968
|
const unlisten = adapter.subscribe(listener);
|
|
893
969
|
return () => {
|
|
894
970
|
unlisten();
|
|
895
971
|
subscribers = Math.max(0, subscribers - 1);
|
|
896
|
-
if (subscribers === 0
|
|
897
|
-
stopIngress();
|
|
972
|
+
if (subscribers === 0) {
|
|
973
|
+
stopIngress?.();
|
|
898
974
|
stopIngress = void 0;
|
|
899
|
-
|
|
975
|
+
ingressStarted = false;
|
|
976
|
+
stopBackHandler?.();
|
|
977
|
+
stopBackHandler = void 0;
|
|
900
978
|
}
|
|
901
979
|
};
|
|
902
|
-
}
|
|
980
|
+
},
|
|
981
|
+
back: adapter.back,
|
|
982
|
+
canGoBack: adapter.canGoBack
|
|
903
983
|
};
|
|
904
984
|
};
|
|
905
985
|
var createUniversalAdapter = (options = {}) => {
|
|
@@ -1735,4 +1815,4 @@ var AutoForm = ({
|
|
|
1735
1815
|
);
|
|
1736
1816
|
};
|
|
1737
1817
|
|
|
1738
|
-
export { ApplicationStateContext, ApplicationStateProvider, AutoForm, AutoFormView, Route, RouteContext, RouteContextConsumer, RouteContextProvider, RouteProvider, TypeInfoORMClient, buildHistoryPath, buildQueryString, buildRoutePath, canUseBrowserHistory, computeAreaBounds, computeTrackPixels, createAutoField, createBrowserRouteAdapter, createEasyLayout, createFormRenderer, createManualRouteAdapter, createMemoryHistory, createNativeRouteAdapter, createRouteAdapterFromHistory, createUniversalAdapter, getApplicationStateIdentifier, getApplicationStateModified, getApplicationStateValue, getApplicationStateValueStructure, getChangedDependencyIndexes, getEasyLayoutTemplateDetails, getFieldKind, getFullUrl, getPascalCaseAreaName, handleRequest, mergeSuites, parseHistoryPath, parseTemplate, requestHandlerFactory, resolveSuite, sendServiceRequest, setApplicationStateModified, setApplicationStateValue, useApplicationStateLoader, useApplicationStateValue, useApplicationStateValueStructure, useController, useDebugDependencies, useFormEngine, useRouteContext, useTypeInfoORMAPI, validateAreas, withRendererOverride };
|
|
1818
|
+
export { ApplicationStateContext, ApplicationStateProvider, AutoForm, AutoFormView, Route, RouteContext, RouteContextConsumer, RouteContextProvider, RouteProvider, TypeInfoORMClient, buildHistoryPath, buildQueryString, buildRoutePath, canUseBrowserHistory, computeAreaBounds, computeTrackPixels, createAutoField, createBrowserRouteAdapter, createEasyLayout, createFormRenderer, createHistoryBackHandler, createManualRouteAdapter, createMemoryHistory, createNativeRouteAdapter, createRouteAdapterFromHistory, createUniversalAdapter, getApplicationStateIdentifier, getApplicationStateModified, getApplicationStateValue, getApplicationStateValueStructure, getChangedDependencyIndexes, getEasyLayoutTemplateDetails, getFieldKind, getFullUrl, getPascalCaseAreaName, handleRequest, mergeSuites, parseHistoryPath, parseTemplate, requestHandlerFactory, resolveSuite, sendServiceRequest, setApplicationStateModified, setApplicationStateValue, tryGetReactNativeBackHandler, useApplicationStateLoader, useApplicationStateValue, useApplicationStateValueStructure, useController, useDebugDependencies, useFormEngine, useRouteContext, useTypeInfoORMAPI, validateAreas, withRendererOverride };
|
package/app/utils/History.d.ts
CHANGED
|
@@ -98,6 +98,23 @@ export type HistoryController = {
|
|
|
98
98
|
*/
|
|
99
99
|
listen: (listener: HistoryListener) => () => void;
|
|
100
100
|
};
|
|
101
|
+
/**
|
|
102
|
+
* Back-navigation consumption helper for shared history controllers.
|
|
103
|
+
*
|
|
104
|
+
* Returns `true` only when history consumed the back action.
|
|
105
|
+
*
|
|
106
|
+
* Example:
|
|
107
|
+
* ```ts
|
|
108
|
+
* const handler = createHistoryBackHandler(history);
|
|
109
|
+
* const consumed = handler.handle();
|
|
110
|
+
* ```
|
|
111
|
+
*/
|
|
112
|
+
export declare const createHistoryBackHandler: (history: HistoryController) => {
|
|
113
|
+
/**
|
|
114
|
+
* @returns True when back navigation was handled by history.
|
|
115
|
+
*/
|
|
116
|
+
handle: () => boolean;
|
|
117
|
+
};
|
|
101
118
|
/**
|
|
102
119
|
* Parse a path-like value into normalized path/search/hash parts.
|
|
103
120
|
*
|
package/app/utils/Route.d.ts
CHANGED
|
@@ -18,6 +18,10 @@ export type RouteAdapter = {
|
|
|
18
18
|
push?: (path: string, title?: string) => void;
|
|
19
19
|
/** Optional navigation helper for adapters that can replace state. */
|
|
20
20
|
replace?: (path: string, title?: string) => void;
|
|
21
|
+
/** Optional navigation helper for adapters that can go backward. */
|
|
22
|
+
back?: () => void;
|
|
23
|
+
/** Optional capability check for backward navigation. */
|
|
24
|
+
canGoBack?: () => boolean;
|
|
21
25
|
};
|
|
22
26
|
/**
|
|
23
27
|
* Supported query value types for route serialization.
|
|
@@ -55,6 +55,16 @@ export type UniversalRouteIngress = {
|
|
|
55
55
|
*/
|
|
56
56
|
mapURLToPath?: (url: string) => string;
|
|
57
57
|
};
|
|
58
|
+
type ReactNativeBackHandler = {
|
|
59
|
+
addEventListener: (eventName: "hardwareBackPress", listener: () => boolean) => {
|
|
60
|
+
remove?: () => void;
|
|
61
|
+
} | void;
|
|
62
|
+
removeEventListener?: (eventName: "hardwareBackPress", listener: () => boolean) => void;
|
|
63
|
+
};
|
|
64
|
+
/**
|
|
65
|
+
* Safely resolve React Native BackHandler for Android runtimes only.
|
|
66
|
+
*/
|
|
67
|
+
export declare const tryGetReactNativeBackHandler: () => ReactNativeBackHandler | undefined;
|
|
58
68
|
/**
|
|
59
69
|
* Detect whether browser history is available at runtime.
|
|
60
70
|
*/
|
|
@@ -71,3 +81,4 @@ export declare const createNativeRouteAdapter: (initialPath?: string, ingress?:
|
|
|
71
81
|
* Create a runtime-selected RouteAdapter for web/native environments.
|
|
72
82
|
*/
|
|
73
83
|
export declare const createUniversalAdapter: (options?: CreateUniversalAdapterOptions) => RouteAdapter;
|
|
84
|
+
export {};
|
package/native/index.js
CHANGED
|
@@ -721,6 +721,20 @@ var AutoForm2 = (props) => {
|
|
|
721
721
|
};
|
|
722
722
|
|
|
723
723
|
// src/app/utils/History.ts
|
|
724
|
+
var createHistoryBackHandler = (history) => {
|
|
725
|
+
return {
|
|
726
|
+
/**
|
|
727
|
+
* @returns True when back navigation was handled by history.
|
|
728
|
+
*/
|
|
729
|
+
handle: () => {
|
|
730
|
+
if (history.index > 0) {
|
|
731
|
+
history.back();
|
|
732
|
+
return true;
|
|
733
|
+
}
|
|
734
|
+
return false;
|
|
735
|
+
}
|
|
736
|
+
};
|
|
737
|
+
};
|
|
724
738
|
var ensurePrefix = (value, prefix) => value ? value.startsWith(prefix) ? value : `${prefix}${value}` : "";
|
|
725
739
|
var parseHistoryPath = (inputPath) => {
|
|
726
740
|
const raw = String(inputPath ?? "").trim();
|
|
@@ -1252,20 +1266,7 @@ var createNativeHistory = (options = {}) => {
|
|
|
1252
1266
|
}
|
|
1253
1267
|
};
|
|
1254
1268
|
};
|
|
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
|
+
var createNativeBackHandler = (history) => createHistoryBackHandler(history);
|
|
1269
1270
|
|
|
1270
1271
|
// src/common/Routing.ts
|
|
1271
1272
|
var PATH_DELIMITER = "/";
|
|
@@ -1356,4 +1357,4 @@ var buildPathFromRouteChain = (routeChain, config, query) => {
|
|
|
1356
1357
|
return buildRoutePath(segments, query);
|
|
1357
1358
|
};
|
|
1358
1359
|
|
|
1359
|
-
export { ArrayContainer, ArrayItemWrapper, AutoField, AutoForm2 as AutoForm, AutoFormView2 as AutoFormView, Button, ErrorMessage, FieldWrapper, NativeEasyLayoutView, buildHistoryPath, buildPathFromRouteChain, createMemoryHistory, createNativeBackHandler, createNativeFormRenderer, createNativeHistory, createNavigationStateRouteAdapter, makeNativeEasyLayout, mapNativeURLToPath, nativeAutoField, nativeSuite, parseHistoryPath, useNativeEasyLayout };
|
|
1360
|
+
export { ArrayContainer, ArrayItemWrapper, AutoField, AutoForm2 as AutoForm, AutoFormView2 as AutoFormView, Button, ErrorMessage, FieldWrapper, NativeEasyLayoutView, buildHistoryPath, buildPathFromRouteChain, createHistoryBackHandler, createMemoryHistory, createNativeBackHandler, createNativeFormRenderer, createNativeHistory, createNavigationStateRouteAdapter, makeNativeEasyLayout, mapNativeURLToPath, nativeAutoField, nativeSuite, parseHistoryPath, useNativeEasyLayout };
|
|
@@ -95,19 +95,8 @@ export declare const mapNativeURLToPath: (url: string) => string;
|
|
|
95
95
|
*/
|
|
96
96
|
export declare const createNativeHistory: (options?: CreateNativeHistoryOptions) => NativeHistoryController;
|
|
97
97
|
/**
|
|
98
|
-
*
|
|
99
|
-
*
|
|
100
|
-
* Returns `true` only when history consumed the back action.
|
|
101
|
-
*
|
|
102
|
-
* Example:
|
|
103
|
-
* ```ts
|
|
104
|
-
* const handler = createNativeBackHandler(history);
|
|
105
|
-
* const consumed = handler.handle();
|
|
106
|
-
* ```
|
|
98
|
+
* @deprecated Use {@link createHistoryBackHandler} from `app/utils/History`.
|
|
107
99
|
*/
|
|
108
100
|
export declare const createNativeBackHandler: (history: HistoryController) => {
|
|
109
|
-
/**
|
|
110
|
-
* @returns True when back navigation was handled by history.
|
|
111
|
-
*/
|
|
112
101
|
handle: () => boolean;
|
|
113
102
|
};
|