@amboss/design-system 4.9.2 → 4.9.4-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.
- package/build/cjs/components/Form/SegmentedControl/-types.d.ts +2 -0
- package/build/cjs/components/Form/SegmentedControl/SegmentedControlOption.d.ts +1 -1
- package/build/cjs/components/Form/SegmentedControl/SegmentedControlOption.js +1 -1
- package/build/cjs/components/Form/ToolbarToggle/-types.d.ts +1 -1
- package/build/cjs/components/Form/ToolbarToggle/ToolbarToggle.d.ts +1 -1
- package/build/cjs/components/Form/ToolbarToggle/ToolbarToggle.js +1 -1
- package/build/cjs/components/Internal/Panel/Panel.d.ts +3 -3
- package/build/cjs/components/Internal/Panel/Panel.js +1 -1
- package/build/cjs/components/Internal/PanelHeader/PanelHeader.d.ts +1 -1
- package/build/cjs/components/Internal/PanelHeader/PanelHeader.js +1 -1
- package/build/cjs/components/Layout/-constants.d.ts +10 -0
- package/build/cjs/components/Layout/-constants.js +1 -1
- package/build/cjs/components/Layout/-types.d.ts +19 -11
- package/build/cjs/components/Layout/BottomBar/LayoutBottomBar.d.ts +9 -0
- package/build/cjs/components/Layout/BottomBar/LayoutBottomBar.js +1 -0
- package/build/cjs/components/Layout/BottomBar/LayoutBottomBarItem.d.ts +14 -0
- package/build/cjs/components/Layout/BottomBar/LayoutBottomBarItem.js +1 -0
- package/build/cjs/components/Layout/BottomBar/LayoutBottomBarStyles.d.ts +7 -0
- package/build/cjs/components/Layout/BottomBar/LayoutBottomBarStyles.js +1 -0
- package/build/cjs/components/Layout/BottomBar/StyledLayoutBottomBar.d.ts +10 -0
- package/build/cjs/components/Layout/BottomBar/StyledLayoutBottomBar.js +1 -0
- package/build/cjs/components/Layout/BottomBar/StyledLayoutBottomBarSection.d.ts +10 -0
- package/build/cjs/components/Layout/BottomBar/StyledLayoutBottomBarSection.js +1 -0
- package/build/cjs/components/Layout/BottomBar/getBottomBarLayout.d.ts +39 -0
- package/build/cjs/components/Layout/BottomBar/getBottomBarLayout.js +1 -0
- package/build/cjs/components/Layout/Layout.d.ts +4 -0
- package/build/cjs/components/Layout/Layout.js +1 -1
- package/build/cjs/components/Layout/LayoutPortal.d.ts +7 -0
- package/build/cjs/components/Layout/LayoutPortal.js +1 -0
- package/build/cjs/components/Layout/LayoutProvider.js +1 -1
- package/build/cjs/components/Layout/LeftPanel/LeftPanelDrawer.d.ts +3 -4
- package/build/cjs/components/Layout/LeftPanel/LeftPanelDrawer.js +1 -1
- package/build/cjs/components/Layout/RightPanel/RightPanel.js +1 -1
- package/build/cjs/components/Layout/index.d.ts +1 -0
- package/build/cjs/components/Layout/registry.d.ts +8 -4
- package/build/cjs/components/Layout/useLayout.js +1 -1
- package/build/cjs/components/Layout/usePanelAnimations.d.ts +12 -0
- package/build/cjs/components/Layout/usePanelAnimations.js +1 -0
- package/build/cjs/components/Layout/usePanelDockedSlide.js +1 -1
- package/build/cjs/web-tokens/_sizes.json +55 -55
- package/build/cjs/web-tokens/layout-vars.d.ts +7 -0
- package/build/cjs/web-tokens/layout-vars.js +1 -1
- package/build/cjs/web-tokens/layout-vars.ts +7 -0
- package/build/cjs/web-tokens/visualConfig.d.ts +25 -0
- package/build/cjs/web-tokens/visualConfig.js +1 -1
- package/build/esm/components/Form/SegmentedControl/-types.d.ts +2 -0
- package/build/esm/components/Form/SegmentedControl/SegmentedControlOption.d.ts +1 -1
- package/build/esm/components/Form/SegmentedControl/SegmentedControlOption.js +1 -1
- package/build/esm/components/Form/ToolbarToggle/-types.d.ts +1 -1
- package/build/esm/components/Form/ToolbarToggle/ToolbarToggle.d.ts +1 -1
- package/build/esm/components/Form/ToolbarToggle/ToolbarToggle.js +1 -1
- package/build/esm/components/Internal/Panel/Panel.d.ts +3 -3
- package/build/esm/components/Internal/Panel/Panel.js +1 -1
- package/build/esm/components/Internal/PanelHeader/PanelHeader.d.ts +1 -1
- package/build/esm/components/Internal/PanelHeader/PanelHeader.js +1 -1
- package/build/esm/components/Layout/-constants.d.ts +10 -0
- package/build/esm/components/Layout/-constants.js +1 -1
- package/build/esm/components/Layout/-types.d.ts +19 -11
- package/build/esm/components/Layout/BottomBar/LayoutBottomBar.d.ts +9 -0
- package/build/esm/components/Layout/BottomBar/LayoutBottomBar.js +1 -0
- package/build/esm/components/Layout/BottomBar/LayoutBottomBarItem.d.ts +14 -0
- package/build/esm/components/Layout/BottomBar/LayoutBottomBarItem.js +1 -0
- package/build/esm/components/Layout/BottomBar/LayoutBottomBarStyles.d.ts +7 -0
- package/build/esm/components/Layout/BottomBar/LayoutBottomBarStyles.js +1 -0
- package/build/esm/components/Layout/BottomBar/StyledLayoutBottomBar.d.ts +10 -0
- package/build/esm/components/Layout/BottomBar/StyledLayoutBottomBar.js +1 -0
- package/build/esm/components/Layout/BottomBar/StyledLayoutBottomBarSection.d.ts +10 -0
- package/build/esm/components/Layout/BottomBar/StyledLayoutBottomBarSection.js +1 -0
- package/build/esm/components/Layout/BottomBar/getBottomBarLayout.d.ts +39 -0
- package/build/esm/components/Layout/BottomBar/getBottomBarLayout.js +1 -0
- package/build/esm/components/Layout/Layout.d.ts +4 -0
- package/build/esm/components/Layout/Layout.js +1 -1
- package/build/esm/components/Layout/LayoutPortal.d.ts +7 -0
- package/build/esm/components/Layout/LayoutPortal.js +1 -0
- package/build/esm/components/Layout/LayoutProvider.js +1 -1
- package/build/esm/components/Layout/LeftPanel/LeftPanelDrawer.d.ts +3 -4
- package/build/esm/components/Layout/LeftPanel/LeftPanelDrawer.js +1 -1
- package/build/esm/components/Layout/RightPanel/RightPanel.js +1 -1
- package/build/esm/components/Layout/index.d.ts +1 -0
- package/build/esm/components/Layout/registry.d.ts +8 -4
- package/build/esm/components/Layout/useLayout.js +1 -1
- package/build/esm/components/Layout/usePanelAnimations.d.ts +12 -0
- package/build/esm/components/Layout/usePanelAnimations.js +1 -0
- package/build/esm/components/Layout/usePanelDockedSlide.js +1 -1
- package/build/esm/web-tokens/_sizes.json +55 -55
- package/build/esm/web-tokens/layout-vars.d.ts +7 -0
- package/build/esm/web-tokens/layout-vars.js +1 -1
- package/build/esm/web-tokens/layout-vars.ts +7 -0
- package/build/esm/web-tokens/visualConfig.d.ts +25 -0
- package/build/esm/web-tokens/visualConfig.js +1 -1
- package/build/scss/_layout.scss +14 -0
- package/package.json +1 -1
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { type ReactNode } from "react";
|
|
2
|
+
import type { LayoutValue, SlotKey } from "../-types";
|
|
3
|
+
import { type LayoutBottomBarItemProps, type LayoutBottomBarFallback } from "./LayoutBottomBarItem";
|
|
4
|
+
type BottomBarLayout = Pick<LayoutValue, SlotKey>;
|
|
5
|
+
type BottomBarItemMode = "column" | LayoutBottomBarFallback;
|
|
6
|
+
type VisibleSection = LayoutBottomBarItemProps & {
|
|
7
|
+
placement: Exclude<BottomBarItemMode, "hide">;
|
|
8
|
+
fallback: LayoutBottomBarFallback;
|
|
9
|
+
};
|
|
10
|
+
type SharedSection = VisibleSection & {
|
|
11
|
+
placement: "column" | "remaining";
|
|
12
|
+
};
|
|
13
|
+
type ArrangedSection = VisibleSection & {
|
|
14
|
+
columnIndex?: number;
|
|
15
|
+
rowIndex: number;
|
|
16
|
+
};
|
|
17
|
+
export type BottomBarCell = {
|
|
18
|
+
kind: "section";
|
|
19
|
+
section: SharedSection;
|
|
20
|
+
flexible: boolean;
|
|
21
|
+
fillLeadingSpace: boolean;
|
|
22
|
+
} | {
|
|
23
|
+
kind: "leading-gap" | "trailing-gap";
|
|
24
|
+
region: SlotKey;
|
|
25
|
+
} | {
|
|
26
|
+
kind: "column-gap";
|
|
27
|
+
region: SlotKey;
|
|
28
|
+
previousRegion: SlotKey;
|
|
29
|
+
} | {
|
|
30
|
+
kind: "flexible-gap";
|
|
31
|
+
};
|
|
32
|
+
type BottomBarArrangement = {
|
|
33
|
+
cells: BottomBarCell[];
|
|
34
|
+
sections: ArrangedSection[];
|
|
35
|
+
rowCount: number;
|
|
36
|
+
hasRightPanel: boolean;
|
|
37
|
+
};
|
|
38
|
+
export declare const getBottomBarLayout: (children: ReactNode, layout: BottomBarLayout) => BottomBarArrangement;
|
|
39
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{Children,isValidElement}from"react";import{PANEL_ORDER}from"../-constants";import{LayoutBottomBarItem}from"./LayoutBottomBarItem";let getBottomBarItemMode=({region,fallback,layout})=>{let handle=layout[region];return"column"===handle.presentation?"column":("leftPanel"!==region||"sidebar"!==layout.leftPanel.state.variant)&&("rightPanel"!==region||"sidebar"!==layout.rightPanel.state.variant)||handle.isVisible||null===handle.animation?fallback:"column"},getVisibleSections=(children,layout)=>Children.toArray(children).flatMap(child=>{if(!isValidElement(child)||child.type!==LayoutBottomBarItem||null==child.props.children||!1===child.props.children)return[];let{region,fallback="hide"}=child.props,placement=getBottomBarItemMode({region,fallback,layout});return"hide"===placement?[]:[{...child.props,placement,fallback}]}),shouldPreserveSplitColumnWidth=sections=>{let hasLeftFallback=sections.some(({region,fallback})=>"leftPanel"===region&&"remaining"===fallback),hasContentColumn=sections.some(({region,placement})=>"content"===region&&"column"===placement),hasSplitColumn=sections.some(({region,placement})=>"splitview"===region&&"column"===placement),hasRightFallback=sections.some(({region,fallback})=>"rightPanel"===region&&"remaining"===fallback);return hasLeftFallback&&hasContentColumn&&hasSplitColumn&&!hasRightFallback},getSharedRowCells=(sections,layout)=>{if(!sections.length)return[];let firstSection=sections[0],lastSection=sections[sections.length-1],hasRemainingActions=sections.some(({fallback})=>"remaining"===fallback),preserveSplitColumn=shouldPreserveSplitColumnWidth(sections),fillLeadingSpace="column"===firstSection.placement&&("content"===firstSection.region||"splitview"===firstSection.region)&&"column"!==layout.leftPanel.presentation,flexibleColumns={leftPanel:!1,content:hasRemainingActions,splitview:hasRemainingActions&&!preserveSplitColumn,rightPanel:!1},hasFlexibleColumn=sections.some(({region,placement})=>"column"===placement&&flexibleColumns[region]),needsFlexibleGap=hasRemainingActions&&!hasFlexibleColumn,rightActions=sections.find(({region})=>"rightPanel"===region);return[..."column"!==firstSection.placement||fillLeadingSpace?[]:[{kind:"leading-gap",region:firstSection.region}],...sections.flatMap((section,index)=>{let previousSection=sections[index-1];return[..."column"===section.placement&&previousSection?.placement==="column"?[{kind:"column-gap",region:section.region,previousRegion:previousSection.region}]:[],...needsFlexibleGap&§ion===rightActions?[{kind:"flexible-gap"}]:[],{kind:"section",section,flexible:flexibleColumns[section.region],fillLeadingSpace:section===firstSection&&fillLeadingSpace&&!hasRemainingActions}]}),...!hasRemainingActions||preserveSplitColumn?[{kind:"trailing-gap",region:lastSection.region}]:[],...needsFlexibleGap&&!rightActions?[{kind:"flexible-gap"}]:[]]};export const getBottomBarLayout=(children,layout)=>{let sections=getVisibleSections(children,layout),sharedSections=PANEL_ORDER.flatMap(region=>sections.filter(section=>section.region===region&&"full"!==section.placement)),fullWidthSections=sections.filter(({placement})=>"full"===placement),sharedRowCount=+!!sharedSections.length,cells=getSharedRowCells(sharedSections,layout);return{cells,sections:[...cells.flatMap((cell,column)=>"section"===cell.kind?[{...cell.section,columnIndex:column,rowIndex:0}]:[]),...fullWidthSections.map((section,row)=>({...section,rowIndex:sharedRowCount+row}))],rowCount:sharedRowCount+fullWidthSections.length,hasRightPanel:sections.some(({region})=>"rightPanel"===region)}};
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import React from "react";
|
|
2
2
|
import { LayoutProvider } from "./LayoutProvider";
|
|
3
|
+
import { LayoutBottomBar } from "./BottomBar/LayoutBottomBar";
|
|
4
|
+
import { LayoutBottomBarItem } from "./BottomBar/LayoutBottomBarItem";
|
|
3
5
|
import { Content } from "./Content/Content";
|
|
4
6
|
import { RightPanel } from "./RightPanel/RightPanel";
|
|
5
7
|
import { RightPanelHeader } from "./RightPanel/RightPanelHeader";
|
|
@@ -20,6 +22,8 @@ export declare const PANEL_HOST_DS_ID = "PanelHost";
|
|
|
20
22
|
declare function LayoutBase({ children, persistenceKey, storage, rules, additionalRulesData, }: LayoutProps): React.ReactElement;
|
|
21
23
|
type LayoutComponent = typeof LayoutBase & {
|
|
22
24
|
Provider: typeof LayoutProvider;
|
|
25
|
+
BottomBar: typeof LayoutBottomBar;
|
|
26
|
+
BottomBarItem: typeof LayoutBottomBarItem;
|
|
23
27
|
LeftPanel: typeof LeftPanel;
|
|
24
28
|
LeftNavBar: typeof LeftNavBar;
|
|
25
29
|
LeftNavBarFooter: typeof LeftNavBarFooter;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import React,{useCallback,useEffect,useMemo,useRef,useState}from"react";import styled from"@emotion/styled";import{Panel}from"../Internal/Panel/Panel";import{LayoutFloat}from"../Internal/LayoutFloat/LayoutFloat";import{useBreakpoints}from"../../shared/useBreakpoints";import{PAGE_BOTTOM_BAR_INSET,PANEL_ORDER,PANEL_WIDTH_VAR,Slot}from"./-constants";import{useLayoutPersistence,useLayoutStore}from"./context";import{MobileSplitStackContext}from"./Split/MobileSplitView/useMobileSplitStack";import{useMobileSplitViewEnabled}from"./Split/MobileSplitView/useMobileSplitView";import{LayoutProvider}from"./LayoutProvider";import{Content}from"./Content/Content";import{RightPanel}from"./RightPanel/RightPanel";import{RightPanelHeader}from"./RightPanel/RightPanelHeader";import{RightPanelFooter}from"./RightPanel/RightPanelFooter";import{LeftPanel}from"./LeftPanel/LeftPanel";import{LeftPanelHeader}from"./LeftPanel/LeftPanelHeader";import{LeftPanelFooter}from"./LeftPanel/LeftPanelFooter";import{LeftNavBar}from"./LeftNavBar/LeftNavBar";import{LeftNavBarFooter}from"./LeftNavBar/LeftNavBarFooter";import{Split}from"./Split/Split";import{SplitHeader}from"./Split/SplitHeader";import{SplitFooter}from"./Split/SplitFooter";import{LayoutPortalContext,PanelRegistryContext,PanelDeclarationsContext,PanelPresenceContext,PanelAnimationContext,PanelRowContext}from"./registry";import{usePortalTargets}from"./usePortalTargets";import{LayoutFloatDragProvider}from"../Internal/LayoutFloat/LayoutFloatDragProvider";import{useLayoutVar}from"./LayoutCssVars";import{useLayout}from"./useLayout";import{useLayoutRules}from"./useLayoutRules";import{DEFAULT_LAYOUT_RULES}from"./rules";let resizableFromState=slotState=>"sidePanel"===slotState.kind?slotState.resizable:void 0,useGlobalCssVariables=slotHosts=>{let leftPanelWidthCssVar=useLayoutVar(PANEL_WIDTH_VAR.leftPanel),contentWidthCssVar=useLayoutVar(PANEL_WIDTH_VAR.content),rightPanelWidthCssVar=useLayoutVar(PANEL_WIDTH_VAR.rightPanel);useEffect(()=>{let targets=[[Slot.leftPanel,leftPanelWidthCssVar],[Slot.content,contentWidthCssVar],[Slot.rightPanel,rightPanelWidthCssVar]],observers=[];return targets.forEach(([slot,handle])=>{let node=slotHosts[slot]??null;if(!node)return void handle.set("0px");let publishNodeWidth=()=>handle.set(`${node.getBoundingClientRect().width}px`);if(publishNodeWidth(),"undefined"==typeof ResizeObserver)return;let observer=new ResizeObserver(publishNodeWidth);observer.observe(node),observers.push(observer)}),()=>observers.forEach(observer=>observer.disconnect())},[leftPanelWidthCssVar,contentWidthCssVar,rightPanelWidthCssVar,slotHosts])},StyledLayout=styled("div",{target:"e1izvg960",label:"StyledLayout"})({position:"relative",height:"100%",width:"100%"}),StyledPanelRow=styled("div",{target:"e1izvg961",label:"StyledPanelRow"})(({theme,hasOffcanvasLeftBar})=>({height:"100%",boxSizing:"border-box",...hasOffcanvasLeftBar&&{paddingLeft:theme.variables.size.dimension.leftNavBar.width}})),StyledPanelHost=styled("div",{target:"e1izvg962",label:"StyledPanelHost"})({position:"relative",height:"100%",width:"100%"});export const PANEL_HOST_DS_ID="PanelHost";let StyledContentColumn=styled("div",{shouldForwardProp:prop=>"isSplitOpen"!==prop,target:"e1izvg963",label:"StyledContentColumn"})(({isSplitOpen,theme})=>({display:"flex",height:`calc(100% - ${PAGE_BOTTOM_BAR_INSET})`,width:"100%",...isSplitOpen&&{maxWidth:theme.variables.layout.split.maxWidth.default,marginInline:"auto",gap:theme.variables.size.spacing.xxs}})),StyledContentColumnHalf=styled("div",{target:"e1izvg964",label:"StyledContentColumnHalf"})({position:"relative",height:"100%",flex:"1 1 0",minWidth:0}),StyledMobileSplitStackHost=styled("div",{target:"e1izvg965",label:"StyledMobileSplitStackHost"})({position:"absolute",top:0,left:0,right:0,bottom:PAGE_BOTTOM_BAR_INSET,overflow:"hidden",pointerEvents:"none"}),isPanelPresent=({slot,declared,present,isShown})=>!!(declared[slot]&&(isShown(slot)||present[slot])),defaultSizeFor=({slot,panel,panelState})=>slot===Slot.content?void 0:panel?.defaultSize!==void 0?panel.defaultSize:panel?.resizable!==!1?panelState.size:void 0,childFor=(slot,contentColumn,slotHostRefs)=>slot===Slot.content?contentColumn:React.createElement(StyledPanelHost,{"data-ds-id":"PanelHost",ref:slotHostRefs[slot]});export const Layout=function({children,persistenceKey,storage,rules=DEFAULT_LAYOUT_RULES,additionalRulesData}){let[declared,setDeclared]=useState({}),layout=useLayout(),{state:layoutState,...panelCallbacks}=layout;useLayoutRules({layout,declared,rules,additionalData:additionalRulesData});let{dispatch}=useLayoutStore(),persistence=useLayoutPersistence(),resolvedKey=persistenceKey??persistence.persistenceKey,resolvedStorage=storage??persistence.storage,{isMobile}=useBreakpoints(),showMobileSplitStack=useMobileSplitViewEnabled(),[mobileSplitStackHost,setMobileSplitStackHost]=useState(null),[splitCount,setSplitCount]=useState(0),registerSplit=useCallback(()=>(setSplitCount(count=>count+1),()=>setSplitCount(count=>count-1)),[]),mobileSplitStack=useMemo(()=>({host:mobileSplitStackHost,isSplitPresent:splitCount>0,registerSplit}),[mobileSplitStackHost,splitCount,registerSplit]),rightPanelVariant=layoutState[Slot.rightPanel].variant??declared[Slot.rightPanel]?.variant??"sidebar",isRightPanelFloating=!isMobile&&"float"===rightPanelVariant,hasOffcanvasLeftBar=!!declared[Slot.leftPanel]&&"offcanvas"===layoutState[Slot.leftPanel].variant,isShown=slot=>layoutState[slot].visible&&!(slot===Slot.rightPanel&&(isRightPanelFloating||isMobile))&&!(slot===Slot.leftPanel&&hasOffcanvasLeftBar),[present,setPresent]=useState({}),presence=useMemo(()=>({setPresent:(slot,isPresent)=>setPresent(prev=>prev[slot]===isPresent?prev:{...prev,[slot]:isPresent})}),[]),panelHandles=useRef({}),panelElements=useRef({}),resizeSuppressed=useRef({}),animationControl=useMemo(()=>({setHandle:(slot,handle)=>{panelHandles.current[slot]=handle},getHandle:slot=>panelHandles.current[slot]??null,setElement:(slot,element)=>{panelElements.current[slot]=element},getElement:slot=>panelElements.current[slot]??null,setResizeSuppressed:(slot,suppressed)=>{resizeSuppressed.current[slot]=suppressed}}),[]),panelRefCallbacks=useMemo(()=>{let handleCallbacks=new Map,elementCallbacks=new Map;return{handleFor:id=>{let callback=handleCallbacks.get(id);return callback||(callback=handle=>animationControl.setHandle(id,handle),handleCallbacks.set(id,callback)),callback},elementFor:id=>{let callback=elementCallbacks.get(id);return callback||(callback=element=>animationControl.setElement(id,element),elementCallbacks.set(id,callback)),callback}}},[animationControl]),shouldSuppressLayoutCallback=useCallback(()=>Object.values(resizeSuppressed.current).some(Boolean),[]),registry=useMemo(()=>({register:(slot,reg)=>setDeclared(prev=>({...prev,[slot]:reg})),unregister:slot=>setDeclared(prev=>{if(!(slot in prev))return prev;let next={...prev};return delete next[slot],next})}),[]),{portalTargets,slotHosts,slotHostRefs,floatHostRef}=usePortalTargets({slots:PANEL_ORDER,floatableSlot:Slot.rightPanel,isFloating:isRightPanelFloating});useGlobalCssVariables(slotHosts);let rowSlots=PANEL_ORDER.filter(slot=>slot!==Slot.splitview),declaredSlots=rowSlots.filter(slot=>declared[slot]),isSolo=declaredSlots.length<=1,soloSlot=declaredSlots[0],isSplitOpen=isPanelPresent({slot:Slot.splitview,declared,present,isShown})&&isPanelPresent({slot:Slot.content,declared,present,isShown}),contentColumn=React.createElement(StyledContentColumn,{isSplitOpen:isSplitOpen},React.createElement(StyledContentColumnHalf,{ref:slotHostRefs[Slot.content]}),isSplitOpen&&React.createElement(StyledContentColumnHalf,{ref:slotHostRefs[Slot.splitview]})),panelItems=rowSlots.filter(slot=>isPanelPresent({slot,declared,present,isShown})).map(slot=>{let panel=declared[slot],panelState=layoutState[slot];return{id:slot,child:childFor(slot,contentColumn,slotHostRefs),defaultSize:defaultSizeFor({slot,panel,panelState}),minSize:panel?.minSize,maxSize:panel?.maxSize,collapsible:slot!==Slot.content&&(panel?.collapsible??!0),lockWidthOnWindowResize:panel?.lockWidthOnWindowResize,resizable:panel?.resizable??resizableFromState(panelState)}}),rowKey=panelItems.map(item=>item.id).join(","),soloHost=soloSlot&&isShown(soloSlot)?childFor(soloSlot,contentColumn,slotHostRefs):null,panelGroup=panelItems.length>0?React.createElement(Panel,{key:resolvedKey,panels:panelItems,persistenceKey:resolvedKey,storage:resolvedStorage,onResize:(id,size)=>{isShown(id)&&declared[id]?.resizable!==!1&&dispatch({type:"resize",slot:id,size:declared[id]?.lockWidthOnWindowResize?Math.round(size.inPixels):`${size.asPercentage}%`})},onCollapse:id=>panelCallbacks[id].hide(),panelHandleFor:panelRefCallbacks.handleFor,panelElementFor:panelRefCallbacks.elementFor,shouldSuppressLayoutCallback:shouldSuppressLayoutCallback}):null;return React.createElement(PanelRegistryContext.Provider,{value:registry},React.createElement(PanelDeclarationsContext.Provider,{value:declared},React.createElement(PanelPresenceContext.Provider,{value:presence},React.createElement(PanelAnimationContext.Provider,{value:animationControl},React.createElement(PanelRowContext.Provider,{value:rowKey},React.createElement(LayoutPortalContext.Provider,{value:portalTargets},React.createElement(LayoutFloatDragProvider,null,React.createElement(MobileSplitStackContext.Provider,{value:mobileSplitStack},React.createElement(StyledLayout,{"data-ds-id":"Layout"},React.createElement(StyledPanelRow,{hasOffcanvasLeftBar:hasOffcanvasLeftBar},isSolo?soloHost:panelGroup),isRightPanelFloating&&layoutState[Slot.rightPanel].visible&&React.createElement(LayoutFloat,{hostRef:floatHostRef}),children,showMobileSplitStack&&React.createElement(StyledMobileSplitStackHost,{ref:setMobileSplitStackHost}))))))))))};Layout.Provider=LayoutProvider,Layout.LeftPanel=LeftPanel,Layout.LeftNavBar=LeftNavBar,Layout.LeftNavBarFooter=LeftNavBarFooter,Layout.LeftPanelHeader=LeftPanelHeader,Layout.LeftPanelFooter=LeftPanelFooter,Layout.RightPanel=RightPanel,Layout.RightPanelHeader=RightPanelHeader,Layout.RightPanelFooter=RightPanelFooter,Layout.Content=Content,Layout.Split=Split,Layout.SplitHeader=SplitHeader,Layout.SplitFooter=SplitFooter;
|
|
1
|
+
import React,{useCallback,useLayoutEffect,useMemo,useRef,useState}from"react";import styled from"@emotion/styled";import{Panel}from"../Internal/Panel/Panel";import{LayoutFloat}from"../Internal/LayoutFloat/LayoutFloat";import{useBreakpoints}from"../../shared/useBreakpoints";import{PAGE_BOTTOM_BAR_INSET,PANEL_ORDER,PANEL_WIDTH_VAR,PANEL_START_VAR,LAYOUT_REGIONS_READY_VAR,Slot}from"./-constants";import{useLayoutPersistence,useLayoutStore}from"./context";import{MobileSplitStackContext}from"./Split/MobileSplitView/useMobileSplitStack";import{useMobileSplitViewEnabled}from"./Split/MobileSplitView/useMobileSplitView";import{LayoutProvider}from"./LayoutProvider";import{LayoutBottomBar}from"./BottomBar/LayoutBottomBar";import{LayoutBottomBarItem}from"./BottomBar/LayoutBottomBarItem";import{Content}from"./Content/Content";import{RightPanel}from"./RightPanel/RightPanel";import{RightPanelHeader}from"./RightPanel/RightPanelHeader";import{RightPanelFooter}from"./RightPanel/RightPanelFooter";import{LeftPanel}from"./LeftPanel/LeftPanel";import{LeftPanelHeader}from"./LeftPanel/LeftPanelHeader";import{LeftPanelFooter}from"./LeftPanel/LeftPanelFooter";import{LeftNavBar}from"./LeftNavBar/LeftNavBar";import{LeftNavBarFooter}from"./LeftNavBar/LeftNavBarFooter";import{Split}from"./Split/Split";import{SplitHeader}from"./Split/SplitHeader";import{SplitFooter}from"./Split/SplitFooter";import{LayoutPortalContext,PanelRegistryContext,PanelDeclarationsContext,PanelPresenceContext,PanelAnimationContext,PanelRowContext}from"./registry";import{usePortalTargets}from"./usePortalTargets";import{LayoutFloatDragProvider}from"../Internal/LayoutFloat/LayoutFloatDragProvider";import{useLayoutVar}from"./LayoutCssVars";import{useLayout}from"./useLayout";import{useLayoutRules}from"./useLayoutRules";import{DEFAULT_LAYOUT_RULES}from"./rules";let resizableFromState=slotState=>"sidePanel"===slotState.kind?slotState.resizable:void 0,useGlobalCssVariables=({slotHosts,root,mobileHost})=>{let leftPanelWidthCssVar=useLayoutVar(PANEL_WIDTH_VAR.leftPanel),contentWidthCssVar=useLayoutVar(PANEL_WIDTH_VAR.content),splitviewWidthCssVar=useLayoutVar(PANEL_WIDTH_VAR.splitview),rightPanelWidthCssVar=useLayoutVar(PANEL_WIDTH_VAR.rightPanel),leftPanelStartCssVar=useLayoutVar(PANEL_START_VAR.leftPanel),contentStartCssVar=useLayoutVar(PANEL_START_VAR.content),splitviewStartCssVar=useLayoutVar(PANEL_START_VAR.splitview),rightPanelStartCssVar=useLayoutVar(PANEL_START_VAR.rightPanel),regionsReadyCssVar=useLayoutVar(LAYOUT_REGIONS_READY_VAR),publishRegions=useCallback(()=>{if(!root)return;let targets=[[Slot.leftPanel,leftPanelWidthCssVar,leftPanelStartCssVar],[Slot.content,contentWidthCssVar,contentStartCssVar],[Slot.splitview,splitviewWidthCssVar,splitviewStartCssVar],[Slot.rightPanel,rightPanelWidthCssVar,rightPanelStartCssVar]],rootRect=root.getBoundingClientRect();targets.forEach(([slot,widthCssVar,startCssVar])=>{let rect=slotHosts[slot]?.getBoundingClientRect(),isMobileRegion=!!mobileHost&&(slot===Slot.content||slot===Slot.splitview),width=isMobileRegion?rootRect.width:rect?.width??0,start=isMobileRegion||!rect?0:rect.left-rootRect.left;widthCssVar.set(`${width}px`),startCssVar.set(`${start}px`)}),regionsReadyCssVar.set("1")},[slotHosts,root,mobileHost,leftPanelWidthCssVar,contentWidthCssVar,splitviewWidthCssVar,rightPanelWidthCssVar,leftPanelStartCssVar,contentStartCssVar,splitviewStartCssVar,rightPanelStartCssVar,regionsReadyCssVar]);useLayoutEffect(()=>{publishRegions()},[publishRegions]),useLayoutEffect(()=>{if(!root||"undefined"==typeof ResizeObserver)return;let observer=new ResizeObserver(publishRegions);return observer.observe(root),Object.values(slotHosts).forEach(host=>{host&&observer.observe(host)}),()=>observer.disconnect()},[root,slotHosts,publishRegions])},StyledLayout=styled("div",{target:"e161k5ur0",label:"StyledLayout"})({position:"relative",height:"100%",width:"100%"}),StyledPanelRow=styled("div",{target:"e161k5ur1",label:"StyledPanelRow"})(({theme,hasOffcanvasLeftBar})=>({height:"100%",boxSizing:"border-box",...hasOffcanvasLeftBar&&{paddingLeft:theme.variables.size.dimension.leftNavBar.width}})),StyledPanelHost=styled("div",{target:"e161k5ur2",label:"StyledPanelHost"})({position:"relative",height:"100%",width:"100%"});export const PANEL_HOST_DS_ID="PanelHost";let StyledContentColumn=styled("div",{shouldForwardProp:prop=>"isSplitOpen"!==prop,target:"e161k5ur3",label:"StyledContentColumn"})(({isSplitOpen,theme})=>({display:"flex",height:`calc(100% - ${PAGE_BOTTOM_BAR_INSET})`,width:"100%",...isSplitOpen&&{maxWidth:theme.variables.layout.split.maxWidth.default,marginInline:"auto",gap:theme.variables.size.spacing.xxs}})),StyledContentColumnHalf=styled("div",{target:"e161k5ur4",label:"StyledContentColumnHalf"})({position:"relative",height:"100%",flex:"1 1 0",minWidth:0}),StyledMobileSplitStackHost=styled("div",{target:"e161k5ur5",label:"StyledMobileSplitStackHost"})({position:"absolute",top:0,left:0,right:0,bottom:PAGE_BOTTOM_BAR_INSET,overflow:"hidden",pointerEvents:"none"}),isPanelPresent=({slot,declared,present,isShown})=>!!(declared[slot]&&(isShown(slot)||present[slot])),defaultSizeFor=({slot,panel,panelState})=>slot===Slot.content?void 0:panel?.defaultSize!==void 0?panel.defaultSize:panel?.resizable!==!1?panelState.size:void 0,childFor=(slot,contentColumn,slotHostRefs)=>slot===Slot.content?contentColumn:React.createElement(StyledPanelHost,{"data-ds-id":"PanelHost",ref:slotHostRefs[slot]});export const Layout=function({children,persistenceKey,storage,rules=DEFAULT_LAYOUT_RULES,additionalRulesData}){let[declared,setDeclared]=useState({}),layout=useLayout(),{state:layoutState,...panelCallbacks}=layout;useLayoutRules({layout,declared,rules,additionalData:additionalRulesData});let{dispatch}=useLayoutStore(),persistence=useLayoutPersistence(),resolvedKey=persistenceKey??persistence.persistenceKey,resolvedStorage=storage??persistence.storage,{isMobile}=useBreakpoints(),showMobileSplitStack=useMobileSplitViewEnabled(),[mobileSplitStackHost,setMobileSplitStackHost]=useState(null),[splitCount,setSplitCount]=useState(0),registerSplit=useCallback(()=>(setSplitCount(count=>count+1),()=>setSplitCount(count=>count-1)),[]),mobileSplitStack=useMemo(()=>({host:mobileSplitStackHost,isSplitPresent:splitCount>0,registerSplit}),[mobileSplitStackHost,splitCount,registerSplit]),rightPanelVariant=layoutState[Slot.rightPanel].variant??declared[Slot.rightPanel]?.variant??"sidebar",isRightPanelFloating=!isMobile&&"float"===rightPanelVariant,hasOffcanvasLeftBar=!!declared[Slot.leftPanel]&&"offcanvas"===layoutState[Slot.leftPanel].variant,isShown=slot=>layoutState[slot].visible&&!(slot===Slot.rightPanel&&(isRightPanelFloating||isMobile))&&(slot!==Slot.leftPanel||"sidebar"===layoutState.leftPanel.variant),[present,setPresent]=useState({}),presence=useMemo(()=>({setPresent:(slot,isPresent)=>setPresent(prev=>prev[slot]===isPresent?prev:{...prev,[slot]:isPresent})}),[]),panelHandles=useRef({}),panelElements=useRef({}),resizeSuppressed=useRef({}),animationControl=useMemo(()=>({setHandle:(slot,handle)=>{panelHandles.current[slot]=handle},getHandle:slot=>panelHandles.current[slot]??null,setElement:(slot,element)=>{panelElements.current[slot]=element},getElement:slot=>panelElements.current[slot]??null,setResizeSuppressed:(slot,suppressed)=>{resizeSuppressed.current[slot]=suppressed}}),[]),panelRefCallbacks=useMemo(()=>{let handleCallbacks=new Map,elementCallbacks=new Map;return{handleFor:id=>{let callback=handleCallbacks.get(id);return callback||(callback=handle=>animationControl.setHandle(id,handle),handleCallbacks.set(id,callback)),callback},elementFor:id=>{let callback=elementCallbacks.get(id);return callback||(callback=element=>animationControl.setElement(id,element),elementCallbacks.set(id,callback)),callback}}},[animationControl]),shouldSuppressLayoutCallback=useCallback(()=>Object.values(resizeSuppressed.current).some(Boolean),[]),registry=useMemo(()=>({register:(slot,reg)=>setDeclared(prev=>({...prev,[slot]:reg})),unregister:slot=>setDeclared(prev=>{if(!(slot in prev))return prev;let next={...prev};return delete next[slot],next})}),[]),{portalTargets,slotHosts,slotHostRefs,floatHostRef}=usePortalTargets({slots:PANEL_ORDER,floatableSlot:Slot.rightPanel,isFloating:isRightPanelFloating}),[layoutRoot,setLayoutRoot]=useState(null),rootPortalTargets=useMemo(()=>({...portalTargets,root:layoutRoot}),[portalTargets,layoutRoot]);useGlobalCssVariables({slotHosts,root:layoutRoot,mobileHost:mobileSplitStackHost});let rowSlots=PANEL_ORDER.filter(slot=>slot!==Slot.splitview),declaredSlots=rowSlots.filter(slot=>declared[slot]),isSolo=declaredSlots.length<=1,soloSlot=declaredSlots[0],isSplitOpen=isPanelPresent({slot:Slot.splitview,declared,present,isShown})&&isPanelPresent({slot:Slot.content,declared,present,isShown}),contentColumn=React.createElement(StyledContentColumn,{isSplitOpen:isSplitOpen},React.createElement(StyledContentColumnHalf,{ref:slotHostRefs[Slot.content]}),isSplitOpen&&React.createElement(StyledContentColumnHalf,{ref:slotHostRefs[Slot.splitview]})),panelItems=rowSlots.filter(slot=>isPanelPresent({slot,declared,present,isShown})).map(slot=>{let panel=declared[slot],panelState=layoutState[slot];return{id:slot,child:childFor(slot,contentColumn,slotHostRefs),defaultSize:defaultSizeFor({slot,panel,panelState}),minSize:panel?.minSize,maxSize:panel?.maxSize,collapsible:slot!==Slot.content&&(panel?.collapsible??!0),lockWidthOnWindowResize:panel?.lockWidthOnWindowResize,resizable:panel?.resizable??resizableFromState(panelState)}}),rowKey=panelItems.map(item=>item.id).join(","),soloHost=soloSlot&&isShown(soloSlot)?childFor(soloSlot,contentColumn,slotHostRefs):null,panelGroup=panelItems.length>0?React.createElement(Panel,{key:resolvedKey,panels:panelItems,persistenceKey:resolvedKey,storage:resolvedStorage,onResize:(id,size)=>{isShown(id)&&declared[id]?.resizable!==!1&&dispatch({type:"resize",slot:id,size:declared[id]?.lockWidthOnWindowResize?Math.round(size.inPixels):`${size.asPercentage}%`})},onCollapse:id=>panelCallbacks[id].hide(),panelHandleFor:panelRefCallbacks.handleFor,panelElementFor:panelRefCallbacks.elementFor,shouldSuppressLayoutCallback:shouldSuppressLayoutCallback}):null;return React.createElement(PanelRegistryContext.Provider,{value:registry},React.createElement(PanelDeclarationsContext.Provider,{value:declared},React.createElement(PanelPresenceContext.Provider,{value:presence},React.createElement(PanelAnimationContext.Provider,{value:animationControl},React.createElement(PanelRowContext.Provider,{value:rowKey},React.createElement(LayoutPortalContext.Provider,{value:rootPortalTargets},React.createElement(LayoutFloatDragProvider,null,React.createElement(MobileSplitStackContext.Provider,{value:mobileSplitStack},React.createElement(StyledLayout,{ref:setLayoutRoot,"data-ds-id":"Layout"},React.createElement(StyledPanelRow,{hasOffcanvasLeftBar:hasOffcanvasLeftBar},isSolo?soloHost:panelGroup),isRightPanelFloating&&layoutState[Slot.rightPanel].visible&&React.createElement(LayoutFloat,{hostRef:floatHostRef}),children,showMobileSplitStack&&React.createElement(StyledMobileSplitStackHost,{ref:setMobileSplitStackHost}))))))))))};Layout.Provider=LayoutProvider,Layout.BottomBar=LayoutBottomBar,Layout.BottomBarItem=LayoutBottomBarItem,Layout.LeftPanel=LeftPanel,Layout.LeftNavBar=LeftNavBar,Layout.LeftNavBarFooter=LeftNavBarFooter,Layout.LeftPanelHeader=LeftPanelHeader,Layout.LeftPanelFooter=LeftPanelFooter,Layout.RightPanel=RightPanel,Layout.RightPanelHeader=RightPanelHeader,Layout.RightPanelFooter=RightPanelFooter,Layout.Content=Content,Layout.Split=Split,Layout.SplitHeader=SplitHeader,Layout.SplitFooter=SplitFooter;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{useLayoutPortal}from"./registry";export function LayoutPortal({children}){return useLayoutPortal("root",children)}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import React,{useMemo,useRef}from"react";import{LayoutPersistenceProvider,LayoutStoreProvider}from"./context";import{LayoutCssVars,LayoutCssVarStoreProvider}from"./LayoutCssVars";import{createLayoutCssVarStore}from"./cssVarStore";import{createInitialState}from"./reducer";import{createLayoutStore}from"./store";export function LayoutProvider({children,config,store,persistenceKey,storage}){let storeRef=useRef(null);null===storeRef.current&&(storeRef.current=store??createLayoutStore(createInitialState(config)));let cssVarStoreRef=useRef(null);null===cssVarStoreRef.current&&(cssVarStoreRef.current=createLayoutCssVarStore());let persistence=useMemo(()=>({persistenceKey,storage}),[persistenceKey,storage]);return React.createElement(LayoutStoreProvider,{value:storeRef.current},React.createElement(LayoutPersistenceProvider,{value:persistence},React.createElement(LayoutCssVarStoreProvider,{value:cssVarStoreRef.current},React.createElement(LayoutCssVars,null),children)))}
|
|
1
|
+
import React,{useMemo,useRef}from"react";import{LayoutPersistenceProvider,LayoutStoreProvider}from"./context";import{LayoutCssVars,LayoutCssVarStoreProvider}from"./LayoutCssVars";import{createLayoutCssVarStore}from"./cssVarStore";import{createPanelAnimationsStore,PanelAnimationsProvider}from"./usePanelAnimations";import{createInitialState}from"./reducer";import{createLayoutStore}from"./store";export function LayoutProvider({children,config,store,persistenceKey,storage}){let storeRef=useRef(null);null===storeRef.current&&(storeRef.current=store??createLayoutStore(createInitialState(config)));let cssVarStoreRef=useRef(null);null===cssVarStoreRef.current&&(cssVarStoreRef.current=createLayoutCssVarStore());let animations=useMemo(createPanelAnimationsStore,[]),persistence=useMemo(()=>({persistenceKey,storage}),[persistenceKey,storage]);return React.createElement(LayoutStoreProvider,{value:storeRef.current},React.createElement(LayoutPersistenceProvider,{value:persistence},React.createElement(LayoutCssVarStoreProvider,{value:cssVarStoreRef.current},React.createElement(LayoutCssVars,null),React.createElement(PanelAnimationsProvider,{value:animations},children))))}
|
|
@@ -8,9 +8,8 @@ export type LeftPanelDrawerProps = ForwardedScrollProps & {
|
|
|
8
8
|
};
|
|
9
9
|
/**
|
|
10
10
|
* Mobile left panel. Renders its content as a modal {@link Drawer} pinned to the
|
|
11
|
-
* left edge
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
* routes back through `hide`.
|
|
11
|
+
* left edge. Registers the region so `useLayout()` reports an open drawer as
|
|
12
|
+
* `overlay`; Layout excludes it from the resizable row. Visibility is the shared
|
|
13
|
+
* `leftPanel` state; outside-click / Escape routes back through `hide`.
|
|
15
14
|
*/
|
|
16
15
|
export declare const LeftPanelDrawer: React.FC<LeftPanelDrawerProps>;
|
|
@@ -1 +1 @@
|
|
|
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:"
|
|
1
|
+
import React from"react";import styled from"@emotion/styled";import{Slot}from"../-constants";import{useDeclarePanel}from"../registry";import{Drawer}from"../../Internal/Drawer/Drawer";import{PanelContainer}from"../PanelContainer";import{useLeftPanelId}from"../useLeftPanelId";let StyledLeftPanelBody=styled("div",{target:"e1q5nxh70",label:"StyledLeftPanelBody"})({width:"80vw",height:"100dvh"});export const LeftPanelDrawer=({children,isVisible,hide,"aria-label":ariaLabel,scrollContainerRef,onScroll})=>{let leftPanelId=useLeftPanelId();return useDeclarePanel(Slot.leftPanel,{}),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{useTheme}from"@emotion/react";import{Slot}from"../-constants";import{useDeclarePanel,useRunCallbackOnValueChange}from"../registry";import{useLayout}from"../useLayout";import{useBreakpoints}from"../../../shared/useBreakpoints";import{RightPanelDocked}from"./RightPanelDocked";import{RightPanelSheet}from"./RightPanelSheet";export const RightPanel=({children,defaultSize=378,collapsible=!1,resizable,variant="sidebar",onVisibleChange,onVariantChange,"aria-label":ariaLabel,scrollContainerRef,onScroll})=>{let{state:layoutState,[Slot.rightPanel]:panel}=useLayout(),{isVisible,hide}=panel,{isMobile}=useBreakpoints(),{minWidth,maxWidth}=useTheme().variables.layout.rightPanel;useDeclarePanel(Slot.rightPanel,{defaultSize,minSize:minWidth.default,maxSize:maxWidth.default,collapsible,resizable,lockWidthOnWindowResize
|
|
1
|
+
import React from"react";import{useTheme}from"@emotion/react";import{Slot}from"../-constants";import{useDeclarePanel,useRunCallbackOnValueChange}from"../registry";import{useLayout}from"../useLayout";import{useBreakpoints}from"../../../shared/useBreakpoints";import{RightPanelDocked}from"./RightPanelDocked";import{RightPanelSheet}from"./RightPanelSheet";export const RightPanel=({children,defaultSize=378,collapsible=!1,resizable,variant="sidebar",onVisibleChange,onVariantChange,"aria-label":ariaLabel,scrollContainerRef,onScroll})=>{let{state:layoutState,[Slot.rightPanel]:panel}=useLayout(),{isVisible,hide}=panel,{isMobile}=useBreakpoints(),{minWidth,maxWidth}=useTheme().variables.layout.rightPanel;useDeclarePanel(Slot.rightPanel,{defaultSize,minSize:minWidth.default,maxSize:maxWidth.default,collapsible,resizable,lockWidthOnWindowResize:"number"==typeof defaultSize||defaultSize.trim().endsWith("px"),variant});let resolvedVariant=layoutState[Slot.rightPanel].variant??variant;return useRunCallbackOnValueChange(isVisible,onVisibleChange),useRunCallbackOnValueChange(resolvedVariant,onVariantChange),isMobile?React.createElement(RightPanelSheet,{isVisible:isVisible,hide:hide,"aria-label":ariaLabel,scrollContainerRef:scrollContainerRef,onScroll:onScroll},children):React.createElement(RightPanelDocked,{isVisible:isVisible,variant:resolvedVariant,"aria-label":ariaLabel,scrollContainerRef:scrollContainerRef,onScroll:onScroll},children)};
|
|
@@ -7,3 +7,4 @@ export { useAutoScrollToBottom } from "./useAutoScrollToBottom";
|
|
|
7
7
|
export { createLayoutStore } from "./store";
|
|
8
8
|
export { createInitialState, layoutReducer } from "./reducer";
|
|
9
9
|
export * from "./-types";
|
|
10
|
+
export type { LayoutBottomBarProps } from "./BottomBar/LayoutBottomBar";
|
|
@@ -2,13 +2,16 @@ import { type ReactNode } from "react";
|
|
|
2
2
|
import type { PanelImperativeHandle } from "react-resizable-panels";
|
|
3
3
|
import type { RightPanelVariant, Size, SlotKey } from "./-types";
|
|
4
4
|
export type PortalTargets = Partial<Record<SlotKey, HTMLElement | null>>;
|
|
5
|
-
|
|
5
|
+
type LayoutPortalTargets = PortalTargets & {
|
|
6
|
+
root?: HTMLElement | null;
|
|
7
|
+
};
|
|
8
|
+
export declare const LayoutPortalContext: React.Context<LayoutPortalTargets>;
|
|
6
9
|
/**
|
|
7
10
|
* Portal `children` into the host DOM node registered for `slot`. Returns the
|
|
8
11
|
* portal (or `null` if the host isn't mounted yet). Call unconditionally -
|
|
9
12
|
* gate content by passing `null` as `children`, not by skipping the call.
|
|
10
13
|
*/
|
|
11
|
-
export declare function useLayoutPortal(slot: SlotKey, children: ReactNode): ReactNode;
|
|
14
|
+
export declare function useLayoutPortal(slot: SlotKey | "root", children: ReactNode): ReactNode;
|
|
12
15
|
/**
|
|
13
16
|
* Panel descriptor a marker contributes. The Group renders one resizable Panel
|
|
14
17
|
* per *declared* panel that is currently shown - regardless of nesting depth.
|
|
@@ -20,8 +23,8 @@ export type PanelReg = {
|
|
|
20
23
|
minSize?: Size;
|
|
21
24
|
maxSize?: Size;
|
|
22
25
|
collapsible?: boolean;
|
|
23
|
-
/** When `false`,
|
|
24
|
-
*
|
|
26
|
+
/** When `false`, user input can't resize the panel (directly or via a
|
|
27
|
+
* neighbour). Container resizing still applies. Defaults to resizable. */
|
|
25
28
|
resizable?: boolean;
|
|
26
29
|
/** Lock this column's width when the window resizes, leaving the change to
|
|
27
30
|
* the columns without it. Declared by the docked side panels, which are
|
|
@@ -89,3 +92,4 @@ export declare function usePanelAnimationControl(): PanelAnimationControl | null
|
|
|
89
92
|
export declare function useRunCallbackOnValueChange<T>(value: T, onChange?: (value: T) => void): void;
|
|
90
93
|
/** Fire `onChange(visible)` when `visible` transitions (not on initial mount). */
|
|
91
94
|
export declare function useVisibleChange(visible: boolean, onChange?: (visible: boolean) => void): void;
|
|
95
|
+
export {};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{useContext}from"react";import{useLayoutSelector,useLayoutStore}from"./context";import{PanelDeclarationsContext}from"./registry";import{DEFAULT_LEFT_PANEL_VARIANT}from"./-constants";let selectAll=state=>state;function panelHandleActions({slot,visible,dispatch}){return{isVisible:visible,show:()=>dispatch({type:"setVisible",slot,visible:!0}),hide:()=>dispatch({type:"setVisible",slot,visible:!1}),reset:()=>dispatch({type:"reset",slot})}}export function useLayout(){let store=useLayoutStore(),state=useLayoutSelector(selectAll),declared=useContext(PanelDeclarationsContext),{dispatch}=store;return{state,leftPanel:{state:{...state.leftPanel,variant:state.leftPanel.variant??DEFAULT_LEFT_PANEL_VARIANT},setVariant:variant=>dispatch({type:"setVariant",panel:"leftPanel",variant}),...panelHandleActions({slot:"leftPanel",visible:state.leftPanel.visible,dispatch})},rightPanel:{state:{...state.rightPanel,variant:state.rightPanel.variant??declared.rightPanel?.variant??"sidebar"},setVariant:variant=>dispatch({type:"setVariant",panel:"rightPanel",variant}),...panelHandleActions({slot:"rightPanel",visible:state.rightPanel.visible,dispatch})},content:{state:state.content,...panelHandleActions({slot:"content",visible:state.content.visible,dispatch})},splitview:{state:state.splitview,...panelHandleActions({slot:"splitview",visible:state.splitview.visible,dispatch})}}}
|
|
1
|
+
import{useContext}from"react";import{useLayoutSelector,useLayoutStore}from"./context";import{usePanelAnimations}from"./usePanelAnimations";import{useBreakpoints}from"../../shared/useBreakpoints";import{MobileSplitStackContext}from"./Split/MobileSplitView/useMobileSplitStack";import{PanelDeclarationsContext}from"./registry";import{DEFAULT_LEFT_PANEL_VARIANT}from"./-constants";let selectAll=state=>state;function panelHandleActions({slot,visible,dispatch}){return{isVisible:visible,show:()=>dispatch({type:"setVisible",slot,visible:!0}),hide:()=>dispatch({type:"setVisible",slot,visible:!1}),reset:()=>dispatch({type:"reset",slot})}}export function useLayout(){let store=useLayoutStore(),state=useLayoutSelector(selectAll),declared=useContext(PanelDeclarationsContext),{dispatch}=store,{isMobile}=useBreakpoints(),animations=usePanelAnimations(),mobileStack=useContext(MobileSplitStackContext),presentationFor=slot=>state[slot].visible&&("splitview"===slot&&isMobile?mobileStack?.isSplitPresent:declared[slot])?"content"===slot?isMobile&&mobileStack?.isSplitPresent&&state.splitview.visible?"hidden":"column":"splitview"===slot?"column":"leftPanel"===slot?(state.leftPanel.variant??DEFAULT_LEFT_PANEL_VARIANT)==="sidebar"?"column":"overlay":isMobile||(state.rightPanel.variant??declared.rightPanel?.variant)==="float"?"overlay":"column":"hidden";return{state,leftPanel:{presentation:presentationFor("leftPanel"),animation:animations.leftPanel??null,state:{...state.leftPanel,variant:state.leftPanel.variant??DEFAULT_LEFT_PANEL_VARIANT},setVariant:variant=>dispatch({type:"setVariant",panel:"leftPanel",variant}),...panelHandleActions({slot:"leftPanel",visible:state.leftPanel.visible,dispatch})},rightPanel:{presentation:presentationFor("rightPanel"),animation:animations.rightPanel??null,state:{...state.rightPanel,variant:state.rightPanel.variant??declared.rightPanel?.variant??"sidebar"},setVariant:variant=>dispatch({type:"setVariant",panel:"rightPanel",variant}),...panelHandleActions({slot:"rightPanel",visible:state.rightPanel.visible,dispatch})},content:{presentation:presentationFor("content"),animation:animations.content??null,state:state.content,...panelHandleActions({slot:"content",visible:state.content.visible,dispatch})},splitview:{presentation:presentationFor("splitview"),animation:animations.splitview??null,state:state.splitview,...panelHandleActions({slot:"splitview",visible:state.splitview.visible,dispatch})}}}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { SlotKey, PanelAnimation } from "./-types";
|
|
2
|
+
type Animations = Partial<Record<SlotKey, PanelAnimation | null>>;
|
|
3
|
+
type PanelAnimationsStore = {
|
|
4
|
+
getSnapshot: () => Animations;
|
|
5
|
+
subscribe: (listener: () => void) => () => void;
|
|
6
|
+
set: (slot: SlotKey, animation: PanelAnimation | null) => void;
|
|
7
|
+
};
|
|
8
|
+
export declare const PanelAnimationsProvider: React.Provider<PanelAnimationsStore | null>;
|
|
9
|
+
export declare const usePanelAnimationsStore: () => PanelAnimationsStore | null;
|
|
10
|
+
export declare const createPanelAnimationsStore: () => PanelAnimationsStore;
|
|
11
|
+
export declare const usePanelAnimations: () => Animations;
|
|
12
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{createContext,useContext,useSyncExternalStore}from"react";let EMPTY={},NOOP_SUBSCRIBE=()=>()=>{},Context=createContext(null);export const PanelAnimationsProvider=Context.Provider;export const usePanelAnimationsStore=()=>useContext(Context);export const createPanelAnimationsStore=()=>{let snapshot={},listeners=new Set;return{getSnapshot:()=>snapshot,subscribe:listener=>(listeners.add(listener),()=>{listeners.delete(listener)}),set:(slot,animation)=>{(snapshot[slot]??null)!==animation&&(snapshot={...snapshot,[slot]:animation},listeners.forEach(listener=>listener()))}}};export const usePanelAnimations=()=>{let store=usePanelAnimationsStore();return useSyncExternalStore(store?.subscribe??NOOP_SUBSCRIBE,store?.getSnapshot??(()=>EMPTY),()=>EMPTY)};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{useLayoutEffect,useRef,useState}from"react";import{useTheme}from"@emotion/react";import{useWindow}from"../../shared/useWindow";import{parseDurationMs}from"../../shared/parseDurationMs";import{prefersReducedMotion}from"../../shared/prefersReducedMotion";import{useDeclarePanel,usePanelAnimationControl,usePanelPresence,usePanelRow}from"./registry";import{useLayout}from"./useLayout";let 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,minSizeFor=({collapsedSize,isVisible,minSize})=>void 0===collapsedSize?minSize:isVisible?minSize??collapsedSize:collapsedSize;export const getMaxSize=({collapsedSize,isVisible,maxSize,openSize,phase})=>void 0===collapsedSize?maxSize:isVisible||"idle"!==phase?maxSize??openSize:collapsedSize;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"),[fixedWidth,setFixedWidth]=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({
|
|
1
|
+
import{useLayoutEffect,useMemo,useRef,useState}from"react";import{flushSync}from"react-dom";import{useTheme}from"@emotion/react";import{useWindow}from"../../shared/useWindow";import{parseDurationMs}from"../../shared/parseDurationMs";import{prefersReducedMotion}from"../../shared/prefersReducedMotion";import{useDeclarePanel,usePanelAnimationControl,usePanelPresence,usePanelRow}from"./registry";import{usePanelAnimationsStore}from"./usePanelAnimations";import{useLayout}from"./useLayout";let 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,minSizeFor=({collapsedSize,isVisible,minSize,phase})=>void 0===collapsedSize?minSize:isVisible&&"idle"===phase?minSize??collapsedSize:collapsedSize;export const getMaxSize=({collapsedSize,isVisible,maxSize,openSize,phase})=>void 0===collapsedSize?maxSize:isVisible||"idle"!==phase?maxSize??openSize:collapsedSize;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"),[fixedWidth,setFixedWidth]=useState(null),animations=usePanelAnimationsStore(),panelSlideAnimation=useMemo(()=>{let timing=hasCollapsedRest?theme.variables.animation.navSlide.collapse:theme.variables.animation.navSlide.open;return{property:"flex-grow",duration:reducedMotion?0:parseDurationMs(timing.duration),easing:timing.timingFunction}},[theme,hasCollapsedRest,reducedMotion]);useLayoutEffect(()=>{animations?.set(slot,"idle"===phase||reducedMotion||!collapsible&&!hasCollapsedRest?null:panelSlideAnimation)},[animations,slot,phase,panelSlideAnimation,reducedMotion,collapsible,hasCollapsedRest]),useLayoutEffect(()=>()=>animations?.set(slot,null),[animations,slot]);let[prevVisible,setPrevVisible]=useState(isVisible),declaredMountSize=useRef(hasCollapsedRest&&!isVisible?collapsedSize:state.size??defaultSize),chosenOpenSize=useRef(state.size??defaultSize),needsRestCorrection=useRef(!1);isVisible!==prevVisible&&(chosenOpenSize.current=state.size??defaultSize,needsRestCorrection.current=!0,hasCollapsedRest&&setFixedWidth(resolveSizePx(state.size??defaultSize,null)),setPrevVisible(isVisible),setPhase(isVisible?"entering":"exiting"),isVisible&&setIsMounted(!0),animation?.setResizeSuppressed(slot,!0));let openSize=hasCollapsedRest?state.size??defaultSize:defaultSize;useDeclarePanel(slot,{defaultSize:hasCollapsedRest?declaredMountSize.current:mountDefaultSizeFor({defaultSize:openSize,isVisible,isSlidingIn:"entering"===phase&&collapsible&&!reducedMotion}),minSize:minSizeFor({collapsedSize,isVisible,minSize,phase}),maxSize:getMaxSize({collapsedSize,isVisible,maxSize,openSize,phase}),collapsible:isCollapsible,resizable:(!hasCollapsedRest||!!isVisible&&"idle"===phase)&&resizable,lockWidthOnWindowResize}),usePanelPresence(slot,hasCollapsedRest||isMounted),useLayoutEffect(()=>{if(!hasCollapsedRest||"idle"!==phase||!needsRestCorrection.current)return;let restSize=isVisible?chosenOpenSize.current:collapsedSize,cancelled=!1;return animation?.setResizeSuppressed(slot,!0),Promise.resolve().then(()=>{if(cancelled)return;let handle=animation?.getHandle(slot);try{handle&&isHandleReady(handle)&&void 0!==restSize&&flushSync(()=>handle.resize(restSize))}finally{needsRestCorrection.current=!1,animation?.setResizeSuppressed(slot,!1)}}),()=>{cancelled=!0,animation?.setResizeSuppressed(slot,!1)}},[phase,hasCollapsedRest,isVisible,collapsedSize,animation,slot]);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 durationMs=panelSlideAnimation.duration,setColumnTransitions=enabled=>{animatedColumns.forEach(column=>{enabled?column.style.setProperty("transition",`${panelSlideAnimation.property} ${panelSlideAnimation.duration}ms ${panelSlideAnimation.easing}`):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{}setFixedWidth(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);setFixedWidth("entering"===phase||hasCollapsedRest?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)},waitForColumn=attempt=>{if(cancelled)return;if(0===attempt&&hasCollapsedRest)return void Promise.resolve().then(()=>waitForColumn(attempt+1));let handle=animation?.getHandle(slot)??null,element=animation?.getElement(slot)??null;if(handle&&element&&isHandleReady(handle)){if(hasCollapsedRest){let startSize="entering"===phase?collapsedSize:chosenOpenSize.current;void 0!==startSize&&flushSync(()=>handle.resize(startSize))}runSlide(handle,element);return}if("exiting"===phase||!animation||attempt>=30)return void settle(handle);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,panelSlideAnimation]),{isMounted:hasCollapsedRest||isMounted,fixedWidth}}
|