diff --git a/src/BlazorUI/Bit.BlazorUI.Extras/Components/DataGrid/BitDataGrid.scss b/src/BlazorUI/Bit.BlazorUI.Extras/Components/DataGrid/BitDataGrid.scss index 13682a615e7..2756176927e 100644 --- a/src/BlazorUI/Bit.BlazorUI.Extras/Components/DataGrid/BitDataGrid.scss +++ b/src/BlazorUI/Bit.BlazorUI.Extras/Components/DataGrid/BitDataGrid.scss @@ -33,6 +33,7 @@ // --bit-DataGrid-detail-background background of the expanded detail rows (default: $clr-bg-sec) // --bit-DataGrid-footer-background background of the footer row (default: $clr-bg-sec) // --bit-DataGrid-disabled-color text color of a disabled grid (default: $clr-fg-dis) +// --bit-DataGrid-placeholder-color placeholder of the search and filter boxes (default: $clr-fg-sec) // The row height is the RowHeight parameter (it also drives virtualization); the cell padding and the line height // set the density around it. @@ -783,6 +784,15 @@ button.bit-dtg-htext { cursor: default; } +.bit-dtg-search-input, +.bit-dtg-filter-input { + @include input-placeholder(var(--bit-DataGrid-placeholder-color, #{$clr-fg-sec})); + + &:disabled { + @include input-placeholder(var(--bit-DataGrid-disabled-color, #{$clr-fg-dis})); + } +} + /* Touch drag-and-drop: without touch-action none the browser turns the drag into a scroll and fires pointercancel. Scoped to the drag handle and to header cells that are actually reorderable (data-col is only rendered on those), so touch scrolling elsewhere is unaffected. */ diff --git a/src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFullCalendar.scss b/src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFullCalendar.scss index 491e005df31..2f1c0702b2b 100644 --- a/src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFullCalendar.scss +++ b/src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFullCalendar.scss @@ -9,7 +9,7 @@ // --bit-FullCalendar-secondary-background tab strips, the day-view sidebar, sticky titles, the timeline gutter // --bit-FullCalendar-hover-background a hovered cell, slot, row or control // --bit-FullCalendar-color text -// --bit-FullCalendar-secondary-color weekday headers, group titles, descriptions +// --bit-FullCalendar-secondary-color weekday headers, group titles, descriptions, placeholders // --bit-FullCalendar-muted-color hour labels, week numbers, days of the neighbouring months // --bit-FullCalendar-border-color grid lines and the border of the calendar // --bit-FullCalendar-control-border-color edges of the fields, selects, search box and switch tracks @@ -1337,6 +1337,7 @@ $bfc-private-properties: evt-color; color: var(--bit-bfc-text); font-size: $tg-fs-sm; outline: none; + @include input-placeholder(var(--bit-bfc-text-secondary)); } .bit-bfc-agenda-search input:focus { @@ -1604,6 +1605,7 @@ $bfc-private-properties: evt-color; font-size: $tg-fs-sm; outline: none; box-sizing: border-box; + @include input-placeholder(var(--bit-bfc-text-secondary)); } .bit-bfc-field input:focus, diff --git a/src/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownEditor/BitMarkdownEditor.scss b/src/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownEditor/BitMarkdownEditor.scss index 9f82c7c1ab2..afc38fe780c 100644 --- a/src/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownEditor/BitMarkdownEditor.scss +++ b/src/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownEditor/BitMarkdownEditor.scss @@ -19,7 +19,7 @@ // --bit-MarkdownEditor-font-size font size of the textarea (default: $tg-fs-sm) // --bit-MarkdownEditor-line-height line height of the textarea (default: 1.6) // --bit-MarkdownEditor-padding padding of the textarea (default: spacing(1.5) spacing(1.75)) -// --bit-MarkdownEditor-placeholder-color placeholder of the textarea (default: $clr-fg-sec) +// --bit-MarkdownEditor-placeholder-color placeholder of the textarea and the find box (default: $clr-fg-sec) // --bit-MarkdownEditor-label-color text of the label (default: --bit-MarkdownEditor-color) // --bit-MarkdownEditor-label-font-size size of the label (default: $tg-fs-sm) // --bit-MarkdownEditor-label-font-weight weight of the label (default: $tg-field-label-font-weight) @@ -140,6 +140,10 @@ $mde-button-active-background: var(--bit-MarkdownEditor-button-active-background color: $clr-fg-dis; } + .bit-mde-txa { + @include input-placeholder($clr-fg-dis); + } + .bit-mde-lbl { cursor: default; } @@ -341,6 +345,7 @@ $mde-button-active-background: var(--bit-MarkdownEditor-button-active-background padding: $siz-ctrl-pad-y-sm $siz-ctrl-pad-x-sm; border-radius: $shp-radius-control; border: $shp-border-width $shp-border-style $clr-brd-pri; + @include input-placeholder(var(--bit-MarkdownEditor-placeholder-color, #{$clr-fg-sec})); &:focus-visible { @include mde-inset-ring; @@ -484,10 +489,7 @@ $mde-button-active-background: var(--bit-MarkdownEditor-button-active-background padding: var(--bit-MarkdownEditor-padding, #{spacing(1.5) spacing(1.75)}); font-family: var(--bit-MarkdownEditor-font-family, #{$tg-font-family-mono}); - &::placeholder { - opacity: 1; - color: var(--bit-MarkdownEditor-placeholder-color, #{$clr-fg-sec}); - } + @include input-placeholder(var(--bit-MarkdownEditor-placeholder-color, #{$clr-fg-sec})); // The textarea fills its pane, so an inset ring keeps the keyboard // focus indicator visible instead of being clipped by the container. diff --git a/src/BlazorUI/Bit.BlazorUI.Extras/Components/PdfViewer/BitPdfViewer.scss b/src/BlazorUI/Bit.BlazorUI.Extras/Components/PdfViewer/BitPdfViewer.scss index b5a3452f1f2..cc71cf8b49e 100644 --- a/src/BlazorUI/Bit.BlazorUI.Extras/Components/PdfViewer/BitPdfViewer.scss +++ b/src/BlazorUI/Bit.BlazorUI.Extras/Components/PdfViewer/BitPdfViewer.scss @@ -23,6 +23,7 @@ // --bit-PdfViewer-button-active-hover-background ... under the pointer (default: $clr-pri-hover) // --bit-PdfViewer-field-background the page box, find box and dropdowns (default: $clr-bg-pri) // --bit-PdfViewer-field-border-color ... their border (default: $clr-brd-pri) +// --bit-PdfViewer-field-placeholder-color ... the placeholder of the find box (default: $clr-fg-sec) // --bit-PdfViewer-sidebar-background background of the side panels (default: $clr-bg-sec) // --bit-PdfViewer-sidebar-width width of the bookmarks/attachments/layers panel (default: spacing(29)) // --bit-PdfViewer-item-hover-background a sidebar row under the pointer (default: $clr-bg-sec-hover) @@ -55,6 +56,9 @@ $pdv-button-active-background: var(--bit-PdfViewer-button-active-background, #{$ $pdv-button-active-hover-background: var(--bit-PdfViewer-button-active-hover-background, #{$clr-pri-hover}); $pdv-field-background: var(--bit-PdfViewer-field-background, #{$clr-bg-pri}); $pdv-field-border: var(--bit-PdfViewer-field-border-color, #{$clr-brd-pri}); +// A field's, named with the field family rather than as the --bit--placeholder-color of the inputs: +// here a placeholder is also the page that has not painted yet (--bit-PdfViewer-placeholder-background). +$pdv-field-placeholder: var(--bit-PdfViewer-field-placeholder-color, #{$clr-fg-sec}); $pdv-sidebar-background: var(--bit-PdfViewer-sidebar-background, #{$clr-bg-sec}); $pdv-sidebar-width: var(--bit-PdfViewer-sidebar-width, #{spacing(29)}); $pdv-item-hover-background: var(--bit-PdfViewer-item-hover-background, #{$clr-bg-sec-hover}); @@ -299,9 +303,12 @@ $pdv-private-properties: scale; @include focus-ring($pdv-focus, 0); } + @include input-placeholder($pdv-field-placeholder); + &:disabled { cursor: default; color: $clr-fg-dis; + @include input-placeholder($clr-fg-dis); } } diff --git a/src/BlazorUI/Bit.BlazorUI.Extras/Components/PhoneInput/BitPhoneInput.scss b/src/BlazorUI/Bit.BlazorUI.Extras/Components/PhoneInput/BitPhoneInput.scss index ab61a30a68c..28972ac27b0 100644 --- a/src/BlazorUI/Bit.BlazorUI.Extras/Components/PhoneInput/BitPhoneInput.scss +++ b/src/BlazorUI/Bit.BlazorUI.Extras/Components/PhoneInput/BitPhoneInput.scss @@ -11,7 +11,7 @@ // --bit-PhoneInput-background fill of the field (default: $clr-bg-pri) // --bit-PhoneInput-color text of the number (default: $clr-fg-pri) // --bit-PhoneInput-placeholder-color placeholder of the number input, of the -// selector and of the search box (default: $clr-fg-ter) +// selector and of the search box (default: $clr-fg-sec) // --bit-PhoneInput-border-color frame at rest (default: $clr-brd-pri) // --bit-PhoneInput-hover-border-color frame under a pointer (default: $clr-brd-pri-hover) // --bit-PhoneInput-border-width thickness of the frame (default: $shp-border-width) @@ -127,7 +127,7 @@ $phi-private-properties: sz-fs, sz-h, sz-pad, sz-icon, sz-itm-h, role-main, role --bit-phi-brd: var(--bit-phi-kind-brd, var(--bit-phi-role-main, var(--bit-PhoneInput-border-color, #{$clr-brd-pri}))); --bit-phi-brd-hover: var(--bit-phi-kind-brd-hover, var(--bit-phi-role-main, var(--bit-PhoneInput-hover-border-color, #{$clr-brd-pri-hover}))); --bit-phi-focus: var(--bit-phi-role-focus, var(--bit-PhoneInput-focus-color)); - --bit-phi-plc: var(--bit-PhoneInput-placeholder-color, #{$clr-fg-ter}); + --bit-phi-plc: var(--bit-PhoneInput-placeholder-color, #{$clr-fg-sec}); --bit-phi-itm-clr: var(--bit-PhoneInput-item-color, #{$clr-fg-pri}); --bit-phi-itm-hover-bg: var(--bit-PhoneInput-item-hover-background, #{$clr-bg-pri-hover}); } @@ -315,9 +315,7 @@ $phi-private-properties: sz-fs, sz-h, sz-pad, sz-icon, sz-itm-h, role-main, role border-start-end-radius: var(--bit-phi-radius); border-end-end-radius: var(--bit-phi-radius); - &::placeholder { - color: var(--bit-phi-plc); - } + @include input-placeholder(var(--bit-phi-plc)); &:disabled { cursor: default; @@ -382,8 +380,8 @@ $phi-private-properties: sz-fs, sz-h, sz-pad, sz-icon, sz-itm-h, role-main, role opacity: $opa-dis; } - .bit-phi-inp::placeholder { - color: var(--bit-PhoneInput-disabled-color, #{$clr-fg-dis}); + .bit-phi-inp { + @include input-placeholder(var(--bit-PhoneInput-disabled-color, #{$clr-fg-dis})); } } @@ -466,10 +464,7 @@ $phi-private-properties: sz-fs, sz-h, sz-pad, sz-icon, sz-itm-h, role-main, role color: var(--bit-phi-itm-clr); letter-spacing: $tg-ctrl-letter-spacing; padding: spacing(1) spacing(1.5); - - &::placeholder { - color: var(--bit-phi-plc); - } + @include input-placeholder(var(--bit-phi-plc)); } .bit-phi-scn { diff --git a/src/BlazorUI/Bit.BlazorUI.Extras/Components/RichTextEditor/BitRichTextEditor.scss b/src/BlazorUI/Bit.BlazorUI.Extras/Components/RichTextEditor/BitRichTextEditor.scss index 4139de8936a..b51c23262bf 100644 --- a/src/BlazorUI/Bit.BlazorUI.Extras/Components/RichTextEditor/BitRichTextEditor.scss +++ b/src/BlazorUI/Bit.BlazorUI.Extras/Components/RichTextEditor/BitRichTextEditor.scss @@ -18,7 +18,8 @@ // --bit-RichTextEditor-font-family font of the content (default: inherit) // --bit-RichTextEditor-font-size font size of the content (default: inherit) // --bit-RichTextEditor-line-height line height of the content (default: 1.6) -// --bit-RichTextEditor-placeholder-color placeholder of the editing surface (default: $clr-fg-sec) +// --bit-RichTextEditor-placeholder-color placeholder of the editing surface and of the +// fields of its panels (default: $clr-fg-sec) // --bit-RichTextEditor-link-color links in the content (default: $clr-pri) // --bit-RichTextEditor-code-background code spans and code blocks (default: $clr-bg-sec) // --bit-RichTextEditor-quote-border-color leading rule of a block quote (default: $clr-brd-pri) @@ -76,6 +77,7 @@ $rte-rule-color: var(--bit-RichTextEditor-table-border-color, #{$clr-brd-pri}); height: $siz-ctrl-sm; border-radius: $shp-radius-control; border: $shp-border-width $shp-border-style $clr-brd-pri; + @include input-placeholder(var(--bit-RichTextEditor-placeholder-color, #{$clr-fg-sec})); &:focus-visible { @include focus-ring($rte-focus, 0); diff --git a/src/BlazorUI/Bit.BlazorUI/Components/Inputs/CircularTimePicker/BitCircularTimePicker.scss b/src/BlazorUI/Bit.BlazorUI/Components/Inputs/CircularTimePicker/BitCircularTimePicker.scss index ab78fcda8fc..603d18971cc 100644 --- a/src/BlazorUI/Bit.BlazorUI/Components/Inputs/CircularTimePicker/BitCircularTimePicker.scss +++ b/src/BlazorUI/Bit.BlazorUI/Components/Inputs/CircularTimePicker/BitCircularTimePicker.scss @@ -33,6 +33,7 @@ * --bit-CircularTimePicker-label-font-size label text size (default: $tg-fs-sm) * --bit-CircularTimePicker-input-background field background (default: $clr-bg-pri) * --bit-CircularTimePicker-input-color field foreground (default: $clr-fg-pri) + * --bit-CircularTimePicker-placeholder-color field placeholder (default: $clr-fg-sec) * --bit-CircularTimePicker-input-font-size field text size (default: $tg-fs-sm) * --bit-CircularTimePicker-input-height field height (default: $siz-ctrl-md) * --bit-CircularTimePicker-input-padding field padding (default: 0 spacing(1)) @@ -217,6 +218,7 @@ $ctp-private-properties: rl-clr, rl-text, rl-focus, inp-h, inp-fs, lbl-fs, clk-s cursor: default; color: var(--bit-ctp-clr-dis); background: none var(--bit-ctp-bg-dis); + @include input-placeholder(var(--bit-ctp-clr-dis)); } } } @@ -364,6 +366,7 @@ $ctp-private-properties: rl-clr, rl-text, rl-focus, inp-h, inp-fs, lbl-fs, clk-s font-family: $tg-font-family; font-size: var(--bit-ctp-inp-fs, var(--bit-CircularTimePicker-input-font-size, #{$tg-fs-sm})); color: var(--bit-CircularTimePicker-input-color, #{$clr-fg-pri}); + @include input-placeholder(var(--bit-CircularTimePicker-placeholder-color, #{$clr-fg-sec})); } .bit-ctp-ein { diff --git a/src/BlazorUI/Bit.BlazorUI/Components/Inputs/DatePicker/BitDatePicker.scss b/src/BlazorUI/Bit.BlazorUI/Components/Inputs/DatePicker/BitDatePicker.scss index 3f06f75a225..5cb0c66ab43 100644 --- a/src/BlazorUI/Bit.BlazorUI/Components/Inputs/DatePicker/BitDatePicker.scss +++ b/src/BlazorUI/Bit.BlazorUI/Components/Inputs/DatePicker/BitDatePicker.scss @@ -15,6 +15,7 @@ // --bit-DatePicker-input-height height of the field (default: $siz-ctrl-md) // --bit-DatePicker-input-font-size text size of the field (default: $tg-fs-sm) // --bit-DatePicker-input-color text color of the field (default: $clr-fg-pri) +// --bit-DatePicker-placeholder-color text color of the placeholder (default: $clr-fg-sec) // --bit-DatePicker-input-background background of the field (default: $clr-bg-pri) // --bit-DatePicker-input-border-color border color of the field at rest, which the // open and the invalid states override (default: $clr-brd-pri) @@ -155,6 +156,7 @@ $dtp-private-properties: clr, clr-txt, clr-hover, clr-active, clr-focus, inp-h-s cursor: default; color: var(--bit-DatePicker-disabled-color, #{$clr-fg-dis}); background: none $clr-bg-dis; + @include input-placeholder(var(--bit-DatePicker-disabled-color, #{$clr-fg-dis})); } .bit-dtp-pkt, @@ -320,6 +322,7 @@ $dtp-private-properties: clr, clr-txt, clr-hover, clr-active, clr-focus, inp-h-s background: none transparent; color: var(--bit-DatePicker-input-color, #{$clr-fg-pri}); font-family: $tg-font-family; + @include input-placeholder(var(--bit-DatePicker-placeholder-color, #{$clr-fg-sec})); } .bit-dtp-ein { diff --git a/src/BlazorUI/Bit.BlazorUI/Components/Inputs/DateRangePicker/BitDateRangePicker.scss b/src/BlazorUI/Bit.BlazorUI/Components/Inputs/DateRangePicker/BitDateRangePicker.scss index 7f4c0a17ca5..c0066973103 100644 --- a/src/BlazorUI/Bit.BlazorUI/Components/Inputs/DateRangePicker/BitDateRangePicker.scss +++ b/src/BlazorUI/Bit.BlazorUI/Components/Inputs/DateRangePicker/BitDateRangePicker.scss @@ -26,6 +26,7 @@ // --bit-DateRangePicker-input-height height of the field (default: $siz-ctrl-md) // --bit-DateRangePicker-input-font-size text size of the field (default: $tg-fs-sm) // --bit-DateRangePicker-input-color text color of the field (default: $clr-fg-pri) +// --bit-DateRangePicker-placeholder-color text color of the placeholder (default: $clr-fg-sec) // --bit-DateRangePicker-input-background background of the field (default: $clr-bg-pri) // --bit-DateRangePicker-input-border-color border of the field (default: $clr-brd-pri) // --bit-DateRangePicker-input-border-width border stroke of the field (default: $shp-border-width) @@ -163,6 +164,7 @@ $dtrp-private-properties: rl-clr, rl-txt, rl-hover, rl-active, rl-body, rl-focus cursor: default; color: var(--bit-DateRangePicker-disabled-color, #{$clr-fg-dis}); background: none $clr-bg-dis; + @include input-placeholder(var(--bit-DateRangePicker-disabled-color, #{$clr-fg-dis})); } @include dtrp-disabled-content; @@ -358,6 +360,7 @@ $dtrp-private-properties: rl-clr, rl-txt, rl-hover, rl-active, rl-body, rl-focus font-size: var(--bit-dtrp-inp-fs, var(--bit-DateRangePicker-input-font-size, #{$tg-fs-sm})); background: none transparent; font-family: $tg-font-family; + @include input-placeholder(var(--bit-DateRangePicker-placeholder-color, #{$clr-fg-sec})); } .bit-dtrp-ein { diff --git a/src/BlazorUI/Bit.BlazorUI/Components/Inputs/Dropdown/BitDropdown.scss b/src/BlazorUI/Bit.BlazorUI/Components/Inputs/Dropdown/BitDropdown.scss index 1963ec74d9c..f7a3a07ca05 100644 --- a/src/BlazorUI/Bit.BlazorUI/Components/Inputs/Dropdown/BitDropdown.scss +++ b/src/BlazorUI/Bit.BlazorUI/Components/Inputs/Dropdown/BitDropdown.scss @@ -257,6 +257,12 @@ $drp-private-properties: sz-fs, sz-h, sz-lbl-lh, sz-itm-h, sz-itm-fs, sz-ico, sz color: var(--bit-Dropdown-disabled-color, #{$clr-fg-dis}); } + // The ComboBox input is painted apart from the field around it, so it greys out apart from it too. + .bit-drp-inp { + color: var(--bit-Dropdown-disabled-color, #{$clr-fg-dis}); + @include input-placeholder(var(--bit-Dropdown-disabled-color, #{$clr-fg-dis})); + } + .bit-drp-icn { cursor: default; @@ -704,9 +710,7 @@ $drp-private-properties: sz-fs, sz-h, sz-lbl-lh, sz-itm-h, sz-itm-fs, sz-ico, sz // The typed text and the placeholder of the ComboBox input are the same two colors the selection // display beside it uses, so the field reads as one control whichever of the two is showing. - &::placeholder { - color: var(--bit-Dropdown-placeholder-color, #{$clr-fg-sec}); - } + @include input-placeholder(var(--bit-Dropdown-placeholder-color, #{$clr-fg-sec})); } .bit-drp-pre, @@ -949,10 +953,7 @@ $drp-private-properties: sz-fs, sz-h, sz-lbl-lh, sz-itm-h, sz-itm-fs, sz-ico, sz padding: 0 0 spacing(0.0625); background-color: transparent; color: var(--bit-Dropdown-color, #{$clr-fg-pri}); - - &::placeholder { - color: var(--bit-Dropdown-placeholder-color, #{$clr-fg-sec}); - } + @include input-placeholder(var(--bit-Dropdown-placeholder-color, #{$clr-fg-sec})); } .bit-drp-sbcc { diff --git a/src/BlazorUI/Bit.BlazorUI/Components/Inputs/NumberField/BitNumberField.scss b/src/BlazorUI/Bit.BlazorUI/Components/Inputs/NumberField/BitNumberField.scss index 48e85d01005..46b2526b919 100644 --- a/src/BlazorUI/Bit.BlazorUI/Components/Inputs/NumberField/BitNumberField.scss +++ b/src/BlazorUI/Bit.BlazorUI/Components/Inputs/NumberField/BitNumberField.scss @@ -98,6 +98,7 @@ $nfl-private-properties: height, fontsize, label-fontsize, icon-size, btn-width, cursor: default; color: var(--bit-NumberField-disabled-color, #{$clr-fg-dis}); background: var(--bit-NumberField-disabled-background, #{$clr-bg-dis}); + @include input-placeholder(var(--bit-NumberField-disabled-color, #{$clr-fg-dis})); } .bit-nfl-pre, @@ -321,9 +322,7 @@ $nfl-private-properties: height, fontsize, label-fontsize, icon-size, btn-width, border-start-end-radius: 0; border-end-end-radius: 0; - &::placeholder { - color: var(--bit-NumberField-placeholder-color, #{$clr-fg-sec}); - } + @include input-placeholder(var(--bit-NumberField-placeholder-color, #{$clr-fg-sec})); } .bit-nfl-cbt { diff --git a/src/BlazorUI/Bit.BlazorUI/Components/Inputs/OtpInput/BitOtpInput.scss b/src/BlazorUI/Bit.BlazorUI/Components/Inputs/OtpInput/BitOtpInput.scss index cb82926283a..f5f5a44cf3e 100644 --- a/src/BlazorUI/Bit.BlazorUI/Components/Inputs/OtpInput/BitOtpInput.scss +++ b/src/BlazorUI/Bit.BlazorUI/Components/Inputs/OtpInput/BitOtpInput.scss @@ -24,7 +24,7 @@ // --bit-OtpInput-filled-border-color rule of a box that holds a character (default: the rest rule) // --bit-OtpInput-focus-border-color box rule while focused (default: $clr-pri) // --bit-OtpInput-focus-color focus ring color (default: $clr-pri-focus) -// --bit-OtpInput-placeholder-color hint character of an empty box (default: $clr-fg-ter) +// --bit-OtpInput-placeholder-color hint character of an empty box (default: $clr-fg-sec) // --bit-OtpInput-label-color label above the boxes (default: $clr-fg-pri) // --bit-OtpInput-description-color helper text under the boxes (default: $clr-fg-sec) // --bit-OtpInput-separator-color text drawn between the groups (default: $clr-fg-sec) @@ -206,9 +206,7 @@ $otp-private-properties: size, fontsize, dsc-fontsize, clr, clr-focus; background-color: var(--bit-otp-inp-sbg, var(--bit-OtpInput-background, var(--bit-otp-bg))); transition: border-color $mot-duration-short $mot-easing, background-color $mot-duration-short $mot-easing; - &::placeholder { - color: var(--bit-OtpInput-placeholder-color, #{$clr-fg-ter}); - } + @include input-placeholder(var(--bit-OtpInput-placeholder-color, #{$clr-fg-sec})); //a box that already holds a character, which is the hook for a row that shows its own progress. Both //of its colors fall back to the ones of the rest state, so nothing changes until one of the two is set. @@ -483,9 +481,7 @@ $otp-private-properties: size, fontsize, dsc-fontsize, clr, clr-focus; //the hint of an empty box is a part of the field, so it has to be dimmed along with it instead of //staying the only thing in the component that still reads as enabled. - &::placeholder { - color: var(--bit-OtpInput-disabled-color, #{$clr-fg-dis}); - } + @include input-placeholder(var(--bit-OtpInput-disabled-color, #{$clr-fg-dis})); } //a disabled component is out of the flow the wait belongs to, so the bar is dimmed along with the rest diff --git a/src/BlazorUI/Bit.BlazorUI/Components/Inputs/SearchBox/BitSearchBox.scss b/src/BlazorUI/Bit.BlazorUI/Components/Inputs/SearchBox/BitSearchBox.scss index 52be23c7c9b..4476b56d545 100644 --- a/src/BlazorUI/Bit.BlazorUI/Components/Inputs/SearchBox/BitSearchBox.scss +++ b/src/BlazorUI/Bit.BlazorUI/Components/Inputs/SearchBox/BitSearchBox.scss @@ -147,6 +147,12 @@ $srb-private-properties: siz-height, siz-fontsize, siz-iconsize, siz-cbt-iconsiz color: var(--bit-srb-dis-clr); } + // The input paints its own text apart from the field around it, so it greys out apart from it too. + .bit-srb-inp { + color: var(--bit-srb-dis-clr); + @include input-placeholder(var(--bit-srb-dis-clr)); + } + .bit-srb-des { color: $clr-fg-dis; } @@ -343,12 +349,7 @@ $srb-private-properties: siz-height, siz-fontsize, siz-iconsize, siz-cbt-iconsiz color: var(--bit-SearchBox-color, #{$clr-fg-pri}); padding: 0 var(--bit-SearchBox-padding, #{spacing(1)}); - // Left to the browser, the placeholder is a light gray that misses the 4.5:1 of WCAG 1.4.3 on most - // surfaces, and a placeholder is regularly the only hint of what the field expects. - &::placeholder { - opacity: 1; // Firefox dims it on top of its color, which would undo the token below. - color: var(--bit-SearchBox-placeholder-color, #{$clr-fg-sec}); - } + @include input-placeholder(var(--bit-SearchBox-placeholder-color, #{$clr-fg-sec})); // WebKit draws a clear button and a pair of result decorations of its own inside a search input. // The component owns that affordance, so the native ones are removed instead of showing twice. diff --git a/src/BlazorUI/Bit.BlazorUI/Components/Inputs/TagsInput/BitTagsInput.scss b/src/BlazorUI/Bit.BlazorUI/Components/Inputs/TagsInput/BitTagsInput.scss index 3266c0394a4..e5b12027db2 100644 --- a/src/BlazorUI/Bit.BlazorUI/Components/Inputs/TagsInput/BitTagsInput.scss +++ b/src/BlazorUI/Bit.BlazorUI/Components/Inputs/TagsInput/BitTagsInput.scss @@ -4,7 +4,7 @@ // tags input and one set on the Style of an instance re-skins that one and the tags inputs nested in it: // --bit-TagsInput-font-size text size of the field (default: $tg-fs-sm) // --bit-TagsInput-color color of the typed text (default: $clr-fg-pri) -// --bit-TagsInput-placeholder-color color of the placeholder (default: $clr-fg-ter) +// --bit-TagsInput-placeholder-color color of the placeholder (default: $clr-fg-sec) // --bit-TagsInput-label-color color of the label above the field (default: $clr-fg-pri) // --bit-TagsInput-required-color color of the asterisk a Required label carries (default: $clr-req) // --bit-TagsInput-description-color color of the helper text under the field (default: $clr-fg-sec) @@ -526,9 +526,7 @@ $tgi-private-properties: clr, clr-txt, clr-hover, clr-focus, gap, fontsize, icon //with no tag in it yet is exactly as tall as the same field once the first one is added. min-height: var(--bit-tgi-tagminheight, var(--bit-TagsInput-tag-min-height, #{$siz-chip-sm})); - &::placeholder { - color: var(--bit-TagsInput-placeholder-color, #{$clr-fg-ter}); - } + @include input-placeholder(var(--bit-TagsInput-placeholder-color, #{$clr-fg-sec})); } @@ -719,10 +717,7 @@ $tgi-private-properties: clr, clr-txt, clr-hover, clr-focus, gap, fontsize, icon .bit-tgi-inp { color: var(--bit-TagsInput-disabled-color, #{$clr-fg-dis}); - - &::placeholder { - color: var(--bit-TagsInput-disabled-color, #{$clr-fg-dis}); - } + @include input-placeholder(var(--bit-TagsInput-disabled-color, #{$clr-fg-dis})); } } diff --git a/src/BlazorUI/Bit.BlazorUI/Components/Inputs/TextField/BitTextField.scss b/src/BlazorUI/Bit.BlazorUI/Components/Inputs/TextField/BitTextField.scss index 8662b4e1b9d..df7247a049e 100644 --- a/src/BlazorUI/Bit.BlazorUI/Components/Inputs/TextField/BitTextField.scss +++ b/src/BlazorUI/Bit.BlazorUI/Components/Inputs/TextField/BitTextField.scss @@ -21,7 +21,7 @@ // collapses under reduced motion) // --bit-TextField-color color of the typed text (default: $clr-fg-pri) // --bit-TextField-caret-color color of the text cursor (default: the typed text color) -// --bit-TextField-placeholder-color color of the placeholder (default: $clr-fg-ter) +// --bit-TextField-placeholder-color color of the placeholder (default: $clr-fg-sec) // --bit-TextField-font-family typeface of the field and of its chrome (default: $tg-font-family) // --bit-TextField-font-size size of the typed text, the label and the // affixes (default: $tg-fs-sm) @@ -135,10 +135,7 @@ $tfl-private-properties: font-size, line-height, min-height, icon-font-size, btn .bit-tfl-inp { color: var(--bit-TextField-disabled-color, #{$clr-fg-dis}); - - &::placeholder { - color: var(--bit-TextField-disabled-color, #{$clr-fg-dis}); - } + @include input-placeholder(var(--bit-TextField-disabled-color, #{$clr-fg-dis})); } .bit-tfl-pre, @@ -316,13 +313,7 @@ $tfl-private-properties: font-size, line-height, min-height, icon-font-size, btn font-size: var(--bit-tfl-font-size, var(--bit-TextField-font-size, #{$tg-fs-sm})); min-height: var(--bit-tfl-inp-min-height); - // The placeholder is left to the browser otherwise, whose default grey is not derived from the theme - // and drops below the contrast floor on a dark surface. Firefox also dims it with an opacity of its - // own, which would darken the themed color again, so that is reset here. - &::placeholder { - opacity: 1; - color: var(--bit-TextField-placeholder-color, #{$clr-fg-ter}); - } + @include input-placeholder(var(--bit-TextField-placeholder-color, #{$clr-fg-sec})); &[type="password"]::-ms-reveal, &[type="password"]::-ms-clear { diff --git a/src/BlazorUI/Bit.BlazorUI/Components/Inputs/TimePicker/BitTimePicker.scss b/src/BlazorUI/Bit.BlazorUI/Components/Inputs/TimePicker/BitTimePicker.scss index fa43741716a..4e83a55d3ff 100644 --- a/src/BlazorUI/Bit.BlazorUI/Components/Inputs/TimePicker/BitTimePicker.scss +++ b/src/BlazorUI/Bit.BlazorUI/Components/Inputs/TimePicker/BitTimePicker.scss @@ -142,6 +142,7 @@ $tpc-private-properties: rl-clr, rl-txt, rl-hover, rl-active, rl-focus, inp-h, i cursor: default; color: var(--bit-TimePicker-disabled-color, #{$clr-fg-dis}); background: none var(--bit-TimePicker-disabled-background, #{$clr-bg-dis}); + @include input-placeholder(var(--bit-TimePicker-disabled-color, #{$clr-fg-dis})); } } @@ -296,10 +297,7 @@ $tpc-private-properties: rl-clr, rl-txt, rl-hover, rl-active, rl-focus, inp-h, i // A placeholder is a hint and not the value, so it is told apart from a time that has been picked - // which the browser default (a shade of the text color it picks itself) does not reliably do. - &::placeholder { - color: var(--bit-TimePicker-placeholder-color, #{$clr-fg-sec}); - opacity: 1; // Firefox dims it a second time on its own. - } + @include input-placeholder(var(--bit-TimePicker-placeholder-color, #{$clr-fg-sec})); } // An input that takes a typed time is a text field, so it carries the caret of one rather than the diff --git a/src/BlazorUI/Bit.BlazorUI/Styles/functions.scss b/src/BlazorUI/Bit.BlazorUI/Styles/functions.scss index 76c11324eda..1200c06b10a 100644 --- a/src/BlazorUI/Bit.BlazorUI/Styles/functions.scss +++ b/src/BlazorUI/Bit.BlazorUI/Styles/functions.scss @@ -327,3 +327,34 @@ $html-font-size: 16px; border-color: Canvas; border-block-start-color: GrayText; } + +/* + * input-placeholder($color) + * -------------------------------------------------- + * The hint an input or a textarea shows while it is empty, painted from the theme rather than left + * to the browser, whose own grey is not derived from the theme and misses the 4.5:1 of WCAG 1.4.3 + * on most surfaces, dark ones above all. Every placeholder of the library is painted through it. + * - $color is the component's public placeholder variable with $clr-fg-sec as its fallback: a + * placeholder is often the only hint of what a field expects, so it is held to the floor of + * text, which the subtle $clr-fg-ter misses on the tertiary surface. + * - Included again in the component's disabled state with its disabled color, so the hint of an + * empty disabled field greys out with the rest of it instead of being the one part that still + * reads as live. + * - Firefox dims a placeholder with an opacity of its own on top of its color, which would darken + * the themed one below the floor again, so that is reset. + * + * Usage: + * .bit-xyz-inp { + * @include input-placeholder(var(--bit-Xyz-placeholder-color, #{$clr-fg-sec})); + * } + * + * .bit-xyz.bit-dis .bit-xyz-inp { + * @include input-placeholder(var(--bit-Xyz-disabled-color, #{$clr-fg-dis})); + * } + */ +@mixin input-placeholder($color) { + &::placeholder { + opacity: 1; + color: $color; + } +} diff --git a/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Extras/DataGrid/BitDataGridDemo.razor.params.cs b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Extras/DataGrid/BitDataGridDemo.razor.params.cs index c8dd61c88da..982f993f168 100644 --- a/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Extras/DataGrid/BitDataGridDemo.razor.params.cs +++ b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Extras/DataGrid/BitDataGridDemo.razor.params.cs @@ -178,6 +178,7 @@ public partial class BitDataGridDemo new() { Name = "--bit-DataGrid-detail-background", DefaultValue = "--bit-clr-bg-sec", Description = "Background of the expanded detail rows." }, new() { Name = "--bit-DataGrid-footer-background", DefaultValue = "--bit-clr-bg-sec", Description = "Background of the footer row." }, new() { Name = "--bit-DataGrid-disabled-color", DefaultValue = "--bit-clr-fg-dis", Description = "Text color of a disabled grid." }, + new() { Name = "--bit-DataGrid-placeholder-color", DefaultValue = "--bit-clr-fg-sec", Description = "Placeholder of the search box and of the filter boxes." }, ]; private readonly List componentSubClasses = diff --git a/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Extras/FullCalendar/BitFullCalendarDemo.razor.cs b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Extras/FullCalendar/BitFullCalendarDemo.razor.cs index d67b6c18c6c..0a06dd20bba 100644 --- a/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Extras/FullCalendar/BitFullCalendarDemo.razor.cs +++ b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Extras/FullCalendar/BitFullCalendarDemo.razor.cs @@ -916,7 +916,7 @@ public partial class BitFullCalendarDemo new() { Name = "--bit-FullCalendar-secondary-background", DefaultValue = "var(--bit-clr-bg-sec)", Description = "Secondary surfaces: the tab strips, the day-view sidebar, sticky group titles, the timeline gutter." }, new() { Name = "--bit-FullCalendar-hover-background", DefaultValue = "var(--bit-clr-bg-pri-hover)", Description = "Background of a hovered cell, slot, row or control." }, new() { Name = "--bit-FullCalendar-color", DefaultValue = "var(--bit-clr-fg-pri)", Description = "Text color." }, - new() { Name = "--bit-FullCalendar-secondary-color", DefaultValue = "var(--bit-clr-fg-sec)", Description = "Secondary text: weekday headers, group titles, descriptions." }, + new() { Name = "--bit-FullCalendar-secondary-color", DefaultValue = "var(--bit-clr-fg-sec)", Description = "Secondary text: weekday headers, group titles, descriptions, and the placeholders of the search box and the event dialog's fields." }, new() { Name = "--bit-FullCalendar-muted-color", DefaultValue = "var(--bit-clr-fg-ter)", Description = "Muted text: hour labels, week numbers, days of the neighbouring months." }, new() { Name = "--bit-FullCalendar-border-color", DefaultValue = "var(--bit-clr-brd-ter)", Description = "Grid lines and the border of the calendar." }, new() { Name = "--bit-FullCalendar-control-border-color", DefaultValue = "var(--bit-clr-brd-pri)", Description = "Edges of the fields, selects, search box and switch tracks (kept at 3:1 against the surface)." }, diff --git a/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Extras/MarkdownEditor/BitMarkdownEditorDemo.razor.cs b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Extras/MarkdownEditor/BitMarkdownEditorDemo.razor.cs index c7f50ccf778..c3376510398 100644 --- a/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Extras/MarkdownEditor/BitMarkdownEditorDemo.razor.cs +++ b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Extras/MarkdownEditor/BitMarkdownEditorDemo.razor.cs @@ -499,7 +499,7 @@ public partial class BitMarkdownEditorDemo new() { Name = "--bit-MarkdownEditor-font-size", DefaultValue = "--bit-tpg-fs-sm", Description = "Font size of the textarea." }, new() { Name = "--bit-MarkdownEditor-line-height", DefaultValue = "1.6", Description = "Line height of the textarea." }, new() { Name = "--bit-MarkdownEditor-padding", DefaultValue = "spacing(1.5) spacing(1.75)", Description = "Padding of the textarea." }, - new() { Name = "--bit-MarkdownEditor-placeholder-color", DefaultValue = "--bit-clr-fg-sec", Description = "Placeholder text of the textarea." }, + new() { Name = "--bit-MarkdownEditor-placeholder-color", DefaultValue = "--bit-clr-fg-sec", Description = "Placeholder text of the textarea and of the find and replace boxes." }, new() { Name = "--bit-MarkdownEditor-label-color", DefaultValue = "--bit-MarkdownEditor-color", Description = "Text of the label." }, new() { Name = "--bit-MarkdownEditor-label-font-size", DefaultValue = "--bit-tpg-fs-sm", Description = "Size of the label." }, new() { Name = "--bit-MarkdownEditor-label-font-weight", DefaultValue = "--bit-tpg-field-label-font-weight", Description = "Weight of the label." }, diff --git a/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Extras/PdfViewer/BitPdfViewerDemo.razor.cs b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Extras/PdfViewer/BitPdfViewerDemo.razor.cs index 1d71d20ca5a..28012d4b9b3 100644 --- a/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Extras/PdfViewer/BitPdfViewerDemo.razor.cs +++ b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Extras/PdfViewer/BitPdfViewerDemo.razor.cs @@ -849,6 +849,7 @@ public partial class BitPdfViewerDemo new() { Name = "--bit-PdfViewer-button-active-hover-background", DefaultValue = "var(--bit-clr-pri-hover)", Description = "Background of a toggle that is on, under the pointer." }, new() { Name = "--bit-PdfViewer-field-background", DefaultValue = "var(--bit-clr-bg-pri)", Description = "Background of the page box, the find box and the dropdowns." }, new() { Name = "--bit-PdfViewer-field-border-color", DefaultValue = "var(--bit-clr-brd-pri)", Description = "Border of the page box, the find box, the dropdowns and the find options." }, + new() { Name = "--bit-PdfViewer-field-placeholder-color", DefaultValue = "var(--bit-clr-fg-sec)", Description = "Placeholder of the find box." }, new() { Name = "--bit-PdfViewer-sidebar-background", DefaultValue = "var(--bit-clr-bg-sec)", Description = "Background of the side panels." }, new() { Name = "--bit-PdfViewer-sidebar-width", DefaultValue = "spacing(29)", Description = "Width of the bookmarks, attachments and layers panels (at most half the viewer)." }, new() { Name = "--bit-PdfViewer-item-hover-background", DefaultValue = "var(--bit-clr-bg-sec-hover)", Description = "A bookmark, attachment or layer row under the pointer." }, diff --git a/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Extras/PhoneInput/BitPhoneInputDemo.razor.cs b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Extras/PhoneInput/BitPhoneInputDemo.razor.cs index 52a6c04bc85..c4964683cf8 100644 --- a/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Extras/PhoneInput/BitPhoneInputDemo.razor.cs +++ b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Extras/PhoneInput/BitPhoneInputDemo.razor.cs @@ -707,7 +707,7 @@ public partial class BitPhoneInputDemo [ new() { Name = "--bit-PhoneInput-background", DefaultValue = "--bit-clr-bg-pri", Description = "Fill of the field. The Background parameter wins over it." }, new() { Name = "--bit-PhoneInput-color", DefaultValue = "--bit-clr-fg-pri", Description = "Text of the number." }, - new() { Name = "--bit-PhoneInput-placeholder-color", DefaultValue = "--bit-clr-fg-ter", Description = "Placeholder of the number input, of the country selector and of the search box." }, + new() { Name = "--bit-PhoneInput-placeholder-color", DefaultValue = "--bit-clr-fg-sec", Description = "Placeholder of the number input, of the country selector and of the search box." }, new() { Name = "--bit-PhoneInput-border-color", DefaultValue = "--bit-clr-brd-pri", Description = "Frame at rest. The Border and Color parameters win over it." }, new() { Name = "--bit-PhoneInput-hover-border-color", DefaultValue = "--bit-clr-brd-pri-hover", Description = "Frame under a pointer, on devices that can hover. The Border and Color parameters win over it." }, new() { Name = "--bit-PhoneInput-border-width", DefaultValue = "--bit-shp-brd-width", Description = "Thickness of the frame and of the rule between the selector and the number." }, diff --git a/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Extras/RichTextEditor/BitRichTextEditorDemo.razor.cs b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Extras/RichTextEditor/BitRichTextEditorDemo.razor.cs index 9961f4c3776..324fa302072 100644 --- a/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Extras/RichTextEditor/BitRichTextEditorDemo.razor.cs +++ b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Extras/RichTextEditor/BitRichTextEditorDemo.razor.cs @@ -437,7 +437,7 @@ public partial class BitRichTextEditorDemo new() { Name = "--bit-RichTextEditor-font-family", DefaultValue = "inherit", Description = "Font of the content." }, new() { Name = "--bit-RichTextEditor-font-size", DefaultValue = "inherit", Description = "Font size of the content." }, new() { Name = "--bit-RichTextEditor-line-height", DefaultValue = "1.6", Description = "Line height of the content and the source view." }, - new() { Name = "--bit-RichTextEditor-placeholder-color", DefaultValue = "var(--bit-clr-fg-sec)", Description = "Placeholder text of the editing surface." }, + new() { Name = "--bit-RichTextEditor-placeholder-color", DefaultValue = "var(--bit-clr-fg-sec)", Description = "Placeholder text of the editing surface and of the fields of its panels (link, image, media, find and replace, search)." }, new() { Name = "--bit-RichTextEditor-link-color", DefaultValue = "var(--bit-clr-pri)", Description = "Links in the content." }, new() { Name = "--bit-RichTextEditor-code-background", DefaultValue = "var(--bit-clr-bg-sec)", Description = "Background of code spans, code blocks and the source view." }, new() { Name = "--bit-RichTextEditor-quote-border-color", DefaultValue = "var(--bit-clr-brd-pri)", Description = "Leading rule of a block quote." }, diff --git a/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/CircularTimePicker/BitCircularTimePickerDemo.razor.cs b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/CircularTimePicker/BitCircularTimePickerDemo.razor.cs index 23ee7678d6e..6b157d28300 100644 --- a/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/CircularTimePicker/BitCircularTimePickerDemo.razor.cs +++ b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/CircularTimePicker/BitCircularTimePickerDemo.razor.cs @@ -932,6 +932,12 @@ public partial class BitCircularTimePickerDemo Description = "The text in the field." }, new() + { + Name = "--bit-CircularTimePicker-placeholder-color", + DefaultValue = "--bit-clr-fg-sec", + Description = "The placeholder of the field. It replaces the grey the browser picks on its own, which is not derived from the theme and drops below the contrast floor on most surfaces." + }, + new() { Name = "--bit-CircularTimePicker-input-font-size", DefaultValue = "--bit-tpg-fs-sm", diff --git a/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/CircularTimePicker/BitCircularTimePickerDemo.razor.samples.cs b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/CircularTimePicker/BitCircularTimePickerDemo.razor.samples.cs index 4798d2db4c4..eced8c4ab4e 100644 --- a/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/CircularTimePicker/BitCircularTimePickerDemo.razor.samples.cs +++ b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/CircularTimePicker/BitCircularTimePickerDemo.razor.samples.cs @@ -566,6 +566,7 @@ private void Log(string message) --bit-CircularTimePicker-border-radius: 1rem; --bit-CircularTimePicker-input-background: #f4efff; --bit-CircularTimePicker-input-color: #3a2358; + --bit-CircularTimePicker-placeholder-color: #6b3fa0; --bit-CircularTimePicker-callout-radius: 1.25rem; --bit-CircularTimePicker-clock-background: #f4efff; --bit-CircularTimePicker-number-color: #3a2358; diff --git a/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/CircularTimePicker/BitCircularTimePickerDemo.razor.scss b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/CircularTimePicker/BitCircularTimePickerDemo.razor.scss index 7265e3e4b27..6d30454d8ed 100644 --- a/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/CircularTimePicker/BitCircularTimePickerDemo.razor.scss +++ b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/CircularTimePicker/BitCircularTimePickerDemo.razor.scss @@ -23,6 +23,7 @@ --bit-CircularTimePicker-border-radius: 1rem; --bit-CircularTimePicker-input-background: #f4efff; --bit-CircularTimePicker-input-color: #3a2358; + --bit-CircularTimePicker-placeholder-color: #6b3fa0; --bit-CircularTimePicker-callout-radius: 1.25rem; --bit-CircularTimePicker-clock-background: #f4efff; --bit-CircularTimePicker-number-color: #3a2358; diff --git a/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/DatePicker/BitDatePickerDemo.razor.cs b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/DatePicker/BitDatePickerDemo.razor.cs index 297aac91835..73acddc8473 100644 --- a/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/DatePicker/BitDatePickerDemo.razor.cs +++ b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/DatePicker/BitDatePickerDemo.razor.cs @@ -1956,6 +1956,12 @@ public partial class BitDatePickerDemo Description = "Text color of the field.", }, new() + { + Name = "--bit-DatePicker-placeholder-color", + DefaultValue = "--bit-clr-fg-sec", + Description = "Text color of the placeholder. It replaces the grey the browser picks on its own, which is not derived from the theme and drops below the contrast floor on most surfaces.", + }, + new() { Name = "--bit-DatePicker-input-background", DefaultValue = "--bit-clr-bg-pri", diff --git a/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/DateRangePicker/BitDateRangePickerDemo.razor.cs b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/DateRangePicker/BitDateRangePickerDemo.razor.cs index 4418eb5d15f..8ad65cefad3 100644 --- a/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/DateRangePicker/BitDateRangePickerDemo.razor.cs +++ b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/DateRangePicker/BitDateRangePickerDemo.razor.cs @@ -1217,6 +1217,12 @@ public partial class BitDateRangePickerDemo Description = "Text color of the field.", }, new() + { + Name = "--bit-DateRangePicker-placeholder-color", + DefaultValue = "--bit-clr-fg-sec", + Description = "Text color of the placeholder. It replaces the grey the browser picks on its own, which is not derived from the theme and drops below the contrast floor on most surfaces.", + }, + new() { Name = "--bit-DateRangePicker-input-background", DefaultValue = "--bit-clr-bg-pri", diff --git a/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/OtpInput/BitOtpInputDemo.razor.cs b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/OtpInput/BitOtpInputDemo.razor.cs index 6b6a463bf8f..0e5eaee7263 100644 --- a/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/OtpInput/BitOtpInputDemo.razor.cs +++ b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/OtpInput/BitOtpInputDemo.razor.cs @@ -533,7 +533,7 @@ public partial class BitOtpInputDemo new() { Name = "--bit-OtpInput-placeholder-color", - DefaultValue = "--bit-clr-fg-ter", + DefaultValue = "--bit-clr-fg-sec", Description = "Hint character of an empty input.", }, new() diff --git a/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/SearchBox/BitSearchBoxDemo.razor.cs b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/SearchBox/BitSearchBoxDemo.razor.cs index 77b09612666..66eb08c8305 100644 --- a/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/SearchBox/BitSearchBoxDemo.razor.cs +++ b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/SearchBox/BitSearchBoxDemo.razor.cs @@ -628,7 +628,7 @@ public partial class BitSearchBoxDemo new() { Name = "--bit-SearchBox-placeholder-color", - DefaultValue = "$clr-fg-sec", + DefaultValue = "--bit-clr-fg-sec", Description = "Text color of the placeholder.", }, new() diff --git a/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/TagsInput/BitTagsInputDemo.razor.cs b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/TagsInput/BitTagsInputDemo.razor.cs index b3aa7af0058..ef1d68c1b83 100644 --- a/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/TagsInput/BitTagsInputDemo.razor.cs +++ b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/TagsInput/BitTagsInputDemo.razor.cs @@ -773,7 +773,7 @@ public partial class BitTagsInputDemo new() { Name = "--bit-TagsInput-placeholder-color", - DefaultValue = "--bit-clr-fg-ter", + DefaultValue = "--bit-clr-fg-sec", Description = "Color of the Placeholder and the TagsPlaceholder.", }, new() diff --git a/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/TextField/BitTextFieldDemo.razor.cs b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/TextField/BitTextFieldDemo.razor.cs index 2c6738e222d..dcadda934b3 100644 --- a/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/TextField/BitTextFieldDemo.razor.cs +++ b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/TextField/BitTextFieldDemo.razor.cs @@ -980,8 +980,8 @@ public partial class BitTextFieldDemo : IDisposable new() { Name = "--bit-TextField-placeholder-color", - DefaultValue = "--bit-clr-fg-ter", - Description = "Color of the placeholder. It replaces the grey the browser picks on its own, which is not derived from the theme and drops below the contrast floor on a dark surface.", + DefaultValue = "--bit-clr-fg-sec", + Description = "Color of the placeholder. It replaces the grey the browser picks on its own, which is not derived from the theme and drops below the contrast floor on most surfaces.", }, new() { diff --git a/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Theming/ThemingPage.razor b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Theming/ThemingPage.razor index 595bb3c7021..651c38e5b9c 100644 --- a/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Theming/ThemingPage.razor +++ b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Theming/ThemingPage.razor @@ -408,7 +408,7 @@ -fg is derived rather than solved: by default it is the role's base color shaded towards --bit-clr-fg-pri, which keeps the hue and follows any palette in either scheme, but promises no ratio for a palette it has never seen. A preset whose role colors sit close to its page surface sets its own -fg values.
  • - --bit-clr-fg-pri and --bit-clr-fg-sec clear 4.5:1 over bg-pri, bg-sec and bg-ter (they sit at 14.6:1 and 6.6:1 even on the deepest of the three). --bit-clr-fg-ter, the subtle/placeholder tier, clears 4.5:1 on the page surface and stays above 4:1 on the deepest one. --bit-clr-brd-pri keeps ≥ 3:1 over all three (SC 1.4.11, non-text contrast). brd-sec and brd-ter are the decorative stroke tiers - spinner tracks, menu separators, calendar grid lines - and are tuned for definition rather than to a contrast floor. Reach for brd-pri when a border is a control boundary. + --bit-clr-fg-pri and --bit-clr-fg-sec clear 4.5:1 over bg-pri, bg-sec and bg-ter (they sit at 14.6:1 and 6.6:1 even on the deepest of the three). --bit-clr-fg-ter, the subtle tier, clears 4.5:1 on the page surface and stays above 4:1 on the deepest one - which is why every input paints its placeholder with fg-sec: a placeholder is often the only hint of what a field expects, so it is held to the floor of text. --bit-clr-brd-pri keeps ≥ 3:1 over all three (SC 1.4.11, non-text contrast). brd-sec and brd-ter are the decorative stroke tiers - spinner tracks, menu separators, calendar grid lines - and are tuned for definition rather than to a contrast floor. Reach for brd-pri when a border is a control boundary.
  • diff --git a/src/BlazorUI/Tests/Bit.BlazorUI.Tests/Components/Extras/DataGrid/BitDataGridStylesheetTests.cs b/src/BlazorUI/Tests/Bit.BlazorUI.Tests/Components/Extras/DataGrid/BitDataGridStylesheetTests.cs index cd01d86d954..ea288dd6f37 100644 --- a/src/BlazorUI/Tests/Bit.BlazorUI.Tests/Components/Extras/DataGrid/BitDataGridStylesheetTests.cs +++ b/src/BlazorUI/Tests/Bit.BlazorUI.Tests/Components/Extras/DataGrid/BitDataGridStylesheetTests.cs @@ -37,6 +37,7 @@ public class BitDataGridStylesheetTests "--bit-DataGrid-detail-background", "--bit-DataGrid-footer-background", "--bit-DataGrid-disabled-color", + "--bit-DataGrid-placeholder-color", ]; [TestMethod] diff --git a/src/BlazorUI/Tests/Bit.BlazorUI.Tests/Components/Extras/PdfViewer/BitPdfViewerStylesheetTests.cs b/src/BlazorUI/Tests/Bit.BlazorUI.Tests/Components/Extras/PdfViewer/BitPdfViewerStylesheetTests.cs index 52146ab8786..eb037e2d709 100644 --- a/src/BlazorUI/Tests/Bit.BlazorUI.Tests/Components/Extras/PdfViewer/BitPdfViewerStylesheetTests.cs +++ b/src/BlazorUI/Tests/Bit.BlazorUI.Tests/Components/Extras/PdfViewer/BitPdfViewerStylesheetTests.cs @@ -20,7 +20,7 @@ public void BitPdfViewerShouldReadEveryPublicVariableItDocuments() var documented = DocumentedVariables(stylesheet); - Assert.AreEqual(38, documented.Length, "The stylesheet does not document the thirty-eight public variables."); + Assert.AreEqual(39, documented.Length, "The stylesheet does not document the thirty-nine public variables."); foreach (var name in documented) { diff --git a/src/BlazorUI/Tests/Bit.BlazorUI.Tests/Utils/Theme/BitInputPlaceholderContractTests.cs b/src/BlazorUI/Tests/Bit.BlazorUI.Tests/Utils/Theme/BitInputPlaceholderContractTests.cs new file mode 100644 index 00000000000..2519c635fe7 --- /dev/null +++ b/src/BlazorUI/Tests/Bit.BlazorUI.Tests/Utils/Theme/BitInputPlaceholderContractTests.cs @@ -0,0 +1,215 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text.RegularExpressions; +using Microsoft.VisualStudio.TestTools.UnitTesting; + +namespace Bit.BlazorUI.Tests.Utils.Theme; + +/// +/// Pins the one way an input paints its placeholder (#13639): through the input-placeholder mixin of +/// functions.scss, which resets the opacity Firefox dims a placeholder with, from a public variable whose default is +/// the secondary foreground - the tier that clears the 4.5:1 of text on every surface - and again with the disabled +/// color in the component's disabled state. +/// +/// +/// The rule used to be written by hand in every stylesheet, and the copies drifted: some lost the opacity reset, some +/// defaulted to the tertiary foreground, some kept the full-contrast hint on a disabled field, and some inputs were +/// left to the browser's grey altogether. These tests fail on a stylesheet that brings any of that back. +/// +[TestClass] +public sealed class BitInputPlaceholderContractTests +{ + private const string Include = "@include input-placeholder("; + + // The HTML attribute an input or a textarea shows its hint through: lower case, so a component's own Placeholder + // parameter does not count, and neither does a data-placeholder or an aria-placeholder. + private static readonly Regex PlaceholderAttribute = new(@"(? SourceFiles.StripScssComments(SourceFiles.ReadFullPath(file)).Contains("::placeholder", StringComparison.Ordinal)) + .Select(Path.GetFileName) + .ToArray(); + + Assert.AreEqual(0, offenders.Length, + "A component stylesheet writes a ::placeholder rule of its own; paint it with @include input-placeholder(...) from " + + "functions.scss, which also resets the opacity Firefox dims it with: " + string.Join(", ", offenders)); + } + + [TestMethod] + public void EveryComponentRenderingAPlaceholderPaintsIt() + { + var offenders = new List(); + var checkedCount = 0; + + foreach (var markup in EnumerateComponentMarkup()) + { + if (PlaceholderAttribute.IsMatch(SourceFiles.ReadFullPath(markup)) is false) continue; + + checkedCount++; + + var stylesheets = OwnStylesheets(markup); + + if (stylesheets.Any(file => SourceFiles.StripScssComments(SourceFiles.ReadFullPath(file)).Contains(Include, StringComparison.Ordinal))) continue; + + offenders.Add(Path.GetFileName(markup)); + } + + Assert.IsTrue(checkedCount > 10, $"Only {checkedCount} component files render a placeholder; the scan no longer finds the inputs."); + + Assert.AreEqual(0, offenders.Count, + "A component renders an input with a placeholder that its stylesheet leaves to the browser's grey, which is not " + + "derived from the theme and misses 4.5:1 on most surfaces; paint it with @include input-placeholder(...): " + + string.Join(", ", offenders)); + } + + [TestMethod] + public void APlaceholderDefaultsToTheSecondaryForeground() + { + var offenders = new List(); + + foreach (var file in EnumerateComponentStylesheets()) + { + var source = SourceFiles.ReadFullPath(file); + var stylesheet = SourceFiles.StripScssComments(source); + var name = Path.GetFileName(file); + + foreach (var argument in IncludeArguments(stylesheet)) + { + if (argument.Contains("fg-ter", StringComparison.Ordinal)) + { + offenders.Add($"{name}: {Include}{argument})"); + } + } + + foreach (Match read in PublicPlaceholderRead.Matches(stylesheet)) + { + if (read.Groups[2].Value != "fg-sec") + { + offenders.Add($"{name}: {read.Groups[1].Value} falls back to $clr-{read.Groups[2].Value}"); + } + } + + foreach (Match documented in DocumentedPlaceholderDefault.Matches(source)) + { + if (documented.Groups[2].Value != "fg-sec") + { + offenders.Add($"{name}: {documented.Groups[1].Value} is documented with the default $clr-{documented.Groups[2].Value}"); + } + } + } + + Assert.AreEqual(0, offenders.Count, + "A placeholder is held to the 4.5:1 of text, which only the secondary foreground clears on every surface; " + + "the tertiary one misses it on bg-ter: " + string.Join("; ", offenders)); + } + + [TestMethod] + public void ADisabledFieldGreysItsPlaceholderOut() + { + var offenders = new List(); + + foreach (var file in EnumerateComponentStylesheets()) + { + var name = Path.GetFileName(file); + + if (NeverDisabled.Contains(name, StringComparer.Ordinal)) continue; + + var arguments = IncludeArguments(SourceFiles.StripScssComments(SourceFiles.ReadFullPath(file))).ToArray(); + + if (arguments.Length == 0) continue; + + if (arguments.Any(IsDisabledColor) is false) + { + offenders.Add(name); + } + } + + Assert.AreEqual(0, offenders.Count, + "A stylesheet paints a placeholder but never with its disabled color, so the hint of an empty disabled field " + + "stays at full contrast and reads as live; include input-placeholder(...) in the disabled state too: " + + string.Join(", ", offenders)); + } + + private static bool IsDisabledColor(string argument) + => Regex.IsMatch(argument, @"fg-dis|disabled-color|dis-clr|clr-dis", RegexOptions.CultureInvariant); + + private static IEnumerable IncludeArguments(string stylesheet) + { + var index = 0; + + while ((index = stylesheet.IndexOf(Include, index, StringComparison.Ordinal)) >= 0) + { + var start = index + Include.Length; + var depth = 1; + var end = start; + + for (; end < stylesheet.Length && depth > 0; end++) + { + if (stylesheet[end] == '(') depth++; + else if (stylesheet[end] == ')') depth--; + } + + yield return stylesheet[start..(end - 1)]; + + index = end; + } + } + + // The stylesheets that style a component's markup: those of its own folder, or of the nearest folder above it + // that has one (a view or a dialog of BitFullCalendar is styled by the calendar's stylesheet). + private static string[] OwnStylesheets(string markup) + { + for (var directory = Path.GetDirectoryName(markup); directory is not null; directory = Path.GetDirectoryName(directory)) + { + var stylesheets = Directory.GetFiles(directory, "*.scss"); + + if (stylesheets.Length > 0) return stylesheets; + + if (string.Equals(Path.GetFileName(directory), "Components", StringComparison.Ordinal)) break; + } + + return []; + } + + private static IEnumerable EnumerateComponentMarkup() + => ComponentFolders().SelectMany(folder => Directory.EnumerateFiles(folder, "*.razor", SearchOption.AllDirectories)); + + private static IEnumerable EnumerateComponentStylesheets() + => ComponentFolders().SelectMany(folder => Directory.EnumerateFiles(folder, "*.scss", SearchOption.AllDirectories)); + + private static IEnumerable ComponentFolders() + => new[] { "Bit.BlazorUI", "Bit.BlazorUI.Extras" }.Select(project => SourceFiles.GetDirectory(project, "Components")); +}