@resistdesign/voltra 3.0.0-alpha.47 → 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/app/index.js CHANGED
@@ -1,6 +1,6 @@
1
- export { createEasyLayout, getEasyLayoutTemplateDetails, getPascalCaseAreaName } from '../chunk-QXYUXJKM.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-UD2ALOCE.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
5
  import '../chunk-3HVYVX3S.js';
6
6
  import { mergeStringPaths, PATH_DELIMITER } from '../chunk-2JDOM6PB.js';
@@ -119,6 +119,11 @@ export type RouteContextType = {
119
119
  * Whether this route is the top-level router.
120
120
  */
121
121
  isTopLevel: boolean;
122
+ /**
123
+ * Absolute matched path used as the base for relative navigation at this
124
+ * route level.
125
+ */
126
+ adapterBasePath: string;
122
127
  /**
123
128
  * Adapter driving route updates.
124
129
  */
@@ -148,7 +153,7 @@ export declare const useRouteContext: () => RouteContextType;
148
153
  * @param adapter - RouteAdapter to normalize.
149
154
  * @returns Adapter with relative-aware `push` and `replace`.
150
155
  */
151
- export declare const wrapRouteAdapterWithPathResolver: (adapter: RouteAdapter) => RouteAdapter;
156
+ export declare const wrapRouteAdapterWithPathResolver: (adapter: RouteAdapter, getBasePath?: () => string) => RouteAdapter;
152
157
  /**
153
158
  * RouteProvider props.
154
159
  */
@@ -1,4 +1,4 @@
1
- import { parseTemplate, validateAreas } from './chunk-UD2ALOCE.js';
1
+ import { parseTemplate, validateAreas } from './chunk-K4R2PFNG.js';
2
2
 
3
3
  // src/app/utils/EasyLayout.tsx
4
4
  var getPascalCaseAreaName = (area) => {
@@ -552,7 +552,8 @@ var RouteContext = createContext({
552
552
  parentPath: "",
553
553
  parentPathInternal: "",
554
554
  params: {},
555
- isTopLevel: true
555
+ isTopLevel: true,
556
+ adapterBasePath: "/"
556
557
  });
557
558
  var {
558
559
  /**
@@ -565,27 +566,42 @@ var {
565
566
  Consumer: RouteContextConsumer
566
567
  } = RouteContext;
567
568
  var useRouteContext = () => useContext(RouteContext);
568
- var wrappedRouteAdapterCache = /* @__PURE__ */ new WeakMap();
569
- var wrapRouteAdapterWithPathResolver = (adapter) => {
569
+ var wrapRouteAdapterWithPathResolver = (adapter, getBasePath = () => adapter.getPath()) => {
570
570
  if (!adapter.push && !adapter.replace) {
571
571
  return adapter;
572
572
  }
573
- const cachedAdapter = wrappedRouteAdapterCache.get(adapter);
574
- if (cachedAdapter) {
575
- return cachedAdapter;
576
- }
577
573
  const wrappedAdapter = {
578
574
  ...adapter,
579
575
  push: adapter.push ? (path, title) => {
580
- adapter.push?.(resolveRouteAdapterPath(adapter.getPath(), path), title);
576
+ adapter.push?.(resolveRouteAdapterPath(getBasePath(), path), title);
581
577
  } : void 0,
582
578
  replace: adapter.replace ? (path, title) => {
583
- adapter.replace?.(resolveRouteAdapterPath(adapter.getPath(), path), title);
579
+ adapter.replace?.(resolveRouteAdapterPath(getBasePath(), path), title);
584
580
  } : void 0
585
581
  };
586
- wrappedRouteAdapterCache.set(adapter, wrappedAdapter);
587
582
  return wrappedAdapter;
588
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
+ };
589
605
  var getWindow2 = () => {
590
606
  if (typeof globalThis === "undefined") {
591
607
  return void 0;
@@ -645,6 +661,10 @@ var RouteProvider = ({
645
661
  const [currentPath, setCurrentPath] = useState(
646
662
  initialPath ?? normalizedAdapter.getPath()
647
663
  );
664
+ const adapterBasePath = useMemo(
665
+ () => getAdapterBasePath(currentPath),
666
+ [currentPath]
667
+ );
648
668
  useEffect(() => {
649
669
  return normalizedAdapter.subscribe((nextPath) => {
650
670
  setCurrentPath(nextPath);
@@ -657,9 +677,10 @@ var RouteProvider = ({
657
677
  parentPathInternal: "",
658
678
  params: {},
659
679
  isTopLevel: true,
680
+ adapterBasePath,
660
681
  adapter: normalizedAdapter
661
682
  }),
662
- [currentPath, normalizedAdapter]
683
+ [currentPath, adapterBasePath, normalizedAdapter]
663
684
  );
664
685
  return /* @__PURE__ */ jsx(RouteContextProvider, { value: contextValue, children });
665
686
  };
@@ -677,6 +698,7 @@ var RouteMatcher = ({
677
698
  parentPath = "",
678
699
  parentPathInternal = "",
679
700
  params: parentParams = {},
701
+ adapterBasePath: inheritedAdapterBasePath = "/",
680
702
  adapter
681
703
  } = useRouteContext();
682
704
  const targetCurrentPath = useMemo(
@@ -722,6 +744,14 @@ var RouteMatcher = ({
722
744
  }),
723
745
  [parentParams, matchedRoute]
724
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
+ );
725
755
  const newRouteContext = useMemo(
726
756
  () => ({
727
757
  currentWindowPath: targetCurrentPath,
@@ -729,9 +759,17 @@ var RouteMatcher = ({
729
759
  parentPathInternal: matchedRoute?.fullPath ?? parentPathInternal,
730
760
  params,
731
761
  isTopLevel: false,
732
- adapter
762
+ adapterBasePath: matchedAdapterBasePath,
763
+ adapter: scopedAdapter
733
764
  }),
734
- [targetCurrentPath, matchedRoute, parentPathInternal, params, adapter]
765
+ [
766
+ targetCurrentPath,
767
+ matchedRoute,
768
+ parentPathInternal,
769
+ params,
770
+ matchedAdapterBasePath,
771
+ scopedAdapter
772
+ ]
735
773
  );
736
774
  useEffect(() => {
737
775
  if (onParamsChange) {
package/native/index.js CHANGED
@@ -1,5 +1,5 @@
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-UD2ALOCE.js';
2
+ import { createFormRenderer, createHistoryBackHandler, buildHistoryPath, AutoFormView, AutoForm, parseTemplate, validateAreas, computeAreaBounds, parseHistoryPath, createMemoryHistory, useRouteContext, createBrowserRouteAdapter, Route, createRouteAdapterFromHistory } from '../chunk-K4R2PFNG.js';
3
3
  import { ERROR_MESSAGE_CONSTANTS } from '../chunk-3HVYVX3S.js';
4
4
  import '../chunk-2JDOM6PB.js';
5
5
  import '../chunk-I2KLQ2HA.js';
@@ -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.47",
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-QXYUXJKM.js';
2
- import { createFormRenderer, AutoFormView, AutoForm, createBrowserRouteAdapter, Route } from '../chunk-UD2ALOCE.js';
1
+ import { createEasyLayout } from '../chunk-BSHQIRBV.js';
2
+ import { createFormRenderer, AutoFormView, AutoForm, useRouteContext, createBrowserRouteAdapter, Route } from '../chunk-K4R2PFNG.js';
3
3
  import { ERROR_MESSAGE_CONSTANTS } from '../chunk-3HVYVX3S.js';
4
- import '../chunk-2JDOM6PB.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";