Skip to content

refactor!: Text Area base styles #9214

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 2 commits into from
Closed
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
92 changes: 87 additions & 5 deletions dev/text-area.html
Original file line number Diff line number Diff line change
@@ -8,14 +8,96 @@
<script type="module" src="./common.js"></script>

<script type="module">
import '@vaadin/text-area';
import '@vaadin/tooltip';
import '@vaadin/text-area/src/vaadin-lit-text-area.js';
import '@vaadin/icon/src/vaadin-lit-icon.js';
import '@vaadin/vaadin-lumo-styles/vaadin-iconset.js';
import '@vaadin/icons';
</script>
</head>

<body>
<vaadin-text-area label="Feedback" required>
<vaadin-tooltip slot="tooltip" text="Help us improve"></vaadin-tooltip>
</vaadin-text-area>
<section>
<h2>Plain</h2>
<vaadin-text-area value="Value"></vaadin-text-area>
<vaadin-text-area placeholder="Placeholder"></vaadin-text-area>
</section>

<section>
<h2>Min &amp; Max Rows</h2>
<vaadin-text-area value="Value" min-rows="1" clear-button-visible>
<vaadin-icon icon="vaadin:search" slot="prefix"></vaadin-icon>
</vaadin-text-area>

<vaadin-text-area value="I’m not sure what I should write here, but I know it should be something long because this is a multi-line text area." max-rows="3" clear-button-visible>
<vaadin-icon icon="vaadin:search" slot="prefix"></vaadin-icon>
</vaadin-text-area>
</section>

<section>
<h2>Bells & Whistles</h2>
<vaadin-text-area
label="Label"
helper-text="Description for this field."
value="Value"
clear-button-visible
error-message="You need to write something in this field."
required>
<vaadin-icon icon="vaadin:search" slot="prefix"></vaadin-icon>
</vaadin-text-area>
</section>

<section>
<h2>States</h2>
<vaadin-text-area
label="Read-only"
helper-text="Description for this field."
value="Value"
clear-button-visible
error-message="You need to write something in this field."
required
readonly>
<vaadin-icon icon="vaadin:search" slot="prefix"></vaadin-icon>
</vaadin-text-area>

<vaadin-text-area
label="Disabled"
helper-text="Description for this field."
value="Value"
clear-button-visible
error-message="You need to write something in this field."
required
disabled>
<vaadin-icon icon="vaadin:search" slot="prefix"></vaadin-icon>
</vaadin-text-area>
</section>

<section>
<h2>Helper Above Field</h2>
<vaadin-text-area
theme="helper-above-field"
label="Label"
helper-text="Description for this field."
value="Value"
clear-button-visible
error-message="You need to write something in this field."
required>
<vaadin-icon icon="vaadin:search" slot="prefix"></vaadin-icon>
</vaadin-text-area>
</section>

<section>
<h2>Content &amp; Layout Variations</h2>
<p>Resize the field to test how content flows.</p>
<vaadin-text-area
label="A very long label for this field"
helper-text="If the label wasn't enough to tell what you should input here, then this long description should be."
value="I’m not sure what I should write here, but I know it should be something long because this is a multi-line text area."
placeholder="Perhaps this gives you an idea what to write?"
clear-button-visible
error-message="In case you didn't write anything in this required field, this error message is here to let you know that you really should write something in this field."
required style="resize: both; overflow: hidden; padding: 1px; width: 50%;">
<vaadin-icon icon="vaadin:envelope-o" slot="prefix"></vaadin-icon>
</vaadin-text-area>
</section>
</body>
</html>
11 changes: 11 additions & 0 deletions packages/field-base/src/styles/field-shared-styles.js
Original file line number Diff line number Diff line change
@@ -24,6 +24,13 @@ export const fieldShared = css`
display: none !important;
}
/* The label, helper text and the error message should neither grow nor shrink. */
[part='label'],
[part='helper-text'],
[part='error-message'] {
flex: none;
}
:host(:not([has-label])) [part='label'],
:host(:not([has-helper])) [part='helper-text'],
:host(:not([has-error-message])) [part='error-message'] {
@@ -50,6 +57,10 @@ export const fieldShared = css`
display: none;
}
[part='input-field'] {
flex: auto;
}
:host([readonly]) [part='input-field'] {
cursor: default;
}
12 changes: 7 additions & 5 deletions packages/input-container/src/vaadin-input-container-styles.js
Original file line number Diff line number Diff line change
@@ -10,7 +10,6 @@ export const inputContainerStyles = css`
:host {
display: flex;
align-items: center;
flex: 0 1 auto;
--_radius: var(--vaadin-input-field-border-radius, var(--_vaadin-radius-m));
border-radius:
/* See https://developer.mozilla.org/en-US/docs/Web/CSS/border-radius */
@@ -46,8 +45,10 @@ export const inputContainerStyles = css`
}
/* Reset the native input styles */
::slotted(input) {
::slotted(:is(input, textarea)) {
appearance: none;
align-self: stretch;
box-sizing: border-box;
flex: auto;
white-space: nowrap;
overflow: hidden;
@@ -60,6 +61,7 @@ export const inputContainerStyles = css`
border-radius: 0;
min-width: 0;
font: inherit;
font-size: 1em;
color: inherit;
background: transparent;
cursor: inherit;
@@ -69,18 +71,18 @@ export const inputContainerStyles = css`
flex: none;
}
slot {
slot[name$='fix'] {
cursor: auto;
}
::slotted(:is(input, textarea))::placeholder {
/* Use ::slotted(input:placeholder-shown) in themes to style the placeholder. */
/* Use ::slotted(:is(input, textarea):placeholder-shown) to style the placeholder */
/* because ::slotted(...)::placeholder does not work in Safari. */
font: inherit;
color: inherit;
}
::slotted(input:placeholder-shown) {
::slotted(:is(input, textarea):placeholder-shown) {
color: var(--vaadin-input-field-placeholder-color, var(--_vaadin-color));
}
44 changes: 5 additions & 39 deletions packages/text-area/src/vaadin-text-area-styles.js
Original file line number Diff line number Diff line change
@@ -6,55 +6,21 @@
import { css } from 'lit';

export const textAreaStyles = css`
.vaadin-text-area-container {
flex: auto;
}
/* The label, helper text and the error message should neither grow nor shrink. */
[part='label'],
[part='helper-text'],
[part='error-message'] {
flex: none;
}
[part='input-field'] {
flex: auto;
overflow: auto;
-webkit-overflow-scrolling: touch;
scroll-padding: var(--vaadin-input-field-padding, var(--_vaadin-padding-container));
}
::slotted(textarea) {
-webkit-appearance: none;
-moz-appearance: none;
flex: auto;
overflow: hidden;
width: 100%;
height: 100%;
outline: none;
resize: none;
margin: 0;
padding: 0 0.25em;
border: 0;
border-radius: 0;
min-width: 0;
font: inherit;
font-size: 1em;
line-height: normal;
color: inherit;
background-color: transparent;
/* Disable default invalid style in Firefox */
box-shadow: none;
}
/* Override styles from <vaadin-input-container> */
[part='input-field'] ::slotted(textarea) {
align-self: stretch;
white-space: pre-wrap;
box-sizing: border-box;
}
[part='input-field'] ::slotted(:not(textarea)) {
[part='input-field'] ::slotted(:not(textarea)),
[part='clear-button'] {
align-self: flex-start;
position: sticky;
top: 0;
}
/* Workaround https://bugzilla.mozilla.org/show_bug.cgi?id=1739079 */
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
173 changes: 173 additions & 0 deletions packages/text-area/test/visual/base/text-area.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,173 @@
import { resetMouse, sendKeys, sendMouseToElement } from '@vaadin/test-runner-commands';
import { fixtureSync, mousedown } from '@vaadin/testing-helpers';
import { visualDiff } from '@web/test-runner-visual-regression';
import '../common.js';
import '../../../src/vaadin-lit-text-area.js';

describe('text-area', () => {
let div, element;

beforeEach(() => {
div = document.createElement('div');
div.style.display = 'inline-block';
div.style.padding = '10px';
// maxRows calculation fails with the default value 'normal', as browsers return the string 'normal' for the computed style.
div.style.lineHeight = '1.2';
element = fixtureSync('<vaadin-text-area></vaadin-text-area>', div);
});

afterEach(() => {
// After tests which use sendKeys() the focus-utils.js -> isKeyboardActive is set to true.
// Click once here on body to reset it so other tests are not affected by it.
// An unwanted focus-ring would be shown in other tests otherwise.
mousedown(document.body);
});

it('basic', async () => {
await visualDiff(div, 'basic');
});

it('disabled', async () => {
element.disabled = true;
await visualDiff(div, 'disabled');
});

it('readonly', async () => {
element.readonly = true;
await visualDiff(div, 'readonly');
});

it('flex', async () => {
div.style.display = 'inline-flex';
div.style.height = '200px';
await visualDiff(div, 'flex');
});

it('label', async () => {
element.label = 'Label';
await visualDiff(div, 'label');
});

it('placeholder', async () => {
element.placeholder = 'Placeholder';
await visualDiff(div, 'placeholder');
});

it('value', async () => {
element.value = 'value';
await visualDiff(div, 'value');
});

it('required', async () => {
element.label = 'Label';
element.required = true;
await visualDiff(div, 'required');
});

it('invalid', async () => {
element.invalid = true;
await visualDiff(div, 'invalid');
});

it('scrolled', async () => {
element.style.height = '70px';
element.value = 'a\nb\nc\nd\ne';
element.focus();
await visualDiff(div, 'scrolled');
});

it('scrolled with prefix, suffix, clear button', async () => {
const prefix = document.createElement('span');
prefix.setAttribute('slot', 'prefix');
prefix.textContent = '$';
element.appendChild(prefix);

const suffix = document.createElement('span');
suffix.setAttribute('slot', 'suffix');
suffix.textContent = '$';
element.appendChild(suffix);

element.clearButtonVisible = true;
element.style.height = '70px';
element.value = 'a\nb\nc\nd\ne';
element.focus();
await visualDiff(div, 'scrolled-with-prefix-suffix-clear-button');
});

it('error message', async () => {
element.label = 'Label';
element.errorMessage = 'This field is required';
element.required = true;
element.validate();
await visualDiff(div, 'error-message');
});

it('helper text', async () => {
element.helperText = 'Helper text';
await visualDiff(div, 'helper-text');
});

it('clear button', async () => {
element.value = 'value';
element.clearButtonVisible = true;
await visualDiff(div, 'clear-button');
});

it('prefix slot', async () => {
const span = document.createElement('span');
span.setAttribute('slot', 'prefix');
span.textContent = '$';
element.appendChild(span);
await visualDiff(div, 'prefix');
});

it('suffix slot', async () => {
const span = document.createElement('span');
span.setAttribute('slot', 'suffix');
span.textContent = '$';
element.appendChild(span);
await visualDiff(div, 'suffix');
});

it('min-rows', async () => {
element.value = 'value';
element.minRows = 4;
await visualDiff(div, 'min-rows');
});

it('max-rows', async () => {
element.value = Array(10).join('value\n');
element.maxRows = 4;
await visualDiff(div, 'max-rows');
});

it('single-row', async () => {
element.minRows = 1;
element.value = 'value';
element.clearButtonVisible = true;

await visualDiff(div, 'single-row');
});

describe('focus', () => {
afterEach(async () => {
await resetMouse();
});

it('keyboard focus-ring', async () => {
await sendKeys({ press: 'Tab' });
await visualDiff(div, 'keyboard-focus-ring');
});

it('pointer focus-ring disabled', async () => {
await sendMouseToElement({ type: 'click', element });
await visualDiff(div, 'pointer-focus-ring-disabled');
});

it('pointer focus-ring enabled', async () => {
element.style.setProperty('--lumo-input-field-pointer-focus-visible', '1');
await sendMouseToElement({ type: 'click', element });
await visualDiff(div, 'pointer-focus-ring-enabled');
});
});
});