Fully support label and help-text

pull/1912/head
Matt Pharoah 2024-03-11 11:31:13 -04:00
rodzic ca71a8939c
commit 56a24b37b9
3 zmienionych plików z 49 dodań i 18 usunięć

Wyświetl plik

@ -102,3 +102,17 @@ const App = () => <SlRange value={[25,50,75]} style={{
``` ```
{% endraw %} {% endraw %}
### Label and Help Text
You can add an accessible label and/or descriptive help text using the `label` and `help-text` attributes or slots.
```html:preview
<sl-multi-range label="Difficulty Range" help-text="Search for challenges within the desired difficulty range"></sl-multi-range>
```
```jsx:react
import SlRange from '@shoelace-style/shoelace/dist/react/multi-range';
const App = () => <SlRange label="Difficulty Range" help-text"Search for challenges within the desired difficulty range" />;
```

Wyświetl plik

@ -1,6 +1,9 @@
import { classMap } from 'lit/directives/class-map.js';
import { HasSlotController } from '../../internal/slot.js';
import { html } from 'lit'; import { html } from 'lit';
import { ifDefined } from 'lit/directives/if-defined.js'; import { ifDefined } from 'lit/directives/if-defined.js';
import { property, query, queryAll } from 'lit/decorators.js'; import { property, query, queryAll } from 'lit/decorators.js';
import formControlStyles from '../../styles/form-control.styles.js';
import ShoelaceElement from '../../internal/shoelace-element.js'; import ShoelaceElement from '../../internal/shoelace-element.js';
import styles from './multi-range.styles.js'; import styles from './multi-range.styles.js';
import type { CSSResultGroup, PropertyValues } from 'lit'; import type { CSSResultGroup, PropertyValues } from 'lit';
@ -25,6 +28,9 @@ const arraysDiffer = function (a: readonly number[], b: readonly number[]): bool
* @status experimental * @status experimental
* @since next * @since next
* *
* @slot label - The range's label. Alternatively, you can use the `label` attribute.
* @slot help-text - Text that describes how to use the input. Alternatively, you can use the `help-text` attribute.
*
* @event sl-change - Emitted when an alteration to the control's value is committed by the user. * @event sl-change - Emitted when an alteration to the control's value is committed by the user.
* @event sl-input - Emitted when the control receives input. * @event sl-input - Emitted when the control receives input.
* *
@ -34,11 +40,14 @@ const arraysDiffer = function (a: readonly number[], b: readonly number[]): bool
* @cssproperty --track-height - The height of the track. * @cssproperty --track-height - The height of the track.
*/ */
export default class SlMultiRange extends ShoelaceElement { export default class SlMultiRange extends ShoelaceElement {
static styles: CSSResultGroup = [styles]; static styles: CSSResultGroup = [formControlStyles, styles];
/** The range's label. */ /** The range's label. If you need to display HTML, use the `label` slot instead. */
@property() label = ''; @property() label = '';
/** The range's help text. If you need to display HTML, use the help-text slot instead. */
@property({ attribute: 'help-text' }) helpText = '';
/** Disables the range. */ /** Disables the range. */
@property({ type: Boolean, reflect: true }) disabled = false; @property({ type: Boolean, reflect: true }) disabled = false;
@ -70,11 +79,15 @@ export default class SlMultiRange extends ShoelaceElement {
@query('.active-track') activeTrack: HTMLDivElement; @query('.active-track') activeTrack: HTMLDivElement;
@queryAll('.handle') handles: NodeListOf<HTMLDivElement>; @queryAll('.handle') handles: NodeListOf<HTMLDivElement>;
#hasSlotController = new HasSlotController(this, 'help-text', 'label');
#value: readonly number[] = [0, 100]; #value: readonly number[] = [0, 100];
#sliderValues = new Map<number, number>(); #sliderValues = new Map<number, number>();
#nextId = 1; #nextId = 1;
override render(): unknown { override render(): unknown {
const hasLabel = !!(this.label || this.#hasSlotController.test('label'));
const hasHelpText = !!(this.helpText || this.#hasSlotController.test('help-text'));
this.#sliderValues.clear(); this.#sliderValues.clear();
const handles = this.#value.map(value => { const handles = this.#value.map(value => {
const sliderId = this.#nextId++; const sliderId = this.#nextId++;
@ -84,7 +97,7 @@ export default class SlMultiRange extends ShoelaceElement {
class="handle" class="handle"
tabindex="${this.disabled ? -1 : 0}" tabindex="${this.disabled ? -1 : 0}"
role="slider" role="slider"
aria-label="${this.label}" aria-labelledby=${ifDefined(hasLabel ? "label" : undefined)}
aria-valuemin="${this.min}" aria-valuemin="${this.min}"
aria-valuemax="${this.max}" aria-valuemax="${this.max}"
aria-disabled=${ifDefined(this.disabled ? 'true' : undefined)} aria-disabled=${ifDefined(this.disabled ? 'true' : undefined)}
@ -100,11 +113,23 @@ export default class SlMultiRange extends ShoelaceElement {
}); });
return html` return html`
<label ?hidden=${!this.label}>${this.label}</label> <div class=${classMap({
<div class="base"> 'form-control': true,
<div class="track"></div> 'form-control--medium': true, // range only has one size
<div class="active-track"></div> 'form-control--has-label': hasLabel,
${handles} 'form-control--has-help-text': hasHelpText
})}>
<label id="label" class="form-control__label" aria-hidden=${hasLabel ? 'false' : 'true'}>
<slot name="label">${this.label}</slot>
</label>
<div class="base">
<div class="track"></div>
<div class="active-track"></div>
${handles}
</div>
<div class="form-control__help-text" aria-hidden=${hasHelpText ? 'false' : 'true'}>
<slot name="help-text">${this.helpText}</slot>
</div>
</div> </div>
`; `;
} }

Wyświetl plik

@ -6,23 +6,15 @@ export default css`
--track-color-active: var(--sl-color-neutral-200); --track-color-active: var(--sl-color-neutral-200);
--track-color-inactive: var(--sl-color-neutral-200); --track-color-inactive: var(--sl-color-neutral-200);
--track-height: 6px; --track-height: 6px;
}
.form-control {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
align-items: stretch; align-items: stretch;
box-sizing: border-box; box-sizing: border-box;
} }
label {
display: inline-block;
color: var(--sl-input-label-color);
margin-bottom: var(--sl-spacing-3x-small);
}
label[hidden] {
display: none;
}
.base { .base {
display: block; display: block;
position: relative; position: relative;