Skip to content
Draft
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
234 changes: 133 additions & 101 deletions docs/src/content/docs/features/dialogs/message.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -127,31 +127,36 @@ func fetchData(app *application.App, url string) ([]byte, error) {

## Question dialog

Ask users questions and handle responses via button callbacks:
Ask users questions and handle responses. `Show()` returns the clicked button's label and an error:

```go
dialog := app.Dialog.Question().
SetTitle("Confirm").
SetMessage("Save changes before closing?")

save := dialog.AddButton("Save")
save.OnClick(func() {
saveChanges()
})

dontSave := dialog.AddButton("Don't Save")
dontSave.OnClick(func() {
// Continue without saving
})

dialog.AddButton("Save")
dialog.AddButton("Don't Save")
cancel := dialog.AddButton("Cancel")
cancel.OnClick(func() {
// Don't close
})

dialog.SetDefaultButton(save)
dialog.SetDefaultButton(dialog.Buttons[0]) // "Save"
dialog.SetCancelButton(cancel)
dialog.Show()

// Show() blocks and returns the clicked button's label and an error
result, err := dialog.Show()
if err != nil {
// Handle error (dialog could not be displayed)
return
}

switch result {
case "Save":
saveChanges()
doClose()
case "Don't Save":
doClose()
case "Cancel":
// Don't close
}
```

**Use cases:**
Expand All @@ -174,23 +179,29 @@ func closeDocument(app *application.App) {
SetMessage("Do you want to save your changes?")

save := dialog.AddButton("Save")
save.OnClick(func() {
if saveDocument() {
doClose()
}
})

dontSave := dialog.AddButton("Don't Save")
dontSave.OnClick(func() {
doClose()
})

dialog.AddButton("Don't Save")
cancel := dialog.AddButton("Cancel")
// Cancel button has no callback - just closes the dialog

dialog.SetDefaultButton(save)
dialog.SetCancelButton(cancel)
dialog.Show()

// Show() returns the clicked button's label and an error
result, err := dialog.Show()
if err != nil {
// Handle error
return
}

switch result {
case "Save":
if saveDocument() {
doClose()
}
case "Don't Save":
doClose()
case "Cancel":
// Don't close - do nothing
}
}
```

Expand Down Expand Up @@ -233,28 +244,44 @@ dialog.Show()

**Multiple buttons (Question):**

Use `AddButton()` to add buttons, which returns a `*Button` you can configure:
Use `WithButton()` for simple button additions with chaining, or `AddButton()` when you need to configure the button.
`Show()` returns the label of the clicked button and an error:

```go
dialog := app.Dialog.Question().
SetMessage("Choose an action")
// Using WithButton() for simple chaining
result, err := app.Dialog.Question().
SetMessage("Choose an action").
WithButton("Option 1").
WithButton("Option 2").
WithButton("Option 3").
Show()
if err != nil {
// Handle error
return
}

option1 := dialog.AddButton("Option 1")
option1.OnClick(func() {
switch result {
case "Option 1":
handleOption1()
})

option2 := dialog.AddButton("Option 2")
option2.OnClick(func() {
case "Option 2":
handleOption2()
})

option3 := dialog.AddButton("Option 3")
option3.OnClick(func() {
case "Option 3":
handleOption3()
})
}
```

dialog.Show()
Use `AddButton()` when you need to configure buttons (returns `*Button` for further configuration):

```go
dialog := app.Dialog.Question().
SetMessage("Choose an action")

dialog.AddButton("Option 1").SetAsDefault()
dialog.AddButton("Option 2")
dialog.AddButton("Option 3").SetAsCancel()

result, err := dialog.Show()
// ...
```

**Default and Cancel buttons:**
Expand All @@ -266,17 +293,21 @@ Use `SetCancelButton()` to specify which button is triggered by Escape.
dialog := app.Dialog.Question().
SetMessage("Delete file?")

deleteBtn := dialog.AddButton("Delete")
deleteBtn.OnClick(func() {
performDelete()
})

dialog.AddButton("Delete")
cancelBtn := dialog.AddButton("Cancel")
// No callback needed - just dismisses dialog

dialog.SetDefaultButton(cancelBtn) // Safe option as default
dialog.SetCancelButton(cancelBtn) // Escape triggers Cancel
dialog.Show()

result, err := dialog.Show()
if err != nil {
// Handle error
return
}

if result == "Delete" {
performDelete()
}
```

You can also use the fluent `SetAsDefault()` and `SetAsCancel()` methods on buttons:
Expand All @@ -285,13 +316,13 @@ You can also use the fluent `SetAsDefault()` and `SetAsCancel()` methods on butt
dialog := app.Dialog.Question().
SetMessage("Delete file?")

dialog.AddButton("Delete").OnClick(func() {
performDelete()
})

dialog.AddButton("Delete")
dialog.AddButton("Cancel").SetAsDefault().SetAsCancel()

dialog.Show()
result, _ := dialog.Show()
if result == "Delete" {
performDelete()
}
```

**Best practices:**
Expand Down Expand Up @@ -346,34 +377,36 @@ func deleteFiles(app *application.App, paths []string) {
SetTitle("Confirm Delete").
SetMessage(message)

deleteBtn := dialog.AddButton("Delete")
deleteBtn.OnClick(func() {
// Perform deletion
var errs []error
for _, path := range paths {
if err := os.Remove(path); err != nil {
errs = append(errs, err)
}
}

// Show result
if len(errs) > 0 {
app.Dialog.Error().
SetTitle("Delete Failed").
SetMessage(fmt.Sprintf("Failed to delete %d file(s)", len(errs))).
Show()
} else {
app.Dialog.Info().
SetTitle("Delete Complete").
SetMessage(fmt.Sprintf("Deleted %d file(s)", len(paths))).
Show()
}
})

dialog.AddButton("Delete")
cancelBtn := dialog.AddButton("Cancel")
dialog.SetDefaultButton(cancelBtn)
dialog.SetCancelButton(cancelBtn)
dialog.Show()

result, err := dialog.Show()
if err != nil || result != "Delete" {
return // Error or user cancelled
}

// Perform deletion
var errs []error
for _, path := range paths {
if err := os.Remove(path); err != nil {
errs = append(errs, err)
}
}

// Show result
if len(errs) > 0 {
app.Dialog.Error().
SetTitle("Delete Failed").
SetMessage(fmt.Sprintf("Failed to delete %d file(s)", len(errs))).
Show()
} else {
app.Dialog.Info().
SetTitle("Delete Complete").
SetMessage(fmt.Sprintf("Deleted %d file(s)", len(paths))).
Show()
}
}
```

Expand All @@ -385,14 +418,14 @@ func confirmQuit(app *application.App) {
SetTitle("Quit").
SetMessage("You have unsaved work. Are you sure you want to quit?")

yes := dialog.AddButton("Yes")
yes.OnClick(func() {
app.Quit()
})

dialog.AddButton("Yes")
no := dialog.AddButton("No")
dialog.SetDefaultButton(no)
dialog.Show()

result, _ := dialog.Show()
if result == "Yes" {
app.Quit()
}
}
```

Expand All @@ -405,15 +438,15 @@ func showUpdateDialog(app *application.App) {
SetMessage("A new version is available. The cancel button is selected when pressing escape.")

download := dialog.AddButton("📥 Download")
download.OnClick(func() {
app.Dialog.Info().SetMessage("Downloading...").Show()
})

cancel := dialog.AddButton("Cancel")

dialog.SetDefaultButton(download)
dialog.SetCancelButton(cancel)
dialog.Show()

result, _ := dialog.Show()
if result == "📥 Download" {
app.Dialog.Info().SetMessage("Downloading...").Show()
}
}
```

Expand All @@ -427,17 +460,16 @@ func showCustomIconQuestion(app *application.App, iconBytes []byte) {
SetIcon(iconBytes)

likeIt := dialog.AddButton("I like it!")
likeIt.OnClick(func() {
app.Dialog.Info().SetMessage("Thanks!").Show()
})
dialog.AddButton("Not so keen...")
dialog.SetDefaultButton(likeIt)

notKeen := dialog.AddButton("Not so keen...")
notKeen.OnClick(func() {
result, _ := dialog.Show()
switch result {
case "I like it!":
app.Dialog.Info().SetMessage("Thanks!").Show()
case "Not so keen...":
app.Dialog.Info().SetMessage("Too bad!").Show()
})

dialog.SetDefaultButton(likeIt)
dialog.Show()
}
}

Comment on lines +519 to 521
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Missing closing code fence for the example.

The code block starting at line 502 for showCustomIconQuestion is missing its closing triple backticks. The ## Best Practices section on line 522 appears immediately after the function, indicating the code block was not properly closed.

🔎 Suggested fix
     case "Not so keen...":
 		_ = app.Dialog.Info().SetMessage("Too bad!").Show()
     }
 }
+```

 ## Best Practices
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
}
}
}
}
🤖 Prompt for AI Agents
In docs/src/content/docs/features/dialogs/message.mdx around lines 519 to 521,
the example code block for showCustomIconQuestion is missing its closing triple
backticks; add a closing ``` fence immediately after the function (right after
the existing closing brace on line 521) so the code block ends before the "##
Best Practices" heading on line 522.

## Best Practices
Expand Down
2 changes: 2 additions & 0 deletions v3/UNRELEASED_CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,11 @@ After processing, the content will be moved to the main changelog and this file

## Added
<!-- New features, capabilities, or enhancements -->
- Add `MessageDialog.WithButton()` method for builder pattern chaining when adding buttons without configuration (#4792)

## Changed
<!-- Changes in existing functionality -->
- **BREAKING**: `MessageDialog.Show()` now returns `(string, error)` - the clicked button's label and an error if the dialog could not be displayed. This enables synchronous dialog workflows and proper error handling (#4792) by @leaanthony
- Update the documentation for Window `X/Y` options @ruhuang2001

## Fixed
Expand Down
Loading
Loading