@@ -12,9 +12,12 @@ type OpenDialogMsg struct {
1212 Model Dialog
1313}
1414
15- // CloseDialogMsg is sent to close the current dialog
15+ // CloseDialogMsg is sent to close the current (topmost) dialog
1616type CloseDialogMsg struct {}
1717
18+ // CloseAllDialogsMsg is sent to close all dialogs in the stack
19+ type CloseAllDialogsMsg struct {}
20+
1821// Dialog defines the interface that all dialogs must implement
1922type Dialog interface {
2023 layout.Model
@@ -25,27 +28,20 @@ type Dialog interface {
2528type Manager interface {
2629 tea.Model
2730
28- GetLayer () * lipgloss.Layer
31+ GetLayers () [] * lipgloss.Layer
2932 HasDialog () bool
3033}
3134
3235// manager implements Manager
3336type manager struct {
3437 width , height int
35- currentDialog Dialog // Single active dialog
36- keyMap KeyMap // Global dialog key bindings
37- }
38-
39- // KeyMap defines global dialog key bindings
40- type KeyMap struct {
41- // Add any global dialog keys here if needed
38+ dialogStack []Dialog
4239}
4340
4441// New creates a new dialog component manager
4542func New () Manager {
4643 return & manager {
47- currentDialog : nil ,
48- keyMap : KeyMap {},
44+ dialogStack : make ([]Dialog , 0 ),
4945 }
5046}
5147
@@ -60,50 +56,56 @@ func (d *manager) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
6056 case tea.WindowSizeMsg :
6157 d .width = msg .Width
6258 d .height = msg .Height
63- // Propagate resize to current dialog if it exists
64- if d .currentDialog != nil {
65- u , cmd := d .currentDialog .Update (msg )
66- d .currentDialog = u .(Dialog )
67- return d , cmd
59+ // Propagate resize to all dialogs in the stack
60+ var cmds []tea.Cmd
61+ for i := range d .dialogStack {
62+ u , cmd := d .dialogStack [i ].Update (msg )
63+ d .dialogStack [i ] = u .(Dialog )
64+ if cmd != nil {
65+ cmds = append (cmds , cmd )
66+ }
6867 }
69- return d , nil
68+ return d , tea . Batch ( cmds ... )
7069
7170 case OpenDialogMsg :
7271 return d .handleOpen (msg )
7372
7473 case CloseDialogMsg :
7574 return d .handleClose ()
75+
76+ case CloseAllDialogsMsg :
77+ return d .handleCloseAll ()
7678 }
7779
78- // Forward messages to current dialog if it exists
79- if d .currentDialog != nil {
80- u , cmd := d .currentDialog .Update (msg )
81- d .currentDialog = u .(Dialog )
80+ // Forward messages to top dialog if it exists
81+ // Only the topmost dialog receives input to prevent conflicts
82+ if len (d .dialogStack ) > 0 {
83+ topIndex := len (d .dialogStack ) - 1
84+ u , cmd := d .dialogStack [topIndex ].Update (msg )
85+ d .dialogStack [topIndex ] = u .(Dialog )
8286 return d , cmd
8387 }
8488 return d , nil
8589}
8690
87- // View renders the current dialog (used for debugging, actual rendering uses GetLayers)
91+ // View renders all dialogs (used for debugging, actual rendering uses GetLayers)
8892func (d * manager ) View () string {
8993 // This is mainly for debugging - actual rendering uses GetLayers
90- if d . currentDialog == nil {
94+ if len ( d . dialogStack ) == 0 {
9195 return ""
9296 }
93- return d .currentDialog .View ()
97+ // Return view of top dialog for debugging
98+ return d .dialogStack [len (d .dialogStack )- 1 ].View ()
9499}
95100
96- // handleOpen processes dialog opening requests
101+ // handleOpen processes dialog opening requests and adds to stack
97102func (d * manager ) handleOpen (msg OpenDialogMsg ) (tea.Model , tea.Cmd ) {
98- // Set the new dialog as current
99- d .currentDialog = msg .Model
103+ d .dialogStack = append (d .dialogStack , msg .Model )
100104
101- // Initialize dialog
102105 var cmds []tea.Cmd
103106 cmd := msg .Model .Init ()
104107 cmds = append (cmds , cmd )
105108
106- // Send initial window size
107109 _ , cmd = msg .Model .Update (tea.WindowSizeMsg {
108110 Width : d .width ,
109111 Height : d .height ,
@@ -113,28 +115,39 @@ func (d *manager) handleOpen(msg OpenDialogMsg) (tea.Model, tea.Cmd) {
113115 return d , tea .Batch (cmds ... )
114116}
115117
116- // handleClose processes dialog closing requests
118+ // handleClose processes dialog closing requests (pops top dialog from stack)
117119func (d * manager ) handleClose () (tea.Model , tea.Cmd ) {
118- if d . currentDialog == nil {
119- return d , nil
120+ if len ( d . dialogStack ) != 0 {
121+ d . dialogStack = d . dialogStack [: len ( d . dialogStack ) - 1 ]
120122 }
121123
122- d .currentDialog = nil
124+ return d , nil
125+ }
123126
127+ // handleCloseAll closes all dialogs in the stack
128+ func (d * manager ) handleCloseAll () (tea.Model , tea.Cmd ) {
129+ d .dialogStack = make ([]Dialog , 0 )
124130 return d , nil
125131}
126132
127- // HasDialog returns true if there is an active dialog
133+ // HasDialog returns true if there is at least one active dialog
128134func (d * manager ) HasDialog () bool {
129- return d . currentDialog != nil
135+ return len ( d . dialogStack ) > 0
130136}
131137
132- // GetLayer returns lipgloss layer for rendering the current dialog
133- func (d * manager ) GetLayer () * lipgloss.Layer {
134- if d .currentDialog == nil {
138+ // GetLayers returns lipgloss layers for rendering all dialogs in the stack
139+ // Dialogs are returned in order from bottom to top (index 0 is bottom-most)
140+ func (d * manager ) GetLayers () []* lipgloss.Layer {
141+ if len (d .dialogStack ) == 0 {
135142 return nil
136143 }
137- dialogView := d .currentDialog .View ()
138- row , col := d .currentDialog .Position ()
139- return lipgloss .NewLayer (dialogView ).X (col ).Y (row )
144+
145+ layers := make ([]* lipgloss.Layer , 0 , len (d .dialogStack ))
146+ for _ , dialog := range d .dialogStack {
147+ dialogView := dialog .View ()
148+ row , col := dialog .Position ()
149+ layers = append (layers , lipgloss .NewLayer (dialogView ).X (col ).Y (row ))
150+ }
151+
152+ return layers
140153}
0 commit comments