@resistdesign/voltra 3.0.0-alpha.46 → 3.0.0-alpha.48

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/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-BSHQIRBV.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-K4R2PFNG.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
  */
@@ -103,6 +119,11 @@ export type RouteContextType = {
103
119
  * Whether this route is the top-level router.
104
120
  */
105
121
  isTopLevel: boolean;
122
+ /**
123
+ * Absolute matched path used as the base for relative navigation at this
124
+ * route level.
125
+ */
126
+ adapterBasePath: string;
106
127
  /**
107
128
  * Adapter driving route updates.
108
129
  */
@@ -116,6 +137,10 @@ export declare const RouteContextProvider: import("react").Provider<RouteContext
116
137
  /**
117
138
  * Access Route path and parameter information.
118
139
  *
140
+ * Use `parentPath` for app-facing route logic. `parentPathInternal` is exposed
141
+ * so advanced integrations can align with the internal routing helpers when
142
+ * needed.
143
+ *
119
144
  * @returns The current route context.
120
145
  */
121
146
  export declare const useRouteContext: () => RouteContextType;
@@ -128,7 +153,7 @@ export declare const useRouteContext: () => RouteContextType;
128
153
  * @param adapter - RouteAdapter to normalize.
129
154
  * @returns Adapter with relative-aware `push` and `replace`.
130
155
  */
131
- export declare const wrapRouteAdapterWithPathResolver: (adapter: RouteAdapter) => RouteAdapter;
156
+ export declare const wrapRouteAdapterWithPathResolver: (adapter: RouteAdapter, getBasePath?: () => string) => RouteAdapter;
132
157
  /**
133
158
  * RouteProvider props.
134
159
  */
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-K4R2PFNG.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,11 +540,20 @@ 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
- isTopLevel: true
555
+ isTopLevel: true,
556
+ adapterBasePath: "/"
548
557
  });
549
558
  var {
550
559
  /**
@@ -557,27 +566,42 @@ var {
557
566
  Consumer: RouteContextConsumer
558
567
  } = RouteContext;
559
568
  var useRouteContext = () => useContext(RouteContext);
560
- var wrappedRouteAdapterCache = /* @__PURE__ */ new WeakMap();
561
- var wrapRouteAdapterWithPathResolver = (adapter) => {
569
+ var wrapRouteAdapterWithPathResolver = (adapter, getBasePath = () => adapter.getPath()) => {
562
570
  if (!adapter.push && !adapter.replace) {
563
571
  return adapter;
564
572
  }
565
- const cachedAdapter = wrappedRouteAdapterCache.get(adapter);
566
- if (cachedAdapter) {
567
- return cachedAdapter;
568
- }
569
573
  const wrappedAdapter = {
570
574
  ...adapter,
571
575
  push: adapter.push ? (path, title) => {
572
- adapter.push?.(resolveRouteAdapterPath(adapter.getPath(), path), title);
576
+ adapter.push?.(resolveRouteAdapterPath(getBasePath(), path), title);
573
577
  } : void 0,
574
578
  replace: adapter.replace ? (path, title) => {
575
- adapter.replace?.(resolveRouteAdapterPath(adapter.getPath(), path), title);
579
+ adapter.replace?.(resolveRouteAdapterPath(getBasePath(), path), title);
576
580
  } : void 0
577
581
  };
578
- wrappedRouteAdapterCache.set(adapter, wrappedAdapter);
579
582
  return wrappedAdapter;
580
583
  };
584
+ var getAdapterBasePath = (currentPath) => {
585
+ const normalizedPath = String(currentPath ?? "").trim();
586
+ if (normalizedPath === "") {
587
+ return "/";
588
+ }
589
+ const [pathOnly] = normalizedPath.split(/[?#]/, 1);
590
+ return pathOnly || "/";
591
+ };
592
+ var getMatchedRouteBasePath = (currentPath, matchedRoutePath) => {
593
+ const currentPathSegments = getPathArray(
594
+ getAdapterBasePath(currentPath),
595
+ PATH_DELIMITER,
596
+ true,
597
+ true,
598
+ false,
599
+ false
600
+ );
601
+ const matchedRouteSegments = getPathArray(matchedRoutePath);
602
+ const resolvedSegments = currentPathSegments.slice(0, matchedRouteSegments.length);
603
+ return resolvedSegments.length > 0 ? `/${resolvedSegments.join(PATH_DELIMITER)}` : "/";
604
+ };
581
605
  var getWindow2 = () => {
582
606
  if (typeof globalThis === "undefined") {
583
607
  return void 0;
@@ -637,6 +661,10 @@ var RouteProvider = ({
637
661
  const [currentPath, setCurrentPath] = useState(
638
662
  initialPath ?? normalizedAdapter.getPath()
639
663
  );
664
+ const adapterBasePath = useMemo(
665
+ () => getAdapterBasePath(currentPath),
666
+ [currentPath]
667
+ );
640
668
  useEffect(() => {
641
669
  return normalizedAdapter.subscribe((nextPath) => {
642
670
  setCurrentPath(nextPath);
@@ -646,11 +674,13 @@ var RouteProvider = ({
646
674
  () => ({
647
675
  currentWindowPath: currentPath,
648
676
  parentPath: "",
677
+ parentPathInternal: "",
649
678
  params: {},
650
679
  isTopLevel: true,
680
+ adapterBasePath,
651
681
  adapter: normalizedAdapter
652
682
  }),
653
- [currentPath, normalizedAdapter]
683
+ [currentPath, adapterBasePath, normalizedAdapter]
654
684
  );
655
685
  return /* @__PURE__ */ jsx(RouteContextProvider, { value: contextValue, children });
656
686
  };
@@ -666,7 +696,9 @@ var RouteMatcher = ({
666
696
  const {
667
697
  currentWindowPath = "",
668
698
  parentPath = "",
699
+ parentPathInternal = "",
669
700
  params: parentParams = {},
701
+ adapterBasePath: inheritedAdapterBasePath = "/",
670
702
  adapter
671
703
  } = useRouteContext();
672
704
  const targetCurrentPath = useMemo(
@@ -685,7 +717,10 @@ var RouteMatcher = ({
685
717
  const matchedRoute = useMemo(
686
718
  () => {
687
719
  for (const routePathConfig of normalizedPaths) {
688
- const fullPath = mergeStringPaths(parentPath, routePathConfig.path);
720
+ const fullPath = mergeStringPaths(
721
+ parentPathInternal,
722
+ routePathConfig.path
723
+ );
689
724
  const newParams = getParamsAndTestPath(
690
725
  targetCurrentPath,
691
726
  fullPath,
@@ -700,7 +735,7 @@ var RouteMatcher = ({
700
735
  }
701
736
  return null;
702
737
  },
703
- [targetCurrentPath, parentPath, normalizedPaths]
738
+ [targetCurrentPath, parentPathInternal, normalizedPaths]
704
739
  );
705
740
  const params = useMemo(
706
741
  () => ({
@@ -709,15 +744,32 @@ var RouteMatcher = ({
709
744
  }),
710
745
  [parentParams, matchedRoute]
711
746
  );
747
+ const matchedAdapterBasePath = useMemo(
748
+ () => matchedRoute ? getMatchedRouteBasePath(targetCurrentPath, matchedRoute.fullPath) : inheritedAdapterBasePath,
749
+ [targetCurrentPath, matchedRoute, inheritedAdapterBasePath]
750
+ );
751
+ const scopedAdapter = useMemo(
752
+ () => adapter ? wrapRouteAdapterWithPathResolver(adapter, () => matchedAdapterBasePath) : adapter,
753
+ [adapter, matchedAdapterBasePath]
754
+ );
712
755
  const newRouteContext = useMemo(
713
756
  () => ({
714
757
  currentWindowPath: targetCurrentPath,
715
- parentPath: matchedRoute?.fullPath ?? parentPath,
758
+ parentPath: getReadableRoutePath(matchedRoute?.fullPath ?? parentPathInternal),
759
+ parentPathInternal: matchedRoute?.fullPath ?? parentPathInternal,
716
760
  params,
717
761
  isTopLevel: false,
718
- adapter
762
+ adapterBasePath: matchedAdapterBasePath,
763
+ adapter: scopedAdapter
719
764
  }),
720
- [targetCurrentPath, matchedRoute, parentPath, params, adapter]
765
+ [
766
+ targetCurrentPath,
767
+ matchedRoute,
768
+ parentPathInternal,
769
+ params,
770
+ matchedAdapterBasePath,
771
+ scopedAdapter
772
+ ]
721
773
  );
722
774
  useEffect(() => {
723
775
  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,7 +1,7 @@
1
1
  import { computeTrackPixels } from '../chunk-TJFTWPXQ.js';
2
- import { createFormRenderer, createHistoryBackHandler, buildHistoryPath, AutoFormView, AutoForm, parseTemplate, validateAreas, computeAreaBounds, parseHistoryPath, createMemoryHistory, createBrowserRouteAdapter, Route, createRouteAdapterFromHistory } from '../chunk-44BMFTKD.js';
3
- import { ERROR_MESSAGE_CONSTANTS } from '../chunk-YCTVEW2I.js';
4
- import '../chunk-WNFRDIBW.js';
2
+ import { createFormRenderer, createHistoryBackHandler, buildHistoryPath, AutoFormView, AutoForm, parseTemplate, validateAreas, computeAreaBounds, parseHistoryPath, createMemoryHistory, useRouteContext, createBrowserRouteAdapter, Route, createRouteAdapterFromHistory } from '../chunk-K4R2PFNG.js';
3
+ import { ERROR_MESSAGE_CONSTANTS } from '../chunk-3HVYVX3S.js';
4
+ import '../chunk-2JDOM6PB.js';
5
5
  import '../chunk-I2KLQ2HA.js';
6
6
  import { createElement, useMemo, useRef } from 'react';
7
7
  import { Text, View, Platform, Switch, TextInput, Pressable, BackHandler } from 'react-native';
@@ -675,6 +675,33 @@ var createNativeHistory = (options = {}) => {
675
675
  };
676
676
  };
677
677
  var createNativeBackHandler = (history) => createHistoryBackHandler(history);
678
+ var NavButton = ({
679
+ path,
680
+ replace = false,
681
+ onPress,
682
+ disabled,
683
+ children,
684
+ ...other
685
+ }) => {
686
+ const { adapter } = useRouteContext();
687
+ const onPressInternal = (event) => {
688
+ onPress?.(event);
689
+ if (disabled || event?.defaultPrevented) {
690
+ return;
691
+ }
692
+ const navigate = replace ? adapter?.replace : adapter?.push;
693
+ navigate?.(path);
694
+ };
695
+ return createElement(
696
+ Pressable,
697
+ {
698
+ ...other,
699
+ disabled,
700
+ onPress: onPressInternal
701
+ },
702
+ children
703
+ );
704
+ };
678
705
  var createNativeHardwareBackHandler = (adapter) => {
679
706
  return () => {
680
707
  if (adapter.canGoBack?.()) {
@@ -762,4 +789,4 @@ var Route2 = (props) => {
762
789
  ) : /* @__PURE__ */ jsx(Route, { ...routeProps });
763
790
  };
764
791
 
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 };
792
+ export { ArrayContainer, ArrayItemWrapper, AutoField, AutoForm2 as AutoForm, AutoFormView2 as AutoFormView, Button, ErrorMessage, FieldWrapper, NativeEasyLayoutView, NavButton, Route2 as Route, createNativeBackHandler, createNativeFormRenderer, createNativeHardwareBackHandler, createNativeHistory, createNativeRouteBackIntegration, makeNativeEasyLayout, mapNativeURLToPath, nativeAutoField, nativeSuite, registerNativeHardwareBackHandler, useNativeEasyLayout };
@@ -0,0 +1,25 @@
1
+ /**
2
+ * @packageDocumentation
3
+ *
4
+ * Native intra-application navigation button.
5
+ */
6
+ import type { FC } from "react";
7
+ import { type PressableProps } from "react-native";
8
+ /**
9
+ * Props for {@link NavButton}.
10
+ */
11
+ export type NavButtonProps = PressableProps & {
12
+ /** Relative or absolute Voltra route path. */
13
+ path: string;
14
+ /** Use adapter `replace` instead of `push` when true. */
15
+ replace?: boolean;
16
+ };
17
+ /**
18
+ * Render a pressable control that navigates within the current Voltra app.
19
+ *
20
+ * Relative paths resolve from the route context where this component renders.
21
+ *
22
+ * @param props - Pressable props plus the destination route path.
23
+ * @returns Pressable element wired to the current route adapter.
24
+ */
25
+ export declare const NavButton: FC<NavButtonProps>;
@@ -13,6 +13,11 @@ export * from "./EasyLayout";
13
13
  * @group Layout and Navigation
14
14
  */
15
15
  export * from "./History";
16
+ /**
17
+ * @category native
18
+ * @group Layout and Navigation
19
+ */
20
+ export * from "./NavButton";
16
21
  /**
17
22
  * @category native
18
23
  * @group Layout and Navigation
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@resistdesign/voltra",
3
- "version": "3.0.0-alpha.46",
3
+ "version": "3.0.0-alpha.48",
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-BSHQIRBV.js';
2
+ import { createFormRenderer, AutoFormView, AutoForm, useRouteContext, createBrowserRouteAdapter, Route } from '../chunk-K4R2PFNG.js';
3
+ import { ERROR_MESSAGE_CONSTANTS } from '../chunk-3HVYVX3S.js';
4
+ import { resolveRouteAdapterPath } from '../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';
@@ -648,6 +648,39 @@ var styledFactory = {
648
648
  var getEasyLayout = (extendFrom, areasExtendFrom, options = {}) => {
649
649
  return createEasyLayout(styledFactory, extendFrom, areasExtendFrom, options);
650
650
  };
651
+ var NavLink = ({
652
+ path,
653
+ replace = false,
654
+ onClick,
655
+ title,
656
+ children,
657
+ ...other
658
+ }) => {
659
+ const { adapter, adapterBasePath } = useRouteContext();
660
+ const href = resolveRouteAdapterPath(adapterBasePath, path);
661
+ const onClickInternal = (event) => {
662
+ onClick?.(event);
663
+ if (event.defaultPrevented || event.button !== 0 || event.metaKey || event.altKey || event.ctrlKey || event.shiftKey) {
664
+ return;
665
+ }
666
+ const navigate = replace ? adapter?.replace : adapter?.push;
667
+ if (!navigate) {
668
+ return;
669
+ }
670
+ event.preventDefault();
671
+ navigate(path, title);
672
+ };
673
+ return createElement(
674
+ "a",
675
+ {
676
+ ...other,
677
+ href,
678
+ title,
679
+ onClick: onClickInternal
680
+ },
681
+ children
682
+ );
683
+ };
651
684
  var Route2 = (props) => {
652
685
  const hasMatcherProps = typeof props.path !== "undefined" || typeof props.exact !== "undefined" || typeof props.onParamsChange !== "undefined";
653
686
  const adapterRef = useRef(null);
@@ -665,4 +698,4 @@ var Route2 = (props) => {
665
698
  ) : /* @__PURE__ */ jsx(Route, { ...routeProps });
666
699
  };
667
700
 
668
- export { ArrayContainer, ArrayItemWrapper, AutoField, AutoForm2 as AutoForm, AutoFormView2 as AutoFormView, ErrorMessage, FieldWrapper, Route2 as Route, createWebFormRenderer, getEasyLayout, webAutoField, webSuite };
701
+ export { ArrayContainer, ArrayItemWrapper, AutoField, AutoForm2 as AutoForm, AutoFormView2 as AutoFormView, ErrorMessage, FieldWrapper, NavLink, Route2 as Route, createWebFormRenderer, getEasyLayout, webAutoField, webSuite };
@@ -0,0 +1,24 @@
1
+ /**
2
+ * @packageDocumentation
3
+ *
4
+ * Web intra-application navigation link.
5
+ */
6
+ import type { AnchorHTMLAttributes, FC } from "react";
7
+ /**
8
+ * Props for {@link NavLink}.
9
+ */
10
+ export type NavLinkProps = Omit<AnchorHTMLAttributes<HTMLAnchorElement>, "href"> & {
11
+ /** Relative or absolute Voltra route path. */
12
+ path: string;
13
+ /** Use adapter `replace` instead of `push` when true. */
14
+ replace?: boolean;
15
+ };
16
+ /**
17
+ * Render an anchor-like control that navigates within the current Voltra app.
18
+ *
19
+ * Relative paths resolve from the route context where this component renders.
20
+ *
21
+ * @param props - Anchor props plus the destination route path.
22
+ * @returns Anchor element wired to the current route adapter.
23
+ */
24
+ export declare const NavLink: FC<NavLinkProps>;
@@ -4,4 +4,5 @@
4
4
  * Web-only utilities.
5
5
  */
6
6
  export * from "./EasyLayout";
7
+ export * from "./NavLink";
7
8
  export * from "./Route";