@resistdesign/voltra 3.0.0-alpha.45 → 3.0.0-alpha.47

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 CHANGED
@@ -242,6 +242,7 @@ const coords = layout.computeNativeCoords({
242
242
 
243
243
  Voltra routing uses the same `Route` API across app/web/native.
244
244
  Use the platform barrel for root `Route` so runtime mechanics are auto-wired.
245
+ The routing model is path/history based on every platform.
245
246
 
246
247
  Reference example: `examples/routing/app-routing.ts`
247
248
 
@@ -271,10 +272,22 @@ import { Route } from "@resistdesign/voltra/native";
271
272
  </Route>;
272
273
  ```
273
274
 
275
+ On native, Voltra provides the missing browser-like pieces:
276
+
277
+ - history-style path state for environments without the browser History API
278
+ - deep-link URL ingress so app opens behave like web navigations
279
+ - hardware back wiring into that same history model
280
+ - the `native` barrel auto-selects browser behavior on React Native web targets
281
+ and native-history behavior on mobile targets
282
+
274
283
  How it works:
275
284
 
276
285
  - Root `<Route>` (no `path`) is provider mode.
277
286
  - Nested `<Route path="...">` entries are matcher mode.
287
+ - Shared app routing matches normalized path strings on every platform.
288
+ - Web already receives a browser pathname.
289
+ - Native provides the browser-like history/path source that mobile lacks.
290
+ - Native deep-link ingress is mapped into that same path/history model.
278
291
  - Strategy is auto-selected:
279
292
  - DOM + History API => browser history strategy.
280
293
  - Otherwise => in-memory native strategy.
package/api/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import { TypeInfoORMUpdateOperators, ITEM_RELATIONSHIP_DAC_RESOURCE_NAME, ComparisonOperators } from '../chunk-RUNXRISF.js';
2
- import { getNoErrorDescriptor, getErrorDescriptor, ERROR_MESSAGE_CONSTANTS, validateTypeOperationAllowed, getValidityValue, validateTypeInfoValue, validateTypeInfoFieldValue } from '../chunk-YCTVEW2I.js';
3
- import { mergeStringPaths, getPathString, getPathArray } from '../chunk-WNFRDIBW.js';
2
+ import { getNoErrorDescriptor, getErrorDescriptor, ERROR_MESSAGE_CONSTANTS, validateTypeOperationAllowed, getValidityValue, validateTypeInfoValue, validateTypeInfoFieldValue } from '../chunk-3HVYVX3S.js';
3
+ import { mergeStringPaths, getPathString, getPathArray } from '../chunk-2JDOM6PB.js';
4
4
  import '../chunk-I2KLQ2HA.js';
5
5
  import { QueryCommand, PutItemCommand, ConditionalCheckFailedException, GetItemCommand, BatchGetItemCommand, BatchWriteItemCommand, DynamoDBClient, UpdateItemCommand, DeleteItemCommand, ScanCommand } from '@aws-sdk/client-dynamodb';
6
6
  import { marshall, unmarshall } from '@aws-sdk/util-dynamodb';
package/app/index.js CHANGED
@@ -1,9 +1,9 @@
1
- export { createEasyLayout, getEasyLayoutTemplateDetails, getPascalCaseAreaName } from '../chunk-CMH6L5QQ.js';
1
+ export { createEasyLayout, getEasyLayoutTemplateDetails, getPascalCaseAreaName } from '../chunk-QXYUXJKM.js';
2
2
  export { computeTrackPixels } from '../chunk-TJFTWPXQ.js';
3
- export { AutoForm, AutoFormView, Route, RouteContext, RouteContextConsumer, RouteContextProvider, RouteProvider, buildHistoryPath, buildQueryString, buildRoutePath, canUseBrowserHistory, computeAreaBounds, createAutoField, createBrowserRouteAdapter, createFormRenderer, createHistoryBackHandler, createManualRouteAdapter, createMemoryHistory, createNativeRouteAdapter, createRouteAdapterFromHistory, createUniversalAdapter, defaultTranslateValidationErrorCode, getFieldKind, parseHistoryPath, parseTemplate, resolveSuite, useFormEngine, useRouteContext, validateAreas, wrapRouteAdapterWithPathResolver } from '../chunk-44BMFTKD.js';
3
+ export { AutoForm, AutoFormView, Route, RouteContext, RouteContextConsumer, RouteContextProvider, RouteProvider, buildHistoryPath, buildQueryString, buildRoutePath, canUseBrowserHistory, computeAreaBounds, createAutoField, createBrowserRouteAdapter, createFormRenderer, createHistoryBackHandler, createManualRouteAdapter, createMemoryHistory, createNativeRouteAdapter, createRouteAdapterFromHistory, createUniversalAdapter, defaultTranslateValidationErrorCode, getFieldKind, parseHistoryPath, parseTemplate, resolveSuite, useFormEngine, useRouteContext, validateAreas, wrapRouteAdapterWithPathResolver } from '../chunk-UD2ALOCE.js';
4
4
  import '../chunk-RUNXRISF.js';
5
- import '../chunk-YCTVEW2I.js';
6
- import { mergeStringPaths, PATH_DELIMITER } from '../chunk-WNFRDIBW.js';
5
+ import '../chunk-3HVYVX3S.js';
6
+ import { mergeStringPaths, PATH_DELIMITER } from '../chunk-2JDOM6PB.js';
7
7
  import '../chunk-I2KLQ2HA.js';
8
8
  import { createContext, useContext, useRef, useMemo, useCallback, useState, useEffect } from 'react';
9
9
  import { jsx } from 'react/jsx-runtime';
@@ -84,7 +84,15 @@ export declare const buildQueryString: (query?: RouteQuery) => string;
84
84
  */
85
85
  export declare const buildRoutePath: (segments: Array<string | number>, query?: RouteQuery) => string;
86
86
  /**
87
- * Access values for the current Route.
87
+ * Access values for the current `Route`.
88
+ *
89
+ * `parentPath` is the consumer-facing route pattern for the currently matched
90
+ * parent route chain, expressed as plain slash-delimited segments such as
91
+ * `app/books/:id`.
92
+ *
93
+ * `parentPathInternal` carries the same logical route pattern in the
94
+ * JSON-serialized segment format used by the shared routing internals. Most
95
+ * consumers should prefer `parentPath`.
88
96
  */
89
97
  export type RouteContextType = {
90
98
  /**
@@ -92,9 +100,17 @@ export type RouteContextType = {
92
100
  */
93
101
  currentWindowPath: string;
94
102
  /**
95
- * The parent path for this route level.
103
+ * Consumer-facing parent route pattern for this route level.
104
+ *
105
+ * Example: `app/books/:id`
96
106
  */
97
107
  parentPath: string;
108
+ /**
109
+ * Internal parent route pattern used by routing utilities and matcher logic.
110
+ *
111
+ * Example: `"app"/"books"/":id"`
112
+ */
113
+ parentPathInternal: string;
98
114
  /**
99
115
  * Aggregated route params from parent and current routes.
100
116
  */
@@ -116,6 +132,10 @@ export declare const RouteContextProvider: import("react").Provider<RouteContext
116
132
  /**
117
133
  * Access Route path and parameter information.
118
134
  *
135
+ * Use `parentPath` for app-facing route logic. `parentPathInternal` is exposed
136
+ * so advanced integrations can align with the internal routing helpers when
137
+ * needed.
138
+ *
119
139
  * @returns The current route context.
120
140
  */
121
141
  export declare const useRouteContext: () => RouteContextType;
package/build/index.js CHANGED
@@ -1,4 +1,4 @@
1
- import { getPotentialJSONValue, getPathArray } from '../chunk-WNFRDIBW.js';
1
+ import { getPotentialJSONValue, getPathArray } from '../chunk-2JDOM6PB.js';
2
2
  import '../chunk-I2KLQ2HA.js';
3
3
  import { SyntaxKind, isLiteralTypeNode, isStringLiteral, isNumericLiteral, createSourceFile, ScriptTarget } from 'typescript';
4
4
 
@@ -33,6 +33,23 @@ var mergeStringPaths = (path1, path2, delimiter = PATH_DELIMITER, filterEmptyOut
33
33
  useJson,
34
34
  uriEncodeParts
35
35
  );
36
+ var resolvePath = (currentPath, newPath) => {
37
+ const newSegments = getPathArray(newPath, PATH_DELIMITER, true);
38
+ let currentSegments = getPathArray(currentPath, PATH_DELIMITER, true);
39
+ if (newPath.startsWith("/")) {
40
+ currentSegments = [];
41
+ }
42
+ newSegments.forEach((segment) => {
43
+ if (segment === "..") {
44
+ if (currentSegments.length > 0) {
45
+ currentSegments.pop();
46
+ }
47
+ } else if (segment !== ".") {
48
+ currentSegments.push(segment);
49
+ }
50
+ });
51
+ return "/" + currentSegments.join("/");
52
+ };
36
53
  var splitRoutePathParts = (rawPath) => {
37
54
  let path = rawPath;
38
55
  let hash = "";
@@ -118,4 +135,4 @@ var getParamsAndTestPath = (path, testPath, exact = false) => {
118
135
  }
119
136
  };
120
137
 
121
- export { PATH_DELIMITER, getParamsAndTestPath, getPathArray, getPathString, getPotentialJSONValue, mergeStringPaths, resolveRouteAdapterPath };
138
+ export { PATH_DELIMITER, getParamsAndTestPath, getPathArray, getPathString, getPotentialJSONValue, mergeStringPaths, resolvePath, resolveRouteAdapterPath };
@@ -1,4 +1,4 @@
1
- import { getPathString } from './chunk-WNFRDIBW.js';
1
+ import { getPathString } from './chunk-2JDOM6PB.js';
2
2
 
3
3
  // src/common/TypeParsing/TypeInfo.ts
4
4
  var TypeOperation = /* @__PURE__ */ ((TypeOperation2) => {
@@ -1,4 +1,4 @@
1
- import { parseTemplate, validateAreas } from './chunk-44BMFTKD.js';
1
+ import { parseTemplate, validateAreas } from './chunk-UD2ALOCE.js';
2
2
 
3
3
  // src/app/utils/EasyLayout.tsx
4
4
  var getPascalCaseAreaName = (area) => {
@@ -1,5 +1,5 @@
1
- import { getErrorDescriptor, getNoErrorDescriptor, validateTypeInfoDataItem, getArrayItemErrorMap, getErrorDescriptors, ERROR_MESSAGE_CONSTANTS } from './chunk-YCTVEW2I.js';
2
- import { resolveRouteAdapterPath, getPathString, mergeStringPaths, getParamsAndTestPath } from './chunk-WNFRDIBW.js';
1
+ import { getErrorDescriptor, getNoErrorDescriptor, validateTypeInfoDataItem, getArrayItemErrorMap, getErrorDescriptors, ERROR_MESSAGE_CONSTANTS } from './chunk-3HVYVX3S.js';
2
+ import { resolveRouteAdapterPath, getPathString, mergeStringPaths, getParamsAndTestPath, getPathArray, PATH_DELIMITER } from './chunk-2JDOM6PB.js';
3
3
  import { createContext, useContext, useMemo, useState, useEffect, useCallback, createElement, useRef } from 'react';
4
4
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
5
5
 
@@ -540,9 +540,17 @@ var buildRoutePath = (segments, query) => {
540
540
  const queryString = query ? buildQueryString(query) : "";
541
541
  return queryString ? `${basePath}?${queryString}` : basePath;
542
542
  };
543
+ var getReadableRoutePath = (path) => getPathString(
544
+ getPathArray(path, PATH_DELIMITER, true, true, true, false),
545
+ PATH_DELIMITER,
546
+ true,
547
+ false,
548
+ false
549
+ );
543
550
  var RouteContext = createContext({
544
551
  currentWindowPath: "",
545
552
  parentPath: "",
553
+ parentPathInternal: "",
546
554
  params: {},
547
555
  isTopLevel: true
548
556
  });
@@ -646,6 +654,7 @@ var RouteProvider = ({
646
654
  () => ({
647
655
  currentWindowPath: currentPath,
648
656
  parentPath: "",
657
+ parentPathInternal: "",
649
658
  params: {},
650
659
  isTopLevel: true,
651
660
  adapter: normalizedAdapter
@@ -666,6 +675,7 @@ var RouteMatcher = ({
666
675
  const {
667
676
  currentWindowPath = "",
668
677
  parentPath = "",
678
+ parentPathInternal = "",
669
679
  params: parentParams = {},
670
680
  adapter
671
681
  } = useRouteContext();
@@ -685,7 +695,10 @@ var RouteMatcher = ({
685
695
  const matchedRoute = useMemo(
686
696
  () => {
687
697
  for (const routePathConfig of normalizedPaths) {
688
- const fullPath = mergeStringPaths(parentPath, routePathConfig.path);
698
+ const fullPath = mergeStringPaths(
699
+ parentPathInternal,
700
+ routePathConfig.path
701
+ );
689
702
  const newParams = getParamsAndTestPath(
690
703
  targetCurrentPath,
691
704
  fullPath,
@@ -700,7 +713,7 @@ var RouteMatcher = ({
700
713
  }
701
714
  return null;
702
715
  },
703
- [targetCurrentPath, parentPath, normalizedPaths]
716
+ [targetCurrentPath, parentPathInternal, normalizedPaths]
704
717
  );
705
718
  const params = useMemo(
706
719
  () => ({
@@ -712,12 +725,13 @@ var RouteMatcher = ({
712
725
  const newRouteContext = useMemo(
713
726
  () => ({
714
727
  currentWindowPath: targetCurrentPath,
715
- parentPath: matchedRoute?.fullPath ?? parentPath,
728
+ parentPath: getReadableRoutePath(matchedRoute?.fullPath ?? parentPathInternal),
729
+ parentPathInternal: matchedRoute?.fullPath ?? parentPathInternal,
716
730
  params,
717
731
  isTopLevel: false,
718
732
  adapter
719
733
  }),
720
- [targetCurrentPath, matchedRoute, parentPath, params, adapter]
734
+ [targetCurrentPath, matchedRoute, parentPathInternal, params, adapter]
721
735
  );
722
736
  useEffect(() => {
723
737
  if (onParamsChange) {
package/common/index.d.ts CHANGED
@@ -7,10 +7,12 @@
7
7
  * Import from the common subpath only:
8
8
  * ```ts
9
9
  * import {
10
+ * getPathArray,
10
11
  * getPathString,
11
12
  * getSimpleId,
12
13
  * } from "@resistdesign/voltra/common";
13
14
  *
15
+ * const segments = getPathArray("/users/42", "/", true, true, false, false);
14
16
  * const path = getPathString(["users", 42], "/", true, false);
15
17
  * const id = getSimpleId();
16
18
  * ```
@@ -28,6 +30,11 @@ export type * from "./HelperTypes";
28
30
  * @group Command Line
29
31
  */
30
32
  export * from "./CommandLine";
33
+ /**
34
+ * @category common
35
+ * @group Routing
36
+ */
37
+ export * from "./Routing";
31
38
  /**
32
39
  * @category common
33
40
  * @group Type Parsing
package/common/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  export { ComparisonOperators, ITEM_RELATIONSHIP_DAC_RESOURCE_NAME, LogicalOperators, OperationGroup, RelationshipOperation, TypeInfoORMAPIRoutePaths, TypeInfoORMServiceError, TypeInfoORMUpdateOperators } from '../chunk-RUNXRISF.js';
2
- export { DENIED_TYPE_OPERATIONS, ERROR_MESSAGE_CONSTANTS, INVALID_CUSTOM_TYPE, PRIMITIVE_ERROR_MESSAGE_CONSTANTS, RelationshipValidationType, TYPE_KEYWORD_ERROR_MESSAGE_CONSTANTS, TYPE_KEYWORD_VALIDATORS, TypeOperation, getArrayItemErrorMap, getErrorDescriptor, getErrorDescriptors, getNoErrorDescriptor, getValidityValue, hasValue, isArrayErrorDescriptorCollection, validateArrayOfTypeInfoFieldValues, validateCustomType, validateKeywordType, validateTypeInfoDataItem, validateTypeInfoFieldOperationAllowed, validateTypeInfoFieldValue, validateTypeInfoValue, validateTypeOperationAllowed, validateValueMatchesPattern } from '../chunk-YCTVEW2I.js';
3
- import '../chunk-WNFRDIBW.js';
2
+ export { DENIED_TYPE_OPERATIONS, ERROR_MESSAGE_CONSTANTS, INVALID_CUSTOM_TYPE, PRIMITIVE_ERROR_MESSAGE_CONSTANTS, RelationshipValidationType, TYPE_KEYWORD_ERROR_MESSAGE_CONSTANTS, TYPE_KEYWORD_VALIDATORS, TypeOperation, getArrayItemErrorMap, getErrorDescriptor, getErrorDescriptors, getNoErrorDescriptor, getValidityValue, hasValue, isArrayErrorDescriptorCollection, validateArrayOfTypeInfoFieldValues, validateCustomType, validateKeywordType, validateTypeInfoDataItem, validateTypeInfoFieldOperationAllowed, validateTypeInfoFieldValue, validateTypeInfoValue, validateTypeOperationAllowed, validateValueMatchesPattern } from '../chunk-3HVYVX3S.js';
3
+ export { PATH_DELIMITER, getParamsAndTestPath, getPathArray, getPathString, getPotentialJSONValue, mergeStringPaths, resolvePath, resolveRouteAdapterPath } from '../chunk-2JDOM6PB.js';
4
4
  import '../chunk-I2KLQ2HA.js';
5
5
 
6
6
  // src/common/CommandLine/collectRequiredEnvironmentVariables.ts
package/native/index.js CHANGED
@@ -1,9 +1,9 @@
1
1
  import { computeTrackPixels } from '../chunk-TJFTWPXQ.js';
2
- import { createFormRenderer, createHistoryBackHandler, buildHistoryPath, AutoFormView, AutoForm, parseTemplate, validateAreas, computeAreaBounds, parseHistoryPath, createMemoryHistory, Route, buildRoutePath } from '../chunk-44BMFTKD.js';
3
- import { ERROR_MESSAGE_CONSTANTS } from '../chunk-YCTVEW2I.js';
4
- import { resolveRouteAdapterPath, getPathArray } from '../chunk-WNFRDIBW.js';
2
+ import { createFormRenderer, createHistoryBackHandler, buildHistoryPath, AutoFormView, AutoForm, parseTemplate, validateAreas, computeAreaBounds, parseHistoryPath, createMemoryHistory, createBrowserRouteAdapter, Route, createRouteAdapterFromHistory } from '../chunk-UD2ALOCE.js';
3
+ import { ERROR_MESSAGE_CONSTANTS } from '../chunk-3HVYVX3S.js';
4
+ import '../chunk-2JDOM6PB.js';
5
5
  import '../chunk-I2KLQ2HA.js';
6
- import { createElement, useMemo } from 'react';
6
+ import { createElement, useMemo, useRef } from 'react';
7
7
  import { Text, View, Platform, Switch, TextInput, Pressable, BackHandler } from 'react-native';
8
8
  import { jsx } from 'react/jsx-runtime';
9
9
 
@@ -580,10 +580,13 @@ var createNativeHistory = (options = {}) => {
580
580
  adapter,
581
581
  initialPath = "/",
582
582
  onIncomingURL = "replace",
583
- mapURLToPath = mapNativeURLToPath
583
+ mapURLToPath = mapNativeURLToPath,
584
+ backHandler
584
585
  } = options;
585
586
  const history = createMemoryHistory(initialPath);
587
+ const historyBackHandler = createHistoryBackHandler(history);
586
588
  let unsubscribe;
589
+ let stopBackHandler;
587
590
  let started = false;
588
591
  const applyIncomingURL = (url) => {
589
592
  if (!url) {
@@ -620,6 +623,20 @@ var createNativeHistory = (options = {}) => {
620
623
  return;
621
624
  }
622
625
  started = true;
626
+ if (backHandler && !stopBackHandler) {
627
+ const listener = () => historyBackHandler.handle();
628
+ const subscription = backHandler.addEventListener(
629
+ "hardwareBackPress",
630
+ listener
631
+ );
632
+ stopBackHandler = () => {
633
+ if (typeof subscription?.remove === "function") {
634
+ subscription.remove();
635
+ return;
636
+ }
637
+ backHandler.removeEventListener?.("hardwareBackPress", listener);
638
+ };
639
+ }
623
640
  if (!adapter) {
624
641
  return;
625
642
  }
@@ -651,23 +668,13 @@ var createNativeHistory = (options = {}) => {
651
668
  }
652
669
  unsubscribe?.();
653
670
  unsubscribe = void 0;
671
+ stopBackHandler?.();
672
+ stopBackHandler = void 0;
654
673
  started = false;
655
674
  }
656
675
  };
657
676
  };
658
677
  var createNativeBackHandler = (history) => createHistoryBackHandler(history);
659
- var createNavigationStateRouteAdapter = (options) => {
660
- const getPath = () => options.toPath(options.getState());
661
- const resolvePath = (path) => resolveRouteAdapterPath(getPath(), path);
662
- return {
663
- getPath,
664
- subscribe: (listener) => options.subscribe(() => {
665
- listener(getPath());
666
- }),
667
- push: options.navigate ? (path) => options.navigate?.(resolvePath(path)) : void 0,
668
- replace: options.replace ? (path) => options.replace?.(resolvePath(path)) : void 0
669
- };
670
- };
671
678
  var createNativeHardwareBackHandler = (adapter) => {
672
679
  return () => {
673
680
  if (adapter.canGoBack?.()) {
@@ -696,53 +703,63 @@ var createNativeRouteBackIntegration = (backHandler) => {
696
703
  setup: (adapter) => registerNativeHardwareBackHandler(adapter, backHandler)
697
704
  };
698
705
  };
706
+ var createNativeHistoryRouteAdapter = (initialPath, ingress, backHandler) => {
707
+ const history = createNativeHistory({
708
+ initialPath,
709
+ backHandler,
710
+ ...ingress ? {
711
+ adapter: {
712
+ getInitialURL: async () => await ingress.getInitialURL?.() ?? null,
713
+ subscribe: (listener) => ingress.subscribe?.(listener) ?? (() => {
714
+ })
715
+ },
716
+ onIncomingURL: ingress.onIncomingURL,
717
+ mapURLToPath: ingress.mapURLToPath
718
+ } : {}
719
+ });
720
+ const adapter = createRouteAdapterFromHistory(history);
721
+ let subscribers = 0;
722
+ return {
723
+ ...adapter,
724
+ subscribe: (listener) => {
725
+ subscribers += 1;
726
+ if (subscribers === 1) {
727
+ void history.start();
728
+ }
729
+ const unlisten = adapter.subscribe(listener);
730
+ return () => {
731
+ unlisten();
732
+ subscribers = Math.max(0, subscribers - 1);
733
+ if (subscribers === 0) {
734
+ history.stop();
735
+ }
736
+ };
737
+ }
738
+ };
739
+ };
699
740
  var Route2 = (props) => {
700
741
  const hasMatcherProps = typeof props.path !== "undefined" || typeof props.exact !== "undefined" || typeof props.onParamsChange !== "undefined";
701
742
  const nativeRuntime = {
702
743
  platformOS: String(Platform?.OS ?? ""),
703
744
  backHandler: BackHandler
704
745
  };
705
- const runtimeIntegration = (() => {
706
- if (hasMatcherProps || nativeRuntime.platformOS === "web") {
707
- return void 0;
708
- }
709
- const backHandler = nativeRuntime.backHandler;
710
- if (!backHandler) {
711
- return void 0;
712
- }
713
- return createNativeRouteBackIntegration(backHandler);
714
- })();
715
- return /* @__PURE__ */ jsx(
746
+ const shouldUseAutoAdapter = !hasMatcherProps && typeof props.adapter === "undefined";
747
+ const routeProps = props;
748
+ const adapterRef = useRef(null);
749
+ if (shouldUseAutoAdapter && !adapterRef.current) {
750
+ adapterRef.current = nativeRuntime.platformOS === "web" ? createBrowserRouteAdapter() : createNativeHistoryRouteAdapter(
751
+ props.initialPath,
752
+ props.ingress,
753
+ nativeRuntime.backHandler
754
+ );
755
+ }
756
+ return shouldUseAutoAdapter ? /* @__PURE__ */ jsx(
716
757
  Route,
717
758
  {
718
- ...props,
719
- runtimeIntegration
759
+ ...routeProps,
760
+ adapter: adapterRef.current ?? void 0
720
761
  }
721
- );
722
- };
723
- var expandPattern = (pattern, params = {}) => {
724
- const segments = getPathArray(pattern, "/", true, true, false, false);
725
- return segments.map((segment) => {
726
- if (segment.startsWith(":")) {
727
- const key = segment.slice(1);
728
- if (!(key in params)) {
729
- throw new Error(`Missing param "${key}" for route pattern "${pattern}".`);
730
- }
731
- return params[key];
732
- }
733
- return segment;
734
- });
735
- };
736
- var buildPathFromRouteChain = (routeChain, config, query) => {
737
- const segments = [];
738
- routeChain.forEach((route) => {
739
- const pattern = config[route.name];
740
- if (!pattern) {
741
- throw new Error(`Missing route pattern for "${route.name}".`);
742
- }
743
- segments.push(...expandPattern(pattern, route.params));
744
- });
745
- return buildRoutePath(segments, query);
762
+ ) : /* @__PURE__ */ jsx(Route, { ...routeProps });
746
763
  };
747
764
 
748
- 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 };
765
+ export { ArrayContainer, ArrayItemWrapper, AutoField, AutoForm2 as AutoForm, AutoFormView2 as AutoFormView, Button, ErrorMessage, FieldWrapper, NativeEasyLayoutView, Route2 as Route, createNativeBackHandler, createNativeFormRenderer, createNativeHardwareBackHandler, createNativeHistory, createNativeRouteBackIntegration, makeNativeEasyLayout, mapNativeURLToPath, nativeAutoField, nativeSuite, registerNativeHardwareBackHandler, useNativeEasyLayout };
@@ -1,13 +1,15 @@
1
1
  /**
2
2
  * @packageDocumentation
3
3
  *
4
- * Native history helpers that adapt deep links into the shared history state machine.
4
+ * Native history helpers that provide the mobile equivalent of browser
5
+ * location/history behavior for shared app Route matching.
5
6
  */
6
7
  import type { HistoryController } from "../../app/utils/History";
7
8
  /**
8
9
  * Adapter contract for React Native deep-link APIs.
9
10
  *
10
- * Intended for RN `Linking` wrappers.
11
+ * Intended for RN `Linking` wrappers so native URL opens behave like browser
12
+ * navigations entering the shared Voltra history model.
11
13
  */
12
14
  export type NativeLinkAdapter = {
13
15
  /**
@@ -23,8 +25,19 @@ export type NativeLinkAdapter = {
23
25
  * Mode for incoming URL handling.
24
26
  */
25
27
  export type NativeIncomingURLMode = "push" | "replace";
28
+ /**
29
+ * BackHandler-like contract for native platform back actions.
30
+ */
31
+ export type NativeBackHandlerLike = {
32
+ addEventListener: (eventName: "hardwareBackPress", listener: () => boolean) => {
33
+ remove?: () => void;
34
+ } | void;
35
+ removeEventListener?: (eventName: "hardwareBackPress", listener: () => boolean) => void;
36
+ };
26
37
  /**
27
38
  * Native history controller with explicit lifecycle hooks.
39
+ *
40
+ * This is the native/mobile analogue to browser-backed history in web apps.
28
41
  */
29
42
  export type NativeHistoryController = HistoryController & {
30
43
  /**
@@ -62,16 +75,25 @@ export type CreateNativeHistoryOptions = {
62
75
  * Default: {@link mapNativeURLToPath}.
63
76
  */
64
77
  mapURLToPath?: (url: string) => string;
78
+ /**
79
+ * Optional native platform back handler wired into this history runtime.
80
+ */
81
+ backHandler?: NativeBackHandlerLike;
65
82
  };
66
83
  /**
67
84
  * Default native URL -> path mapping.
68
85
  *
69
- * Strips scheme and host, preserves path + query + hash.
86
+ * Strips scheme and host, preserves path + query + hash so incoming native URLs
87
+ * become the same route paths used on web.
70
88
  */
71
89
  export declare const mapNativeURLToPath: (url: string) => string;
72
90
  /**
73
91
  * Create a native history controller backed by in-memory history.
74
92
  *
93
+ * This is the primary native routing primitive when the environment does not
94
+ * provide browser history. It gives shared Route matching a stable path/history
95
+ * source and applies incoming deep links as navigations in that same model.
96
+ *
75
97
  * Lifecycle behavior:
76
98
  * - `start()` is idempotent.
77
99
  * - `stop()` is idempotent.
@@ -1,54 +1,19 @@
1
1
  /**
2
2
  * @packageDocumentation
3
3
  *
4
- * Native routing helpers that adapt common navigation state to RouteAdapter.
5
- */
6
- import { type PropsWithChildren } from "react";
7
- import type { RouteAdapter, RouteProps, RouteQuery, RouteRuntimeIntegration } from "../../app/utils/Route";
8
- /**
9
- * Options to adapt a navigation state container into a RouteAdapter.
10
- */
11
- export type NavigationStateAdapterOptions<TState> = {
12
- /** Return the current navigation state. */
13
- getState: () => TState;
14
- /** Subscribe to navigation state changes. */
15
- subscribe: (listener: () => void) => () => void;
16
- /** Convert navigation state into a path string. */
17
- toPath: (state: TState) => string;
18
- /** Optional navigation handler used for push-style transitions. */
19
- navigate?: (path: string) => void;
20
- /** Optional navigation handler used for replace-style transitions. */
21
- replace?: (path: string) => void;
22
- };
23
- /**
24
- * Contract for React Native BackHandler-like integrations.
25
- */
26
- export type NativeBackHandlerLike = {
27
- addEventListener: (eventName: "hardwareBackPress", listener: () => boolean) => {
28
- remove?: () => void;
29
- } | void;
30
- removeEventListener?: (eventName: "hardwareBackPress", listener: () => boolean) => void;
31
- };
32
- /**
33
- * Route node in a navigation chain.
34
- */
35
- export type NavigationRouteNode = {
36
- /** Route name as reported by the navigation library. */
37
- name: string;
38
- /** Optional route params used to populate path patterns. */
39
- params?: Record<string, any>;
40
- };
41
- /**
42
- * Mapping of route names to path patterns (e.g. "books/:id").
43
- */
44
- export type NavigationRouteConfig = Record<string, string>;
45
- /**
46
- * Create a RouteAdapter from a navigation state container (e.g., react-navigation).
4
+ * Native routing helpers that keep shared app Route semantics intact on mobile.
47
5
  *
48
- * @param options - Adapter options for accessing and observing navigation state.
49
- * @returns RouteAdapter bound to the navigation state.
6
+ * The primary native model is still Voltra path/history routing. These helpers
7
+ * supply the runtime selection needed by the `native` barrel:
8
+ * - React Native mobile uses native history + deep-link + platform back
9
+ * - React Native web uses the browser adapter
10
+ *
11
+ * This separation keeps `app` free of native-platform code.
50
12
  */
51
- export declare const createNavigationStateRouteAdapter: <TState>(options: NavigationStateAdapterOptions<TState>) => RouteAdapter;
13
+ import { type PropsWithChildren } from "react";
14
+ import type { RouteProps, RouteRuntimeIntegration } from "../../app/utils/Route";
15
+ import type { RouteAdapter } from "../../app/utils/Route";
16
+ import { type NativeBackHandlerLike } from "./History";
52
17
  /**
53
18
  * Create a hardware-back listener from a route adapter.
54
19
  */
@@ -58,23 +23,19 @@ export declare const createNativeHardwareBackHandler: (adapter: RouteAdapter) =>
58
23
  */
59
24
  export declare const registerNativeHardwareBackHandler: (adapter: RouteAdapter, backHandler: NativeBackHandlerLike) => () => void;
60
25
  /**
61
- * Build a core Route runtime integration using a native BackHandler.
26
+ * Low-level helper to build a Route runtime integration from a BackHandler.
27
+ *
28
+ * Native Route no longer uses this for the default path because platform back
29
+ * ownership now lives with the native adapter/history layer. This remains
30
+ * available for manual integrations.
62
31
  */
63
32
  export declare const createNativeRouteBackIntegration: (backHandler: NativeBackHandlerLike) => RouteRuntimeIntegration;
64
33
  /**
65
34
  * Native Route wrapper for root/provider mode.
66
35
  *
67
36
  * Behavior:
68
- * - On mobile native runtimes, injects back-handler integration into app Route.
69
- * - On web runtimes, passes no integration so app Route uses browser behavior.
37
+ * - On React Native mobile runtimes, auto-injects a native-history-backed
38
+ * adapter so native history owns platform back actions.
39
+ * - On React Native web runtimes, auto-injects the browser adapter.
70
40
  */
71
41
  export declare const Route: <ParamsType extends Record<string, any>>(props: PropsWithChildren<RouteProps<ParamsType>>) => import("react/jsx-runtime").JSX.Element;
72
- /**
73
- * Build a path from a navigation route chain and route config mapping.
74
- *
75
- * @param routeChain - Ordered list of routes from root to leaf.
76
- * @param config - Route name to path pattern mapping.
77
- * @param query - Optional query parameters appended to the path.
78
- * @returns Serialized path string.
79
- */
80
- export declare const buildPathFromRouteChain: (routeChain: NavigationRouteNode[], config: NavigationRouteConfig, query?: RouteQuery) => string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@resistdesign/voltra",
3
- "version": "3.0.0-alpha.45",
3
+ "version": "3.0.0-alpha.47",
4
4
  "description": "With our powers combined!",
5
5
  "homepage": "https://voltra.app",
6
6
  "repository": "git@github.com:resistdesign/voltra.git",
package/web/index.js CHANGED
@@ -1,7 +1,7 @@
1
- import { createEasyLayout } from '../chunk-CMH6L5QQ.js';
2
- import { createFormRenderer, AutoFormView, AutoForm, createBrowserRouteAdapter, Route } from '../chunk-44BMFTKD.js';
3
- import { ERROR_MESSAGE_CONSTANTS } from '../chunk-YCTVEW2I.js';
4
- import '../chunk-WNFRDIBW.js';
1
+ import { createEasyLayout } from '../chunk-QXYUXJKM.js';
2
+ import { createFormRenderer, AutoFormView, AutoForm, createBrowserRouteAdapter, Route } from '../chunk-UD2ALOCE.js';
3
+ import { ERROR_MESSAGE_CONSTANTS } from '../chunk-3HVYVX3S.js';
4
+ import '../chunk-2JDOM6PB.js';
5
5
  import { __export, __reExport } from '../chunk-I2KLQ2HA.js';
6
6
  import { createElement, useCallback, useRef } from 'react';
7
7
  import * as styledBase from 'styled-components';