mirror of
https://github.com/shoelace-style/webawesome.git
synced 2026-01-12 12:09:26 +00:00
Merge textarea & input styles
Also simplify textarea component DOM
This commit is contained in:
@@ -10,11 +10,14 @@
|
||||
align-items: stretch;
|
||||
justify-content: start;
|
||||
position: relative;
|
||||
height: var(--wa-form-control-height);
|
||||
|
||||
border-color: inherit;
|
||||
border-style: inherit;
|
||||
border-radius: inherit;
|
||||
transition: inherit;
|
||||
|
||||
height: var(--wa-form-control-height);
|
||||
padding-block: 0;
|
||||
}
|
||||
|
||||
input {
|
||||
@@ -26,6 +29,7 @@ input {
|
||||
/* prettier-ignore */
|
||||
background-color: rgb(118 118 118 / 0); /* ensures proper placeholder styles in webkit's date input */
|
||||
height: calc(var(--wa-form-control-height) - var(--border-width) * 2);
|
||||
padding-block: 0;
|
||||
}
|
||||
|
||||
input::-webkit-search-decoration,
|
||||
|
||||
@@ -1,13 +1,26 @@
|
||||
:host {
|
||||
display: block;
|
||||
display: flex;
|
||||
flex-flow: column;
|
||||
border-width: 0;
|
||||
}
|
||||
|
||||
:host([appearance='filled']) {
|
||||
--background-color: var(--wa-color-neutral-fill-quiet);
|
||||
--border-color: var(--background-color);
|
||||
.wa-text-field {
|
||||
display: grid;
|
||||
align-items: center;
|
||||
padding: 0;
|
||||
border-color: inherit;
|
||||
border-style: inherit;
|
||||
border-radius: inherit;
|
||||
transition: inherit;
|
||||
}
|
||||
|
||||
.control,
|
||||
textarea[part] {
|
||||
padding: var(--wa-space);
|
||||
border-radius: inherit;
|
||||
border: var(--border-width) solid transparent; /* make resizer look a little nicer */
|
||||
}
|
||||
|
||||
textarea,
|
||||
.size-adjuster {
|
||||
grid-area: 1 / 1 / 2 / 2;
|
||||
}
|
||||
@@ -18,38 +31,26 @@
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.control {
|
||||
border: none;
|
||||
background: none;
|
||||
box-shadow: none;
|
||||
cursor: inherit;
|
||||
textarea::-webkit-search-decoration,
|
||||
textarea::-webkit-search-cancel-button,
|
||||
textarea::-webkit-search-results-button,
|
||||
textarea::-webkit-search-results-decoration {
|
||||
-webkit-appearance: none;
|
||||
}
|
||||
|
||||
.control::-webkit-search-decoration,
|
||||
.control::-webkit-search-cancel-button,
|
||||
.control::-webkit-search-results-button,
|
||||
.control::-webkit-search-results-decoration {
|
||||
-webkit-appearance: none;
|
||||
}
|
||||
|
||||
.control:focus {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
/*
|
||||
* Resize types
|
||||
*/
|
||||
|
||||
.textarea--resize-none .control {
|
||||
:host([resize='none']) textarea {
|
||||
resize: none;
|
||||
}
|
||||
|
||||
.textarea--resize-vertical .control {
|
||||
:host([resize='vertical']) textarea {
|
||||
resize: vertical;
|
||||
}
|
||||
|
||||
.textarea--resize-auto .control {
|
||||
:host([resize='auto']) textarea {
|
||||
height: auto;
|
||||
resize: none;
|
||||
overflow-y: hidden;
|
||||
|
||||
@@ -11,7 +11,7 @@ import { HasSlotController } from '../../internal/slot.js';
|
||||
import { MirrorValidator } from '../../internal/validators/mirror-validator.js';
|
||||
import { watch } from '../../internal/watch.js';
|
||||
import { WebAwesomeFormAssociatedElement } from '../../internal/webawesome-element.js';
|
||||
import nativeStyles from '../../styles/native/textarea.css';
|
||||
import nativeStyles from '../../styles/native/input.css';
|
||||
import formControlStyles from '../../styles/shadow/form-control.css';
|
||||
import appearanceStyles from '../../styles/utilities/appearance.css';
|
||||
import sizeStyles from '../../styles/utilities/size.css';
|
||||
@@ -32,12 +32,10 @@ import styles from './textarea.css';
|
||||
* @event wa-input - Emitted when the control receives input.
|
||||
* @event wa-invalid - Emitted when the form control has been checked for validity and its constraints aren't satisfied.
|
||||
*
|
||||
* @csspart form-control - The form control that wraps the label, input, and hint.
|
||||
* @csspart form-control-label - The label's wrapper.
|
||||
* @csspart label - The label
|
||||
* @csspart form-control-input - The input's wrapper.
|
||||
* @csspart hint - The hint's wrapper.
|
||||
* @csspart base - The component's base wrapper.
|
||||
* @csspart textarea - The internal `<textarea>` control.
|
||||
* @csspart base - The internal `<textarea>` control.
|
||||
*
|
||||
* @cssproperty --background-color - The textarea's background color.
|
||||
* @cssproperty --border-color - The color of the textarea's borders.
|
||||
@@ -61,7 +59,6 @@ export default class WaTextarea extends WebAwesomeFormAssociatedElement {
|
||||
@query('.control') input: HTMLTextAreaElement;
|
||||
@query('.size-adjuster') sizeAdjuster: HTMLTextAreaElement;
|
||||
|
||||
@state() private hasFocus = false;
|
||||
@property() title = ''; // make reactive to pass through
|
||||
|
||||
/** The name of the textarea, submitted as a name/value pair with form data. */
|
||||
@@ -204,7 +201,6 @@ export default class WaTextarea extends WebAwesomeFormAssociatedElement {
|
||||
}
|
||||
|
||||
private handleBlur() {
|
||||
this.hasFocus = false;
|
||||
this.dispatchEvent(new WaBlurEvent());
|
||||
this.checkValidity();
|
||||
}
|
||||
@@ -218,7 +214,6 @@ export default class WaTextarea extends WebAwesomeFormAssociatedElement {
|
||||
}
|
||||
|
||||
private handleFocus() {
|
||||
this.hasFocus = true;
|
||||
this.dispatchEvent(new WaFocusEvent());
|
||||
}
|
||||
|
||||
@@ -230,7 +225,9 @@ export default class WaTextarea extends WebAwesomeFormAssociatedElement {
|
||||
|
||||
private setTextareaHeight() {
|
||||
if (this.resize === 'auto') {
|
||||
// This prevents layout shifts. We use `clientHeight` instead of `scrollHeight` to account for if the `<textarea>` has a max-height set on it. In my tests, this has worked fine. Im not aware of any edge cases. [Konnor]
|
||||
// This prevents layout shifts. We use `clientHeight` instead of `scrollHeight` to account for if the `<textarea>` has a max-height set on it.
|
||||
// In my tests, this has worked fine. Im not aware of any edge cases. [Konnor]
|
||||
// Let’s switch to `field-sizing: content` once it has better support: https://caniuse.com/mdn-css_properties_field-sizing [Lea]
|
||||
this.sizeAdjuster.style.height = `${this.input.clientHeight}px`;
|
||||
this.input.style.height = 'auto';
|
||||
this.input.style.height = `${this.input.scrollHeight}px`;
|
||||
@@ -320,77 +317,51 @@ export default class WaTextarea extends WebAwesomeFormAssociatedElement {
|
||||
const hasHint = this.hint ? true : !!hasHintSlot;
|
||||
|
||||
return html`
|
||||
<div
|
||||
part="form-control"
|
||||
class=${classMap({
|
||||
'form-control': true,
|
||||
'form-control--has-label': hasLabel,
|
||||
})}
|
||||
>
|
||||
<label part="form-control-label" class="label" for="input" aria-hidden=${hasLabel ? 'false' : 'true'}>
|
||||
<slot name="label">${this.label}</slot>
|
||||
</label>
|
||||
<label part="label" class="label" for="input" aria-hidden=${hasLabel ? 'false' : 'true'}>
|
||||
<slot name="label">${this.label}</slot>
|
||||
</label>
|
||||
|
||||
<div part="form-control-input" class="form-control-input">
|
||||
<div
|
||||
part="base"
|
||||
class=${classMap({
|
||||
textarea: true,
|
||||
'textarea--small': this.size === 'small',
|
||||
'textarea--medium': this.size === 'medium',
|
||||
'textarea--large': this.size === 'large',
|
||||
'textarea--standard': this.appearance !== 'filled',
|
||||
'textarea--filled': this.appearance === 'filled',
|
||||
'textarea--disabled': this.disabled,
|
||||
'textarea--focused': this.hasFocus,
|
||||
'textarea--empty': !this.value,
|
||||
'textarea--resize-none': this.resize === 'none',
|
||||
'textarea--resize-vertical': this.resize === 'vertical',
|
||||
'textarea--resize-auto': this.resize === 'auto',
|
||||
})}
|
||||
>
|
||||
<textarea
|
||||
part="textarea"
|
||||
id="input"
|
||||
class="control"
|
||||
title=${this.title /* An empty title prevents browser validation tooltips from appearing on hover */}
|
||||
name=${ifDefined(this.name)}
|
||||
.value=${live(this.value)}
|
||||
?disabled=${this.disabled}
|
||||
?readonly=${this.readonly}
|
||||
?required=${this.required}
|
||||
placeholder=${ifDefined(this.placeholder)}
|
||||
rows=${ifDefined(this.rows)}
|
||||
minlength=${ifDefined(this.minlength)}
|
||||
maxlength=${ifDefined(this.maxlength)}
|
||||
autocapitalize=${ifDefined(this.autocapitalize)}
|
||||
autocorrect=${ifDefined(this.autocorrect)}
|
||||
?autofocus=${this.autofocus}
|
||||
spellcheck=${ifDefined(this.spellcheck)}
|
||||
enterkeyhint=${ifDefined(this.enterkeyhint)}
|
||||
inputmode=${ifDefined(this.inputmode)}
|
||||
aria-describedby="hint"
|
||||
@change=${this.handleChange}
|
||||
@input=${this.handleInput}
|
||||
@focus=${this.handleFocus}
|
||||
@blur=${this.handleBlur}
|
||||
></textarea>
|
||||
<div part="textarea" class="textarea wa-text-field">
|
||||
<textarea
|
||||
part="base"
|
||||
id="input"
|
||||
class="control"
|
||||
title=${this.title /* An empty title prevents browser validation tooltips from appearing on hover */}
|
||||
name=${ifDefined(this.name)}
|
||||
.value=${live(this.value)}
|
||||
?disabled=${this.disabled}
|
||||
?readonly=${this.readonly}
|
||||
?required=${this.required}
|
||||
placeholder=${ifDefined(this.placeholder)}
|
||||
rows=${ifDefined(this.rows)}
|
||||
minlength=${ifDefined(this.minlength)}
|
||||
maxlength=${ifDefined(this.maxlength)}
|
||||
autocapitalize=${ifDefined(this.autocapitalize)}
|
||||
autocorrect=${ifDefined(this.autocorrect)}
|
||||
?autofocus=${this.autofocus}
|
||||
spellcheck=${ifDefined(this.spellcheck)}
|
||||
enterkeyhint=${ifDefined(this.enterkeyhint)}
|
||||
inputmode=${ifDefined(this.inputmode)}
|
||||
aria-describedby="hint"
|
||||
@change=${this.handleChange}
|
||||
@input=${this.handleInput}
|
||||
@focus=${this.handleFocus}
|
||||
@blur=${this.handleBlur}
|
||||
></textarea>
|
||||
|
||||
<!-- This "adjuster" exists to prevent layout shifting. https://github.com/shoelace-style/shoelace/issues/2180 -->
|
||||
<div part="textarea-adjuster" class="size-adjuster" ?hidden=${this.resize !== 'auto'}></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<slot
|
||||
name="hint"
|
||||
part="hint"
|
||||
aria-hidden=${hasHint ? 'false' : 'true'}
|
||||
class=${classMap({
|
||||
'has-slotted': hasHint,
|
||||
})}
|
||||
>${this.hint}</slot
|
||||
>
|
||||
<!-- This "adjuster" exists to prevent layout shifting. https://github.com/shoelace-style/shoelace/issues/2180 -->
|
||||
<div part="textarea-adjuster" class="size-adjuster" ?hidden=${this.resize !== 'auto'}></div>
|
||||
</div>
|
||||
|
||||
<slot
|
||||
name="hint"
|
||||
part="hint"
|
||||
aria-hidden=${hasHint ? 'false' : 'true'}
|
||||
class=${classMap({
|
||||
'has-slotted': hasHint,
|
||||
})}
|
||||
>${this.hint}</slot
|
||||
>
|
||||
`;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,7 +8,6 @@
|
||||
@import url('native/input.css');
|
||||
@import url('native/details.css');
|
||||
@import url('native/tables.css');
|
||||
@import url('native/textarea.css');
|
||||
@import url('native/blockquote.css');
|
||||
@import url('native/dialog.css');
|
||||
@import url('native/slider.css');
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
.wa-text-field,
|
||||
:host,
|
||||
input:not(
|
||||
textarea,
|
||||
input:where(:not(
|
||||
/* Exclude inputs that don't accept text */
|
||||
[type='button'],
|
||||
[type='checkbox'],
|
||||
@@ -12,9 +13,9 @@ input:not(
|
||||
[type='range'],
|
||||
[type='reset'],
|
||||
[type='submit']
|
||||
) {
|
||||
)) {
|
||||
/* Style native inputs and <wa-input>'s visible container */
|
||||
&:where(:not(.wa-text-field *, :host input)) {
|
||||
&:where(:not(.wa-text-field *, :host input, :host textarea)) {
|
||||
/* Do NOT reset --background-color and --border-color here so they trickle in from the appearance utils
|
||||
* Instead we provide the fallback when setting
|
||||
*/
|
||||
@@ -39,12 +40,11 @@ input:not(
|
||||
}
|
||||
|
||||
/* Style text controls of inputs, including within <wa-input> */
|
||||
&:not(:host, input:where(.wa-text-field *)) {
|
||||
&:where(:not(:host, .wa-text-field :is(input, textarea))) {
|
||||
background-color: var(--background-color, var(--wa-form-control-background-color));
|
||||
border-width: var(--border-width);
|
||||
box-shadow: var(--box-shadow);
|
||||
padding: 0 var(--wa-space);
|
||||
height: var(--wa-form-control-height);
|
||||
padding: var(--wa-space-smaller) var(--wa-space);
|
||||
|
||||
/* Style focused inputs */
|
||||
&:focus-within {
|
||||
@@ -60,14 +60,16 @@ input:not(
|
||||
}
|
||||
}
|
||||
|
||||
&:where(input) {
|
||||
&:where(input, textarea) {
|
||||
/* Actual inputs */
|
||||
&:-webkit-autofill,
|
||||
&:-webkit-autofill:hover,
|
||||
&:-webkit-autofill:focus,
|
||||
&:-webkit-autofill:active {
|
||||
box-shadow: none;
|
||||
caret-color: var(--wa-form-control-value-color);
|
||||
&:autofill {
|
||||
&,
|
||||
&:hover,
|
||||
&:focus,
|
||||
&:active {
|
||||
box-shadow: none;
|
||||
caret-color: var(--wa-form-control-value-color);
|
||||
}
|
||||
}
|
||||
|
||||
&::placeholder {
|
||||
@@ -78,7 +80,8 @@ input:not(
|
||||
}
|
||||
}
|
||||
|
||||
.wa-text-field input {
|
||||
.wa-text-field input,
|
||||
.wa-text-field textarea {
|
||||
padding: 0;
|
||||
border: none;
|
||||
outline: none;
|
||||
|
||||
@@ -1,56 +0,0 @@
|
||||
textarea:not(:host *, .wa-off, .wa-off-deep *),
|
||||
:host {
|
||||
--background-color: var(--wa-form-control-background-color);
|
||||
--border-color: var(--wa-form-control-resting-color);
|
||||
--border-radius: var(--wa-form-control-border-radius);
|
||||
--border-style: var(--wa-form-control-border-style);
|
||||
--border-width: var(--wa-form-control-border-width);
|
||||
--box-shadow: initial;
|
||||
}
|
||||
|
||||
textarea:not(:host *, .wa-off, .wa-off-deep *),
|
||||
:host .textarea {
|
||||
background-color: var(--background-color);
|
||||
border-color: var(--border-color);
|
||||
border-radius: var(--border-radius);
|
||||
border-style: var(--border-style);
|
||||
border-width: var(--border-width);
|
||||
box-shadow: var(--box-shadow);
|
||||
display: grid;
|
||||
align-items: center;
|
||||
position: relative;
|
||||
width: 100%;
|
||||
font: inherit;
|
||||
line-height: var(--wa-form-control-value-line-height);
|
||||
vertical-align: middle;
|
||||
transition:
|
||||
background var(--wa-transition-normal) var(--wa-transition-easing),
|
||||
border var(--wa-transition-normal) var(--wa-transition-easing),
|
||||
outline var(--wa-transition-fast) var(--wa-transition-easing);
|
||||
cursor: text;
|
||||
}
|
||||
|
||||
textarea:not(:host *, .wa-off, .wa-off-deep *):focus:not(:disabled),
|
||||
:host .textarea:has(> textarea:focus:not(:disabled)) {
|
||||
outline: var(--wa-focus-ring);
|
||||
outline-offset: var(--wa-focus-ring-offset);
|
||||
}
|
||||
|
||||
textarea:not(:host *, .wa-off, .wa-off-deep *):disabled,
|
||||
:host .textarea:has(> textarea:disabled) {
|
||||
opacity: 0.5;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
textarea:not(.wa-off, .wa-off-deep *) {
|
||||
font: inherit;
|
||||
line-height: var(--wa-line-height-normal);
|
||||
color: var(--wa-form-control-value-color);
|
||||
padding: calc(var(--wa-space-smaller) - var(--border-width)) var(--wa-space);
|
||||
|
||||
&::placeholder {
|
||||
color: var(--wa-form-control-placeholder-color);
|
||||
user-select: none;
|
||||
-webkit-user-select: none;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user