@wallarm-org/design-system 1.28.0 → 1.28.1
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/dist/components/RemoteShell/NavPanelContent.d.ts +5 -0
- package/dist/components/RemoteShell/NavPanelContent.js +6 -4
- package/dist/components/RemoteShell/RemoteShell.d.ts +30 -1
- package/dist/components/RemoteShell/RemoteShell.js +35 -18
- package/dist/components/RemoteShell/RemoteShellPanel.js +10 -4
- package/dist/components/RemoteShell/model/index.d.ts +1 -1
- package/dist/components/RemoteShell/model/index.js +1 -1
- package/dist/components/RemoteShell/model/useDrillTransition.d.ts +12 -1
- package/dist/components/RemoteShell/model/useDrillTransition.js +24 -12
- package/dist/components/RemoteShell/model/useLocationPathname.d.ts +2 -0
- package/dist/components/RemoteShell/model/useLocationPathname.js +4 -1
- package/dist/metadata/components.json +25 -7
- package/package.json +2 -1
- package/dist/components/AppShell/story-content/_storyAccountDropdown.d.ts +0 -11
- package/dist/components/AppShell/story-content/_storyAccountDropdown.js +0 -242
- package/dist/components/AppShell/story-content/_storyConfigRenderer.d.ts +0 -12
- package/dist/components/AppShell/story-content/_storyConfigRenderer.js +0 -81
- package/dist/components/AppShell/story-content/_storyHeaderActions.d.ts +0 -1
- package/dist/components/AppShell/story-content/_storyHeaderActions.js +0 -59
- package/dist/components/AppShell/story-content/_storyHomeContent.d.ts +0 -2
- package/dist/components/AppShell/story-content/_storyHomeContent.js +0 -15
- package/dist/components/AppShell/story-content/_storyLib.d.ts +0 -9
- package/dist/components/AppShell/story-content/_storyLib.js +0 -39
- package/dist/components/AppShell/story-content/_storyNavConfigs.d.ts +0 -6
- package/dist/components/AppShell/story-content/_storyNavConfigs.js +0 -772
- package/dist/components/AppShell/story-content/_storyNavRailFooter.d.ts +0 -13
- package/dist/components/AppShell/story-content/_storyNavRailFooter.js +0 -26
- package/dist/components/AppShell/story-content/_storyProductNavItems.d.ts +0 -7
- package/dist/components/AppShell/story-content/_storyProductNavItems.js +0 -49
- package/dist/components/AppShell/story-content/_storyQuickHelpDropdown.d.ts +0 -1
- package/dist/components/AppShell/story-content/_storyQuickHelpDropdown.js +0 -144
- package/dist/components/AppShell/story-content/_storyRecentDropdown.d.ts +0 -1
- package/dist/components/AppShell/story-content/_storyRecentDropdown.js +0 -89
- package/dist/components/AppShell/story-content/_storySearchModal.d.ts +0 -1
- package/dist/components/AppShell/story-content/_storySearchModal.js +0 -252
- package/dist/components/AppShell/story-content/_storyWallarmLogo.d.ts +0 -1
- package/dist/components/AppShell/story-content/_storyWallarmLogo.js +0 -21
- package/dist/components/AppShell/story-content/index.d.ts +0 -11
- package/dist/components/AppShell/story-content/index.js +0 -11
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
import type { FC } from 'react';
|
|
2
|
+
import type { NavStackEntry } from './model';
|
|
3
|
+
interface NavigationSnapshot {
|
|
4
|
+
navStack: NavStackEntry[];
|
|
5
|
+
}
|
|
2
6
|
interface NavPanelContentProps {
|
|
3
7
|
level: number;
|
|
8
|
+
navigationSnapshot?: NavigationSnapshot;
|
|
4
9
|
}
|
|
5
10
|
export declare const NavPanelContent: FC<NavPanelContentProps>;
|
|
6
11
|
export {};
|
|
@@ -4,10 +4,12 @@ import { Text } from "../Text/index.js";
|
|
|
4
4
|
import { HeaderActions } from "./HeaderActions.js";
|
|
5
5
|
import { findDrillNode, useRemoteShellContext } from "./model/index.js";
|
|
6
6
|
import { NavItemsList } from "./NavItemsList.js";
|
|
7
|
-
const NavPanelContent = ({ level: rawLevel })=>{
|
|
8
|
-
const { config, navStack
|
|
7
|
+
const NavPanelContent = ({ level: rawLevel, navigationSnapshot })=>{
|
|
8
|
+
const { config, navStack: currentNavStack, navigate, drillInto, goBack } = useRemoteShellContext();
|
|
9
|
+
const navStack = navigationSnapshot?.navStack ?? currentNavStack;
|
|
9
10
|
const level = Math.min(rawLevel, navStack.length - 1);
|
|
10
11
|
const entry = navStack[level];
|
|
12
|
+
const activeItemId = entry.activeItemId;
|
|
11
13
|
const hasHeaderActions = !!config.headerActions?.length;
|
|
12
14
|
if (0 === level) return /*#__PURE__*/ jsxs(Fragment, {
|
|
13
15
|
children: [
|
|
@@ -28,7 +30,7 @@ const NavPanelContent = ({ level: rawLevel })=>{
|
|
|
28
30
|
}),
|
|
29
31
|
/*#__PURE__*/ jsx(NavItemsList, {
|
|
30
32
|
items: config.items,
|
|
31
|
-
activeItemId:
|
|
33
|
+
activeItemId: activeItemId,
|
|
32
34
|
onNavigate: navigate,
|
|
33
35
|
onDrillClick: drillInto
|
|
34
36
|
})
|
|
@@ -54,7 +56,7 @@ const NavPanelContent = ({ level: rawLevel })=>{
|
|
|
54
56
|
}),
|
|
55
57
|
/*#__PURE__*/ jsx(NavItemsList, {
|
|
56
58
|
items: entry.items,
|
|
57
|
-
activeItemId:
|
|
59
|
+
activeItemId: activeItemId,
|
|
58
60
|
onNavigate: navigate,
|
|
59
61
|
onDrillClick: drillInto
|
|
60
62
|
})
|
|
@@ -8,7 +8,36 @@ export interface RemoteShellProps extends HTMLAttributes<HTMLDivElement>, Testab
|
|
|
8
8
|
config: NavConfig;
|
|
9
9
|
/** URL prefix stripped before matching and prepended when navigating (e.g. `"/edge"`). */
|
|
10
10
|
basePath?: string;
|
|
11
|
-
/**
|
|
11
|
+
/**
|
|
12
|
+
* Current pathname. When set, it is the single source of truth for the active nav
|
|
13
|
+
* item, drill level and breadcrumbs, and `window.location` is ignored.
|
|
14
|
+
*
|
|
15
|
+
* Pass it — **together with `onNavigate`** — whenever a router owns the URL: router
|
|
16
|
+
* navigations (links in page content, `router.navigate`, memory history, the host's
|
|
17
|
+
* rail) do not fire `popstate`, so without it the shell can go stale. Without
|
|
18
|
+
* `onNavigate` the shell's own navigations would only reach `window.history`, which
|
|
19
|
+
* a controlled shell ignores (a dev warning flags this).
|
|
20
|
+
*
|
|
21
|
+
* Either form is accepted: with the `basePath` prefix (what `onNavigate` receives) or
|
|
22
|
+
* without it — the prefix is stripped only when the pathname starts with a whole
|
|
23
|
+
* `basePath` segment. With TanStack Router, `useRouterState({ select: s =>
|
|
24
|
+
* s.location.pathname })` is router-relative: it excludes the router's own
|
|
25
|
+
* `basepath`. So when the router has `basepath`:
|
|
26
|
+
* - omit `basePath` here — `pathname` and `onNavigate` are then both router-relative
|
|
27
|
+
* and `onNavigate={to => navigate({ to })}` is correct; or
|
|
28
|
+
* - keep `basePath` and strip it in `onNavigate`
|
|
29
|
+
* (`to => navigate({ to: to.slice(basePath.length) || '/' })`), otherwise the
|
|
30
|
+
* router prefixes it a second time.
|
|
31
|
+
*
|
|
32
|
+
* Omit it to read `window.location.pathname` (updated on `popstate` and on the
|
|
33
|
+
* shell's own navigations).
|
|
34
|
+
*/
|
|
35
|
+
pathname?: string;
|
|
36
|
+
/**
|
|
37
|
+
* Navigation handler for router integration (TanStack Router, React Router,
|
|
38
|
+
* Next.js, …). Receives the target pathname, prefixed with `basePath` when one is
|
|
39
|
+
* set. Without it the shell pushes to `window.history` itself.
|
|
40
|
+
*/
|
|
12
41
|
onNavigate?: (pathname: string) => void;
|
|
13
42
|
}
|
|
14
43
|
export declare const RemoteShell: FC<RemoteShellProps>;
|
|
@@ -2,14 +2,30 @@ import { jsx } from "react/jsx-runtime";
|
|
|
2
2
|
import { useCallback, useEffect, useMemo, useState } from "react";
|
|
3
3
|
import { cn } from "../../utils/cn.js";
|
|
4
4
|
import { TestIdProvider } from "../../utils/testId.js";
|
|
5
|
-
import { RemoteShellContextProvider, findFirstLinkPath, matchNav, pushPathname, useLocationPathname } from "./model/index.js";
|
|
6
|
-
const
|
|
7
|
-
|
|
8
|
-
|
|
5
|
+
import { RemoteShellContextProvider, findFirstLinkPath, matchNav, notifyPathnameChanged, pushPathname, useLocationPathname } from "./model/index.js";
|
|
6
|
+
const stripBasePath = (fullPathname, basePath)=>{
|
|
7
|
+
if (!basePath) return fullPathname;
|
|
8
|
+
if (fullPathname === basePath) return '/';
|
|
9
|
+
return fullPathname.startsWith(`${basePath}/`) ? fullPathname.slice(basePath.length) : fullPathname;
|
|
10
|
+
};
|
|
11
|
+
const RemoteShell = ({ ref, className, children, config, basePath, onNavigate, pathname: controlledPathname, 'data-testid': testId, ...props })=>{
|
|
12
|
+
const locationPathname = useLocationPathname();
|
|
13
|
+
const fullPathname = controlledPathname ?? locationPathname;
|
|
14
|
+
const pathname = stripBasePath(fullPathname, basePath);
|
|
15
|
+
const isControlled = void 0 !== controlledPathname;
|
|
16
|
+
const hasOnNavigate = void 0 !== onNavigate;
|
|
17
|
+
useEffect(()=>{
|
|
18
|
+
if (isControlled && !hasOnNavigate && 'production' !== process.env.NODE_ENV) console.warn('[RemoteShell] `pathname` is controlled but `onNavigate` is missing: shell navigations will update `window.history` only, and the shell will keep showing the old route. Pass `onNavigate` to route them through your router.');
|
|
19
|
+
}, [
|
|
20
|
+
isControlled,
|
|
21
|
+
hasOnNavigate
|
|
22
|
+
]);
|
|
9
23
|
const setPathname = useCallback((next)=>{
|
|
10
24
|
const fullPath = basePath ? `${basePath}${next}` : next;
|
|
11
|
-
if (onNavigate)
|
|
12
|
-
|
|
25
|
+
if (onNavigate) {
|
|
26
|
+
onNavigate(fullPath);
|
|
27
|
+
notifyPathnameChanged();
|
|
28
|
+
} else pushPathname(fullPath);
|
|
13
29
|
}, [
|
|
14
30
|
basePath,
|
|
15
31
|
onNavigate
|
|
@@ -19,17 +35,14 @@ const RemoteShell = ({ ref, className, children, config, basePath, onNavigate, '
|
|
|
19
35
|
config
|
|
20
36
|
]);
|
|
21
37
|
const urlDrillLevel = navStack.length - 1;
|
|
22
|
-
const [
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
}, [
|
|
26
|
-
pathname
|
|
27
|
-
]);
|
|
38
|
+
const [drillOverride, setDrillOverride] = useState(null);
|
|
39
|
+
const visualDrillLevel = drillOverride?.pathname === pathname ? drillOverride.level : null;
|
|
40
|
+
if (drillOverride && drillOverride.pathname !== pathname) setDrillOverride(null);
|
|
28
41
|
const effectiveDrillLevel = visualDrillLevel ?? urlDrillLevel;
|
|
29
42
|
const effectiveActiveItemId = effectiveDrillLevel < urlDrillLevel ? navStack[effectiveDrillLevel]?.activeItemId ?? activeItemId : activeItemId;
|
|
30
43
|
const prefixSegmentCount = navStack[effectiveDrillLevel]?.segmentCount ?? 2 * effectiveDrillLevel;
|
|
31
44
|
const navigate = useCallback((path)=>{
|
|
32
|
-
|
|
45
|
+
setDrillOverride(null);
|
|
33
46
|
const segments = pathname.replace(/^\/+|\/+$/g, '').split('/').filter(Boolean);
|
|
34
47
|
const prefixSegments = segments.slice(0, prefixSegmentCount);
|
|
35
48
|
setPathname(`/${[
|
|
@@ -42,7 +55,7 @@ const RemoteShell = ({ ref, className, children, config, basePath, onNavigate, '
|
|
|
42
55
|
setPathname
|
|
43
56
|
]);
|
|
44
57
|
const drillInto = useCallback((drill)=>{
|
|
45
|
-
|
|
58
|
+
setDrillOverride(null);
|
|
46
59
|
const segments = pathname.replace(/^\/+|\/+$/g, '').split('/').filter(Boolean);
|
|
47
60
|
const prefixSegments = segments.slice(0, prefixSegmentCount);
|
|
48
61
|
const defaultEntity = drill.entities?.[0]?.id ?? 'default';
|
|
@@ -64,15 +77,19 @@ const RemoteShell = ({ ref, className, children, config, basePath, onNavigate, '
|
|
|
64
77
|
setPathname
|
|
65
78
|
]);
|
|
66
79
|
const goBack = useCallback(()=>{
|
|
67
|
-
|
|
68
|
-
const current = prev
|
|
69
|
-
return
|
|
80
|
+
setDrillOverride((prev)=>{
|
|
81
|
+
const current = prev?.pathname === pathname ? prev.level : urlDrillLevel;
|
|
82
|
+
return {
|
|
83
|
+
level: Math.max(current - 1, 0),
|
|
84
|
+
pathname
|
|
85
|
+
};
|
|
70
86
|
});
|
|
71
87
|
}, [
|
|
88
|
+
pathname,
|
|
72
89
|
urlDrillLevel
|
|
73
90
|
]);
|
|
74
91
|
const navigateTo = useCallback((href)=>{
|
|
75
|
-
|
|
92
|
+
setDrillOverride(null);
|
|
76
93
|
href === config.productPath ? setPathname('/') : setPathname(href);
|
|
77
94
|
}, [
|
|
78
95
|
config.productPath,
|
|
@@ -7,8 +7,8 @@ import { DRILL_ANIMATION_DURATION, DRILL_ANIMATION_EASING, useDrillTransition }
|
|
|
7
7
|
import { NavPanelContent } from "./NavPanelContent.js";
|
|
8
8
|
const RemoteShellPanel = ({ ref, className, resizable, isLoading, loaderCount = 6, ...props })=>{
|
|
9
9
|
const testId = useTestId('panel');
|
|
10
|
-
const { config, drillLevel } = useRemoteShellContext();
|
|
11
|
-
const { transition, clearTransition } = useDrillTransition(drillLevel);
|
|
10
|
+
const { config, drillLevel, navStack } = useRemoteShellContext();
|
|
11
|
+
const { transition, clearTransition } = useDrillTransition(drillLevel, navStack, config.productPath);
|
|
12
12
|
if (isLoading) return /*#__PURE__*/ jsx("div", {
|
|
13
13
|
...props,
|
|
14
14
|
ref: ref,
|
|
@@ -53,7 +53,10 @@ const RemoteShellPanel = ({ ref, className, resizable, isLoading, loaderCount =
|
|
|
53
53
|
animation: `${isForward ? 'ds-nav-blur-out' : 'ds-nav-blur-in'} ${timing}`
|
|
54
54
|
},
|
|
55
55
|
children: /*#__PURE__*/ jsx(NavPanelContent, {
|
|
56
|
-
level: isForward ? transition.fromLevel : drillLevel
|
|
56
|
+
level: isForward ? transition.fromLevel : drillLevel,
|
|
57
|
+
navigationSnapshot: isForward ? {
|
|
58
|
+
navStack: transition.fromNavStack
|
|
59
|
+
} : void 0
|
|
57
60
|
})
|
|
58
61
|
}),
|
|
59
62
|
/*#__PURE__*/ jsx("div", {
|
|
@@ -62,7 +65,10 @@ const RemoteShellPanel = ({ ref, className, resizable, isLoading, loaderCount =
|
|
|
62
65
|
animation: `${isForward ? 'ds-nav-blur-in' : 'ds-nav-blur-out'} ${timing}`
|
|
63
66
|
},
|
|
64
67
|
children: /*#__PURE__*/ jsx(NavPanelContent, {
|
|
65
|
-
level: isForward ? drillLevel : transition.fromLevel
|
|
68
|
+
level: isForward ? drillLevel : transition.fromLevel,
|
|
69
|
+
navigationSnapshot: isForward ? void 0 : {
|
|
70
|
+
navStack: transition.fromNavStack
|
|
71
|
+
}
|
|
66
72
|
})
|
|
67
73
|
})
|
|
68
74
|
]
|
|
@@ -2,4 +2,4 @@ export { type MatchNavResult, matchNav } from './matchNav';
|
|
|
2
2
|
export { findDrillNode, findFirstLinkPath } from './navUtils';
|
|
3
3
|
export { RemoteShellContextProvider, type RemoteShellContextValue, useRemoteShellContext, } from './RemoteShellContext';
|
|
4
4
|
export type { BreadcrumbSegment, NavConfig, NavConfigDrill, NavConfigGroup, NavConfigHeaderAction, NavConfigLink, NavConfigNode, NavConfigSectionHeader, NavStackEntry, } from './types';
|
|
5
|
-
export { pushPathname, useLocationPathname } from './useLocationPathname';
|
|
5
|
+
export { notifyPathnameChanged, pushPathname, useLocationPathname } from './useLocationPathname';
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
export { matchNav } from "./matchNav.js";
|
|
2
2
|
export { findDrillNode, findFirstLinkPath } from "./navUtils.js";
|
|
3
3
|
export { RemoteShellContextProvider, useRemoteShellContext } from "./RemoteShellContext.js";
|
|
4
|
-
export { pushPathname, useLocationPathname } from "./useLocationPathname.js";
|
|
4
|
+
export { notifyPathnameChanged, pushPathname, useLocationPathname } from "./useLocationPathname.js";
|
|
@@ -1,10 +1,21 @@
|
|
|
1
|
+
import type { NavStackEntry } from './types';
|
|
1
2
|
export declare const DRILL_ANIMATION_DURATION = "220ms";
|
|
2
3
|
export declare const DRILL_ANIMATION_EASING = "cubic-bezier(0.4, 0, 0.2, 1)";
|
|
3
4
|
export interface DrillTransition {
|
|
4
5
|
fromLevel: number;
|
|
5
6
|
direction: 'forward' | 'backward';
|
|
7
|
+
fromNavStack: NavStackEntry[];
|
|
6
8
|
}
|
|
7
|
-
|
|
9
|
+
/**
|
|
10
|
+
* Tracks drill-level changes and exposes the transition to animate.
|
|
11
|
+
*
|
|
12
|
+
* `scope` identifies the nav tree (the config's `productPath`). A level change that
|
|
13
|
+
* coincides with a scope change — the same `RemoteShell` instance re-rendered for a
|
|
14
|
+
* different product — is not animated: sliding from the previous product's menu would
|
|
15
|
+
* show the wrong items. Keyed on `productPath` rather than config identity so a config
|
|
16
|
+
* rebuilt for the same product (e.g. when scope-switcher entities load) still animates.
|
|
17
|
+
*/
|
|
18
|
+
export declare const useDrillTransition: (drillLevel: number, navStack: NavStackEntry[], scope: string) => {
|
|
8
19
|
transition: DrillTransition | null;
|
|
9
20
|
clearTransition: () => void;
|
|
10
21
|
};
|
|
@@ -1,24 +1,36 @@
|
|
|
1
1
|
import { useLayoutEffect, useRef, useState } from "react";
|
|
2
2
|
const DRILL_ANIMATION_DURATION = '220ms';
|
|
3
3
|
const DRILL_ANIMATION_EASING = 'cubic-bezier(0.4, 0, 0.2, 1)';
|
|
4
|
-
const useDrillTransition = (drillLevel)=>{
|
|
5
|
-
const
|
|
4
|
+
const useDrillTransition = (drillLevel, navStack, scope)=>{
|
|
5
|
+
const previousRef = useRef({
|
|
6
|
+
drillLevel,
|
|
7
|
+
navStack,
|
|
8
|
+
scope
|
|
9
|
+
});
|
|
6
10
|
const [transition, setTransition] = useState(null);
|
|
7
11
|
useLayoutEffect(()=>{
|
|
8
|
-
const
|
|
9
|
-
if (
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
}
|
|
12
|
+
const previous = previousRef.current;
|
|
13
|
+
if (previous.scope !== scope) setTransition(null);
|
|
14
|
+
else if (previous.drillLevel !== drillLevel) setTransition({
|
|
15
|
+
fromLevel: previous.drillLevel,
|
|
16
|
+
direction: drillLevel > previous.drillLevel ? 'forward' : 'backward',
|
|
17
|
+
fromNavStack: previous.navStack,
|
|
18
|
+
scope
|
|
19
|
+
});
|
|
20
|
+
previousRef.current = {
|
|
21
|
+
drillLevel,
|
|
22
|
+
navStack,
|
|
23
|
+
scope
|
|
24
|
+
};
|
|
16
25
|
}, [
|
|
17
|
-
drillLevel
|
|
26
|
+
drillLevel,
|
|
27
|
+
navStack,
|
|
28
|
+
scope
|
|
18
29
|
]);
|
|
19
30
|
const clearTransition = ()=>setTransition(null);
|
|
31
|
+
const activeTransition = transition && transition.scope === scope ? transition : null;
|
|
20
32
|
return {
|
|
21
|
-
transition,
|
|
33
|
+
transition: activeTransition,
|
|
22
34
|
clearTransition
|
|
23
35
|
};
|
|
24
36
|
};
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
/** Push a new pathname to the browser history and notify subscribers. */
|
|
2
2
|
export declare function pushPathname(path: string): void;
|
|
3
|
+
/** Notify pathname subscribers after navigation handled by an external router. */
|
|
4
|
+
export declare function notifyPathnameChanged(): void;
|
|
3
5
|
/** Subscribe to `window.location.pathname` via `useSyncExternalStore`. */
|
|
4
6
|
export declare function useLocationPathname(): string;
|
|
@@ -16,9 +16,12 @@ function getSnapshot() {
|
|
|
16
16
|
}
|
|
17
17
|
function pushPathname(path) {
|
|
18
18
|
window.history.pushState(null, '', path);
|
|
19
|
+
notifyPathnameChanged();
|
|
20
|
+
}
|
|
21
|
+
function notifyPathnameChanged() {
|
|
19
22
|
for (const listener of listeners)listener();
|
|
20
23
|
}
|
|
21
24
|
function useLocationPathname() {
|
|
22
25
|
return useSyncExternalStore(subscribe, getSnapshot);
|
|
23
26
|
}
|
|
24
|
-
export { pushPathname, useLocationPathname };
|
|
27
|
+
export { notifyPathnameChanged, pushPathname, useLocationPathname };
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
|
-
"version": "1.
|
|
3
|
-
"generatedAt": "2026-09-30T12:
|
|
2
|
+
"version": "1.28.0",
|
|
3
|
+
"generatedAt": "2026-09-30T12:59:20.784Z",
|
|
4
4
|
"components": [
|
|
5
5
|
{
|
|
6
6
|
"name": "Accordion",
|
|
@@ -5341,23 +5341,28 @@
|
|
|
5341
5341
|
"examples": [
|
|
5342
5342
|
{
|
|
5343
5343
|
"name": "Basic",
|
|
5344
|
-
"code": "({ ambient }) => <Shell ambient={ambient}
|
|
5344
|
+
"code": "({ ambient }) => (\n <StoryRouter>\n <Shell ambient={ambient} />\n </StoryRouter>\n)",
|
|
5345
5345
|
"description": "The three regions composed once — `AppShellHeader`, `AppShellRail`, `AppShellRemote` — with the content surface being the only part that scrolls. Pick a product in the rail to drill into it, and the account item at the bottom for appearance and sidebar mode."
|
|
5346
5346
|
},
|
|
5347
5347
|
{
|
|
5348
5348
|
"name": "Loading",
|
|
5349
|
-
"code": "({ ambient, loading }) => (\n <Shell ambient={ambient} loading={loading} simulateProductLoading />\n)",
|
|
5349
|
+
"code": "({ ambient, loading }) => (\n <StoryRouter>\n <Shell ambient={ambient} loading={loading} simulateProductLoading />\n </StoryRouter>\n)",
|
|
5350
5350
|
"description": "How the shell looks while the platform loads. The header actions and the product rail hold skeletons that sit exactly where the real items land, so nothing jumps when they arrive. Turn `loading` off in Controls to watch the swap. Opening a product also shows its own panel and content loading."
|
|
5351
5351
|
},
|
|
5352
5352
|
{
|
|
5353
5353
|
"name": "RevealFlow",
|
|
5354
|
-
"code": "() =>
|
|
5354
|
+
"code": "() => (\n <StoryRouter>\n <RevealFlowShell />\n </StoryRouter>\n)",
|
|
5355
5355
|
"description": "`reveal` animates the chrome in on the first application load only. Leave it unset for an ordinary screen; this exists for prototyping the boot moment itself."
|
|
5356
5356
|
},
|
|
5357
5357
|
{
|
|
5358
5358
|
"name": "LoginFlow",
|
|
5359
|
-
"code": "() =>
|
|
5359
|
+
"code": "() => (\n <StoryRouter>\n <LoginFlowShell />\n </StoryRouter>\n)",
|
|
5360
5360
|
"description": "The whole entrance: the splash hands off, the content surface expands from the sign-in card into the full shell. `onRevealed` fires when it has settled."
|
|
5361
|
+
},
|
|
5362
|
+
{
|
|
5363
|
+
"name": "WithTanStackRouter",
|
|
5364
|
+
"code": "() => {\n const [router] = useState(createShellRouter);\n\n return <RouterProvider router={router} />;\n}",
|
|
5365
|
+
"description": "`AppShell` and a `RemoteShell` per product on one TanStack Router: the root route is\nthe shell (rail → `navigate`, `AppShellRemote` → `<Outlet />`), `/$product` is the\nremote (`RemoteShell` with `pathname` + `onNavigate`, content → `<Outlet />`), and\n`/$product/$` is the page. Every way of moving — the rail, the nav panel, the\nbreadcrumbs, links in the page — goes through the router, and the active items follow."
|
|
5361
5366
|
}
|
|
5362
5367
|
]
|
|
5363
5368
|
},
|
|
@@ -56736,6 +56741,7 @@
|
|
|
56736
56741
|
},
|
|
56737
56742
|
{
|
|
56738
56743
|
"name": "RemoteShell",
|
|
56744
|
+
"description": "Strips `basePath` only on a segment boundary: `/edge-nodes` is not under `/edge`.",
|
|
56739
56745
|
"importPath": "@wallarm-org/design-system/RemoteShell",
|
|
56740
56746
|
"props": [
|
|
56741
56747
|
{
|
|
@@ -56750,6 +56756,12 @@
|
|
|
56750
56756
|
"required": false,
|
|
56751
56757
|
"description": "URL prefix stripped before matching and prepended when navigating (e.g. `\"/edge\"`)."
|
|
56752
56758
|
},
|
|
56759
|
+
{
|
|
56760
|
+
"name": "pathname",
|
|
56761
|
+
"type": "string | undefined",
|
|
56762
|
+
"required": false,
|
|
56763
|
+
"description": "Current pathname. When set, it is the single source of truth for the active nav\nitem, drill level and breadcrumbs, and `window.location` is ignored.\n\nPass it — **together with `onNavigate`** — whenever a router owns the URL: router\nnavigations (links in page content, `router.navigate`, memory history, the host's\nrail) do not fire `popstate`, so without it the shell can go stale. Without\n`onNavigate` the shell's own navigations would only reach `window.history`, which\na controlled shell ignores (a dev warning flags this).\n\nEither form is accepted: with the `basePath` prefix (what `onNavigate` receives) or\nwithout it — the prefix is stripped only when the pathname starts with a whole\n`basePath` segment. With TanStack Router, `useRouterState({ select: s =>\ns.location.pathname })` is router-relative: it excludes the router's own\n`basepath`. So when the router has `basepath`:\n- omit `basePath` here — `pathname` and `onNavigate` are then both router-relative\n and `onNavigate={to => navigate({ to })}` is correct; or\n- keep `basePath` and strip it in `onNavigate`\n (`to => navigate({ to: to.slice(basePath.length) || '/' })`), otherwise the\n router prefixes it a second time.\n\nOmit it to read `window.location.pathname` (updated on `popstate` and on the\nshell's own navigations)."
|
|
56764
|
+
},
|
|
56753
56765
|
{
|
|
56754
56766
|
"name": "defaultChecked",
|
|
56755
56767
|
"type": "boolean | undefined",
|
|
@@ -57870,7 +57882,13 @@
|
|
|
57870
57882
|
]
|
|
57871
57883
|
}
|
|
57872
57884
|
],
|
|
57873
|
-
"examples": [
|
|
57885
|
+
"examples": [
|
|
57886
|
+
{
|
|
57887
|
+
"name": "Basic",
|
|
57888
|
+
"code": "() => {\n const navigate = useNavigate();\n const pathname = useRouterState({ select: state => state.location.pathname });\n\n return (\n <div className='h-screen bg-bg-page-bg'>\n <RemoteShell\n config={edgeNavConfig}\n basePath='/edge'\n pathname={pathname}\n onNavigate={to => navigate({ to })}\n >\n <RemoteShellPanel resizable />\n <RemoteShellBreadcrumb />\n <RemoteShellContent>\n <EdgePage />\n </RemoteShellContent>\n </RemoteShell>\n </div>\n );\n}",
|
|
57889
|
+
"description": "A standalone product on TanStack Router — the recommended integration. `pathname` is\nthe router’s `location.pathname` and `onNavigate` calls `navigate`, so the menu, drill\nlevel and breadcrumbs follow every navigation: the panel, the breadcrumbs and the\nrouter links in the page. This router has no `basepath` (its routes include `/edge`),\nso both sides use the full pathname. If your router sets `basepath`, its\n`location.pathname` is router-relative: omit `basePath` on `RemoteShell` (or keep it\nand strip it in `onNavigate`), otherwise `navigate` prefixes it twice."
|
|
57890
|
+
}
|
|
57891
|
+
]
|
|
57874
57892
|
},
|
|
57875
57893
|
{
|
|
57876
57894
|
"name": "Resizable",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@wallarm-org/design-system",
|
|
3
|
-
"version": "1.28.
|
|
3
|
+
"version": "1.28.1",
|
|
4
4
|
"description": "Core design system library with React components and Storybook documentation",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public",
|
|
@@ -97,6 +97,7 @@
|
|
|
97
97
|
"@storybook/addon-docs": "10.4.6",
|
|
98
98
|
"@storybook/addon-themes": "10.4.6",
|
|
99
99
|
"@tailwindcss/postcss": "4.3.3",
|
|
100
|
+
"@tanstack/react-router": "1.170.21",
|
|
100
101
|
"@testing-library/jest-dom": "7.0.0",
|
|
101
102
|
"@testing-library/react": "catalog:",
|
|
102
103
|
"@testing-library/user-event": "catalog:",
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
import { type NavRailMode } from '../../NavRail';
|
|
2
|
-
import { type Theme } from '../../ThemeProvider';
|
|
3
|
-
export type SidebarMode = 'adaptive' | 'expanded' | 'collapsed' | 'compact';
|
|
4
|
-
/** Adaptive collapses the rail inside a product and expands it on Home; the other modes pin it. */
|
|
5
|
-
export declare const railModeFor: (mode: SidebarMode, onHome: boolean) => NavRailMode;
|
|
6
|
-
export declare const AccountDropdown: ({ sidebarMode, onSidebarModeChange, theme, onThemeChange, }: {
|
|
7
|
-
sidebarMode: SidebarMode;
|
|
8
|
-
onSidebarModeChange: (mode: SidebarMode) => void;
|
|
9
|
-
theme: Theme;
|
|
10
|
-
onThemeChange: (theme: Theme) => void;
|
|
11
|
-
}) => import("react").JSX.Element;
|