77 ReactNode ,
88 useEffect ,
99 useMemo ,
10+ useRef ,
11+ useState ,
1012} from 'react' ;
1113
1214import {
@@ -24,6 +26,8 @@ import {
2426 Styles ,
2527 tasty ,
2628} from '../../../tasty' ;
29+ import { isDevEnv } from '../../../tasty/utils/isDevEnv' ;
30+ import { Alert } from '../Alert' ;
2731
2832import { LayoutProvider , useLayoutContext } from './LayoutContext' ;
2933
@@ -42,6 +46,11 @@ const LayoutElement = tasty({
4246 overflow : 'hidden' ,
4347 flexGrow : 1 ,
4448 placeSelf : 'stretch' ,
49+ height : {
50+ '' : 'auto' ,
51+ 'auto-height' : 'fixed 100%' ,
52+ collapsed : '6x' ,
53+ } ,
4554
4655 '$content-padding' : '1x' ,
4756
@@ -82,6 +91,10 @@ export interface CubeLayoutProps
8291 /** Styles for wrapper and Inner sub-element */
8392 styles ?: Styles ;
8493 children ?: ReactNode ;
94+ /**
95+ * @internal Force show dev warning even in production (for storybook testing)
96+ */
97+ _forceShowDevWarning ?: boolean ;
8598}
8699
87100// Check if a child is a Layout.Panel
@@ -97,6 +110,9 @@ function LayoutInner(
97110 props : CubeLayoutProps & { forwardedRef ?: ForwardedRef < HTMLDivElement > } ,
98111) {
99112 const layoutContext = useLayoutContext ( ) ;
113+ const localRef = useRef < HTMLDivElement > ( null ) ;
114+ const [ isAutoHeight , setIsAutoHeight ] = useState ( false ) ;
115+ const [ isCollapsed , setIsCollapsed ] = useState ( false ) ;
100116
101117 const {
102118 isGrid,
@@ -108,6 +124,7 @@ function LayoutInner(
108124 children,
109125 style,
110126 forwardedRef,
127+ _forceShowDevWarning,
111128 ...otherProps
112129 } = props ;
113130
@@ -183,6 +200,29 @@ function LayoutInner(
183200 return ( ) => cancelAnimationFrame ( frameId ) ;
184201 } , [ markReady ] ) ;
185202
203+ // Auto-height detection: if layout collapses to 0 height after initialization,
204+ // automatically set height to 100% to prevent invisible layout
205+ useEffect ( ( ) => {
206+ if ( isReady && localRef . current && localRef . current . offsetHeight === 0 ) {
207+ setIsAutoHeight ( true ) ;
208+ }
209+ } , [ isReady ] ) ;
210+
211+ // Second check: if still 0 height after auto-height was applied,
212+ // show collapsed state with warning
213+ useEffect ( ( ) => {
214+ if ( isAutoHeight && localRef . current ) {
215+ // Use requestAnimationFrame to check after styles have been applied
216+ const frameId = requestAnimationFrame ( ( ) => {
217+ if ( localRef . current && localRef . current . offsetHeight === 0 ) {
218+ setIsCollapsed ( true ) ;
219+ }
220+ } ) ;
221+
222+ return ( ) => cancelAnimationFrame ( frameId ) ;
223+ }
224+ } , [ isAutoHeight ] ) ;
225+
186226 const insetStyle = useMemo ( ( ) => {
187227 const baseStyle : Record < string , string > = {
188228 '--inset-top' : `${ panelSizes . top } px` ,
@@ -199,22 +239,51 @@ function LayoutInner(
199239 } , [ panelSizes , style ] ) ;
200240
201241 const mods = useMemo (
202- ( ) => ( { dragging : isDragging , 'not-ready' : ! isReady } ) ,
203- [ isDragging , isReady ] ,
242+ ( ) => ( {
243+ dragging : isDragging ,
244+ 'not-ready' : ! isReady ,
245+ 'auto-height' : isAutoHeight && ! isCollapsed ,
246+ collapsed : isCollapsed ,
247+ } ) ,
248+ [ isDragging , isReady , isAutoHeight , isCollapsed ] ,
204249 ) ;
205250
251+ // Combine local ref with forwarded ref
252+ const setRefs = ( element : HTMLDivElement | null ) => {
253+ localRef . current = element ;
254+
255+ if ( typeof forwardedRef === 'function' ) {
256+ forwardedRef ( element ) ;
257+ } else if ( forwardedRef ) {
258+ forwardedRef . current = element ;
259+ }
260+ } ;
261+
262+ // Show dev warning when collapsed and in dev mode (or forced for stories)
263+ const showDevWarning = isCollapsed && ( _forceShowDevWarning || isDevEnv ( ) ) ;
264+
206265 return (
207266 < LayoutElement
208- ref = { forwardedRef }
267+ ref = { setRefs }
209268 { ...filterBaseProps ( otherProps , { eventProps : true } ) }
210269 mods = { mods }
211270 styles = { finalStyles }
212271 style = { insetStyle }
213272 >
214- { /* Panels are rendered outside the Inner element */ }
215- { panels }
216- { /* Other content goes inside the Inner element */ }
217- < div data-element = "Inner" > { content } </ div >
273+ { showDevWarning ? (
274+ < Alert theme = "danger" >
275+ < b > UIKit:</ b > < b > <Layout/></ b > has collapsed to < b > 0</ b > height.
276+ Ensure the parent container has a defined height or use the{ ' ' }
277+ < b > height</ b > prop on < b > <Layout/></ b > .
278+ </ Alert >
279+ ) : (
280+ < >
281+ { /* Panels are rendered outside the Inner element */ }
282+ { panels }
283+ { /* Other content goes inside the Inner element */ }
284+ < div data-element = "Inner" > { content } </ div >
285+ </ >
286+ ) }
218287 </ LayoutElement >
219288 ) ;
220289}
0 commit comments