mirror of
https://github.com/shoelace-style/webawesome.git
synced 2026-01-12 12:09:26 +00:00
Add labels to textarea and input
This commit is contained in:
@@ -14,6 +14,14 @@ Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor i
|
||||
|
||||
## Examples
|
||||
|
||||
### Labels
|
||||
|
||||
```html preview
|
||||
<sl-input type="text" label="Name"></sl-input>
|
||||
<br>
|
||||
<sl-input type="email" label="Email" placeholder="bob@example.com"></sl-input>
|
||||
```
|
||||
|
||||
### Size
|
||||
|
||||
```html preview
|
||||
|
||||
@@ -14,6 +14,12 @@ Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor i
|
||||
|
||||
## Examples
|
||||
|
||||
### Labels
|
||||
|
||||
```html preview
|
||||
<sl-textarea label="Comments"></sl-textarea>
|
||||
```
|
||||
|
||||
### No Resize
|
||||
|
||||
```html preview
|
||||
|
||||
20
src/components.d.ts
vendored
20
src/components.d.ts
vendored
@@ -184,7 +184,7 @@ export namespace Components {
|
||||
*/
|
||||
"show": () => Promise<boolean>;
|
||||
/**
|
||||
* The plain-text summary to show in the details header. To show an HTML summary, use the `summary` slot.
|
||||
* The summary to show in the details header.
|
||||
*/
|
||||
"summary": string;
|
||||
}
|
||||
@@ -358,6 +358,10 @@ export namespace Components {
|
||||
* The input's inputmode attribute.
|
||||
*/
|
||||
"inputmode": 'none' | 'text' | 'decimal' | 'numeric' | 'tel' | 'search' | 'email' | 'url';
|
||||
/**
|
||||
* The input's label.
|
||||
*/
|
||||
"label": string;
|
||||
/**
|
||||
* The input's max attribute.
|
||||
*/
|
||||
@@ -706,6 +710,10 @@ export namespace Components {
|
||||
* The textarea's inputmode attribute.
|
||||
*/
|
||||
"inputmode": 'none' | 'text' | 'decimal' | 'numeric' | 'tel' | 'search' | 'email' | 'url';
|
||||
/**
|
||||
* The textarea's label.
|
||||
*/
|
||||
"label": string;
|
||||
/**
|
||||
* The textarea's maxlength attribute.
|
||||
*/
|
||||
@@ -1246,7 +1254,7 @@ declare namespace LocalJSX {
|
||||
*/
|
||||
"open"?: boolean;
|
||||
/**
|
||||
* The plain-text summary to show in the details header. To show an HTML summary, use the `summary` slot.
|
||||
* The summary to show in the details header.
|
||||
*/
|
||||
"summary"?: string;
|
||||
}
|
||||
@@ -1444,6 +1452,10 @@ declare namespace LocalJSX {
|
||||
* The input's inputmode attribute.
|
||||
*/
|
||||
"inputmode"?: 'none' | 'text' | 'decimal' | 'numeric' | 'tel' | 'search' | 'email' | 'url';
|
||||
/**
|
||||
* The input's label.
|
||||
*/
|
||||
"label"?: string;
|
||||
/**
|
||||
* The input's max attribute.
|
||||
*/
|
||||
@@ -1816,6 +1828,10 @@ declare namespace LocalJSX {
|
||||
* The textarea's inputmode attribute.
|
||||
*/
|
||||
"inputmode"?: 'none' | 'text' | 'decimal' | 'numeric' | 'tel' | 'search' | 'email' | 'url';
|
||||
/**
|
||||
* The textarea's label.
|
||||
*/
|
||||
"label"?: string;
|
||||
/**
|
||||
* The textarea's maxlength attribute.
|
||||
*/
|
||||
|
||||
@@ -5,6 +5,34 @@
|
||||
cursor: text;
|
||||
}
|
||||
|
||||
.form-control {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
.label {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
.form-control--has-label {
|
||||
.label {
|
||||
display: inline-block;
|
||||
margin-bottom: var(--sl-spacing-xx-small);
|
||||
|
||||
&.label--small {
|
||||
font-size: var(--sl-input-font-size-small);
|
||||
}
|
||||
|
||||
&.label--medium {
|
||||
font-size: var(--sl-input-font-size-medium);
|
||||
}
|
||||
|
||||
&.label--large {
|
||||
font-size: var(--sl-input-font-size-large);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.input {
|
||||
flex: 1 1 auto;
|
||||
display: inline-flex;
|
||||
@@ -14,8 +42,7 @@
|
||||
width: 100%;
|
||||
font-family: var(--sl-input-font-family);
|
||||
font-weight: var(--sl-input-font-weight);
|
||||
line-height: var(--sl-line-height-normal);
|
||||
letter-spacing: var(--sl-letter-spacing-normal);
|
||||
letter-spacing: var(--sl-input-letter-spacing);
|
||||
background-color: var(--sl-input-background-color);
|
||||
border: solid var(--sl-input-border-width) var(--sl-input-border-color);
|
||||
vertical-align: middle;
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
import { Component, Element, Event, EventEmitter, Method, Prop, State, h } from '@stencil/core';
|
||||
|
||||
let id = 0;
|
||||
|
||||
/**
|
||||
* @since 1.0
|
||||
* @status stable
|
||||
@@ -27,6 +29,8 @@ export class Input {
|
||||
this.handlePasswordToggle = this.handlePasswordToggle.bind(this);
|
||||
}
|
||||
|
||||
inputId = `input-${++id}`;
|
||||
labelId = `input-label-${id}`;
|
||||
input: HTMLInputElement;
|
||||
|
||||
@Element() host: HTMLSlInputElement;
|
||||
@@ -46,6 +50,9 @@ export class Input {
|
||||
/** The input's value attribute. */
|
||||
@Prop({ mutable: true }) value: string = '';
|
||||
|
||||
/** The input's label. */
|
||||
@Prop() label = '';
|
||||
|
||||
/** The input's placeholder text. */
|
||||
@Prop() placeholder: string;
|
||||
|
||||
@@ -194,77 +201,98 @@ export class Input {
|
||||
return (
|
||||
<div
|
||||
class={{
|
||||
input: true,
|
||||
|
||||
// Sizes
|
||||
'input--small': this.size === 'small',
|
||||
'input--medium': this.size === 'medium',
|
||||
'input--large': this.size === 'large',
|
||||
|
||||
// States
|
||||
'input--disabled': this.disabled,
|
||||
'input--focused': this.hasFocus,
|
||||
'input--empty': this.value.length === 0
|
||||
'form-control': true,
|
||||
'form-control--has-label': this.label.length > 0
|
||||
}}
|
||||
onMouseDown={this.handleMouseDown}
|
||||
>
|
||||
<span class="input__prefix">
|
||||
<slot name="prefix" />
|
||||
</span>
|
||||
<label
|
||||
class={{
|
||||
label: true,
|
||||
'label--small': this.size === 'small',
|
||||
'label--medium': this.size === 'medium',
|
||||
'label--large': this.size === 'large'
|
||||
}}
|
||||
htmlFor={this.inputId}
|
||||
>
|
||||
<slot name="label">{this.label}</slot>
|
||||
</label>
|
||||
|
||||
<input
|
||||
ref={el => (this.input = el)}
|
||||
class="input__control"
|
||||
type={this.type === 'password' && this.isPasswordVisible ? 'text' : this.type}
|
||||
name={this.name}
|
||||
placeholder={this.placeholder}
|
||||
disabled={this.disabled}
|
||||
readonly={this.readonly}
|
||||
minLength={this.minlength}
|
||||
maxLength={this.maxlength}
|
||||
min={this.min}
|
||||
max={this.max}
|
||||
step={this.step}
|
||||
value={this.value}
|
||||
autoCapitalize={this.autocapitalize}
|
||||
autoComplete={this.autocomplete}
|
||||
autoCorrect={this.autocorrect}
|
||||
autoFocus={this.autofocus}
|
||||
pattern={this.pattern}
|
||||
required={this.required}
|
||||
inputMode={this.inputmode}
|
||||
onChange={this.handleChange}
|
||||
onInput={this.handleInput}
|
||||
onFocus={this.handleFocus}
|
||||
onBlur={this.handleBlur}
|
||||
/>
|
||||
<div
|
||||
class={{
|
||||
input: true,
|
||||
|
||||
{this.clearable && (
|
||||
<button class="input__clear" type="button" onClick={this.handleClearClick} tabindex="-1">
|
||||
<slot name="clear-icon">
|
||||
<sl-icon name="x-circle" />
|
||||
</slot>
|
||||
</button>
|
||||
)}
|
||||
// Sizes
|
||||
'input--small': this.size === 'small',
|
||||
'input--medium': this.size === 'medium',
|
||||
'input--large': this.size === 'large',
|
||||
|
||||
{this.togglePassword && (
|
||||
<button class="input__password-toggle" type="button" onClick={this.handlePasswordToggle} tabindex="-1">
|
||||
{this.isPasswordVisible ? (
|
||||
<slot name="show-password-icon">
|
||||
<sl-icon name="eye-slash" />
|
||||
// States
|
||||
'input--disabled': this.disabled,
|
||||
'input--focused': this.hasFocus,
|
||||
'input--empty': this.value.length === 0
|
||||
}}
|
||||
onMouseDown={this.handleMouseDown}
|
||||
>
|
||||
<span class="input__prefix">
|
||||
<slot name="prefix" />
|
||||
</span>
|
||||
|
||||
<input
|
||||
ref={el => (this.input = el)}
|
||||
id={this.inputId}
|
||||
class="input__control"
|
||||
type={this.type === 'password' && this.isPasswordVisible ? 'text' : this.type}
|
||||
name={this.name}
|
||||
placeholder={this.placeholder}
|
||||
disabled={this.disabled}
|
||||
readonly={this.readonly}
|
||||
minLength={this.minlength}
|
||||
maxLength={this.maxlength}
|
||||
min={this.min}
|
||||
max={this.max}
|
||||
step={this.step}
|
||||
value={this.value}
|
||||
autoCapitalize={this.autocapitalize}
|
||||
autoComplete={this.autocomplete}
|
||||
autoCorrect={this.autocorrect}
|
||||
autoFocus={this.autofocus}
|
||||
pattern={this.pattern}
|
||||
required={this.required}
|
||||
inputMode={this.inputmode}
|
||||
aria-labelledby={this.labelId}
|
||||
onChange={this.handleChange}
|
||||
onInput={this.handleInput}
|
||||
onFocus={this.handleFocus}
|
||||
onBlur={this.handleBlur}
|
||||
/>
|
||||
|
||||
{this.clearable && (
|
||||
<button class="input__clear" type="button" onClick={this.handleClearClick} tabindex="-1">
|
||||
<slot name="clear-icon">
|
||||
<sl-icon name="x-circle" />
|
||||
</slot>
|
||||
) : (
|
||||
<slot name="hide-password-icon">
|
||||
{' '}
|
||||
<sl-icon name="eye" />
|
||||
</slot>
|
||||
)}
|
||||
</button>
|
||||
)}
|
||||
</button>
|
||||
)}
|
||||
|
||||
<span class="input__suffix">
|
||||
<slot name="suffix" />
|
||||
</span>
|
||||
{this.togglePassword && (
|
||||
<button class="input__password-toggle" type="button" onClick={this.handlePasswordToggle} tabindex="-1">
|
||||
{this.isPasswordVisible ? (
|
||||
<slot name="show-password-icon">
|
||||
<sl-icon name="eye-slash" />
|
||||
</slot>
|
||||
) : (
|
||||
<slot name="hide-password-icon">
|
||||
{' '}
|
||||
<sl-icon name="eye" />
|
||||
</slot>
|
||||
)}
|
||||
</button>
|
||||
)}
|
||||
|
||||
<span class="input__suffix">
|
||||
<slot name="suffix" />
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -5,6 +5,34 @@
|
||||
cursor: text;
|
||||
}
|
||||
|
||||
.form-control {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
.label {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
.form-control--has-label {
|
||||
.label {
|
||||
display: inline-block;
|
||||
margin-bottom: var(--sl-spacing-xx-small);
|
||||
|
||||
&.label--small {
|
||||
font-size: var(--sl-input-font-size-small);
|
||||
}
|
||||
|
||||
&.label--medium {
|
||||
font-size: var(--sl-input-font-size-medium);
|
||||
}
|
||||
|
||||
&.label--large {
|
||||
font-size: var(--sl-input-font-size-large);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.textarea {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
@@ -13,7 +41,7 @@
|
||||
font-family: var(--sl-input-font-family);
|
||||
font-weight: var(--sl-input-font-weight);
|
||||
line-height: var(--sl-line-height-normal);
|
||||
letter-spacing: var(--sl-letter-spacing-normal);
|
||||
letter-spacing: var(--sl-input-letter-spacing);
|
||||
background-color: var(--sl-input-background-color);
|
||||
border: solid var(--sl-input-border-width) var(--sl-input-border-color);
|
||||
vertical-align: middle;
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
import { Component, Event, EventEmitter, Method, Prop, State, Watch, h } from '@stencil/core';
|
||||
import ResizeObserver from 'resize-observer-polyfill';
|
||||
|
||||
let id = 0;
|
||||
|
||||
/**
|
||||
* @since 1.0
|
||||
* @status stable
|
||||
@@ -19,6 +21,8 @@ export class Textarea {
|
||||
this.handleFocus = this.handleFocus.bind(this);
|
||||
}
|
||||
|
||||
textareaId = `input-${++id}`;
|
||||
labelId = `input-label-${id}`;
|
||||
resizeObserver: any;
|
||||
textarea: HTMLTextAreaElement;
|
||||
|
||||
@@ -33,6 +37,9 @@ export class Textarea {
|
||||
/** The textarea's value attribute. */
|
||||
@Prop({ mutable: true }) value = '';
|
||||
|
||||
/** The textarea's label. */
|
||||
@Prop() label = '';
|
||||
|
||||
/** The textarea's placeholder text. */
|
||||
@Prop() placeholder: string;
|
||||
|
||||
@@ -168,44 +175,63 @@ export class Textarea {
|
||||
return (
|
||||
<div
|
||||
class={{
|
||||
textarea: true,
|
||||
|
||||
// Sizes
|
||||
'textarea--small': this.size === 'small',
|
||||
'textarea--medium': this.size === 'medium',
|
||||
'textarea--large': this.size === 'large',
|
||||
|
||||
// States
|
||||
'textarea--disabled': this.disabled,
|
||||
'textarea--focused': this.hasFocus,
|
||||
'textarea--empty': this.value.length === 0,
|
||||
|
||||
// Modifiers
|
||||
'textarea--resize-none': this.resize === 'none',
|
||||
'textarea--resize-vertical': this.resize === 'vertical',
|
||||
'textarea--resize-auto': this.resize === 'auto'
|
||||
'form-control': true,
|
||||
'form-control--has-label': this.label.length > 0
|
||||
}}
|
||||
>
|
||||
<textarea
|
||||
ref={el => (this.textarea = el)}
|
||||
class="textarea__control"
|
||||
name={this.name}
|
||||
placeholder={this.placeholder}
|
||||
disabled={this.disabled}
|
||||
readOnly={this.readonly}
|
||||
rows={this.rows}
|
||||
maxLength={this.maxlength}
|
||||
value={this.value}
|
||||
autoCapitalize={this.autocapitalize}
|
||||
autoCorrect={this.autocorrect}
|
||||
autoFocus={this.autofocus}
|
||||
required={this.required}
|
||||
inputMode={this.inputmode}
|
||||
onChange={this.handleChange}
|
||||
onInput={this.handleInput}
|
||||
onFocus={this.handleFocus}
|
||||
onBlur={this.handleBlur}
|
||||
/>
|
||||
<label
|
||||
class={{
|
||||
label: true,
|
||||
'label--small': this.size === 'small',
|
||||
'label--medium': this.size === 'medium',
|
||||
'label--large': this.size === 'large'
|
||||
}}
|
||||
htmlFor={this.textareaId}
|
||||
>
|
||||
<slot name="label">{this.label}</slot>
|
||||
</label>
|
||||
<div
|
||||
class={{
|
||||
textarea: true,
|
||||
|
||||
// Sizes
|
||||
'textarea--small': this.size === 'small',
|
||||
'textarea--medium': this.size === 'medium',
|
||||
'textarea--large': this.size === 'large',
|
||||
|
||||
// States
|
||||
'textarea--disabled': this.disabled,
|
||||
'textarea--focused': this.hasFocus,
|
||||
'textarea--empty': this.value.length === 0,
|
||||
|
||||
// Modifiers
|
||||
'textarea--resize-none': this.resize === 'none',
|
||||
'textarea--resize-vertical': this.resize === 'vertical',
|
||||
'textarea--resize-auto': this.resize === 'auto'
|
||||
}}
|
||||
>
|
||||
<textarea
|
||||
ref={el => (this.textarea = el)}
|
||||
id={this.textareaId}
|
||||
class="textarea__control"
|
||||
name={this.name}
|
||||
placeholder={this.placeholder}
|
||||
disabled={this.disabled}
|
||||
readOnly={this.readonly}
|
||||
rows={this.rows}
|
||||
maxLength={this.maxlength}
|
||||
value={this.value}
|
||||
autoCapitalize={this.autocapitalize}
|
||||
autoCorrect={this.autocorrect}
|
||||
autoFocus={this.autofocus}
|
||||
required={this.required}
|
||||
inputMode={this.inputmode}
|
||||
onChange={this.handleChange}
|
||||
onInput={this.handleInput}
|
||||
onFocus={this.handleFocus}
|
||||
onBlur={this.handleBlur}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -176,6 +176,7 @@
|
||||
--sl-input-font-size-small: var(--sl-font-size-x-small);
|
||||
--sl-input-font-size-medium: var(--sl-font-size-small);
|
||||
--sl-input-font-size-large: var(--sl-font-size-medium);
|
||||
--sl-input-letter-spacing: var(--sl-letter-spacing-normal);
|
||||
|
||||
--sl-input-color: var(--sl-color-gray-30);
|
||||
--sl-input-color-hover: var(--sl-color-gray-30);
|
||||
|
||||
Reference in New Issue
Block a user