Add D-prefixed Blazor wrappers for every daisyUI 5 component

Components/Daisy/ wraps all 69 components in daisyUI's llms.txt, grouped by
daisyUI's categories (Actions, DataDisplay, Navigation, Feedback, DataInput,
Layout, Mockup), with part components where daisyUI has repeating parts (DTab,
DMenuItem, DTimelineItem, ...).
- Each enum maps to whole literal class names in a switch, so Tailwind's scanner
  generates them. Nothing is concatenated.
- Value-holding fields derive from DInputBase<TValue>, Blazor's InputBase, so
  @bind-Value and EditForm validation work. Invalid fields get the component's
  *-error class.
- Open and active state lives in C# (@bind-IsOpen, @bind-Active) and is rendered
  with daisyUI's *-open modifiers. DDropdown adds an outside-click layer and
  Escape. No component uses JS interop.
- The one exception is DCalendar, which wraps the Cally web component, vendored
  as wwwroot/vendor/cally.js (0.9.2, MIT).

/styleguide (not linked) renders every component in all its colours, sizes and
states, with a theme and hue picker that previews without saving.

neo.css follows what the styleguide showed:
- select keeps daisyUI's arrow;
- skeleton-text isn't sunk;
- the phone mockup and dock are raised;
- active menu items and OTP digits are inset;
- a joined accordion is raised as one block.
The primary, secondary and accent colours are deeper, so they still read as
text.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LsXgEaXee4GCU1hwYgPJXw
This commit is contained in:
thepraandClaude Opus 5.5 committed 2026-10-03 12:01:42 +02:00
1 parent 8e03d12a3e
commit 90e4b9200c
127 files changed
+6962 -17

No files matched your search

+44
View File
@@ -0,0 +1,44 @@
@inherits DComponentBase
@* daisyUI Alert: https://daisyui.com/components/alert/ . The alert is a grid of up to three cells: Icon, ChildContent
(wrapped in one <div>, so a heading plus text stays one cell) and Actions. role="alert" comes before the splatted
attributes, so a consumer can pass role="status" for a non-urgent message. *@
<div role="alert" @attributes="AdditionalAttributes" class="@CssClass">
@Icon
<div>@ChildContent</div>
@if (Actions is not null)
{
<div class="flex gap-2">@Actions</div>
}
</div>
@code {
[Parameter] public RenderFragment Icon { get; set; }
[Parameter] public RenderFragment ChildContent { get; set; }
[Parameter] public RenderFragment Actions { get; set; }
[Parameter] public DAlertColor Color { get; set; }
[Parameter] public DAlertVariant Variant { get; set; }
[Parameter] public DDirection Direction { get; set; }
/// <summary>Vertical on small screens, horizontal from sm up (alert-vertical sm:alert-horizontal).</summary>
[Parameter] public bool Responsive { get; set; }
string CssClass => Cx("alert", ColorClass, VariantClass,
Direction == DDirection.Vertical || Responsive ? "alert-vertical" : null, Responsive ? "sm:alert-horizontal" : null, Class);
string ColorClass => Color switch
{
DAlertColor.Info => "alert-info",
DAlertColor.Success => "alert-success",
DAlertColor.Warning => "alert-warning",
DAlertColor.Error => "alert-error",
_ => null
};
string VariantClass => Variant switch
{
DAlertVariant.Outline => "alert-outline",
DAlertVariant.Dash => "alert-dash",
DAlertVariant.Soft => "alert-soft",
_ => null
};
}
+19
View File
@@ -0,0 +1,19 @@
namespace decePubClient.Components.Daisy.Feedback;
/// <summary>daisyUI's alert colours; there is no neutral/primary/secondary/accent alert, hence not DColor.</summary>
public enum DAlertColor
{
Default,
Info,
Success,
Warning,
Error
}
public enum DAlertVariant
{
Default,
Outline,
Dash,
Soft
}
+47
View File
@@ -0,0 +1,47 @@
@inherits DComponentBase
@* daisyUI Loading: https://daisyui.com/components/loading/ . It is drawn in currentColor, so Color maps to text-*
classes. role="status" and aria-label come before the splatted attributes, so a consumer can override them. *@
<span role="status" aria-label="@LabelText" @attributes="AdditionalAttributes" class="@CssClass"></span>
@code {
[Parameter] public DLoadingVariant Variant { get; set; }
[Parameter] public DSize Size { get; set; }
[Parameter] public DColor Color { get; set; }
/// <summary>What screen readers announce (aria-label).</summary>
[Parameter] public string LabelText { get; set; } = "Loading";
string CssClass => Cx("loading", VariantClass, SizeClass, ColorClass, Class);
string VariantClass => Variant switch
{
DLoadingVariant.Dots => "loading-dots",
DLoadingVariant.Ring => "loading-ring",
DLoadingVariant.Ball => "loading-ball",
DLoadingVariant.Bars => "loading-bars",
DLoadingVariant.Infinity => "loading-infinity",
_ => null
};
string SizeClass => Size switch
{
DSize.Xs => "loading-xs",
DSize.Sm => "loading-sm",
DSize.Lg => "loading-lg",
DSize.Xl => "loading-xl",
_ => null
};
string ColorClass => Color switch
{
DColor.Neutral => "text-neutral",
DColor.Primary => "text-primary",
DColor.Secondary => "text-secondary",
DColor.Accent => "text-accent",
DColor.Info => "text-info",
DColor.Success => "text-success",
DColor.Warning => "text-warning",
DColor.Error => "text-error",
_ => null
};
}
@@ -0,0 +1,12 @@
namespace decePubClient.Components.Daisy.Feedback;
/// <summary>The animation; Spinner is what a bare loading class draws.</summary>
public enum DLoadingVariant
{
Spinner,
Dots,
Ring,
Ball,
Bars,
Infinity
}
+30
View File
@@ -0,0 +1,30 @@
@using System.Globalization
@inherits DComponentBase
@* daisyUI Progress: https://daisyui.com/components/progress/ . A null Value leaves out the value attribute, which makes
the bar indeterminate (animated). Numbers are written with the invariant culture. The width comes from class
(it is 100% by default). *@
<progress @attributes="AdditionalAttributes" class="@CssClass" value="@(Value?.ToString(CultureInfo.InvariantCulture))"
max="@(Max.ToString(CultureInfo.InvariantCulture))"></progress>
@code {
/// <summary>The progress, from 0 to Max; null shows an indeterminate bar.</summary>
[Parameter] public double? Value { get; set; }
[Parameter] public double Max { get; set; } = 100;
[Parameter] public DColor Color { get; set; }
string CssClass => Cx("progress", ColorClass, Class);
string ColorClass => Color switch
{
DColor.Neutral => "progress-neutral",
DColor.Primary => "progress-primary",
DColor.Secondary => "progress-secondary",
DColor.Accent => "progress-accent",
DColor.Info => "progress-info",
DColor.Success => "progress-success",
DColor.Warning => "progress-warning",
DColor.Error => "progress-error",
_ => null
};
}
@@ -0,0 +1,63 @@
@using System.Globalization
@inherits DComponentBase
@* daisyUI Radial progress: https://daisyui.com/components/radial-progress/ . Value/Max becomes a 0-100 percentage in
the --value style variable and aria-valuenow, and the default text; Diameter and Thickness set --size and
--thickness. A consumer's style is appended to those. It is drawn in currentColor, so Color maps to text-*. *@
<div @attributes="AdditionalAttributes" class="@CssClass" style="@StyleValue" role="progressbar"
aria-valuenow="@PercentText" aria-valuemin="0" aria-valuemax="100">
@if (ChildContent is null)
{
@($"{Math.Round(Percent)}%")
}
else
{
@ChildContent
}
</div>
@code {
[Parameter] public double Value { get; set; }
[Parameter] public double Max { get; set; } = 100;
[Parameter] public DColor Color { get; set; }
/// <summary>A CSS length for --size (daisyUI's default is 5rem).</summary>
[Parameter] public string Diameter { get; set; }
/// <summary>A CSS length for --thickness (daisyUI's default is a tenth of the size).</summary>
[Parameter] public string Thickness { get; set; }
/// <summary>Replaces the default "NN%" text.</summary>
[Parameter] public RenderFragment ChildContent { get; set; }
double Percent => Max > 0 ? Math.Clamp(Value / Max * 100, 0, 100) : 0;
string PercentText => Math.Round(Percent, 2).ToString(CultureInfo.InvariantCulture);
string StyleValue
{
get
{
var style = $"--value:{PercentText};";
if (!string.IsNullOrEmpty(Diameter))
style += $" --size:{Diameter};";
if (!string.IsNullOrEmpty(Thickness))
style += $" --thickness:{Thickness};";
if (AdditionalAttributes != null && AdditionalAttributes.TryGetValue("style", out var extra) && extra is not null)
style += " " + extra;
return style;
}
}
string CssClass => Cx("radial-progress", ColorClass, Class);
string ColorClass => Color switch
{
DColor.Neutral => "text-neutral",
DColor.Primary => "text-primary",
DColor.Secondary => "text-secondary",
DColor.Accent => "text-accent",
DColor.Info => "text-info",
DColor.Success => "text-success",
DColor.Warning => "text-warning",
DColor.Error => "text-error",
_ => null
};
}
+13
View File
@@ -0,0 +1,13 @@
@inherits DComponentBase
@* daisyUI Skeleton: https://daisyui.com/components/skeleton/ . Size it with h-* / w-* classes; IsText (skeleton-text)
animates ChildContent's text instead of drawing a block. *@
<div @attributes="AdditionalAttributes" class="@Cx("skeleton", IsText ? "skeleton-text" : null, Class)">
@ChildContent
</div>
@code {
[Parameter] public RenderFragment ChildContent { get; set; }
/// <summary>Shimmer the text in ChildContent (skeleton-text) rather than a filled block.</summary>
[Parameter] public bool IsText { get; set; }
}
+29
View File
@@ -0,0 +1,29 @@
@inherits DComponentBase
@* daisyUI Toast: https://daisyui.com/components/toast/ . A fixed-position stack (ChildContent, usually DAlerts) in a
corner or edge of the viewport; End/Bottom is daisyUI's default and adds no class. *@
<div @attributes="AdditionalAttributes" class="@CssClass">
@ChildContent
</div>
@code {
[Parameter] public RenderFragment ChildContent { get; set; }
[Parameter] public DToastHorizontal Horizontal { get; set; }
[Parameter] public DToastVertical Vertical { get; set; }
string CssClass => Cx("toast", HorizontalClass, VerticalClass, Class);
string HorizontalClass => Horizontal switch
{
DToastHorizontal.Start => "toast-start",
DToastHorizontal.Center => "toast-center",
_ => null
};
string VerticalClass => Vertical switch
{
DToastVertical.Top => "toast-top",
DToastVertical.Middle => "toast-middle",
_ => null
};
}
+17
View File
@@ -0,0 +1,17 @@
namespace decePubClient.Components.Daisy.Feedback;
/// <summary>Where the toast sits horizontally; End is daisyUI's default.</summary>
public enum DToastHorizontal
{
End,
Start,
Center
}
/// <summary>Where the toast sits vertically; Bottom is daisyUI's default.</summary>
public enum DToastVertical
{
Bottom,
Top,
Middle
}
+51
View File
@@ -0,0 +1,51 @@
@inherits DComponentBase
@* daisyUI Tooltip: https://daisyui.com/components/tooltip/ . Shows on hover or keyboard focus of ChildContent: Tip
sets data-tip, or TipContent renders a tooltip-content part for markup. IsOpen keeps it shown (tooltip-open). *@
<div @attributes="AdditionalAttributes" class="@CssClass" data-tip="@Tip">
@if (TipContent is not null)
{
<div class="tooltip-content">@TipContent</div>
}
@ChildContent
</div>
@code {
[Parameter] public RenderFragment ChildContent { get; set; }
[Parameter] public string Tip { get; set; }
[Parameter] public RenderFragment TipContent { get; set; }
[Parameter] public DTooltipPlacement Placement { get; set; }
[Parameter] public DTooltipAlign Align { get; set; }
/// <summary>Neutral is the default look; daisyUI has no tooltip-neutral.</summary>
[Parameter] public DColor Color { get; set; }
[Parameter] public bool IsOpen { get; set; }
string CssClass => Cx("tooltip", PlacementClass, AlignClass, ColorClass, IsOpen ? "tooltip-open" : null, Class);
string PlacementClass => Placement switch
{
DTooltipPlacement.Bottom => "tooltip-bottom",
DTooltipPlacement.Left => "tooltip-left",
DTooltipPlacement.Right => "tooltip-right",
_ => null
};
string AlignClass => Align switch
{
DTooltipAlign.Start => "tooltip-start",
DTooltipAlign.End => "tooltip-end",
_ => null
};
string ColorClass => Color switch
{
DColor.Primary => "tooltip-primary",
DColor.Secondary => "tooltip-secondary",
DColor.Accent => "tooltip-accent",
DColor.Info => "tooltip-info",
DColor.Success => "tooltip-success",
DColor.Warning => "tooltip-warning",
DColor.Error => "tooltip-error",
_ => null
};
}
@@ -0,0 +1,18 @@
namespace decePubClient.Components.Daisy.Feedback;
/// <summary>Which side of the element the tooltip shows on; Top is daisyUI's default.</summary>
public enum DTooltipPlacement
{
Top,
Bottom,
Left,
Right
}
/// <summary>How the tooltip lines up with the element along that side; Center is daisyUI's default.</summary>
public enum DTooltipAlign
{
Center,
Start,
End
}