@@ -58,12 +58,14 @@ const themeIcon = `<svg viewBox="0 0 16 16"><circle cx="8" cy="8" r="5.5" fill="
5858
5959const gridIcon = `<svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5"><rect x="2.5" y="2.5" width="4.5" height="4.5" rx="1"/><rect x="9" y="2.5" width="4.5" height="4.5" rx="1"/><rect x="2.5" y="9" width="4.5" height="4.5" rx="1"/><rect x="9" y="9" width="4.5" height="4.5" rx="1"/></svg>`
6060
61+ // Standalone stories mount fixture runtimes that must not access the live app's storage.
6162// Vite needs the patterns as literals in each call.
6263const modules = import . meta. glob < StoryModule > ( [
6364 "../**/*.stories.tsx" ,
6465 "../../../ui/src/**/*.stories.tsx" ,
6566 "../../../session-ui/src/**/*.stories.tsx" ,
6667 "../../../gui-plugins/src/**/*.stories.tsx" ,
68+ "!../**/*.standalone.stories.tsx" ,
6769] )
6870
6971// Each file's text, for the order its states were written in.
@@ -73,6 +75,7 @@ const sources = import.meta.glob<string>(
7375 "../../../ui/src/**/*.stories.tsx" ,
7476 "../../../session-ui/src/**/*.stories.tsx" ,
7577 "../../../gui-plugins/src/**/*.stories.tsx" ,
78+ "!../**/*.standalone.stories.tsx" ,
7679 ] ,
7780 { query : "?raw" , import : "default" } ,
7881)
@@ -230,7 +233,7 @@ export default function ComponentsLab() {
230233 when = { ! grid ( ) }
231234 fallback = {
232235 < Grid
233- entries = { entries ( ) . filter ( ( entry ) => entry . title . startsWith ( "UI/" ) ) }
236+ entries = { entries ( ) . filter ( ( entry ) => entry . title . startsWith ( "UI/" ) || isDialogEntry ( entry ) ) }
234237 scheme = { untrack ( scheme ) }
235238 onOpen = { open }
236239 />
@@ -613,21 +616,25 @@ function Grid(props: { entries: LabEntry[]; scheme: "dark" | "light"; onOpen: (f
613616 const board = canvas ( element , {
614617 theme : props . scheme ,
615618 label : language . t ( "lab.grid" ) ,
616- // Neighbours share the library's folder: actions, forms, overlays and so on .
619+ // Neighbours share the library's folder: actions, forms, overlays, then app dialogs .
617620 items : props . entries
618621 . toSorted ( ( a , b ) => folderOf ( a ) . localeCompare ( folderOf ( b ) ) )
619- . map ( ( entry ) => ( {
620- id : entry . file ,
621- title : entry . title . split ( "/" ) . at ( - 1 ) ,
622- w : 320 ,
623- h : 240 ,
624- render : ( card : HTMLElement ) =>
625- createRoot ( ( dispose ) => {
626- insert ( card , ( ) => < Tile entry = { entry } /> )
627-
628- return dispose
629- } , owner ?? undefined ) ,
630- } ) ) ,
622+ . map ( ( entry ) => {
623+ const size = tileSize ( entry )
624+
625+ return {
626+ id : entry . file ,
627+ title : entry . title . split ( "/" ) . at ( - 1 ) ,
628+ w : size . w ,
629+ h : size . h ,
630+ render : ( card : HTMLElement ) =>
631+ createRoot ( ( dispose ) => {
632+ insert ( card , ( ) => < Tile entry = { entry } /> )
633+
634+ return dispose
635+ } , owner ?? undefined ) ,
636+ }
637+ } ) ,
631638 } )
632639
633640 // The canvas captures the pointer to pan, so a card never sees its click: a press that ends where it began opens
@@ -667,30 +674,54 @@ function Tile(props: { entry: LabEntry }) {
667674 < div
668675 ref = { setCanvas }
669676 data-lab-story = { props . entry . file }
670- class = "relative flex size-full cursor-pointer items-center justify-center overflow-hidden bg-v2-background-bg-base p-4 [contain:layout]"
677+ class = "relative flex size-full cursor-pointer overflow-hidden bg-v2-background-bg-base [contain:layout]"
678+ classList = { {
679+ "items-center justify-center p-4" : ! props . entry . fullscreen ,
680+ "flex-col" : props . entry . fullscreen ,
681+ } }
671682 >
672683 { /* The provider waits for the card, so a story that opens a dialog at once opens it inside. */ }
673684 < Show when = { canvas ( ) } >
674685 { ( container ) => (
675686 < div class = "pointer-events-none contents" >
676- < DialogProvider container = { container ( ) } >
677- < ErrorBoundary
678- fallback = { ( error ) => < pre class = "font-mono text-[11px] text-v2-state-fg-danger" > { String ( error ) } </ pre > }
679- >
680- { render
681- ? untrack ( ( ) => render ( stateArgs ( props . entry , 0 ) ) )
682- : component && < Dynamic component = { component } { ...stateArgs ( props . entry , 0 ) } /> }
683- </ ErrorBoundary >
684- </ DialogProvider >
687+ < Plugin file = { props . entry . file } >
688+ < DialogProvider container = { container ( ) } >
689+ < ErrorBoundary
690+ fallback = { ( error ) => < pre class = "font-mono text-[11px] text-v2-state-fg-danger" > { String ( error ) } </ pre > }
691+ >
692+ { render
693+ ? untrack ( ( ) => render ( stateArgs ( props . entry , 0 ) ) )
694+ : component && < Dynamic component = { component } { ...stateArgs ( props . entry , 0 ) } /> }
695+ </ ErrorBoundary >
696+ </ DialogProvider >
697+ </ Plugin >
685698 </ div >
686699 ) }
687700 </ Show >
688701 </ div >
689702 )
690703}
691704
705+ function isDialogEntry ( entry : LabEntry ) {
706+ return (
707+ entry . title . startsWith ( "App/Dialogs/" ) ||
708+ entry . file . endsWith ( "/beta-dialog.stories.tsx" ) ||
709+ entry . file . endsWith ( "/overlays/dialog/dialog.stories.tsx" )
710+ )
711+ }
712+
713+ function tileSize ( entry : LabEntry ) {
714+ if ( entry . fullscreen ) return { w : 1120 , h : 720 }
715+
716+ if ( isDialogEntry ( entry ) ) return { w : 720 , h : 820 }
717+
718+ return { w : 320 , h : 240 }
719+ }
720+
692721function folderOf ( entry : LabEntry ) {
693- return entry . file . match ( / u i \/ s r c \/ ( [ ^ / ] + ) \/ / ) ?. [ 1 ] ?? ""
722+ if ( isDialogEntry ( entry ) ) return `1:dialogs:${ entry . title } `
723+
724+ return `0:${ entry . file . match ( / u i \/ s r c \/ ( [ ^ / ] + ) \/ / ) ?. [ 1 ] ?? "" } `
694725}
695726
696727function typing ( target : EventTarget | null ) {
0 commit comments