Add label to select and fix label bug

This commit is contained in:
Cory LaViska
2020-07-02 08:10:40 -04:00
parent fe4ec0525d
commit bc4fdc866e
8 changed files with 123 additions and 52 deletions

View File

@@ -8,9 +8,9 @@ All of Shoelace's components make use of the [shadow DOM](https://developer.mozi
```html preview
<sl-form class="form-overview">
<sl-input name="name" type="text" placeholder="Name"></sl-input>
<sl-input name="name" type="text" label="Name"></sl-input>
<br>
<sl-select name="options" placeholder="Select your favorite">
<sl-select name="options" label="Select your favorite">
<sl-menu-item value="birds">Birds</sl-menu-item>
<sl-menu-item value="cats">Cats</sl-menu-item>
<sl-menu-item value="dogs">Dogs</sl-menu-item>

View File

@@ -22,6 +22,16 @@ Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor i
## Examples
### Labels
```html preview
<sl-select label="Select one">
<sl-menu-item value="option-1">Option 1</sl-menu-item>
<sl-menu-item value="option-2">Option 2</sl-menu-item>
<sl-menu-item value="option-3">Option 3</sl-menu-item>
</sl-select>
```
### Multiple
```html preview

8
src/components.d.ts vendored
View File

@@ -568,6 +568,10 @@ export namespace Components {
* Set to true to disable the select control.
*/
"disabled": boolean;
/**
* The select's label.
*/
"label": string;
/**
* The maximum number of tags to show when `multiple` is true. After the maximum, "+n" will be shown to indicate the number of additional items that are selected. Set to -1 to remove the limit.
*/
@@ -1670,6 +1674,10 @@ declare namespace LocalJSX {
* Set to true to disable the select control.
*/
"disabled"?: boolean;
/**
* The select's label.
*/
"label"?: string;
/**
* The maximum number of tags to show when `multiple` is true. After the maximum, "+n" will be shown to indicate the number of additional items that are selected. Set to -1 to remove the limit.
*/

View File

@@ -6,9 +6,6 @@
}
.form-control {
display: flex;
flex-direction: column;
.label {
display: none;
}

View File

@@ -4,6 +4,31 @@
display: block;
}
.form-control {
.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);
}
}
}
.select {
width: 100%;
}

View File

@@ -2,6 +2,8 @@ import { Component, Element, Event, EventEmitter, Prop, State, Watch, h } from '
import ResizeObserver from 'resize-observer-polyfill';
import { getTextContent } from '../../utilities/slot';
let id = 0;
/**
* @since 1.0
* @status stable
@@ -17,6 +19,7 @@ export class Select {
this.handleBlur = this.handleBlur.bind(this);
this.handleFocus = this.handleFocus.bind(this);
this.handleKeyDown = this.handleKeyDown.bind(this);
this.handleLabelClick = this.handleLabelClick.bind(this);
this.handleMenuKeyDown = this.handleMenuKeyDown.bind(this);
this.handleMenuHide = this.handleMenuHide.bind(this);
this.handleMenuShow = this.handleMenuShow.bind(this);
@@ -26,6 +29,8 @@ export class Select {
dropdown: HTMLSlDropdownElement;
input: HTMLSlInputElement;
inputId = `input-${++id}`;
labelId = `input-label-${id}`;
menu: HTMLSlMenuElement;
resizeObserver: any;
@@ -61,6 +66,9 @@ export class Select {
/** The value of the control. This will be a string or an array depending on `multiple`. */
@Prop({ mutable: true }) value: string | Array<string> = '';
/** The select's label. */
@Prop() label = '';
@Watch('multiple')
handleMultipleChange() {
// Cast to array | string based on `this.multiple`
@@ -130,6 +138,10 @@ export class Select {
}
}
handleLabelClick() {
this.input.setFocus();
}
handleMenuKeyDown(event: KeyboardEvent) {
event.stopPropagation();
@@ -252,55 +264,76 @@ export class Select {
render() {
return (
<sl-dropdown
ref={el => (this.dropdown = el)}
closeOnSelect={!this.multiple}
containingElement={this.host}
<div
class={{
select: true,
'select--open': this.isOpen,
'select--focused': this.hasFocus,
'select--disabled': this.disabled,
'select--multiple': this.multiple,
'select--small': this.size === 'small',
'select--medium': this.size === 'medium',
'select--large': this.size === 'large'
'form-control': true,
'form-control--has-label': this.label.length > 0
}}
onSlShow={this.handleMenuShow}
onSlHide={this.handleMenuHide}
>
<sl-input
slot="trigger"
ref={el => (this.input = el)}
class="select__input"
name={this.name}
value={this.displayLabel}
disabled={this.disabled}
placeholder={this.displayLabel === '' && this.displayTags.length === 0 ? this.placeholder : null}
readonly={true}
size={this.size}
onSlFocus={this.handleFocus}
onSlBlur={this.handleBlur}
onKeyDown={this.handleKeyDown}
<label
class={{
label: true,
'label--small': this.size === 'small',
'label--medium': this.size === 'medium',
'label--large': this.size === 'large'
}}
htmlFor={this.inputId}
onClick={this.handleLabelClick}
>
{this.displayTags.length && (
<span slot="prefix" class="select__tags">
{this.displayTags}
</span>
)}
<sl-icon slot="suffix" class="select__icon" name="chevron-down" />
</sl-input>
<sl-menu
ref={el => (this.menu = el)}
class="select__menu"
onSlSelect={this.handleMenuSelect}
onKeyDown={this.handleMenuKeyDown}
<slot name="label">{this.label}</slot>
</label>
<sl-dropdown
ref={el => (this.dropdown = el)}
closeOnSelect={!this.multiple}
containingElement={this.host}
class={{
select: true,
'select--open': this.isOpen,
'select--focused': this.hasFocus,
'select--disabled': this.disabled,
'select--multiple': this.multiple,
'select--small': this.size === 'small',
'select--medium': this.size === 'medium',
'select--large': this.size === 'large'
}}
onSlShow={this.handleMenuShow}
onSlHide={this.handleMenuHide}
>
<slot />
</sl-menu>
</sl-dropdown>
<sl-input
slot="trigger"
ref={el => (this.input = el)}
id={this.inputId}
class="select__input"
name={this.name}
value={this.displayLabel}
disabled={this.disabled}
placeholder={this.displayLabel === '' && this.displayTags.length === 0 ? this.placeholder : null}
readonly={true}
size={this.size}
aria-labelledby={this.labelId}
onSlFocus={this.handleFocus}
onSlBlur={this.handleBlur}
onKeyDown={this.handleKeyDown}
>
{this.displayTags.length && (
<span slot="prefix" class="select__tags">
{this.displayTags}
</span>
)}
<sl-icon slot="suffix" class="select__icon" name="chevron-down" />
</sl-input>
<sl-menu
ref={el => (this.menu = el)}
class="select__menu"
onSlSelect={this.handleMenuSelect}
onKeyDown={this.handleMenuKeyDown}
>
<slot />
</sl-menu>
</sl-dropdown>
</div>
);
}
}

View File

@@ -6,9 +6,6 @@
}
.form-control {
display: flex;
flex-direction: column;
.label {
display: none;
}

View File

@@ -226,6 +226,7 @@ export class Textarea {
autoFocus={this.autofocus}
required={this.required}
inputMode={this.inputmode}
aria-labelledby={this.labelId}
onChange={this.handleChange}
onInput={this.handleInput}
onFocus={this.handleFocus}