Skip to content
Open
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
106 changes: 77 additions & 29 deletions components/inputs/input-styles.js

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What I did here was basically expose some base-style-generator-functions that I used in the new file input-text-styles.js

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I will revert these changes in the test file. The report results are really good and there is not significant difference

Original file line number Diff line number Diff line change
Expand Up @@ -14,23 +14,28 @@ registerSemanticVariableForSvgImageUrl(
</svg>`
);

/**
* A private helper method that should not be used by general consumers
*/
export function _getInputBaseStyleDelegates(selector, focusSelector) {
return {
selector: focusClass => `
${focusSelector ? `${focusSelector},` : ''}
${selector}:${focusClass}:not(:disabled),
${selector}:hover:not(:disabled)`,
style: fullSelector => css`
${fullSelector} {
border-color: var(--d2l-theme-border-color-focus);
border-width: 2px;
outline: none;
padding: var(--d2l-input-padding-focus, calc(0.4rem - 1px) calc(0.75rem - 1px));
}`
};
}

function getStyleDelegates(selector, focusSelector, textAreaSelector) {
return {
input: {
selector: focusClass => `
${focusSelector ? `${focusSelector},` : ''}
${selector}:${focusClass}:not(:disabled),
${selector}:hover:not(:disabled)
`,
style: fullSelector => css`
${fullSelector} {
border-color: var(--d2l-theme-border-color-focus);
border-width: 2px;
outline: none;
padding: var(--d2l-input-padding-focus, calc(0.4rem - 1px) calc(0.75rem - 1px));
}
`
},
input: _getInputBaseStyleDelegates(selector, focusSelector),
textarea: {
selector: focusClass => `
${textAreaSelector}:hover:not(:disabled),
Expand Down Expand Up @@ -58,13 +63,10 @@ function getStyleDelegates(selector, focusSelector, textAreaSelector) {
};
}

export function _generateInputStyles(selector, focusSelector) {
if (!_isValidCssSelector(selector) || (focusSelector && !_isValidCssSelector(focusSelector))) return '';
const lastSpaceIndex = selector.lastIndexOf(' ');
const textareaSelector = unsafeCSS(`${selector.substring(0, lastSpaceIndex + 1)}textarea${selector.substring(lastSpaceIndex + 1)}`);
const delegates = getStyleDelegates(selector, focusSelector, textareaSelector);

selector = unsafeCSS(selector);
/**
* A private helper method that should not be used by general consumers
*/
export function _generateInputBaseStyles(selector) {
return css`
${selector} {
background-color: var(--d2l-input-background-color, var(--d2l-theme-background-color-base));
Expand All @@ -88,26 +90,72 @@ export function _generateInputStyles(selector, focusSelector) {
vertical-align: middle;
width: 100%;
}
${getFocusVisibleStyles(delegates.input.selector, delegates.input.style)}
`;
}

/**
* A private helper method that should not be used by general consumers
*/
export function _generateInputPlaceholderBaseStyles(selector) {
return css`
${selector}::placeholder {
color: var(--d2l-theme-text-color-static-faint);
font-size: 0.8rem;
font-weight: 400;
opacity: 1; /* Firefox has non-1 default */
}
${selector}::-ms-input-placeholder {
color: var(--d2l-theme-text-color-static-faint);
font-size: 0.8rem;
font-weight: 400;
}
`;
}

[aria-invalid="true"]${selector}:not(:disabled) {
/**
* A private helper method that should not be used by general consumers
*/
export function _generateInputAriaInvalidBaseStyles(selector) {
return css`
${selector}[aria-invalid="true"]:not(:disabled) {
border-color: var(--d2l-theme-status-color-error);
}
`;
}

/**
* A private helper method that should not be used by general consumers
*/
export function _generateInputDisabledBaseStyles(selector) {
return css`
${selector}:disabled {
opacity: var(--d2l-theme-opacity-disabled-control);
}
`;
}

/**
* A private helper method that should not be used by general consumers
*/
export function _generateInputStyles(selector, focusSelector) {
if (!_isValidCssSelector(selector) || (focusSelector && !_isValidCssSelector(focusSelector))) return '';
const lastSpaceIndex = selector.lastIndexOf(' ');
const textareaSelector = unsafeCSS(`${selector.substring(0, lastSpaceIndex + 1)}textarea${selector.substring(lastSpaceIndex + 1)}`);
const delegates = getStyleDelegates(selector, focusSelector, textareaSelector);

selector = unsafeCSS(selector);
return css`
${_generateInputBaseStyles(selector)}

${getFocusVisibleStyles(delegates.input.selector, delegates.input.style)}

${_generateInputPlaceholderBaseStyles(selector)}

${selector}::-ms-input-placeholder {
color: var(--d2l-theme-text-color-static-faint);
font-size: 0.8rem;
font-weight: 400;
}

${_generateInputAriaInvalidBaseStyles(selector)}

${_generateInputDisabledBaseStyles(selector)}

${selector}::-webkit-search-cancel-button,
${selector}::-webkit-search-decoration {
display: none;
Expand Down
36 changes: 36 additions & 0 deletions components/inputs/input-text-styles.js

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I thought that would be easier to understand and implement style in BSI, therefore I created this new file with the generator function.

Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@

import {
_generateInputAriaInvalidBaseStyles,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is the plan to use this functions separately on BSI? I think it would be cleaner to merge everything that is always used together under a single function so that consumers wouldn't need to import all of them separately.

@EdwinACL831 EdwinACL831 Jul 6, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, The plan is to only use the exported function _generateInputTextStyles from this file. I used only these ones to build it up easier and readable

_generateInputBaseStyles,
_generateInputDisabledBaseStyles,
_generateInputPlaceholderBaseStyles,
_getInputBaseStyleDelegates,
} from './input-styles.js';
import { css, unsafeCSS } from 'lit';
import { _isValidCssSelector } from '../../helpers/internal/css.js';
import { getFocusVisibleStyles } from '../../helpers/focus.js';

function _generateInputTextFocusStyles(selector) {
const input = _getInputBaseStyleDelegates(selector);
return getFocusVisibleStyles(input.selector, input.style);
}

/**
* A private helper method that should not be used by general consumers
*/
export function _generateInputTextStyles(selector) {
if (!_isValidCssSelector(selector)) return '';
const finalSelector = unsafeCSS(selector);

return css`
${ _generateInputBaseStyles(finalSelector) }

${ _generateInputPlaceholderBaseStyles(finalSelector) }

${ _generateInputTextFocusStyles(finalSelector) }

${ _generateInputAriaInvalidBaseStyles(finalSelector) }

${_generateInputDisabledBaseStyles(finalSelector)}
`;
}
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
38 changes: 0 additions & 38 deletions components/inputs/test/input-text.vdiff.js

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is a good practice that @dlockhart suggested me last time, and I found it very useful. Here we might see how different (if there is any) the component would look with these generated styles, compared to the sass ones

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I will revert these changes in this file. The report results are really good and there is not significant difference

Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import '../../button/button-icon.js';
import '../../icons/icon.js';
import '../input-text.js';
import { expect, fixture, focusElem, hoverElem, hoverElemAt, html } from '@brightspace-ui/testing';
import { loadSass, unloadSass } from '../../../test/load-sass.js';
import { inlineHelpFixtures } from './input-shared-content.js';

const createIcon = (icon, slot) => html`<d2l-icon icon="tier1:${icon}" slot="${slot}" style="margin-left: 0.55rem; margin-right: 0.55rem"></d2l-icon>`;
Expand Down Expand Up @@ -164,41 +163,4 @@ describe('d2l-input-text', () => {

});

describe('sass', () => {

before(loadSass);
after(unloadSass);

const sassBasicFixture = html`<input class="d2l-test-input-text" type="text" value="text">`;
const sassInvalidFixture = html`<input class="d2l-test-input-text" type="email" value="invalid@">`;
const sassAriaInvalidFixture = html`<input class="d2l-test-input-text" value="aria-invalid" aria-invalid="true">`;

[
{ name: 'basic', template: sassBasicFixture },
{ name: 'basic-focus', template: sassBasicFixture, focus: true },
{ name: 'email', template: html`<input class="d2l-test-input-text" type="email" value="bill@nye.com">` },
{ name: 'number', template: html`<input class="d2l-test-input-text" type="number" value="500">` },
{ name: 'password', template: html`<input class="d2l-test-input-text" type="password" value="123456">` },
{ name: 'search', template: html`<input class="d2l-test-input-text" type="search" value="search">` },
{ name: 'tel', template: html`<input class="d2l-test-input-text" type="tel" value="123-456-7890">` },
{ name: 'url', template: html`<input class="d2l-test-input-text" type="url" value="https://www.d2l.com">` },
{ name: 'disabled', template: html`<input class="d2l-test-input-text" disabled value="text disabled">` },
{ name: 'placeholder', template: html`<input class="d2l-test-input-text" placeholder="placeholder">` },
{ name: 'placeholder-disabled', template: html`<input class="d2l-test-input-text" disabled placeholder="placeholder disabled">` },
{ name: 'invalid', template: sassInvalidFixture },
{ name: 'invalid-disabled', template: html`<input class="d2l-test-input-text" disabled type="email" value="invalid-disabled@">` },
{ name: 'invalid-focus', template: sassInvalidFixture, focus: true },
{ name: 'aria-invalid', template: sassAriaInvalidFixture },
{ name: 'aria-invalid-disabled', template: html`<input class="d2l-test-input-text" disabled value="aria-invalid-disabled" aria-invalid="true">` },
{ name: 'aria-invalid-focus', template: sassAriaInvalidFixture, focus: true },
].forEach(({ name, template, focus }) => {
it(name, async() => {
const elem = await fixture(template, { viewport });
if (focus) await focusElem(elem);
await expect(elem).to.be.golden();
});
});

});

});