diff --git a/components/inputs/input-checkbox-styles.js b/components/inputs/input-checkbox-styles.js new file mode 100644 index 00000000000..dd478b1593c --- /dev/null +++ b/components/inputs/input-checkbox-styles.js @@ -0,0 +1,119 @@ +import { css, unsafeCSS } from 'lit'; +import { _isValidCssSelector } from '../../helpers/internal/css.js'; +import { registerSemanticVariableForSvgImageUrl } from '../colors/colors.js'; + +registerSemanticVariableForSvgImageUrl( + '--d2l-input-checkbox-check-image', + ` + \ + ` +); + +registerSemanticVariableForSvgImageUrl( + '--d2l-input-checkbox-indeterminate-image', + ` + + ` +); + +export const cssSizes = { + inputBoxSize: 1.2, + checkboxMargin: 0.5, +}; + +/** + * A private helper method that should not be used by general consumers + */ +export const _generateInputCheckboxStyles = (selector) => { + if (!_isValidCssSelector(selector)) return; + + const selectorCSS = unsafeCSS(selector); + return css` + ${selectorCSS} { + --d2l-input-checkbox-background-image: none; + --d2l-input-checkbox-background-color: var(--d2l-theme-background-color-interactive-faint-default); + --d2l-input-checkbox-background-image-disabled: + linear-gradient( + var(--d2l-theme-background-color-interactive-faint-disabled), + var(--d2l-theme-background-color-interactive-faint-disabled) + ), + var(--d2l-input-checkbox-background-image); + -webkit-appearance: none; + -moz-appearance: none; + appearance: none; + background-image: var(--d2l-input-checkbox-background-image); + background-position: center center; + background-repeat: no-repeat; + background-size: ${cssSizes.inputBoxSize}rem ${cssSizes.inputBoxSize}rem; + border-radius: 0.3rem; + border-style: solid; + box-sizing: border-box; + display: inline-block; + height: ${cssSizes.inputBoxSize}rem; + margin: 0; + padding: 0; + vertical-align: middle; + width: ${cssSizes.inputBoxSize}rem; + } + ${selectorCSS}:checked { + --d2l-input-checkbox-background-image: var(--d2l-input-checkbox-check-image); + } + ${selectorCSS}:indeterminate { + --d2l-input-checkbox-background-image: var(--d2l-input-checkbox-indeterminate-image); + } + ${selectorCSS}, + ${selectorCSS}:hover:disabled { + background-color: var(--d2l-input-checkbox-background-color); + border-color: var(--d2l-theme-border-color-emphasized); + border-width: 1px; + } + ${selectorCSS}:hover:disabled { + border-color: var(--d2l-theme-border-color-disabled); + } + ${selectorCSS}:hover, + ${selectorCSS}:focus, + ${selectorCSS}.d2l-input-checkbox-focus, + :host(.d2l-hovering) input[type="checkbox"]:not(:disabled).d2l-input-checkbox { + border-color: var(--d2l-input-checkbox-border-color-hover-focus, var(--d2l-theme-border-color-focus)); + border-width: 2px; + outline: none; + } + ${selectorCSS}:disabled, + ${selectorCSS}:where([aria-disabled="true"]) { + background-image: var(--d2l-input-checkbox-background-image-disabled); + border-color: var(--d2l-theme-border-color-disabled); + } + @media (forced-colors: active) { + ${selectorCSS}:checked, + ${selectorCSS}:indeterminate { + background-image: none; + position: relative; + } + ${selectorCSS}:checked::after, + ${selectorCSS}:indeterminate::after { + background-color: FieldText; + content: ""; + display: block; + height: ${cssSizes.inputBoxSize}rem; + left: 50%; + position: absolute; + top: 50%; + transform: translate(-50%, -50%); + width: ${cssSizes.inputBoxSize}rem; + } + + ${selectorCSS}:disabled, + ${selectorCSS}:where([aria-disabled="true"]) { + opacity: var(--d2l-theme-opacity-disabled-control); + } + + ${selectorCSS}:checked::after { + mask-image: var(--d2l-input-checkbox-check-image); + } + + ${selectorCSS}:indeterminate::after { + mask-image: var(--d2l-input-checkbox-indeterminate-image); + } + } + `; +}; diff --git a/components/inputs/input-checkbox.js b/components/inputs/input-checkbox.js index 287cd0ec191..960bc77155e 100644 --- a/components/inputs/input-checkbox.js +++ b/components/inputs/input-checkbox.js @@ -1,5 +1,6 @@ import '../expand-collapse/expand-collapse-content.js'; import '../tooltip/tooltip.js'; +import { _generateInputCheckboxStyles, cssSizes } from './input-checkbox-styles.js'; import { css, html, LitElement, nothing } from 'lit'; import { classMap } from 'lit/directives/class-map.js'; import { FocusMixin } from '../../mixins/focus/focus-mixin.js'; @@ -8,116 +9,9 @@ import { getUniqueId } from '../../helpers/uniqueId.js'; import { ifDefined } from 'lit/directives/if-defined.js'; import { InputInlineHelpMixin } from './input-inline-help.js'; import { offscreenStyles } from '../offscreen/offscreen.js'; -import { registerSemanticVariableForSvgImageUrl } from '../colors/colors.js'; import { SkeletonMixin } from '../skeleton/skeleton-mixin.js'; -registerSemanticVariableForSvgImageUrl( - '--d2l-input-checkbox-check-image', - ` - \ - ` -); - -registerSemanticVariableForSvgImageUrl( - '--d2l-input-checkbox-indeterminate-image', - ` - - ` -); - -export const cssSizes = { - inputBoxSize: 1.2, - checkboxMargin: 0.5, -}; - -export const checkboxStyles = css` - input[type="checkbox"].d2l-input-checkbox { - --d2l-input-checkbox-background-image: none; - --d2l-input-checkbox-background-color: var(--d2l-theme-background-color-interactive-faint-default); - --d2l-input-checkbox-background-image-disabled: - linear-gradient( - var(--d2l-theme-background-color-interactive-faint-disabled), - var(--d2l-theme-background-color-interactive-faint-disabled) - ), - var(--d2l-input-checkbox-background-image); - -webkit-appearance: none; - -moz-appearance: none; - appearance: none; - background-image: var(--d2l-input-checkbox-background-image); - background-position: center center; - background-repeat: no-repeat; - background-size: ${cssSizes.inputBoxSize}rem ${cssSizes.inputBoxSize}rem; - border-radius: 0.3rem; - border-style: solid; - box-sizing: border-box; - display: inline-block; - height: ${cssSizes.inputBoxSize}rem; - margin: 0; - padding: 0; - vertical-align: middle; - width: ${cssSizes.inputBoxSize}rem; - } - input[type="checkbox"].d2l-input-checkbox:checked { - --d2l-input-checkbox-background-image: var(--d2l-input-checkbox-check-image); - } - input[type="checkbox"].d2l-input-checkbox:indeterminate { - --d2l-input-checkbox-background-image: var(--d2l-input-checkbox-indeterminate-image); - } - input[type="checkbox"].d2l-input-checkbox, - input[type="checkbox"].d2l-input-checkbox:hover:disabled { - background-color: var(--d2l-input-checkbox-background-color); - border-color: var(--d2l-theme-border-color-emphasized); - border-width: 1px; - } - input[type="checkbox"].d2l-input-checkbox:hover:disabled { - border-color: var(--d2l-theme-border-color-disabled); - } - input[type="checkbox"].d2l-input-checkbox:hover, - input[type="checkbox"].d2l-input-checkbox:focus, - input[type="checkbox"].d2l-input-checkbox.d2l-input-checkbox-focus, - :host(.d2l-hovering) input[type="checkbox"]:not(:disabled).d2l-input-checkbox { - border-color: var(--d2l-input-checkbox-border-color-hover-focus, var(--d2l-theme-border-color-focus)); - border-width: 2px; - outline: none; - } - input[type="checkbox"].d2l-input-checkbox:disabled, - input[type="checkbox"].d2l-input-checkbox:where([aria-disabled="true"]) { - background-image: var(--d2l-input-checkbox-background-image-disabled); - border-color: var(--d2l-theme-border-color-disabled); - } - @media (forced-colors: active) { - input[type="checkbox"].d2l-input-checkbox:checked, - input[type="checkbox"].d2l-input-checkbox:indeterminate { - background-image: none; - position: relative; - } - input[type="checkbox"].d2l-input-checkbox:checked::after, - input[type="checkbox"].d2l-input-checkbox:indeterminate::after { - background-color: FieldText; - content: ""; - display: block; - height: ${cssSizes.inputBoxSize}rem; - left: 50%; - position: absolute; - top: 50%; - transform: translate(-50%, -50%); - width: ${cssSizes.inputBoxSize}rem; - } - - input[type="checkbox"].d2l-input-checkbox:disabled, - input[type="checkbox"].d2l-input-checkbox:where([aria-disabled="true"]) { - opacity: var(--d2l-theme-opacity-disabled-control); - } - - input[type="checkbox"].d2l-input-checkbox:checked::after { - mask-image: var(--d2l-input-checkbox-check-image); - } - - input[type="checkbox"].d2l-input-checkbox:indeterminate::after { - mask-image: var(--d2l-input-checkbox-indeterminate-image); - } - } -`; +export const checkboxStyles = _generateInputCheckboxStyles('input[type="checkbox"].d2l-input-checkbox'); /** * A component that can be used to show a checkbox and optional visible label. diff --git a/components/table/table-wrapper.js b/components/table/table-wrapper.js index 780249f5348..48cfec4545d 100644 --- a/components/table/table-wrapper.js +++ b/components/table/table-wrapper.js @@ -2,7 +2,7 @@ import '../colors/colors.js'; import '../scroll-wrapper/scroll-wrapper.js'; import '../backdrop/backdrop-loading.js'; import { css, html, LitElement, nothing } from 'lit'; -import { cssSizes } from '../inputs/input-checkbox.js'; +import { cssSizes } from '../inputs/input-checkbox-styles.js'; import { getComposedParent } from '../../helpers/dom.js'; import { getFlag } from '../../helpers/flags.js'; import { ifDefined } from 'lit/directives/if-defined.js'; diff --git a/helpers/internal/css.js b/helpers/internal/css.js index e7231ed9cba..623a793b01a 100644 --- a/helpers/internal/css.js +++ b/helpers/internal/css.js @@ -1,6 +1,6 @@ export function _isValidCssSelector(selector) { const partIsValid = (part) => { - const re = /([a-zA-Z0-9-_ >.#]+)(\[[a-zA-Z0-9-_]+\])?([a-zA-Z0-9-_ >.#]+)?/g; + const re = /([a-zA-Z0-9-_ >.#]+)(\[[a-zA-Z0-9-_="]+\])?([a-zA-Z0-9-_ >.#]+)?/g; if (part === ':host') return true; const match = part.match(re); const isValid = !!match && match.length === 1 && match[0].length === part.length; diff --git a/components/typography/test/styles.test.js b/helpers/test/css.test.js similarity index 94% rename from components/typography/test/styles.test.js rename to helpers/test/css.test.js index 6e7d94a78ff..ea867169229 100644 --- a/components/typography/test/styles.test.js +++ b/helpers/test/css.test.js @@ -1,4 +1,4 @@ -import { _isValidCssSelector } from '../../../helpers/internal/css.js'; +import { _isValidCssSelector } from '../internal/css.js'; import { expect } from '@brightspace-ui/testing'; describe('_isValidCssSelector', () => { @@ -33,6 +33,7 @@ describe('_isValidCssSelector', () => { expect(_isValidCssSelector('dl #id')).to.be.true; expect(_isValidCssSelector('dl > dt')).to.be.true; expect(_isValidCssSelector('dl > dt > dd')).to.be.true; + expect(_isValidCssSelector('input[type="checkbox"].d2l-input-checkbox')).to.be.true; }); it('should support simple :host selector', () => {