@amboss/design-system 4.8.0 → 4.8.1-canary.0

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.
Files changed (98) hide show
  1. package/build/cjs/components/Internal/Panel/Panel.d.ts +7 -3
  2. package/build/cjs/components/Internal/Panel/Panel.js +1 -1
  3. package/build/cjs/components/Internal/PanelHeader/PanelHeader.d.ts +8 -4
  4. package/build/cjs/components/Internal/PanelHeader/PanelHeader.js +1 -1
  5. package/build/cjs/components/Internal/Sandwich/-types.d.ts +5 -0
  6. package/build/cjs/components/Internal/Sandwich/Sandwich.d.ts +1 -1
  7. package/build/cjs/components/Internal/Sandwich/Sandwich.js +1 -1
  8. package/build/cjs/components/Layout/-types.d.ts +64 -8
  9. package/build/cjs/components/Layout/Layout.d.ts +4 -0
  10. package/build/cjs/components/Layout/Layout.js +1 -1
  11. package/build/cjs/components/Layout/LeftNavBar/LeftNavBar.d.ts +17 -0
  12. package/build/cjs/components/Layout/LeftNavBar/LeftNavBar.js +1 -0
  13. package/build/cjs/components/Layout/LeftNavBar/LeftNavBarFooter.d.ts +7 -0
  14. package/build/cjs/components/Layout/LeftNavBar/LeftNavBarFooter.js +1 -0
  15. package/build/cjs/components/Layout/LeftPanel/LeftBarLayers.d.ts +45 -0
  16. package/build/cjs/components/Layout/LeftPanel/LeftBarLayers.js +1 -0
  17. package/build/cjs/components/Layout/LeftPanel/LeftBarToggle.d.ts +15 -0
  18. package/build/cjs/components/Layout/LeftPanel/LeftBarToggle.js +1 -0
  19. package/build/cjs/components/Layout/LeftPanel/LeftPanel.js +1 -1
  20. package/build/cjs/components/Layout/LeftPanel/LeftPanelDocked.d.ts +15 -5
  21. package/build/cjs/components/Layout/LeftPanel/LeftPanelDocked.js +1 -1
  22. package/build/cjs/components/Layout/LeftPanel/LeftPanelDrawer.js +1 -1
  23. package/build/cjs/components/Layout/LeftPanel/LeftPanelFooter.js +1 -1
  24. package/build/cjs/components/Layout/LeftPanel/LeftPanelHeader.d.ts +5 -3
  25. package/build/cjs/components/Layout/LeftPanel/LeftPanelHeader.js +1 -1
  26. package/build/cjs/components/Layout/LeftPanel/LeftPanelOffcanvas.d.ts +29 -0
  27. package/build/cjs/components/Layout/LeftPanel/LeftPanelOffcanvas.js +1 -0
  28. package/build/cjs/components/Layout/LeftPanel/useLeftBarContext.d.ts +11 -0
  29. package/build/cjs/components/Layout/LeftPanel/useLeftBarContext.js +1 -0
  30. package/build/cjs/components/Layout/LeftPanel/useLeftPanelCollapseContext.d.ts +11 -0
  31. package/build/cjs/components/Layout/LeftPanel/useLeftPanelCollapseContext.js +1 -0
  32. package/build/cjs/components/Layout/registry.d.ts +11 -0
  33. package/build/cjs/components/Layout/registry.js +1 -1
  34. package/build/cjs/components/Layout/rules.js +1 -1
  35. package/build/cjs/components/Layout/useLayoutRules.js +1 -1
  36. package/build/cjs/components/Layout/useLeftPanelId.d.ts +6 -0
  37. package/build/cjs/components/Layout/useLeftPanelId.js +1 -0
  38. package/build/cjs/components/Layout/usePanelDockedSlide.d.ts +10 -5
  39. package/build/cjs/components/Layout/usePanelDockedSlide.js +1 -1
  40. package/build/cjs/shared/mixins/getLeftPanelFadeStyles.d.ts +19 -0
  41. package/build/cjs/shared/mixins/getLeftPanelFadeStyles.js +1 -0
  42. package/build/cjs/shared/mixins/index.d.ts +1 -0
  43. package/build/cjs/shared/mixins/index.js +1 -1
  44. package/build/cjs/web-tokens/_sizes.json +64 -54
  45. package/build/cjs/web-tokens/visualConfig.d.ts +7 -0
  46. package/build/cjs/web-tokens/visualConfig.js +1 -1
  47. package/build/esm/components/Internal/Panel/Panel.d.ts +7 -3
  48. package/build/esm/components/Internal/Panel/Panel.js +1 -1
  49. package/build/esm/components/Internal/PanelHeader/PanelHeader.d.ts +8 -4
  50. package/build/esm/components/Internal/PanelHeader/PanelHeader.js +1 -1
  51. package/build/esm/components/Internal/Sandwich/-types.d.ts +5 -0
  52. package/build/esm/components/Internal/Sandwich/Sandwich.d.ts +1 -1
  53. package/build/esm/components/Internal/Sandwich/Sandwich.js +1 -1
  54. package/build/esm/components/Layout/-types.d.ts +64 -8
  55. package/build/esm/components/Layout/Layout.d.ts +4 -0
  56. package/build/esm/components/Layout/Layout.js +1 -1
  57. package/build/esm/components/Layout/LeftNavBar/LeftNavBar.d.ts +17 -0
  58. package/build/esm/components/Layout/LeftNavBar/LeftNavBar.js +1 -0
  59. package/build/esm/components/Layout/LeftNavBar/LeftNavBarFooter.d.ts +7 -0
  60. package/build/esm/components/Layout/LeftNavBar/LeftNavBarFooter.js +1 -0
  61. package/build/esm/components/Layout/LeftPanel/LeftBarLayers.d.ts +45 -0
  62. package/build/esm/components/Layout/LeftPanel/LeftBarLayers.js +1 -0
  63. package/build/esm/components/Layout/LeftPanel/LeftBarToggle.d.ts +15 -0
  64. package/build/esm/components/Layout/LeftPanel/LeftBarToggle.js +1 -0
  65. package/build/esm/components/Layout/LeftPanel/LeftPanel.js +1 -1
  66. package/build/esm/components/Layout/LeftPanel/LeftPanelDocked.d.ts +15 -5
  67. package/build/esm/components/Layout/LeftPanel/LeftPanelDocked.js +1 -1
  68. package/build/esm/components/Layout/LeftPanel/LeftPanelDrawer.js +1 -1
  69. package/build/esm/components/Layout/LeftPanel/LeftPanelFooter.js +1 -1
  70. package/build/esm/components/Layout/LeftPanel/LeftPanelHeader.d.ts +5 -3
  71. package/build/esm/components/Layout/LeftPanel/LeftPanelHeader.js +1 -1
  72. package/build/esm/components/Layout/LeftPanel/LeftPanelOffcanvas.d.ts +29 -0
  73. package/build/esm/components/Layout/LeftPanel/LeftPanelOffcanvas.js +1 -0
  74. package/build/esm/components/Layout/LeftPanel/useLeftBarContext.d.ts +11 -0
  75. package/build/esm/components/Layout/LeftPanel/useLeftBarContext.js +1 -0
  76. package/build/esm/components/Layout/LeftPanel/useLeftPanelCollapseContext.d.ts +11 -0
  77. package/build/esm/components/Layout/LeftPanel/useLeftPanelCollapseContext.js +1 -0
  78. package/build/esm/components/Layout/registry.d.ts +11 -0
  79. package/build/esm/components/Layout/registry.js +1 -1
  80. package/build/esm/components/Layout/rules.js +1 -1
  81. package/build/esm/components/Layout/useLayoutRules.js +1 -1
  82. package/build/esm/components/Layout/useLeftPanelId.d.ts +6 -0
  83. package/build/esm/components/Layout/useLeftPanelId.js +1 -0
  84. package/build/esm/components/Layout/usePanelDockedSlide.d.ts +10 -5
  85. package/build/esm/components/Layout/usePanelDockedSlide.js +1 -1
  86. package/build/esm/shared/mixins/getLeftPanelFadeStyles.d.ts +19 -0
  87. package/build/esm/shared/mixins/getLeftPanelFadeStyles.js +1 -0
  88. package/build/esm/shared/mixins/index.d.ts +1 -0
  89. package/build/esm/shared/mixins/index.js +1 -1
  90. package/build/esm/web-tokens/_sizes.json +64 -54
  91. package/build/esm/web-tokens/visualConfig.d.ts +7 -0
  92. package/build/esm/web-tokens/visualConfig.js +1 -1
  93. package/build/scss/_variables.scss +3 -0
  94. package/package.json +1 -1
  95. package/build/cjs/components/Layout/PanelSlideBody.d.ts +0 -18
  96. package/build/cjs/components/Layout/PanelSlideBody.js +0 -1
  97. package/build/esm/components/Layout/PanelSlideBody.d.ts +0 -18
  98. package/build/esm/components/Layout/PanelSlideBody.js +0 -1
@@ -0,0 +1,17 @@
1
+ import React from "react";
2
+ import type { LeftNavBarProps } from "../-types";
3
+ /**
4
+ * What `Layout.LeftPanel` shows in the left bar beneath the button that opens
5
+ * it, for panels whose left bar carries something other than the panel's own
6
+ * leading column - persistent destinations beside an article outline, say.
7
+ * Author it among the panel's children; it renders into the layer behind the
8
+ * panel, so opening widens that one column rather than adding a second box.
9
+ *
10
+ * Optional: the bar keeps its open button either way. This only fills the strip
11
+ * below it, on its own terms - scrolling, and sticking a
12
+ * `Layout.LeftNavBarFooter` to the bottom.
13
+ *
14
+ * Renders nothing where the panel has no left bar, so the mobile drawer shows
15
+ * the panel's own content alone even though the left bar is authored among it.
16
+ */
17
+ export declare function LeftNavBar({ children, "data-e2e-test-id": dataE2eTestId, }: LeftNavBarProps): React.ReactElement | null;
@@ -0,0 +1 @@
1
+ import React from"react";import{createPortal}from"react-dom";import styled from"@emotion/styled";import{Sandwich}from"../../Internal/Sandwich/Sandwich";import{useLeftBarContext}from"../LeftPanel/useLeftBarContext";let StyledNavBarFrame=styled("div",{target:"e1e9dsmx0",label:"StyledNavBarFrame"})({height:"100%"});export function LeftNavBar({children,"data-e2e-test-id":dataE2eTestId}){let{slotNode}=useLeftBarContext();return slotNode?createPortal(React.createElement(StyledNavBarFrame,{"data-ds-id":"LeftNavBar","data-e2e-test-id":dataE2eTestId},React.createElement(Sandwich,{hideScrollbar:!0},children)),slotNode):null}
@@ -0,0 +1,7 @@
1
+ import React from "react";
2
+ import type { LeftNavBarFooterProps } from "../-types";
3
+ /**
4
+ * Optional sticky footer for `Layout.LeftNavBar` - place it among the left bar's
5
+ * children; it sticks to the bottom while the rest of the content scrolls.
6
+ */
7
+ export declare function LeftNavBarFooter({ children, "data-e2e-test-id": dataE2eTestId, }: LeftNavBarFooterProps): React.ReactElement;
@@ -0,0 +1 @@
1
+ import React from"react";import{Sandwich}from"../../Internal/Sandwich/Sandwich";export function LeftNavBarFooter({children,"data-e2e-test-id":dataE2eTestId}){return React.createElement(Sandwich.Footer,{"data-e2e-test-id":dataE2eTestId},children)}
@@ -0,0 +1,45 @@
1
+ import React from "react";
2
+ import type { CSSObject, Theme } from "@emotion/react";
3
+ import type { ForwardedScrollProps } from "../-types";
4
+ /**
5
+ * The box the layers live in: one surface, one divider, and a clip. Shared by
6
+ * the two presentations that carry a left bar - the in-row column and the offcanvas
7
+ * overlay - which differ only in how they are positioned and sized.
8
+ *
9
+ * The surface is painted here, once and constantly, so nothing new appears
10
+ * mid-collapse: were each layer to paint its own, fading the panel's would only
11
+ * uncover the left bar's, identical and full-width, and the dissolve would reveal
12
+ * nothing.
13
+ *
14
+ * The divider is overlaid on the trailing edge rather than declared as a border,
15
+ * so it costs the box no width - the left bar's leading column and the header's
16
+ * trailing button are placed against the full width, and a border would put them
17
+ * half a pixel out.
18
+ */
19
+ export declare const getLeftBarColumnStyles: (theme: Theme) => CSSObject;
20
+ /**
21
+ * Where the box's top edge sits: below a sticky subnav, by the offset the subnav
22
+ * publishes, and at the host's top when no subnav is mounted. The edge moves
23
+ * with the subnav, so the transition is the one the subnav slides with, and
24
+ * the two travel as one. `RightPanelDocked` tracks the same var the same way,
25
+ * so the two side panels stay level.
26
+ */
27
+ export declare const LEFT_BAR_TOP_INSET: string;
28
+ export declare const getLeftBarTopTransition: (theme: Theme) => string;
29
+ export type LeftBarLayersProps = ForwardedScrollProps & {
30
+ children: React.ReactNode;
31
+ isVisible: boolean;
32
+ /** Width the panel's content holds on to while the box is narrower. */
33
+ openWidth: string;
34
+ /** Accessible name for the left bar's open button. */
35
+ toggleButtonLabel: string;
36
+ "aria-label"?: string;
37
+ };
38
+ /**
39
+ * The left bar and the panel, stacked in one box. Whichever of the two is showing,
40
+ * the box's width alone does the animating: content and footer hold `openWidth`
41
+ * and are clipped as it narrows, so nothing in them moves, while the header is
42
+ * left to narrow with the box - which walks its trailing control down into the
43
+ * left bar.
44
+ */
45
+ export declare const LeftBarLayers: React.FC<LeftBarLayersProps>;
@@ -0,0 +1 @@
1
+ import React,{useEffect,useMemo,useRef,useState}from"react";import styled from"@emotion/styled";import{useDocument}from"../../../shared/useDocument";import{getLeftPanelFadeStyles}from"../../../shared/mixins";import{SUBNAV_OFFSET_VAR}from"../-constants";import{Sandwich}from"../../Internal/Sandwich/Sandwich";import{useLeftPanelId}from"../useLeftPanelId";import{LeftPanelCollapseProvider}from"./useLeftPanelCollapseContext";import{LeftBarProvider}from"./useLeftBarContext";import{LeftBarToggle}from"./LeftBarToggle";export const getLeftBarColumnStyles=theme=>({overflow:"hidden",backgroundColor:theme.values.color.background.primary.default,"&::after":{content:'""',position:"absolute",top:0,bottom:0,right:0,width:1,backgroundColor:theme.values.color.border.secondary.default}});export const LEFT_BAR_TOP_INSET=`var(${SUBNAV_OFFSET_VAR}, 0px)`;export const getLeftBarTopTransition=theme=>{let{duration,timingFunction}=theme.variables.animation.navSlide.open;return`top ${duration} ${timingFunction}`};let StyledLeftBarLayer=styled("div",{target:"e1oedn8k0",label:"StyledLeftBarLayer"})(({isPanelOpen})=>({position:"absolute",inset:0,display:"flex",flexDirection:"column",visibility:isPanelOpen?"hidden":"visible"})),StyledNavBarSlot=styled("div",{target:"e1oedn8k1",label:"StyledNavBarSlot"})({flex:"1 1 auto",minHeight:0}),StyledPanelLayer=styled("div",{target:"e1oedn8k2",label:"StyledPanelLayer"})(({theme,isPanelOpen})=>{let{duration}=theme.variables.animation.navSlide.collapse;return{position:"absolute",inset:0,overflow:"hidden",visibility:isPanelOpen?"visible":"hidden",transition:isPanelOpen?"none":`visibility 0s linear ${duration}`,"@media (prefers-reduced-motion: reduce)":{transition:"none"}}}),StyledFadingContent=styled("div",{target:"e1oedn8k3",label:"StyledFadingContent"})(({theme,isFaded,pinnedContentWidth})=>({display:"flex",flexDirection:"column",flex:"1 0 auto",minWidth:pinnedContentWidth,...getLeftPanelFadeStyles({theme,isFaded})})),handOverFocus=({document,from,to})=>{from&&to&&from.contains(document.activeElement)&&to.focus()};export const LeftBarLayers=({children,isVisible,openWidth,toggleButtonLabel,"aria-label":ariaLabel,scrollContainerRef,onScroll})=>{let leftPanelId=useLeftPanelId(),document=useDocument(),leftBarLayerRef=useRef(null),panelLayerRef=useRef(null),toggleRef=useRef(null),[leftBarSlotNode,setLeftBarSlotNode]=useState(null),leftBarSlot=useMemo(()=>({slotNode:leftBarSlotNode}),[leftBarSlotNode]),isContentFaded=!isVisible,collapseState=useMemo(()=>({isContentFaded,pinnedContentWidth:openWidth}),[isContentFaded,openWidth]),wasVisible=useRef(isVisible);return useEffect(()=>{isVisible!==wasVisible.current&&(wasVisible.current=isVisible,handOverFocus({document,from:isVisible?leftBarLayerRef.current:panelLayerRef.current,to:isVisible?panelLayerRef.current:toggleRef.current}))},[isVisible,document]),React.createElement(LeftBarProvider,{value:leftBarSlot},React.createElement(StyledLeftBarLayer,{isPanelOpen:isVisible,ref:leftBarLayerRef},React.createElement(LeftBarToggle,{"aria-label":toggleButtonLabel,buttonRef:toggleRef}),React.createElement(StyledNavBarSlot,{ref:setLeftBarSlotNode})),React.createElement(StyledPanelLayer,{ref:panelLayerRef,isPanelOpen:isVisible,id:leftPanelId,tabIndex:-1,role:ariaLabel?"region":void 0,"aria-label":ariaLabel},React.createElement(Sandwich,{hideScrollbar:!0,scrollRef:scrollContainerRef,onScroll:onScroll},React.createElement(LeftPanelCollapseProvider,{value:collapseState},React.createElement(StyledFadingContent,{isFaded:isContentFaded,pinnedContentWidth:openWidth},children)))))};
@@ -0,0 +1,15 @@
1
+ import React from "react";
2
+ export type LeftBarToggleProps = {
3
+ /** Accessible name for the button, which is icon-only. */
4
+ "aria-label"?: string;
5
+ /** Handed out so the layer above can put focus here when the panel closes -
6
+ * this is the control that replaces the one the panel is taking away. */
7
+ buttonRef?: React.Ref<HTMLButtonElement>;
8
+ };
9
+ /**
10
+ * The one control the left bar always carries: the button that opens the panel
11
+ * back up. It belongs to the bar rather than to `Layout.LeftNavBar` - which only
12
+ * adds content beneath it - because a panel that authored no nav bar would
13
+ * otherwise close to a strip with no way back out of it.
14
+ */
15
+ export declare function LeftBarToggle({ "aria-label": ariaLabel, buttonRef, }: LeftBarToggleProps): React.ReactElement;
@@ -0,0 +1 @@
1
+ import React from"react";import{Box}from"../../Box/Box";import{PictogramButton}from"../../PictogramButton/PictogramButton";import{Slot}from"../-constants";import{useLayout}from"../useLayout";import{useLeftPanelId}from"../useLeftPanelId";export function LeftBarToggle({"aria-label":ariaLabel,buttonRef}){let{show,isVisible}=useLayout()[Slot.leftPanel],leftPanelId=useLeftPanelId();return React.createElement(Box,{space:"s",vSpace:"xs"},React.createElement(PictogramButton,{ref:buttonRef,icon:"open-sidebar-left",size:"s",onClick:show,"aria-label":ariaLabel,"aria-controls":leftPanelId,"aria-expanded":isVisible}))}
@@ -1 +1 @@
1
- import React from"react";import{Slot}from"../-constants";import{useVisibleChange}from"../registry";import{useLayout}from"../useLayout";import{useCanRenderPanel}from"../context";import{LeftPanelDocked}from"./LeftPanelDocked";import{LeftPanelDrawer}from"./LeftPanelDrawer";export const LeftPanel=({children,defaultSize,minSize,maxSize,collapsible=!0,resizable,onVisibleChange,"aria-label":ariaLabel,scrollContainerRef,onScroll})=>{let{isVisible,hide,state}=useLayout()[Slot.leftPanel],canRender=useCanRenderPanel();useVisibleChange(isVisible,onVisibleChange);let isDrawer="drawer"===state.variant;return canRender?isDrawer?React.createElement(LeftPanelDrawer,{isVisible:isVisible,hide:hide,"aria-label":ariaLabel,scrollContainerRef:scrollContainerRef,onScroll:onScroll},children):React.createElement(LeftPanelDocked,{"aria-label":ariaLabel,defaultSize:defaultSize,minSize:minSize,maxSize:maxSize,collapsible:collapsible,resizable:resizable,scrollContainerRef:scrollContainerRef,onScroll:onScroll},children):null};
1
+ import React,{useId}from"react";import{Slot}from"../-constants";import{useVisibleChange}from"../registry";import{useLayout}from"../useLayout";import{useCanRenderPanel}from"../context";import{LeftPanelIdContext}from"../useLeftPanelId";import{LeftPanelDocked}from"./LeftPanelDocked";import{LeftPanelDrawer}from"./LeftPanelDrawer";import{LeftPanelOffcanvas}from"./LeftPanelOffcanvas";let pixelsOf=size=>"number"==typeof size?size:void 0,defaultSizeOf=({defaultSize,minSize,state})=>defaultSize??minSize??pixelsOf(state.size)??pixelsOf(state.minSize)??320;export const LeftPanel=({children,slotProps,defaultSize,minSize,maxSize,collapsible=!0,resizable,onVisibleChange,"aria-label":ariaLabel,scrollContainerRef,onScroll})=>{let{isVisible,hide,state}=useLayout()[Slot.leftPanel],canRender=useCanRenderPanel(),leftPanelId=useId(),resolvedDefaultSize=defaultSizeOf({defaultSize,minSize,state});if(useVisibleChange(isVisible,onVisibleChange),!canRender)return null;let drawer=React.createElement(LeftPanelDrawer,{isVisible:isVisible,hide:hide,"aria-label":ariaLabel,scrollContainerRef:scrollContainerRef,onScroll:onScroll},children),offcanvas=React.createElement(LeftPanelOffcanvas,{toggleButtonLabel:slotProps.toggleButton["aria-label"],isVisible:isVisible,hide:hide,openWidth:`${resolvedDefaultSize}px`,"aria-label":ariaLabel,scrollContainerRef:scrollContainerRef,onScroll:onScroll},children),docked=React.createElement(LeftPanelDocked,{toggleButtonLabel:slotProps.toggleButton["aria-label"],"aria-label":ariaLabel,defaultSize:resolvedDefaultSize,minSize:minSize,maxSize:maxSize,collapsible:collapsible,resizable:resizable,scrollContainerRef:scrollContainerRef,onScroll:onScroll},children);return React.createElement(LeftPanelIdContext.Provider,{value:leftPanelId},{drawer,offcanvas,sidebar:docked}[state.variant])};
@@ -1,11 +1,15 @@
1
1
  import React from "react";
2
- import type { ForwardedScrollProps, Size } from "../-types";
2
+ import type { ForwardedScrollProps } from "../-types";
3
3
  export type LeftPanelDockedProps = ForwardedScrollProps & {
4
4
  children: React.ReactNode;
5
+ /** Accessible name for the left bar's open button. */
6
+ toggleButtonLabel: string;
5
7
  "aria-label"?: string;
6
- defaultSize?: Size;
7
- minSize?: Size;
8
- maxSize?: Size;
8
+ /** Pixel width the column widens to. Resolved by `LeftPanel` from its own
9
+ * prop and the provider config, so it is always a width. */
10
+ defaultSize: number;
11
+ minSize?: number;
12
+ maxSize?: number;
9
13
  collapsible?: boolean;
10
14
  resizable?: boolean;
11
15
  };
@@ -13,9 +17,15 @@ export type LeftPanelDockedProps = ForwardedScrollProps & {
13
17
  * Docked (desktop) left panel. Declares the `leftPanel` slot and portals its
14
18
  * content into the Group's host - an in-flow, resizable column whose width
15
19
  * slides open/closed via {@link usePanelDockedSlide} (when collapsible). Content
16
- * lives in a {@link PanelContainer} so `Layout.LeftPanelHeader` /
20
+ * lives in {@link LeftBarLayers} so `Layout.LeftPanelHeader` /
17
21
  * `Layout.LeftPanelFooter` children stick to the edges. The mobile presentation
18
22
  * lives in {@link LeftPanelDrawer}; `LeftPanel` picks between the two by
19
23
  * breakpoint.
24
+ *
25
+ * The column never leaves the row: it rests at the left bar's width and widens
26
+ * to `defaultSize`. Content and footer hold the open width and are clipped, so
27
+ * nothing in them moves - the panel simply shows less of itself. The header is
28
+ * left to narrow with the column, which walks a control at its trailing edge
29
+ * down into the left bar.
20
30
  */
21
31
  export declare const LeftPanelDocked: React.FC<LeftPanelDockedProps>;
@@ -1 +1 @@
1
- import React from"react";import{Slot}from"../-constants";import{useLayoutPortal}from"../registry";import{usePanelDockedSlide}from"../usePanelDockedSlide";import{PanelSlideBody}from"../PanelSlideBody";import{PanelContainer}from"../PanelContainer";export const LeftPanelDocked=({children,"aria-label":ariaLabel,defaultSize,minSize,maxSize,collapsible=!0,resizable,scrollContainerRef,onScroll})=>{let{isMounted,pinnedWidth}=usePanelDockedSlide({slot:Slot.leftPanel,defaultSize,minSize,maxSize,collapsible,resizable,lockWidthOnWindowResize:!0});return useLayoutPortal(Slot.leftPanel,isMounted?React.createElement(PanelSlideBody,{anchor:"right",pinnedWidth:pinnedWidth},React.createElement(PanelContainer,{showBorderRight:!0,"aria-label":ariaLabel,scrollContainerRef:scrollContainerRef,onScroll:onScroll},children)):null)};
1
+ import React from"react";import styled from"@emotion/styled";import{useTheme}from"@emotion/react";import{PAGE_BOTTOM_BAR_INSET,Slot}from"../-constants";import{useLayoutPortal}from"../registry";import{usePanelDockedSlide}from"../usePanelDockedSlide";import{LEFT_BAR_TOP_INSET,LeftBarLayers,getLeftBarColumnStyles,getLeftBarTopTransition}from"./LeftBarLayers";import{useLayout}from"../useLayout";let StyledLeftBarColumn=styled("div",{target:"e1apd56i0",label:"StyledLeftBarColumn"})(({theme})=>({position:"absolute",left:0,right:0,top:LEFT_BAR_TOP_INSET,bottom:PAGE_BOTTOM_BAR_INSET,transition:getLeftBarTopTransition(theme),"@media (prefers-reduced-motion: reduce)":{transition:"none"},...getLeftBarColumnStyles(theme)}));export const LeftPanelDocked=({children,toggleButtonLabel,"aria-label":ariaLabel,defaultSize,minSize,maxSize,collapsible=!0,resizable,scrollContainerRef,onScroll})=>{let theme=useTheme(),{isVisible}=useLayout()[Slot.leftPanel];return usePanelDockedSlide({slot:Slot.leftPanel,defaultSize,minSize,maxSize,collapsible,resizable,lockWidthOnWindowResize:!0,collapsedSize:parseFloat(theme.variables.size.dimension.leftNavBar.width)}),useLayoutPortal(Slot.leftPanel,React.createElement(StyledLeftBarColumn,null,React.createElement(LeftBarLayers,{isVisible:isVisible,toggleButtonLabel:toggleButtonLabel,openWidth:`${defaultSize}px`,"aria-label":ariaLabel,scrollContainerRef:scrollContainerRef,onScroll:onScroll},children)))};
@@ -1 +1 @@
1
- import React from"react";import styled from"@emotion/styled";import{Drawer}from"../../Internal/Drawer/Drawer";import{PanelContainer}from"../PanelContainer";let StyledLeftPanelBody=styled("div",{target:"e1pciy730",label:"StyledLeftPanelBody"})({width:"80vw",height:"100dvh"});export const LeftPanelDrawer=({children,isVisible,hide,"aria-label":ariaLabel,scrollContainerRef,onScroll})=>React.createElement(Drawer,{isVisible:isVisible,positionX:"left",handleClose:hide,"aria-label":ariaLabel},React.createElement(StyledLeftPanelBody,null,React.createElement(PanelContainer,{scrollContainerRef:scrollContainerRef,onScroll:onScroll},children)));
1
+ import React from"react";import styled from"@emotion/styled";import{Drawer}from"../../Internal/Drawer/Drawer";import{PanelContainer}from"../PanelContainer";import{useLeftPanelId}from"../useLeftPanelId";let StyledLeftPanelBody=styled("div",{target:"e158aetq0",label:"StyledLeftPanelBody"})({width:"80vw",height:"100dvh"});export const LeftPanelDrawer=({children,isVisible,hide,"aria-label":ariaLabel,scrollContainerRef,onScroll})=>{let leftPanelId=useLeftPanelId();return React.createElement(Drawer,{isVisible:isVisible,positionX:"left",handleClose:hide,"aria-label":ariaLabel},React.createElement(StyledLeftPanelBody,null,React.createElement(PanelContainer,{id:leftPanelId,scrollContainerRef:scrollContainerRef,onScroll:onScroll},children)))};
@@ -1 +1 @@
1
- import React from"react";import{Sandwich}from"../../Internal/Sandwich/Sandwich";export function LeftPanelFooter({children,"data-e2e-test-id":dataE2eTestId}){return React.createElement(Sandwich.Footer,{"data-e2e-test-id":dataE2eTestId},children)}
1
+ import React from"react";import styled from"@emotion/styled";import{getLeftPanelFadeStyles}from"../../../shared/mixins";import{Sandwich}from"../../Internal/Sandwich/Sandwich";import{useLeftPanelCollapseContext}from"./useLeftPanelCollapseContext";let StyledFadingFooter=styled("div",{target:"emmyo1o0",label:"StyledFadingFooter"})(({theme,isFaded,pinnedContentWidth})=>({minWidth:pinnedContentWidth,...getLeftPanelFadeStyles({theme,isFaded})}));export function LeftPanelFooter({children,"data-e2e-test-id":dataE2eTestId}){let{isContentFaded,pinnedContentWidth}=useLeftPanelCollapseContext();return React.createElement(Sandwich.Footer,{"data-e2e-test-id":dataE2eTestId},React.createElement(StyledFadingFooter,{isFaded:isContentFaded,pinnedContentWidth:pinnedContentWidth},children))}
@@ -1,7 +1,9 @@
1
1
  import React from "react";
2
2
  import type { LeftPanelHeaderProps } from "../-types";
3
3
  /**
4
- * Optional sticky header for `Layout.LeftPanel` - place it among the panel's
5
- * children; it sticks to the top while the rest of the content scrolls.
4
+ * Header for the left panel. Place among `Layout.LeftPanel`'s children; it
5
+ * sticks to the top while the rest of the content scrolls. Content is a left
6
+ * slot, an optional title, a right slot, and beneath them whatever is passed as
7
+ * `children`.
6
8
  */
7
- export declare function LeftPanelHeader({ leftSlot, rightSlot, "data-e2e-test-id": dataE2eTestId, }: LeftPanelHeaderProps): React.ReactElement;
9
+ export declare function LeftPanelHeader({ leftSlot, title, rightSlot, children, "data-e2e-test-id": dataE2eTestId, }: LeftPanelHeaderProps): React.ReactElement;
@@ -1 +1 @@
1
- import React from"react";import{Sandwich}from"../../Internal/Sandwich/Sandwich";import{PanelHeader}from"../../Internal/PanelHeader/PanelHeader";export function LeftPanelHeader({leftSlot,rightSlot,"data-e2e-test-id":dataE2eTestId}){return React.createElement(Sandwich.Header,{"data-e2e-test-id":dataE2eTestId},React.createElement(PanelHeader,{leftSlot:leftSlot,rightSlot:rightSlot}))}
1
+ import React from"react";import styled from"@emotion/styled";import{getLeftPanelFadeStyles}from"../../../shared/mixins/getLeftPanelFadeStyles";import{Sandwich}from"../../Internal/Sandwich/Sandwich";import{PanelHeader}from"../../Internal/PanelHeader/PanelHeader";import{useLeftPanelCollapseContext}from"./useLeftPanelCollapseContext";let StyledHeaderStrip=styled("div",{target:"e1asip2n0",label:"StyledHeaderStrip"})(({theme,isFaded,pinnedContentWidth})=>({minWidth:pinnedContentWidth,...getLeftPanelFadeStyles({theme,isFaded})}));export function LeftPanelHeader({leftSlot,title,rightSlot,children,"data-e2e-test-id":dataE2eTestId}){let{isContentFaded,pinnedContentWidth}=useLeftPanelCollapseContext();return React.createElement(Sandwich.Header,{"data-e2e-test-id":dataE2eTestId},React.createElement(PanelHeader,{leftSlot:leftSlot,title:title,rightSlot:rightSlot,isContentFaded:isContentFaded}),children&&React.createElement(StyledHeaderStrip,{isFaded:isContentFaded,pinnedContentWidth:pinnedContentWidth},children))}
@@ -0,0 +1,29 @@
1
+ import React from "react";
2
+ import type { ForwardedScrollProps } from "../-types";
3
+ export type LeftPanelOffcanvasProps = ForwardedScrollProps & {
4
+ children: React.ReactNode;
5
+ /** Accessible name for the left bar's open button. */
6
+ toggleButtonLabel: string;
7
+ isVisible: boolean;
8
+ hide: () => void;
9
+ openWidth: string;
10
+ "aria-label"?: string;
11
+ };
12
+ /**
13
+ * Left panel as a non-modal overlay: a drawer without the dialog. Used when the
14
+ * docked budget has no column left but the panel should stay reachable - it
15
+ * opens over the row instead of taking a column from it, and instead of being
16
+ * hidden outright. The left bar stays on screen throughout; only the mobile drawer
17
+ * gives it up.
18
+ *
19
+ * Deliberately not a {@link Drawer}: a Drawer traps focus, claims `aria-modal`
20
+ * and covers the viewport with a click-catching layer. Here the page behind
21
+ * stays live and usable, so the panel is a plain `region` (named by
22
+ * `aria-label`) that happens to be layered - nothing about it is modal.
23
+ *
24
+ * It still dismisses like something laid over the page, because that is what it
25
+ * is: Escape and a click beyond its edge both close it back to its left bar. Only
26
+ * while it is open - closed, it is just the left bar, and the left bar is not something
27
+ * to dismiss.
28
+ */
29
+ export declare const LeftPanelOffcanvas: React.FC<LeftPanelOffcanvasProps>;
@@ -0,0 +1 @@
1
+ import React,{useRef}from"react";import styled from"@emotion/styled";import{useTheme}from"@emotion/react";import{LEFT_BAR_TOP_INSET,LeftBarLayers,getLeftBarColumnStyles,getLeftBarTopTransition}from"./LeftBarLayers";import{PAGE_BOTTOM_BAR_INSET,Slot}from"../-constants";import{useDeclarePanel}from"../registry";import{useOnEscapePress}from"../../../shared/useOnEscapePress";import{useOutsideClick}from"../../../shared/useOutsideClick";let getOffcanvasBoxStyles=(theme,{isVisible,leftBarWidth,openWidth})=>({position:"absolute",left:0,top:LEFT_BAR_TOP_INSET,bottom:PAGE_BOTTOM_BAR_INSET,zIndex:1,width:isVisible?openWidth:leftBarWidth}),StyledOffcanvasShadow=styled("div",{target:"exeyzov0",label:"StyledOffcanvasShadow"})(({theme,...box})=>{let{duration,timingFunction}=theme.variables.animation.navSlide.collapse;return{...getOffcanvasBoxStyles(theme,box),pointerEvents:"none",boxShadow:theme.values.elevation[2],opacity:box.isVisible?theme.variables.opacity.visible:theme.variables.opacity.hidden,transition:[`width ${duration} ${timingFunction}`,`opacity ${duration} ${timingFunction}`,getLeftBarTopTransition(theme)].join(", "),"@media (prefers-reduced-motion: reduce)":{transition:"none"}}}),StyledOffcanvasColumn=styled("div",{target:"exeyzov1",label:"StyledOffcanvasColumn"})(({theme,...box})=>{let{duration,timingFunction}=theme.variables.animation.navSlide.collapse;return{...getOffcanvasBoxStyles(theme,box),transition:[`width ${duration} ${timingFunction}`,getLeftBarTopTransition(theme)].join(", "),"@media (prefers-reduced-motion: reduce)":{transition:"none"},...getLeftBarColumnStyles(theme)}});export const LeftPanelOffcanvas=({children,toggleButtonLabel,isVisible,hide,openWidth,"aria-label":ariaLabel,scrollContainerRef,onScroll})=>{let theme=useTheme();useDeclarePanel(Slot.leftPanel,{});let columnRef=useRef(null);useOnEscapePress(event=>{isVisible&&(event.preventDefault(),hide())},[isVisible,hide]),useOutsideClick(columnRef,hide,isVisible);let box={isVisible,leftBarWidth:theme.variables.size.dimension.leftNavBar.width,openWidth};return React.createElement(React.Fragment,null,React.createElement(StyledOffcanvasShadow,{...box,"aria-hidden":!0}),React.createElement(StyledOffcanvasColumn,{...box,ref:columnRef},React.createElement(LeftBarLayers,{isVisible:isVisible,toggleButtonLabel:toggleButtonLabel,openWidth:openWidth,"aria-label":ariaLabel,scrollContainerRef:scrollContainerRef,onScroll:onScroll},children)))};
@@ -0,0 +1,11 @@
1
+ export type LeftBarSlot = {
2
+ /** Static host the left bar's content portals into. Null until the layer
3
+ * behind the panel has mounted, and never provided at all by the
4
+ * presentations that carry no left bar - which is how `Layout.LeftNavBar`
5
+ * knows to render nothing on mobile, where the drawer shows the panel's own
6
+ * content alone. */
7
+ slotNode: HTMLElement | null;
8
+ };
9
+ export declare const LeftBarProvider: React.Provider<LeftBarSlot>;
10
+ /** The left bar slot behind the left panel, if this presentation has one. */
11
+ export declare function useLeftBarContext(): LeftBarSlot;
@@ -0,0 +1 @@
1
+ import{createContext,useContext}from"react";let LeftBarContext=createContext({slotNode:null});export const LeftBarProvider=LeftBarContext.Provider;export function useLeftBarContext(){return useContext(LeftBarContext)}
@@ -0,0 +1,11 @@
1
+ /** How the left panel's parts have to behave while its column narrows to a left bar. */
2
+ export type LeftPanelCollapseState = {
3
+ /** The content is dissolving into the left bar beneath it. */
4
+ isContentFaded: boolean;
5
+ /** Width the content holds on to while the column narrows around it, clipped
6
+ * at the column's edge so nothing inside reflows on the way down. */
7
+ pinnedContentWidth?: string;
8
+ };
9
+ export declare const LeftPanelCollapseProvider: React.Provider<LeftPanelCollapseState>;
10
+ /** How the left panel's parts have to behave while its column narrows. */
11
+ export declare function useLeftPanelCollapseContext(): LeftPanelCollapseState;
@@ -0,0 +1 @@
1
+ import{createContext,useContext}from"react";let LeftPanelCollapseContext=createContext({isContentFaded:!1});export const LeftPanelCollapseProvider=LeftPanelCollapseContext.Provider;export function useLeftPanelCollapseContext(){return useContext(LeftPanelCollapseContext)}
@@ -40,6 +40,17 @@ export declare const PanelRegistryContext: React.Context<PanelRegistry>;
40
40
  export declare function useDeclarePanel(slot: SlotKey, reg: PanelReg): void;
41
41
  export type PanelDeclarations = Partial<Record<SlotKey, PanelReg>>;
42
42
  export declare const PanelDeclarationsContext: React.Context<Partial<Record<"content" | "leftPanel" | "splitview" | "rightPanel", PanelReg>>>;
43
+ /**
44
+ * The ids of the columns in the resizable row, in order, joined with commas.
45
+ * Changes when a column joins or leaves the row, and only then. A column that
46
+ * has to hold a width of its own across such a change - the left bar column,
47
+ * which react-resizable-panels would otherwise put back at whatever width it
48
+ * had the last time the same set of columns was on screen - re-checks its rest
49
+ * against it.
50
+ */
51
+ export declare const PanelRowContext: React.Context<string>;
52
+ /** The row's current column set, as a stable key. Empty outside a Layout. */
53
+ export declare function usePanelRow(): string;
43
54
  /**
44
55
  * Keeps an animating-out panel in the resizable row while its exit plays - the
45
56
  * Group would otherwise drop the column the instant it's hidden. The panel
@@ -1 +1 @@
1
- import{createContext,useContext,useEffect,useLayoutEffect,useRef}from"react";import{createPortal}from"react-dom";import{Slot}from"./-constants";import{useLayoutPanelsEnabled}from"./context";export const LayoutPortalContext=createContext({});export function useLayoutPortal(slot,children){let slotNode=useContext(LayoutPortalContext)[slot]??null;return slotNode?createPortal(children,slotNode):null}export const PanelRegistryContext=createContext(null);export function useDeclarePanel(slot,reg){let registry=useContext(PanelRegistryContext),declarationEnabled=!0===useLayoutPanelsEnabled()||slot===Slot.content,{defaultSize,minSize,maxSize,collapsible,resizable,lockWidthOnWindowResize,variant}=reg;useLayoutEffect(()=>{if(registry&&declarationEnabled)return registry.register(slot,{defaultSize,minSize,maxSize,collapsible,resizable,lockWidthOnWindowResize,variant}),()=>registry.unregister(slot)},[registry,declarationEnabled,slot,defaultSize,minSize,maxSize,collapsible,resizable,lockWidthOnWindowResize,variant])}export const PanelDeclarationsContext=createContext({});export const PanelPresenceContext=createContext(null);export function usePanelPresence(slot,isPresent){let presence=useContext(PanelPresenceContext);useLayoutEffect(()=>{if(presence)return presence.setPresent(slot,isPresent),()=>presence.setPresent(slot,!1)},[presence,slot,isPresent])}export const PanelAnimationContext=createContext(null);export function usePanelAnimationControl(){return useContext(PanelAnimationContext)}export function useRunCallbackOnValueChange(value,onChange){let prev=useRef(value);useEffect(()=>{prev.current!==value&&(prev.current=value,onChange?.(value))},[value,onChange])}export function useVisibleChange(visible,onChange){useRunCallbackOnValueChange(visible,onChange)}
1
+ import{createContext,useContext,useEffect,useLayoutEffect,useRef}from"react";import{createPortal}from"react-dom";import{Slot}from"./-constants";import{useLayoutPanelsEnabled}from"./context";export const LayoutPortalContext=createContext({});export function useLayoutPortal(slot,children){let slotNode=useContext(LayoutPortalContext)[slot]??null;return slotNode?createPortal(children,slotNode):null}export const PanelRegistryContext=createContext(null);export function useDeclarePanel(slot,reg){let registry=useContext(PanelRegistryContext),declarationEnabled=!0===useLayoutPanelsEnabled()||slot===Slot.content,{defaultSize,minSize,maxSize,collapsible,resizable,lockWidthOnWindowResize,variant}=reg;useLayoutEffect(()=>{if(registry&&declarationEnabled)return registry.register(slot,{defaultSize,minSize,maxSize,collapsible,resizable,lockWidthOnWindowResize,variant}),()=>registry.unregister(slot)},[registry,declarationEnabled,slot,defaultSize,minSize,maxSize,collapsible,resizable,lockWidthOnWindowResize,variant])}export const PanelDeclarationsContext=createContext({});export const PanelRowContext=createContext("");export function usePanelRow(){return useContext(PanelRowContext)}export const PanelPresenceContext=createContext(null);export function usePanelPresence(slot,isPresent){let presence=useContext(PanelPresenceContext);useLayoutEffect(()=>{if(presence)return presence.setPresent(slot,isPresent),()=>presence.setPresent(slot,!1)},[presence,slot,isPresent])}export const PanelAnimationContext=createContext(null);export function usePanelAnimationControl(){return useContext(PanelAnimationContext)}export function useRunCallbackOnValueChange(value,onChange){let prev=useRef(value);useEffect(()=>{prev.current!==value&&(prev.current=value,onChange?.(value))},[value,onChange])}export function useVisibleChange(visible,onChange){useRunCallbackOnValueChange(visible,onChange)}
@@ -1 +1 @@
1
- export const DEFAULT_LAYOUT_RULES={maxDockedPanels:{xs:1,m:2,l:3},rightPanel:{priority:1,condition:({isLowPrio,isMobile,layout})=>{isLowPrio&&!isMobile&&layout.rightPanel.setVariant("float")}},splitview:{priority:2,condition:({isLowPrio,isMobile,layout})=>{isLowPrio&&!isMobile&&layout.splitview.hide()}},leftPanel:{priority:3,condition:({isLowPrio,isMobile,layout})=>{let variant=isMobile||isLowPrio?"drawer":"sidebar";variant!==layout.leftPanel.state.variant&&(layout.leftPanel.setVariant(variant),"drawer"!==variant||isMobile||layout.leftPanel.hide())}}};
1
+ let leftPanelVariantFor=({isMobile,isLowPrio})=>isMobile?"drawer":isLowPrio?"offcanvas":"sidebar";export const DEFAULT_LAYOUT_RULES={maxDockedPanels:{xs:1,m:2,l:3},rightPanel:{priority:1,condition:({isLowPrio,isMobile,layout})=>{isLowPrio&&!isMobile&&layout.rightPanel.setVariant("float")}},splitview:{priority:2,condition:({isLowPrio,isMobile,layout})=>{isLowPrio&&!isMobile&&layout.splitview.hide()}},leftPanel:{priority:3,condition:({isLowPrio,isMobile,layout})=>{let variant=leftPanelVariantFor({isMobile,isLowPrio});variant!==layout.leftPanel.state.variant&&(layout.leftPanel.setVariant(variant),"offcanvas"===variant&&layout.leftPanel.hide())}}};
@@ -1 +1 @@
1
- import{useEffect,useRef}from"react";import{useBreakpoints}from"../../shared/useBreakpoints";import{PANEL_ORDER,Slot,TOGGLABLE_SLOTS}from"./-constants";let DEFAULT_PRIORITY={[Slot.rightPanel]:1,[Slot.splitview]:2,[Slot.leftPanel]:3},maxDockedFor=(maxDockedPanels,breakpoints)=>{let{xs,m=xs,l=m}=maxDockedPanels;return breakpoints.isMobile?xs:breakpoints.isTablet?m:l},isDockedPanel=({state,declared,slot})=>!!declared[slot]&&!!state[slot].visible&&(slot===Slot.rightPanel?"float"!==state.rightPanel.variant:slot!==Slot.leftPanel||"drawer"!==state.leftPanel.variant),resolveLowPrioSlots=({rules,state,declared,breakpoints})=>{let freeSlots=Math.max(0,maxDockedFor(rules.maxDockedPanels,breakpoints)-1),priorityFor=slot=>rules[slot]?.priority??DEFAULT_PRIORITY[slot],outranks=(slot,other)=>{let byPriority=priorityFor(slot)-priorityFor(other);return 0!==byPriority?byPriority<0:PANEL_ORDER.indexOf(slot)<PANEL_ORDER.indexOf(other)},countStrongerDocked=slot=>TOGGLABLE_SLOTS.filter(other=>other!==slot&&isDockedPanel({state,declared,slot:other})&&outranks(other,slot)).length;return TOGGLABLE_SLOTS.filter(slot=>countStrongerDocked(slot)>=freeSlots)};export function useLayoutRules({layout,declared,rules,additionalData}){let layoutRef=useRef(layout);layoutRef.current=layout;let{isMobile,isTablet,isDesktop}=useBreakpoints(),{state}=layout;useEffect(()=>{if(!rules)return;let lowPrioSlots=resolveLowPrioSlots({rules,state,declared,breakpoints:{isMobile,isTablet,isDesktop}});TOGGLABLE_SLOTS.forEach(slot=>{let condition=rules[slot]?.condition;condition&&condition({...additionalData,isLowPrio:lowPrioSlots.includes(slot),isMobile,isTablet,isDesktop,layout:layoutRef.current})})},[rules,additionalData,state,declared,isMobile,isTablet,isDesktop])}
1
+ import{useEffect,useRef}from"react";import{useBreakpoints}from"../../shared/useBreakpoints";import{PANEL_ORDER,Slot,TOGGLABLE_SLOTS}from"./-constants";let DEFAULT_PRIORITY={[Slot.rightPanel]:1,[Slot.splitview]:2,[Slot.leftPanel]:3},maxDockedFor=(maxDockedPanels,breakpoints)=>{let{xs,m=xs,l=m}=maxDockedPanels;return breakpoints.isMobile?xs:breakpoints.isTablet?m:l},isDockedPanel=({state,declared,slot})=>!!declared[slot]&&!!state[slot].visible&&(slot===Slot.rightPanel?"float"!==state.rightPanel.variant:slot!==Slot.leftPanel||"sidebar"===state.leftPanel.variant),resolveLowPrioSlots=({rules,state,declared,breakpoints})=>{let freeSlots=Math.max(0,maxDockedFor(rules.maxDockedPanels,breakpoints)-1),priorityFor=slot=>rules[slot]?.priority??DEFAULT_PRIORITY[slot],outranks=(slot,other)=>{let byPriority=priorityFor(slot)-priorityFor(other);return 0!==byPriority?byPriority<0:PANEL_ORDER.indexOf(slot)<PANEL_ORDER.indexOf(other)},countStrongerDocked=slot=>TOGGLABLE_SLOTS.filter(other=>other!==slot&&isDockedPanel({state,declared,slot:other})&&outranks(other,slot)).length;return TOGGLABLE_SLOTS.filter(slot=>countStrongerDocked(slot)>=freeSlots)};export function useLayoutRules({layout,declared,rules,additionalData}){let layoutRef=useRef(layout);layoutRef.current=layout;let{isMobile,isTablet,isDesktop}=useBreakpoints(),{state}=layout;useEffect(()=>{if(!rules)return;let lowPrioSlots=resolveLowPrioSlots({rules,state,declared,breakpoints:{isMobile,isTablet,isDesktop}});TOGGLABLE_SLOTS.forEach(slot=>{let condition=rules[slot]?.condition;condition&&condition({...additionalData,isLowPrio:lowPrioSlots.includes(slot),isMobile,isTablet,isDesktop,layout:layoutRef.current})})},[rules,additionalData,state,declared,isMobile,isTablet,isDesktop])}
@@ -0,0 +1,6 @@
1
+ /** DOM id of the rendered left panel, generated once per `Layout`. Lets a
2
+ * control living OUTSIDE the panel - the nav left bar's open button - point
3
+ * `aria-controls` at it without the two components knowing each other. Empty
4
+ * outside a `Layout`, where there is no panel to reference. */
5
+ export declare const LeftPanelIdContext: React.Context<string>;
6
+ export declare const useLeftPanelId: () => string;
@@ -0,0 +1 @@
1
+ import{createContext,useContext}from"react";export const LeftPanelIdContext=createContext("");export const useLeftPanelId=()=>useContext(LeftPanelIdContext);
@@ -14,6 +14,12 @@ export type PanelDockedSlideOptions = {
14
14
  /** Forwarded to the declaration: lock the column's width when the window
15
15
  * resizes. Doesn't affect the slide, which resizes the column outright. */
16
16
  lockWidthOnWindowResize?: boolean;
17
+ /** Width the column rests at while hidden, instead of collapsing to nothing.
18
+ * Set it and the column never unmounts: closing narrows it to this, opening
19
+ * widens it back, so one box carries both states (a nav left bar that widens
20
+ * into the panel). The column stops being collapsible - there is no zero to
21
+ * collapse to - and this becomes its `minSize` while it is hidden. */
22
+ collapsedSize?: Size;
17
23
  };
18
24
  export type PanelDockedSlide = {
19
25
  /** Whether the panel's content should render at all (entering, open, or
@@ -26,10 +32,9 @@ export type PanelDockedSlide = {
26
32
  /**
27
33
  * Animates a docked side panel's open/close as a width slide on its
28
34
  * `react-resizable-panels` column, pushing neighbouring content smoothly
29
- * instead of snapping. Slot-generic - works for either side panel; render the
30
- * returned state with {@link PanelSlideBody}. Falls back to an instant
31
- * open/close when the panel isn't collapsible, no handle is available, or
32
- * reduced motion is requested. The mobile modal-drawer lifecycle lives in
35
+ * instead of snapping. Slot-generic - works for either side panel. Falls back to
36
+ * an instant open/close when the panel isn't collapsible, no handle is
37
+ * available, or reduced motion is requested. The mobile modal-drawer lifecycle lives in
33
38
  * {@link useExitAnimation} and the Drawer's styled components.
34
39
  */
35
- export declare function usePanelDockedSlide({ slot, defaultSize, minSize, maxSize, collapsible, resizable, lockWidthOnWindowResize, }: PanelDockedSlideOptions): PanelDockedSlide;
40
+ export declare function usePanelDockedSlide({ slot, defaultSize, minSize, maxSize, collapsible, resizable, lockWidthOnWindowResize, collapsedSize, }: PanelDockedSlideOptions): PanelDockedSlide;
@@ -1 +1 @@
1
- import{useLayoutEffect,useState}from"react";import{useTheme}from"@emotion/react";import{useWindow}from"../../shared/useWindow";import{prefersReducedMotion}from"../../shared/prefersReducedMotion";import{useDeclarePanel,usePanelAnimationControl,usePanelPresence}from"./registry";import{useLayout}from"./useLayout";let parseDurationMs=duration=>{let trimmed=duration.trim();return trimmed.endsWith("ms")?parseFloat(trimmed):trimmed.endsWith("s")?1e3*parseFloat(trimmed):parseFloat(trimmed)||0},resolveSizePx=(size,groupWidthPx)=>{if("number"==typeof size)return size;if("string"!=typeof size)return null;let parsed=parseFloat(size);return Number.isFinite(parsed)?size.trim().endsWith("px")?parsed:null!=groupWidthPx?parsed/100*groupWidthPx:null:null},groupColumnsOf=element=>{let columns=element.closest("[data-group]")?.querySelectorAll("[data-panel]");return columns?Array.from(columns):[element]},isHandleReady=handle=>{try{return handle.isCollapsed(),!0}catch{return!1}};export function usePanelDockedSlide({slot,defaultSize,minSize,maxSize,collapsible,resizable,lockWidthOnWindowResize}){let{isVisible,state}=useLayout()[slot],theme=useTheme(),window=useWindow(),animation=usePanelAnimationControl(),reducedMotion=prefersReducedMotion(window),[isMounted,setIsMounted]=useState(isVisible),[phase,setPhase]=useState("idle"),[pinnedWidth,setPinnedWidth]=useState(null),[prevVisible,setPrevVisible]=useState(isVisible);return isVisible!==prevVisible&&(setPrevVisible(isVisible),setPhase(isVisible?"entering":"exiting"),isVisible&&setIsMounted(!0)),useDeclarePanel(slot,{defaultSize:"entering"===phase&&collapsible&&!reducedMotion?0:defaultSize,minSize,maxSize,collapsible,resizable,lockWidthOnWindowResize}),usePanelPresence(slot,isMounted),useLayoutEffect(()=>{if("idle"===phase)return;let cancelled=!1,frame=0,settleTimer=0,animatedColumns=[];animation?.setResizeSuppressed(slot,!0);let{duration,timingFunction}=theme.variables.animation.navSlide.open,durationMs=parseDurationMs(duration),setColumnTransitions=enabled=>{animatedColumns.forEach(column=>{enabled?column.style.setProperty("transition",`flex-grow ${duration} ${timingFunction}`):column.style.removeProperty("transition")})},targetSize=state.size??defaultSize??minSize,openColumn=(handle,targetPx)=>{handle.isCollapsed()&&handle.expand(),handle.resize(targetPx??targetSize??minSize??"20%")},settle=handle=>{if(setColumnTransitions(!1),animation?.setResizeSuppressed(slot,!1),"entering"===phase&&handle)try{handle.getSize().inPixels<1&&openColumn(handle,null)}catch{}setPinnedWidth(null),"exiting"===phase&&setIsMounted(!1),setPhase("idle")},runSlide=(handle,element)=>{animatedColumns=groupColumnsOf(element);let targetPx=resolveSizePx(targetSize,element.closest("[data-group]")?.getBoundingClientRect().width??null);setPinnedWidth("entering"===phase?targetPx:handle.getSize().inPixels),setColumnTransitions(!0),element.getBoundingClientRect();try{"entering"===phase?openColumn(handle,targetPx):handle.collapse()}catch{settle(handle);return}settleTimer=window.setTimeout(()=>settle(handle),durationMs+80)},waitForColumn=attempt=>{if(cancelled)return;let handle=animation?.getHandle(slot)??null,element=animation?.getElement(slot)??null;return handle&&element&&isHandleReady(handle)?void runSlide(handle,element):"exiting"===phase||!animation||attempt>=30?void settle(handle):void(frame=window.requestAnimationFrame(()=>waitForColumn(attempt+1)))};return!collapsible||reducedMotion?settle(animation?.getHandle(slot)??null):waitForColumn(0),()=>{cancelled=!0,window.cancelAnimationFrame(frame),window.clearTimeout(settleTimer),setColumnTransitions(!1),animation?.setResizeSuppressed(slot,!1)}},[phase,slot,collapsible,animation,window,theme]),{isMounted,pinnedWidth}}
1
+ import{useLayoutEffect,useRef,useState}from"react";import{useTheme}from"@emotion/react";import{useWindow}from"../../shared/useWindow";import{prefersReducedMotion}from"../../shared/prefersReducedMotion";import{useDeclarePanel,usePanelAnimationControl,usePanelPresence,usePanelRow}from"./registry";import{useLayout}from"./useLayout";let parseDurationMs=duration=>{let trimmed=duration.trim();return trimmed.endsWith("ms")?parseFloat(trimmed):trimmed.endsWith("s")?1e3*parseFloat(trimmed):parseFloat(trimmed)||0},resolveSizePx=(size,groupWidthPx)=>{if("number"==typeof size)return size;if("string"!=typeof size)return null;let parsed=parseFloat(size);return Number.isFinite(parsed)?size.trim().endsWith("px")?parsed:null!=groupWidthPx?parsed/100*groupWidthPx:null:null},groupColumnsOf=element=>{let columns=element.closest("[data-group]")?.querySelectorAll("[data-panel]");return columns?Array.from(columns):[element]},isHandleReady=handle=>{try{return handle.isCollapsed(),!0}catch{return!1}},mountDefaultSizeFor=({collapsedSize,defaultSize,isVisible,isSlidingIn})=>void 0!==collapsedSize?isVisible?defaultSize:collapsedSize:isSlidingIn?0:defaultSize;export function usePanelDockedSlide({slot,defaultSize,minSize,maxSize,collapsible,resizable,lockWidthOnWindowResize,collapsedSize}){let{isVisible,state}=useLayout()[slot],theme=useTheme(),window=useWindow(),animation=usePanelAnimationControl(),rowKey=usePanelRow(),reducedMotion=prefersReducedMotion(window),hasCollapsedRest=void 0!==collapsedSize,isCollapsible=collapsible&&!hasCollapsedRest,[isMounted,setIsMounted]=useState(isVisible),[phase,setPhase]=useState("idle"),[pinnedWidth,setPinnedWidth]=useState(null),[prevVisible,setPrevVisible]=useState(isVisible);isVisible!==prevVisible&&(setPrevVisible(isVisible),setPhase(isVisible?"entering":"exiting"),isVisible&&setIsMounted(!0),animation?.setResizeSuppressed(slot,!0));let openSize=hasCollapsedRest?state.size??defaultSize:defaultSize;useDeclarePanel(slot,{defaultSize:mountDefaultSizeFor({collapsedSize,defaultSize:openSize,isVisible,isSlidingIn:"entering"===phase&&collapsible&&!reducedMotion}),minSize:hasCollapsedRest&&!isVisible?collapsedSize:minSize??collapsedSize,maxSize,collapsible:isCollapsible,resizable,lockWidthOnWindowResize}),usePanelPresence(slot,hasCollapsedRest||isMounted);let latestRest=useRef({isVisible,openSize,phase});return latestRest.current={isVisible,openSize,phase},useLayoutEffect(()=>{if(!hasCollapsedRest)return;let frame=0,cancelled=!1,resizeToRest=attempt=>{if(cancelled)return;let handle=animation?.getHandle(slot)??null;if(handle&&isHandleReady(handle)){let rest=latestRest.current;if("idle"!==rest.phase)return;let restSize=rest.isVisible?rest.openSize??minSize:collapsedSize;try{void 0!==restSize&&handle.resize(restSize)}catch{}return}animation&&!(attempt>=30)&&(frame=window.requestAnimationFrame(()=>resizeToRest(attempt+1)))};return Promise.resolve().then(()=>resizeToRest(0)),()=>{cancelled=!0,window.cancelAnimationFrame(frame)}},[rowKey]),useLayoutEffect(()=>{if("idle"===phase)return;let cancelled=!1,frame=0,settleTimer=0,animatedColumns=[];animation?.setResizeSuppressed(slot,!0);let{duration,timingFunction}=hasCollapsedRest?theme.variables.animation.navSlide.collapse:theme.variables.animation.navSlide.open,durationMs=parseDurationMs(duration),setColumnTransitions=enabled=>{animatedColumns.forEach(column=>{enabled?column.style.setProperty("transition",`flex-grow ${duration} ${timingFunction}`):column.style.removeProperty("transition")})},targetSize=state.size??defaultSize??minSize,openColumn=(handle,targetPx)=>{handle.isCollapsed()&&handle.expand(),handle.resize(targetPx??targetSize??minSize??"20%")},settle=handle=>{if(setColumnTransitions(!1),animation?.setResizeSuppressed(slot,!1),"entering"===phase&&handle&&!hasCollapsedRest)try{handle.getSize().inPixels<1&&openColumn(handle,null)}catch{}setPinnedWidth(null),"exiting"!==phase||hasCollapsedRest||setIsMounted(!1),setPhase("idle")},runSlide=(handle,element)=>{animatedColumns=groupColumnsOf(element);let groupWidthPx=element.closest("[data-group]")?.getBoundingClientRect().width??null,targetPx=resolveSizePx(targetSize,groupWidthPx),collapsedPx=resolveSizePx(collapsedSize,groupWidthPx);setPinnedWidth("entering"===phase?targetPx:handle.getSize().inPixels),reducedMotion||setColumnTransitions(!0),element.getBoundingClientRect();try{"entering"===phase?openColumn(handle,targetPx):hasCollapsedRest?handle.resize(collapsedPx??collapsedSize):handle.collapse()}catch{settle(handle);return}settleTimer=window.setTimeout(()=>settle(handle),reducedMotion?0:durationMs+80)},waitsForRelaxedMinimum="exiting"===phase&&hasCollapsedRest,waitForColumn=attempt=>{if(cancelled)return;if(0===attempt&&waitsForRelaxedMinimum){frame=window.requestAnimationFrame(()=>waitForColumn(attempt+1));return}let handle=animation?.getHandle(slot)??null,element=animation?.getElement(slot)??null;return handle&&element&&isHandleReady(handle)?void runSlide(handle,element):"exiting"===phase||!animation||attempt>=30?void settle(handle):void(frame=window.requestAnimationFrame(()=>waitForColumn(attempt+1)))};return collapsible||hasCollapsedRest?waitForColumn(0):settle(animation?.getHandle(slot)??null),()=>{cancelled=!0,window.cancelAnimationFrame(frame),window.clearTimeout(settleTimer),setColumnTransitions(!1),animation?.setResizeSuppressed(slot,!1)}},[phase,slot,collapsible,hasCollapsedRest,reducedMotion,animation,window,theme]),{isMounted:hasCollapsedRest||isMounted,pinnedWidth}}
@@ -0,0 +1,19 @@
1
+ import type { CSSObject, Theme } from "@emotion/react";
2
+ type PanelContentFadeOptions = {
3
+ theme: Theme;
4
+ /** Whether the content is currently faded out. */
5
+ isFaded: boolean;
6
+ };
7
+ /**
8
+ * Fades a docked panel's content out across its collapse, and back in at once
9
+ * when it reopens - the panel covers the left bar the instant it is shown, so
10
+ * there is nothing to reveal on the way in.
11
+ *
12
+ * Runs on the column's own slide timing, so the two move together.
13
+ *
14
+ * Applied per part rather than to the whole panel: a control at the header's
15
+ * trailing edge travels down onto the left bar's own and has to stay solid the
16
+ * whole way, so it is left out.
17
+ */
18
+ export declare function getLeftPanelFadeStyles({ theme, isFaded, }: PanelContentFadeOptions): CSSObject;
19
+ export {};
@@ -0,0 +1 @@
1
+ export function getLeftPanelFadeStyles({theme,isFaded}){let{duration,timingFunction}=theme.variables.animation.navSlide.collapse;return{opacity:isFaded?theme.variables.opacity.hidden:theme.variables.opacity.visible,transition:isFaded?`opacity ${duration} ${timingFunction}`:"none","@media (prefers-reduced-motion: reduce)":{transition:"none"}}}
@@ -6,4 +6,5 @@ export { getBaseButtonStyles } from "./Button/getBaseButtonStyles";
6
6
  export { getPressedStyles } from "./Button/getPressedStyles";
7
7
  export { getPillStyles } from "./Button/getPillStyles";
8
8
  export { getFocusStyles } from "./getFocusStyles";
9
+ export { getLeftPanelFadeStyles } from "./getLeftPanelFadeStyles";
9
10
  export { getPrimaryVariantStyles, getSecondaryVariantStyles, getTertiaryVariantStyles, } from "./Button/getVariantStyles";
@@ -1 +1 @@
1
- export{getInputTextPlaceholder}from"./TextInput/getInputTextPlaceholder";export{getInputTextStyles}from"./TextInput/getInputTextStyles";export{getDisabledStyles}from"./Button/getDisabledStyles";export{getButtonAppearanceReset}from"./Button/getButtonAppearanceReset";export{getBaseButtonStyles}from"./Button/getBaseButtonStyles";export{getPressedStyles}from"./Button/getPressedStyles";export{getPillStyles}from"./Button/getPillStyles";export{getFocusStyles}from"./getFocusStyles";export{getPrimaryVariantStyles,getSecondaryVariantStyles,getTertiaryVariantStyles}from"./Button/getVariantStyles";
1
+ export{getInputTextPlaceholder}from"./TextInput/getInputTextPlaceholder";export{getInputTextStyles}from"./TextInput/getInputTextStyles";export{getDisabledStyles}from"./Button/getDisabledStyles";export{getButtonAppearanceReset}from"./Button/getButtonAppearanceReset";export{getBaseButtonStyles}from"./Button/getBaseButtonStyles";export{getPressedStyles}from"./Button/getPressedStyles";export{getPillStyles}from"./Button/getPillStyles";export{getFocusStyles}from"./getFocusStyles";export{getLeftPanelFadeStyles}from"./getLeftPanelFadeStyles";export{getPrimaryVariantStyles,getSecondaryVariantStyles,getTertiaryVariantStyles}from"./Button/getVariantStyles";