@@ -4,40 +4,41 @@ import {DrawerItem, Drawer as GravityDrawer} from '@gravity-ui/navigation';
44
55import { cn } from '../../utils/cn' ;
66
7+ const DEFAULT_DRAWER_WIDTH_PERCENTS = 60 ;
78const DEFAULT_DRAWER_WIDTH = 600 ;
89const DRAWER_WIDTH_KEY = 'drawer-width' ;
910const b = cn ( 'ydb-drawer' ) ;
1011
1112import './Drawer.scss' ;
1213
13- interface ContainerProps {
14- children : React . ReactNode ;
15- className ?: string ;
14+ // Create a context for sharing container dimensions
15+ interface DrawerContextType {
16+ containerWidth : number ;
17+ setContainerWidth : React . Dispatch < React . SetStateAction < number > > ;
1618}
1719
18- interface WrapperProps {
19- children : React . ReactNode ;
20- renderDrawerContent : ( ) => React . ReactNode ;
21- isDrawerVisible : boolean ;
22- onCloseDrawer : ( ) => void ;
23- drawerId ?: string ;
24- storageKey ?: string ;
25- defaultWidth ?: number ;
26- direction ?: 'left' | 'right' ;
27- className ?: string ;
28- detectClickOutside ?: boolean ;
29- }
20+ const DrawerContext = React . createContext < DrawerContextType | undefined > ( undefined ) ;
21+
22+ // Custom hook to use the drawer context
23+ const useDrawerContext = ( ) => {
24+ const context = React . useContext ( DrawerContext ) ;
25+ if ( context === undefined ) {
26+ return { containerWidth : 0 , setContainerWidth : ( ) => { } } ;
27+ }
28+ return context ;
29+ } ;
3030
3131interface ContentWrapperProps {
3232 isVisible : boolean ;
3333 onClose : ( ) => void ;
3434 children : React . ReactNode ;
3535 drawerId ?: string ;
3636 storageKey ?: string ;
37- defaultWidth ?: number ;
3837 direction ?: 'left' | 'right' ;
3938 className ?: string ;
4039 detectClickOutside ?: boolean ;
40+ defaultWidth ?: number ;
41+ isPercentageWidth ?: boolean ;
4142}
4243
4344const ContentWrapper = ( {
@@ -46,17 +47,28 @@ const ContentWrapper = ({
4647 children,
4748 drawerId = 'drawer' ,
4849 storageKey = DRAWER_WIDTH_KEY ,
49- defaultWidth = DEFAULT_DRAWER_WIDTH ,
50+ defaultWidth,
5051 direction = 'right' ,
5152 className,
5253 detectClickOutside = false ,
54+ isPercentageWidth,
5355} : ContentWrapperProps ) => {
5456 const [ drawerWidth , setDrawerWidth ] = React . useState ( ( ) => {
5557 const savedWidth = localStorage . getItem ( storageKey ) ;
5658 return savedWidth ? Number ( savedWidth ) : defaultWidth ;
5759 } ) ;
5860
5961 const drawerRef = React . useRef < HTMLDivElement > ( null ) ;
62+ const { containerWidth} = useDrawerContext ( ) ;
63+ // Calculate drawer width based on container width percentage if specified
64+ const calculatedWidth = React . useMemo ( ( ) => {
65+ if ( isPercentageWidth && containerWidth > 0 ) {
66+ return Math . round (
67+ ( containerWidth * ( drawerWidth || DEFAULT_DRAWER_WIDTH_PERCENTS ) ) / 100 ,
68+ ) ;
69+ }
70+ return drawerWidth || DEFAULT_DRAWER_WIDTH ;
71+ } , [ containerWidth , isPercentageWidth , drawerWidth ] ) ;
6072
6173 React . useEffect ( ( ) => {
6274 if ( ! detectClickOutside ) {
@@ -80,8 +92,14 @@ const ContentWrapper = ({
8092 } , [ isVisible , onClose , detectClickOutside ] ) ;
8193
8294 const handleResizeDrawer = ( width : number ) => {
83- setDrawerWidth ( width ) ;
84- localStorage . setItem ( storageKey , width . toString ( ) ) ;
95+ if ( isPercentageWidth && containerWidth > 0 ) {
96+ const percentageWidth = Math . round ( ( width / containerWidth ) * 100 ) ;
97+ setDrawerWidth ( percentageWidth ) ;
98+ localStorage . setItem ( storageKey , percentageWidth . toString ( ) ) ;
99+ } else {
100+ setDrawerWidth ( width ) ;
101+ localStorage . setItem ( storageKey , width . toString ( ) ) ;
102+ }
85103 } ;
86104
87105 return (
@@ -95,7 +113,8 @@ const ContentWrapper = ({
95113 id = { drawerId }
96114 visible = { isVisible }
97115 resizable
98- width = { drawerWidth }
116+ maxResizeWidth = { containerWidth }
117+ width = { isPercentageWidth ? calculatedWidth : drawerWidth }
99118 onResize = { handleResizeDrawer }
100119 direction = { direction }
101120 className = { b ( 'item' ) }
@@ -107,12 +126,65 @@ const ContentWrapper = ({
107126 ) ;
108127} ;
109128
129+ interface ContainerProps {
130+ children : React . ReactNode ;
131+ className ?: string ;
132+ }
133+
134+ interface ItemWrapperProps {
135+ children : React . ReactNode ;
136+ renderDrawerContent : ( ) => React . ReactNode ;
137+ isDrawerVisible : boolean ;
138+ onCloseDrawer : ( ) => void ;
139+ drawerId ?: string ;
140+ storageKey ?: string ;
141+ defaultWidth ?: number ;
142+ direction ?: 'left' | 'right' ;
143+ className ?: string ;
144+ detectClickOutside ?: boolean ;
145+ isPercentageWidth ?: boolean ;
146+ }
147+
110148export const Drawer = {
111149 Container : ( { children, className} : ContainerProps ) => {
112- return < div className = { b ( 'drawer-container' , className ) } > { children } </ div > ;
150+ const [ containerWidth , setContainerWidth ] = React . useState ( 0 ) ;
151+ const containerRef = React . useRef < HTMLDivElement > ( null ) ;
152+
153+ React . useEffect ( ( ) => {
154+ if ( ! containerRef . current ) {
155+ return undefined ;
156+ }
157+
158+ const updateWidth = ( ) => {
159+ if ( containerRef . current ) {
160+ setContainerWidth ( containerRef . current . clientWidth ) ;
161+ }
162+ } ;
163+
164+ // Set initial width
165+ updateWidth ( ) ;
166+
167+ // Update width on resize
168+ const resizeObserver = new ResizeObserver ( updateWidth ) ;
169+ resizeObserver . observe ( containerRef . current ) ;
170+
171+ return ( ) => {
172+ if ( containerRef . current ) {
173+ resizeObserver . disconnect ( ) ;
174+ }
175+ } ;
176+ } , [ ] ) ;
177+
178+ return (
179+ < DrawerContext . Provider value = { { containerWidth, setContainerWidth} } >
180+ < div ref = { containerRef } className = { b ( 'drawer-container' , className ) } >
181+ { children }
182+ </ div >
183+ </ DrawerContext . Provider >
184+ ) ;
113185 } ,
114186
115- Wrapper : ( {
187+ ItemWrapper : ( {
116188 children,
117189 renderDrawerContent,
118190 isDrawerVisible,
@@ -123,7 +195,8 @@ export const Drawer = {
123195 direction,
124196 className,
125197 detectClickOutside,
126- } : WrapperProps ) => {
198+ isPercentageWidth,
199+ } : ItemWrapperProps ) => {
127200 React . useEffect ( ( ) => {
128201 return ( ) => {
129202 onCloseDrawer ( ) ;
@@ -141,6 +214,7 @@ export const Drawer = {
141214 direction = { direction }
142215 className = { className }
143216 detectClickOutside = { detectClickOutside }
217+ isPercentageWidth = { isPercentageWidth }
144218 >
145219 { renderDrawerContent ( ) }
146220 </ ContentWrapper >
0 commit comments