Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
d077382
feat(dialogs): added support for alert, prompt, and custom dialogs
Denny09310 Mar 2, 2026
14aec6d
fix(dialogs): 'IComponent' taken from wrong using
Denny09310 Mar 2, 2026
1c3e198
fix(dialog): dialog closing from IDialogReference
Denny09310 Mar 2, 2026
5dfa6fc
chore(demo): added demo for new dialog variants
Denny09310 Mar 2, 2026
9ffb90d
feat(dialogs): added support for alert, prompt, and custom dialogs
Denny09310 Mar 2, 2026
18bf2d7
fix(dialogs): changed 'AlertDialog' cancelling instead of acknowledging
Denny09310 Mar 4, 2026
2106c03
fix(dialogs): adding a backward compatible 'Confirm' method, ensuring…
Denny09310 Mar 4, 2026
200aaa4
fix(dialogs): added default text to 'ConfirmText' property
Denny09310 Mar 4, 2026
532c8fd
fix(dialogs): renamed 'Task' property to 'Completion' avoiding overla…
Denny09310 Mar 4, 2026
1a19678
fix(dialogs): restored accessibility attributes for every dialog type
Denny09310 Mar 4, 2026
0c7e9f1
fix(dialogs): remove orphaned/duplicate summaries
Denny09310 Mar 4, 2026
8df7157
chore(demo): added code samples for dialog services
Denny09310 Mar 4, 2026
a2d4bac
chore(dialog): moved dialog wrapper up to 'BbDialogProvider'
Denny09310 Mar 4, 2026
c6eb53b
fix(dialogs): better 'PromptDialog' validation
Denny09310 Mar 4, 2026
af37d8e
chore(dialogs): removed check on 'Title' as it's required, avoid cast…
Denny09310 Mar 4, 2026
bc33d17
fix. avoid injecting service in custom dialog data
Denny09310 Mar 4, 2026
9d2392d
fix: for some reason adding the dialogs new classes, makes the compil…
Denny09310 Mar 4, 2026
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
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
@inject DialogService DialogService

private async Task HandleAlert()
{
alertStatus = "Waiting...";
await DialogService.AlertAsync(
"Session Expired",
"Please log in again.");
}

// With custom options:
var confirmed = await DialogService.ConfirmAsync(
"Delete item?",
"This action cannot be undone.",
new AlertDialogOptions
{
ButtonText = "Ok, I Accept!",
});
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

private async Task HandleDelete()
{
var confirmed = await DialogService.Confirm(
var confirmed = await DialogService.ConfirmAsync(
"Delete item?",
"This action cannot be undone.");

Expand All @@ -13,12 +13,12 @@ private async Task HandleDelete()
}

// With custom options:
var confirmed = await DialogService.Confirm(
var confirmed = await DialogService.ConfirmAsync(
"Delete item?",
"This action cannot be undone.",
new ConfirmDialogOptions
{
ConfirmText = "Yes, delete",
CancelText = "Keep it",
Destructive = true
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
@inject DialogService DialogService

private async Task HandleCustomDialog()
{
var result = await DialogService.OpenAsync<EditUserComponent>(
new Dictionary<string, object?>
{
[nameof(EditUserComponent.UserId)] = 42
},
new DialogOpenOptions
{
Title = "Edit User",
Size = DialogSize.Large
});

if (result.Cancelled)
{
return;
}

var data = result.GetData<UserDto>();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
@inject DialogService DialogService

private async Task HandlePrompt()
{
var name = await DialogService.PromptAsync(
"Rename File",
"Enter a new file name:",
new PromptDialogOptions
{
DefaultValue = "document.txt",
Placeholder = "file-name.txt",
Required = true,
MaxLength = 50
});

var text = name.Value ?? "Cancelled";
}
188 changes: 183 additions & 5 deletions demos/BlazorBlueprint.Demo.Shared/Pages/Components/DialogDemo.razor
Original file line number Diff line number Diff line change
Expand Up @@ -394,6 +394,84 @@
<CodeBlock Source="Components/Dialog/confirm-service.txt" />
</div>

<div class="mt-10 space-y-4">
<h2 class="text-2xl font-semibold">
Alert Service
<span class="bg-primary/10 text-primary rounded px-1.5 py-0.5 text-xs font-normal">
New
</span>
</h2>

<p class="text-muted-foreground text-sm">
Use <code>DialogService.Alert()</code> for simple acknowledgment dialogs.
Returns a <code>Task</code> that completes when the user clicks OK.
</p>

<div class="flex items-center gap-4">
<BbButton OnClick="HandleAlert">
Show Alert
</BbButton>

<span class="text-muted-foreground text-sm">
Status: @alertStatus
</span>
</div>

<CodeBlock Source="Components/Dialog/alert-service.txt" />
</div>

<div class="mt-10 space-y-4">
<h2 class="text-2xl font-semibold">
Prompt Service
<span class="bg-primary/10 text-primary rounded px-1.5 py-0.5 text-xs font-normal">
New
</span>
</h2>

<p class="text-muted-foreground text-sm">
Use <code>DialogService.Prompt()</code> to collect text input asynchronously.
Returns <code>string?</code>.
</p>

<div class="flex items-center gap-4">
<BbButton OnClick="HandlePrompt">
Rename File
</BbButton>

<span class="text-muted-foreground text-sm">
Result: @promptResult
</span>
</div>

<CodeBlock Source="Components/Dialog/prompt-service.txt" />
</div>

<div class="mt-10 space-y-4">
<h2 class="text-2xl font-semibold">
Custom Component Dialog
<span class="bg-primary/10 text-primary rounded px-1.5 py-0.5 text-xs font-normal">
New
</span>
</h2>

<p class="text-muted-foreground text-sm">
Use <code>DialogService.Open&lt;TComponent&gt;()</code> to render a fully custom dialog component.
Returns a <code>DialogResult</code>.
</p>

<div class="flex items-center gap-4">
<BbButton OnClick="HandleCustomDialog">
Edit User
</BbButton>

<span class="text-muted-foreground text-sm">
Result: @customResult
</span>
</div>

<CodeBlock Source="Components/Dialog/custom-service.txt" />
</div>

<div class="space-y-4">
<h2 class="text-2xl font-semibold">Form in Dialog</h2>
<p class="text-sm text-muted-foreground">
Expand Down Expand Up @@ -603,13 +681,17 @@
</div>

@code {
private string confirmResult = "None";
private bool isDialogOpen = false;
private DateTime? dialogDatePickerValue;
private string? selectedComboboxFramework;
private string? selectedDialogFruit;
private IEnumerable<string>? selectedTechnologies = new List<string>();

private string confirmResult = "None";
private string alertStatus = "Idle";
private string promptResult = "-";
private string customResult = "-";

// Form in Dialog
private string? formFirstName;
private string? formLastName;
Expand Down Expand Up @@ -663,16 +745,16 @@

private async Task HandleConfirmDelete()
{
var confirmed = await DialogService.Confirm(
var result = await DialogService.ConfirmAsync(
"Delete item?",
"This action cannot be undone. The item will be permanently removed.");

confirmResult = confirmed ? "Confirmed" : "Cancelled";
confirmResult = result.Confirmed ? "Confirmed" : "Cancelled";
}

private async Task HandleDestructiveDelete()
{
var confirmed = await DialogService.Confirm(
var data = await DialogService.ConfirmAsync(
"Delete item?",
"This action cannot be undone.",
new ConfirmDialogOptions
Expand All @@ -682,6 +764,102 @@
Destructive = true
});

confirmResult = confirmed ? "Deleted!" : "Kept";
confirmResult = data.Confirmed ? "Deleted!" : "Kept";
}

private async Task HandleAlert()
{
alertStatus = "Waiting...";
await DialogService.AlertAsync(
"Session Expired",
"Please log in again.");

alertStatus = "Acknowledged";
}

private async Task HandlePrompt()
{
var name = await DialogService.PromptAsync(
"Rename File",
"Enter a new file name:",
new PromptDialogOptions
{
DefaultValue = "document.txt",
Placeholder = "file-name.txt",
Required = true,
MaxLength = 50
});

promptResult = name.Value ?? "Cancelled";
}

private async Task HandleCustomDialog()
{
var result = await DialogService.OpenAsync<EditUserDemoComponent>(
new Dictionary<string, object?>
{
["UserId"] = 42
},
new DialogOpenOptions
{
Title = "Edit User",
Size = DialogSize.Large
});

if (!result.Cancelled)
{
var data = result.GetData<UserDto>();
customResult = $"Saved: {data}";
}
else
{
customResult = "Cancelled";
}
}

public sealed class EditUserDemoComponent : ComponentBase
{
[Parameter] public int UserId { get; set; }

[CascadingParameter]
public IDialogReference DialogRef { get; set; } = default!;

private string? userName;
private string? userEmail;

protected override void OnInitialized()
{
// Simulate loading user data
userName = $"User {UserId}";
userEmail = "example@company.com";
}

private Task Save()
{
var dto = new UserDto(
UserId,
userName ?? string.Empty,
userEmail ?? string.Empty);

return DialogRef.CloseAsync(DialogResult.Ok(dto));
}

private Task Cancel()
=> DialogRef.CancelAsync();

protected override void BuildRenderTree(Microsoft.AspNetCore.Components.Rendering.RenderTreeBuilder __builder)
{
<div class="space-y-4">
<div>Editing User @UserId</div>
<BbInput @bind-Value="userName" Placeholder="Name" />
<BbInput @bind-Value="userEmail" Placeholder="Email" Type="InputType.Email" />
<div class="flex justify-end gap-2">
<BbButton Variant="ButtonVariant.Outline" OnClick="Cancel">Cancel</BbButton>
<BbButton OnClick="Save">Save</BbButton>
</div>
</div>
}
}

public sealed record UserDto(int Id, string Name, string Email);
}
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ public partial class BbBar : SeriesBase
/// Gets or sets the position of the data label relative to the bar.
/// </summary>
/// <remarks>
/// Default is <see cref="Components.LabelPosition.Top"/> for vertical bars.
/// Default is <see cref="LabelPosition.Top"/> for vertical bars.
/// </remarks>
[Parameter]
public LabelPosition LabelPosition { get; set; } = LabelPosition.Top;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ public partial class BbPie : SeriesBase
/// Gets or sets the label position relative to pie slices.
/// </summary>
/// <remarks>
/// Default is <see cref="Components.LabelPosition.Outside"/>. Use <see cref="Components.LabelPosition.Inside"/>
/// Default is <see cref="LabelPosition.Outside"/>. Use <see cref="LabelPosition.Inside"/>
/// to render labels within slice areas.
/// </remarks>
[Parameter]
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
namespace BlazorBlueprint.Components;

/// <summary>
/// Represents a pending alert dialog managed by <see cref="DialogService"/>.
/// </summary>
/// <remarks>
/// An alert dialog presents a message with a single acknowledgment button.
/// It resolves with a confirmed <see cref="DialogResult"/> when dismissed.
/// </remarks>
public sealed class AlertDialogData : DialogData
{
/// <summary>
/// Gets or sets the customization options for the alert dialog.
/// </summary>
public AlertDialogOptions Options { get; set; } = new();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
namespace BlazorBlueprint.Components;

/// <summary>
/// Options for customizing an alert dialog shown via <see cref="DialogService"/>.
/// </summary>
public sealed class AlertDialogOptions
{
/// <summary>
/// The label for the acknowledgment button.
/// Default: "OK".
/// </summary>
public string ButtonText { get; set; } = "OK";
}
Loading