Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
14 changes: 14 additions & 0 deletions PanoramicData.Blazor.Demo/Pages/PDComboBoxDocumentation.razor
Original file line number Diff line number Diff line change
Expand Up @@ -49,4 +49,18 @@
</table>
</section>

<section id="colours">
<h2 class="doc-section">Colours</h2>
<p>
The box's focus ring comes from CSS variables, beside the existing <code>--pdcb-*</code> colours, so a host
can match it to its theme on <code>:root</code> or on a theme class.
</p>
<table class="table table-sm doc-props-table">
<thead><tr><th>Variable</th><th>Default</th><th>Description</th></tr></thead>
<tbody>
<tr><td><code>--pdcb-focus-border</code></td><td><code>#007bff</code></td><td>The input's border while it has focus</td></tr>
<tr><td><code>--pdcb-focus-ring</code></td><td><code>rgba(0, 123, 255, 0.25)</code></td><td>The glow around the input while it has focus</td></tr>
</tbody>
</table>
</section>
</div>
18 changes: 18 additions & 0 deletions PanoramicData.Blazor.Demo/Pages/PDContextMenuDocumentation.razor
Original file line number Diff line number Diff line change
Expand Up @@ -59,4 +59,22 @@
</table>
</section>

<section id="colours">
<h2 class="doc-section">Colours</h2>
<p>
The menu's colours come from CSS variables, so a host can set them on <code>:root</code> or on a theme class.
Without them the menu is light, or dark under Bootstrap 5.3's <code>data-bs-theme="dark"</code>; a host's
variables win in both.
</p>
<table class="table table-sm doc-props-table">
<thead><tr><th>Variable</th><th>Default</th><th>Description</th></tr></thead>
<tbody>
<tr><td><code>--pd-contextmenu-bg</code></td><td><code>#fff</code></td><td>The items' and separators' background</td></tr>
<tr><td><code>--pd-contextmenu-color</code></td><td><code>inherit</code></td><td>The items' text</td></tr>
<tr><td><code>--pd-contextmenu-hover-bg</code></td><td><code>#eee</code></td><td>The item under the pointer</td></tr>
<tr><td><code>--pd-contextmenu-border-color</code></td><td><code>rgba(0,0,0,.125)</code></td><td>The menu's edges and the separator lines</td></tr>
<tr><td><code>--pd-contextmenu-disabled-color</code></td><td><code>#6c757d</code></td><td>A disabled item's text</td></tr>
</tbody>
</table>
</section>
</div>
13 changes: 13 additions & 0 deletions PanoramicData.Blazor.Demo/Pages/PDFormDocumentation.razor
Original file line number Diff line number Diff line change
Expand Up @@ -211,4 +211,17 @@
</table>
</section>

<section id="colours">
<h2 class="doc-section">Colours</h2>
<p>
The frame around each field's editor comes from a CSS variable, so a host can match it to its own control
borders on <code>:root</code> or on a theme class, for example on a dark theme.
</p>
<table class="table table-sm doc-props-table">
<thead><tr><th>Variable</th><th>Default</th><th>Description</th></tr></thead>
<tbody>
<tr><td><code>--pd-form-editor-border-color</code></td><td><code>#ced4da</code></td><td>The border around a field's editor, to the right of its label</td></tr>
</tbody>
</table>
</section>
</div>
17 changes: 17 additions & 0 deletions PanoramicData.Blazor.Demo/Pages/PDTreeDocumentation.razor
Original file line number Diff line number Diff line change
Expand Up @@ -203,4 +203,21 @@
</table>
</section>

<section id="colours">
<h2 class="doc-section">Colours</h2>
<p>
A node's selection and shape come from CSS variables, so a host can set them on <code>:root</code> or on a
theme class. The hover and the selection share the shape, so rounding one rounds both. For example,
<code>body.theme-dark { --pd-tree-selected-bg: #2a3a5c; --pd-tree-node-radius: 0.25em; }</code>.
</p>
<table class="table table-sm doc-props-table">
<thead><tr><th>Variable</th><th>Default</th><th>Description</th></tr></thead>
<tbody>
<tr><td><code>--pd-tree-selected-bg</code></td><td><code>#007bff</code></td><td>The selected node's background</td></tr>
<tr><td><code>--pd-tree-selected-color</code></td><td><code>inherit</code></td><td>The selected node's text</td></tr>
<tr><td><code>--pd-tree-node-radius</code></td><td><code>0</code></td><td>The corner radius of a node's hover and selection</td></tr>
<tr><td><code>--pd-tree-node-inset-end</code></td><td><code>0</code></td><td>The gap between a node's hover and selection and the end of the tree, so rounded corners stay clear of the panel's edge</td></tr>
</tbody>
</table>
</section>
</div>
46 changes: 46 additions & 0 deletions PanoramicData.Blazor.Test/ThemeVariableStylesheetTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
using AwesomeAssertions;

namespace PanoramicData.Blazor.Test;

/// <summary>
/// The tree, combo box and context menu take their colours from CSS variables a host can set, and each default is the
/// colour the component had before, so a host that sets nothing sees no change.
/// </summary>
public class ThemeVariableStylesheetTests
{
/// <summary>Each themable colour reads its variable, falling back to the component's original colour.</summary>
/// <param name="stylesheet">The component stylesheet.</param>
/// <param name="declaration">The declaration it must contain.</param>
[Theory]
[InlineData("PDTreeNode.razor.css", "background-color: var(--pd-tree-selected-bg, #007bff);")]
[InlineData("PDTreeNode.razor.css", "color: var(--pd-tree-selected-color, inherit);")]
[InlineData("PDTreeNode.razor.css", "margin-right: var(--pd-tree-node-inset-end, 0);")]
[InlineData("PDTreeNode.razor.css", "border-radius: var(--pd-tree-node-radius, 0);")]
[InlineData("PDComboBox.razor.css", "border-color: var(--pdcb-focus-border, #007bff);")]
[InlineData("PDComboBox.razor.css", "box-shadow: 0 0 0 0.2rem var(--pdcb-focus-ring, rgba(0, 123, 255, 0.25));")]
[InlineData("PDContextMenu.razor.css", "background-color: var(--pd-contextmenu-bg, #fff);")]
[InlineData("PDContextMenu.razor.css", "background-color: var(--pd-contextmenu-hover-bg, #eee);")]
[InlineData("PDContextMenu.razor.css", "color: var(--pd-contextmenu-disabled-color, #6c757d);")]
[InlineData("PDContextMenu.razor.css", "border-bottom: 1px solid var(--pd-contextmenu-border-color, rgba(0,0,0,.125));")]
[InlineData("PDFormFieldEditor.razor.css", "border-top: 1px solid var(--pd-form-editor-border-color, #ced4da);")]
public void A_colour_reads_its_variable_with_the_original_default(string stylesheet, string declaration)
=> Read(stylesheet).Should().Contain(declaration);

/// <summary>No colour in the context menu's stylesheet is fixed, so a host can theme the whole menu.</summary>
[Fact]
public void Every_context_menu_colour_reads_a_variable()
{
var colourLines = Read("PDContextMenu.razor.css")
.Split('\n')
.Select(line => line.Trim())
.Where(line => line.StartsWith("background-color:", StringComparison.Ordinal)
|| line.StartsWith("color:", StringComparison.Ordinal)
|| line.StartsWith("border-color:", StringComparison.Ordinal)
|| (line.StartsWith("border", StringComparison.Ordinal) && line.Contains("solid", StringComparison.Ordinal)));

colourLines.Should().NotBeEmpty().And.AllSatisfy(line => line.Should().Contain("var(--pd-contextmenu-"));
}

private static string Read(string stylesheet)
=> File.ReadAllText(Path.Combine(PackagingGuardTests.RepositoryRoot, "PanoramicData.Blazor", stylesheet));
}
4 changes: 2 additions & 2 deletions PanoramicData.Blazor/PDComboBox.razor.css
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@
}

.pd-combobox .combo-input:focus {
border-color: #007bff;
box-shadow: 0 0 0 0.2rem rgba(0, 123, 255, 0.25);
border-color: var(--pdcb-focus-border, #007bff);
box-shadow: 0 0 0 0.2rem var(--pdcb-focus-ring, rgba(0, 123, 255, 0.25));
}

.pd-combobox .combo-dropdown {
Expand Down
52 changes: 27 additions & 25 deletions PanoramicData.Blazor/PDContextMenu.razor.css
Original file line number Diff line number Diff line change
Expand Up @@ -24,76 +24,78 @@
display: flex;
}

/* Colours come from variables a host can set, for example on a theme class; the defaults are the original light ones */
.pdcontextmenuitem {
background-color: #fff;
background-color: var(--pd-contextmenu-bg, #fff);
color: var(--pd-contextmenu-color, inherit);
padding: .25rem .50rem;
border-left: 1px solid rgba(0,0,0,.125);
border-right: 1px solid rgba(0,0,0,.125);
border-left: 1px solid var(--pd-contextmenu-border-color, rgba(0,0,0,.125));
border-right: 1px solid var(--pd-contextmenu-border-color, rgba(0,0,0,.125));
cursor: pointer;
}

.pdcontextmenuitem.disabled {
color: #6c757d;
color: var(--pd-contextmenu-disabled-color, #6c757d);
pointer-events: none;
background-color: #fff;
background-color: var(--pd-contextmenu-bg, #fff);
}

.pdcontextmenu.disabled:hover {
background-color: #fff;
background-color: var(--pd-contextmenu-bg, #fff);
}

.pdcontextmenuitem:first-child {
border-top: 1px solid rgba(0,0,0,.125);
border-top: 1px solid var(--pd-contextmenu-border-color, rgba(0,0,0,.125));
border-top-left-radius: .25rem;
border-top-right-radius: .25rem;
}

.pdcontextmenuitem:last-child {
border-bottom: 1px solid rgba(0,0,0,.125);
border-bottom: 1px solid var(--pd-contextmenu-border-color, rgba(0,0,0,.125));
border-bottom-left-radius: .25rem;
border-bottom-right-radius: .25rem;
}

.pdcontextmenuitem:hover {
background-color: #eee;
background-color: var(--pd-contextmenu-hover-bg, #eee);
}

.pdcontextmenuseparator {
background-color: #fff;
border-bottom: 1px solid rgba(0,0,0,.125);
border-left: 1px solid rgba(0,0,0,.125);
border-right: 1px solid rgba(0,0,0,.125);
background-color: var(--pd-contextmenu-bg, #fff);
border-bottom: 1px solid var(--pd-contextmenu-border-color, rgba(0,0,0,.125));
border-left: 1px solid var(--pd-contextmenu-border-color, rgba(0,0,0,.125));
border-right: 1px solid var(--pd-contextmenu-border-color, rgba(0,0,0,.125));
}

/* Dark mode support for Bootstrap 5.3+ */
/* Dark mode support for Bootstrap 5.3+; the same variables still win when a host sets them */
[data-bs-theme="dark"] .pdcontextmenuitem {
background-color: #2b2f33;
border-color: rgba(255, 255, 255, 0.15);
color: #e9ecef;
background-color: var(--pd-contextmenu-bg, #2b2f33);
border-color: var(--pd-contextmenu-border-color, rgba(255, 255, 255, 0.15));
color: var(--pd-contextmenu-color, #e9ecef);
}

[data-bs-theme="dark"] .pdcontextmenuitem.disabled {
color: #6c757d;
background-color: #2b2f33;
color: var(--pd-contextmenu-disabled-color, #6c757d);
background-color: var(--pd-contextmenu-bg, #2b2f33);
}

[data-bs-theme="dark"] .pdcontextmenu.disabled:hover {
background-color: #2b2f33;
background-color: var(--pd-contextmenu-bg, #2b2f33);
}

[data-bs-theme="dark"] .pdcontextmenuitem:first-child {
border-top-color: rgba(255, 255, 255, 0.15);
border-top-color: var(--pd-contextmenu-border-color, rgba(255, 255, 255, 0.15));
}

[data-bs-theme="dark"] .pdcontextmenuitem:last-child {
border-bottom-color: rgba(255, 255, 255, 0.15);
border-bottom-color: var(--pd-contextmenu-border-color, rgba(255, 255, 255, 0.15));
}

[data-bs-theme="dark"] .pdcontextmenuitem:hover {
background-color: #343a40;
background-color: var(--pd-contextmenu-hover-bg, #343a40);
}

[data-bs-theme="dark"] .pdcontextmenuseparator {
background-color: #2b2f33;
border-color: rgba(255, 255, 255, 0.15);
background-color: var(--pd-contextmenu-bg, #2b2f33);
border-color: var(--pd-contextmenu-border-color, rgba(255, 255, 255, 0.15));
}
7 changes: 4 additions & 3 deletions PanoramicData.Blazor/PDFormFieldEditor.razor.css
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
/* The frame around a field's editor; a host can match it to its own control borders */
.editor {
align-items: center;
border-bottom: 1px solid #ced4da;
border-top: 1px solid #ced4da;
border-right: 1px solid #ced4da;
border-bottom: 1px solid var(--pd-form-editor-border-color, #ced4da);
border-top: 1px solid var(--pd-form-editor-border-color, #ced4da);
border-right: 1px solid var(--pd-form-editor-border-color, #ced4da);
display: flex;
flex: 1 1;
padding: 0 2px;
Expand Down
6 changes: 5 additions & 1 deletion PanoramicData.Blazor/PDTreeNode.razor.css
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@
}

.pdtreenode .selected {
background-color: #007bff;
background-color: var(--pd-tree-selected-bg, #007bff);
color: var(--pd-tree-selected-color, inherit);
}

.pdtreenode .pdtreenode_child_content {
Expand All @@ -18,10 +19,13 @@
white-space: nowrap;
}

/* The hover and the selection share this shape, so a host can round both and keep them clear of the panel's edge */
.pdtreenode .pdtreenode_header .pdtreenode_content {
width: 100%;
padding-left: 3px;
margin-left: 3px;
margin-right: var(--pd-tree-node-inset-end, 0);
border-radius: var(--pd-tree-node-radius, 0);
}

.pdtreenode .pdtreenode_content:not(.selected):hover {
Expand Down
Loading