kopia lustrzana https://github.com/shoelace-style/shoelace
refactor form control parts
rodzic
fdeb7689d7
commit
c26b1335f5
|
@ -262,4 +262,31 @@ const App = () => (
|
|||
);
|
||||
```
|
||||
|
||||
### Customizing Label Position
|
||||
|
||||
Use parts to to customize the label's position.
|
||||
|
||||
```html preview
|
||||
<sl-input class="label-on-left" label="Name"></sl-input><br />
|
||||
<sl-input class="label-on-left" label="Email" type="email"></sl-input>
|
||||
|
||||
<style>
|
||||
.label-on-left::part(form-control) {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 1rem;
|
||||
}
|
||||
|
||||
.label-on-left::part(form-control-label) {
|
||||
flex: 0 0 auto;
|
||||
width: 60px;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.label-on-left::part(form-control-input) {
|
||||
flex: 1 1 auto;
|
||||
}
|
||||
</style>
|
||||
```
|
||||
|
||||
[component-metadata:sl-input]
|
||||
|
|
|
@ -36,6 +36,54 @@ const App = () => (
|
|||
|
||||
## Examples
|
||||
|
||||
### Labels
|
||||
|
||||
Use the `label` attribute to give the select an accessible label. For labels that contain HTML, use the `label` slot instead.
|
||||
|
||||
```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>
|
||||
```
|
||||
|
||||
```jsx react
|
||||
import { SlMenuItem, SlSelect } from '@shoelace-style/shoelace/dist/react';
|
||||
|
||||
const App = () => (
|
||||
<SlSelect label="Select one">
|
||||
<SlMenuItem value="option-1">Option 1</SlMenuItem>
|
||||
<SlMenuItem value="option-2">Option 2</SlMenuItem>
|
||||
<SlMenuItem value="option-3">Option 3</SlMenuItem>
|
||||
</SlSelect>
|
||||
);
|
||||
```
|
||||
|
||||
### Help Text
|
||||
|
||||
Add descriptive help text to a select with the `help-text` attribute. For help texts that contain HTML, use the `help-text` slot instead.
|
||||
|
||||
```html preview
|
||||
<sl-select label="Experience" help-text="Please tell us your skill level.">
|
||||
<sl-menu-item value="1">Novice</sl-menu-item>
|
||||
<sl-menu-item value="2">Intermediate</sl-menu-item>
|
||||
<sl-menu-item value="3">Advanced</sl-menu-item>
|
||||
</sl-select>
|
||||
```
|
||||
|
||||
```jsx react
|
||||
import { SlMenuItem, SlSelect } from '@shoelace-style/shoelace/dist/react';
|
||||
|
||||
const App = () => (
|
||||
<SlSelect label="Experience" help-text="Please tell us your skill level.">
|
||||
<SlMenuItem value="1">Novice</SlMenuItem>
|
||||
<SlMenuItem value="2">Intermediate</SlMenuItem>
|
||||
<SlMenuItem value="3">Advanced</SlMenuItem>
|
||||
</SlSelect>
|
||||
);
|
||||
```
|
||||
|
||||
### Placeholders
|
||||
|
||||
Use the `placeholder` attribute to add a placeholder.
|
||||
|
@ -364,54 +412,6 @@ const App = () => (
|
|||
);
|
||||
```
|
||||
|
||||
### Labels
|
||||
|
||||
Use the `label` attribute to give the select an accessible label. For labels that contain HTML, use the `label` slot instead.
|
||||
|
||||
```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>
|
||||
```
|
||||
|
||||
```jsx react
|
||||
import { SlMenuItem, SlSelect } from '@shoelace-style/shoelace/dist/react';
|
||||
|
||||
const App = () => (
|
||||
<SlSelect label="Select one">
|
||||
<SlMenuItem value="option-1">Option 1</SlMenuItem>
|
||||
<SlMenuItem value="option-2">Option 2</SlMenuItem>
|
||||
<SlMenuItem value="option-3">Option 3</SlMenuItem>
|
||||
</SlSelect>
|
||||
);
|
||||
```
|
||||
|
||||
### Help Text
|
||||
|
||||
Add descriptive help text to a select with the `help-text` attribute. For help texts that contain HTML, use the `help-text` slot instead.
|
||||
|
||||
```html preview
|
||||
<sl-select label="Experience" help-text="Please tell us your skill level.">
|
||||
<sl-menu-item value="1">Novice</sl-menu-item>
|
||||
<sl-menu-item value="2">Intermediate</sl-menu-item>
|
||||
<sl-menu-item value="3">Advanced</sl-menu-item>
|
||||
</sl-select>
|
||||
```
|
||||
|
||||
```jsx react
|
||||
import { SlMenuItem, SlSelect } from '@shoelace-style/shoelace/dist/react';
|
||||
|
||||
const App = () => (
|
||||
<SlSelect label="Experience" help-text="Please tell us your skill level.">
|
||||
<SlMenuItem value="1">Novice</SlMenuItem>
|
||||
<SlMenuItem value="2">Intermediate</SlMenuItem>
|
||||
<SlMenuItem value="3">Advanced</SlMenuItem>
|
||||
</SlSelect>
|
||||
);
|
||||
```
|
||||
|
||||
### Placement
|
||||
|
||||
The preferred placement of the select's menu can be set with the `placement` attribute. Note that the actual position may vary to ensure the panel remains in the viewport. Valid placements are `top` and `bottom`.
|
||||
|
|
|
@ -8,6 +8,10 @@ _During the beta period, these restrictions may be relaxed in the event of a mis
|
|||
|
||||
## Next
|
||||
|
||||
- 🚨 BREAKING: refactored parts in `<sl-input>`, `<sl-range>`, `<sl-select>`, and `<sl-textarea>` to allow you to customize the label and help text position
|
||||
- Added `form-control-input` part
|
||||
- Renamed `label` to `form-control-label`
|
||||
- Renamed `help-text` to `form-control-help-text`
|
||||
- 🚨 BREAKING: removed status from the `sl-error` event payload in `<sl-icon>`
|
||||
- Added the experimental `<sl-radio-button>` component
|
||||
- Added `button-group` and `button-group__base` parts to `<sl-radio-group>`
|
||||
|
|
|
@ -5,7 +5,7 @@ import { ifDefined } from 'lit/directives/if-defined.js';
|
|||
import { html, literal } from 'lit/static-html.js';
|
||||
import '~/components/spinner/spinner';
|
||||
import { emit } from '~/internal/event';
|
||||
import { FormSubmitController } from '~/internal/form-control';
|
||||
import { FormSubmitController } from '~/internal/form';
|
||||
import { HasSlotController } from '~/internal/slot';
|
||||
import styles from './button.styles';
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@ import { classMap } from 'lit/directives/class-map.js';
|
|||
import { ifDefined } from 'lit/directives/if-defined.js';
|
||||
import { live } from 'lit/directives/live.js';
|
||||
import { emit } from '~/internal/event';
|
||||
import { FormSubmitController } from '~/internal/form-control';
|
||||
import { FormSubmitController } from '~/internal/form';
|
||||
import { watch } from '~/internal/watch';
|
||||
import styles from './checkbox.styles';
|
||||
|
||||
|
|
|
@ -15,7 +15,7 @@ import type SlInput from '~/components/input/input';
|
|||
import '~/components/visually-hidden/visually-hidden';
|
||||
import { drag } from '~/internal/drag';
|
||||
import { emit } from '~/internal/event';
|
||||
import { FormSubmitController } from '~/internal/form-control';
|
||||
import { FormSubmitController } from '~/internal/form';
|
||||
import { clamp } from '~/internal/math';
|
||||
import { watch } from '~/internal/watch';
|
||||
import { LocalizeController } from '~/utilities/localize';
|
||||
|
|
|
@ -42,7 +42,7 @@ describe('<sl-input>', () => {
|
|||
|
||||
it('should focus the input when clicking on the label', async () => {
|
||||
const el = await fixture<SlInput>(html` <sl-input label="Name"></sl-input> `);
|
||||
const label = el.shadowRoot!.querySelector('[part="label"]')!;
|
||||
const label = el.shadowRoot!.querySelector('[part="form-control-label"]')!;
|
||||
const submitHandler = sinon.spy();
|
||||
|
||||
el.addEventListener('sl-focus', submitHandler);
|
||||
|
|
|
@ -5,7 +5,7 @@ import { ifDefined } from 'lit/directives/if-defined.js';
|
|||
import { live } from 'lit/directives/live.js';
|
||||
import '~/components/icon/icon';
|
||||
import { emit } from '~/internal/event';
|
||||
import { FormSubmitController } from '~/internal/form-control';
|
||||
import { FormSubmitController } from '~/internal/form';
|
||||
import { HasSlotController } from '~/internal/slot';
|
||||
import { watch } from '~/internal/watch';
|
||||
import styles from './input.styles';
|
||||
|
@ -30,15 +30,16 @@ import styles from './input.styles';
|
|||
* @event sl-focus - Emitted when the control gains focus.
|
||||
* @event sl-blur - Emitted when the control loses focus.
|
||||
*
|
||||
* @csspart base - The component's internal wrapper.
|
||||
* @csspart form-control - The form control that wraps the label, input, and help-text.
|
||||
* @csspart label - The input label.
|
||||
* @csspart form-control-label - The label's wrapper.
|
||||
* @csspart form-control-input - The input's wrapper.
|
||||
* @csspart form-control-help-text - The help text's wrapper.
|
||||
* @csspart base - The component's internal wrapper.
|
||||
* @csspart input - The input control.
|
||||
* @csspart prefix - The input prefix container.
|
||||
* @csspart clear-button - The clear button.
|
||||
* @csspart password-toggle-button - The password toggle button.
|
||||
* @csspart suffix - The input suffix container.
|
||||
* @csspart help-text - The input help text.
|
||||
*/
|
||||
@customElement('sl-input')
|
||||
export default class SlInput extends LitElement {
|
||||
|
@ -293,11 +294,16 @@ export default class SlInput extends LitElement {
|
|||
'form-control--has-help-text': hasHelpText
|
||||
})}
|
||||
>
|
||||
<label part="label" class="form-control__label" for="input" aria-hidden=${hasLabel ? 'false' : 'true'}>
|
||||
<label
|
||||
part="form-control-label"
|
||||
class="form-control__label"
|
||||
for="input"
|
||||
aria-hidden=${hasLabel ? 'false' : 'true'}
|
||||
>
|
||||
<slot name="label">${this.label}</slot>
|
||||
</label>
|
||||
|
||||
<div class="form-control__input">
|
||||
<div part="form-control-input" class="form-control-input">
|
||||
<div
|
||||
part="base"
|
||||
class=${classMap({
|
||||
|
@ -403,7 +409,7 @@ export default class SlInput extends LitElement {
|
|||
</div>
|
||||
|
||||
<div
|
||||
part="help-text"
|
||||
part="form-control-help-text"
|
||||
id="help-text"
|
||||
class="form-control__help-text"
|
||||
aria-hidden=${hasHelpText ? 'false' : 'true'}
|
||||
|
|
|
@ -4,7 +4,7 @@ import { classMap } from 'lit/directives/class-map.js';
|
|||
import { ifDefined } from 'lit/directives/if-defined.js';
|
||||
import { live } from 'lit/directives/live.js';
|
||||
import { emit } from '~/internal/event';
|
||||
import { FormSubmitController } from '~/internal/form-control';
|
||||
import { FormSubmitController } from '~/internal/form';
|
||||
import { HasSlotController } from '~/internal/slot';
|
||||
import { watch } from '~/internal/watch';
|
||||
import styles from './range.styles';
|
||||
|
@ -20,6 +20,10 @@ import styles from './range.styles';
|
|||
* @event sl-blur - Emitted when the control loses focus.
|
||||
* @event sl-focus - Emitted when the control gains focus.
|
||||
*
|
||||
* @csspart form-control - The form control that wraps the label, input, and help-text.
|
||||
* @csspart form-control-label - The label's wrapper.
|
||||
* @csspart form-control-input - The range's wrapper.
|
||||
* @csspart form-control-help-text - The help text's wrapper.
|
||||
* @csspart base - The component's internal wrapper.
|
||||
* @csspart input - The native range input.
|
||||
* @csspart tooltip - The range tooltip.
|
||||
|
@ -213,11 +217,16 @@ export default class SlRange extends LitElement {
|
|||
'form-control--has-help-text': hasHelpText
|
||||
})}
|
||||
>
|
||||
<label part="label" class="form-control__label" for="input" aria-hidden=${hasLabel ? 'false' : 'true'}>
|
||||
<label
|
||||
part="form-control-label"
|
||||
class="form-control__label"
|
||||
for="input"
|
||||
aria-hidden=${hasLabel ? 'false' : 'true'}
|
||||
>
|
||||
<slot name="label">${this.label}</slot>
|
||||
</label>
|
||||
|
||||
<div class="form-control__input">
|
||||
<div part="form-control-input" class="form-control-input">
|
||||
<div
|
||||
part="base"
|
||||
class=${classMap({
|
||||
|
@ -260,7 +269,7 @@ export default class SlRange extends LitElement {
|
|||
</div>
|
||||
|
||||
<div
|
||||
part="help-text"
|
||||
part="form-control-help-text"
|
||||
id="help-text"
|
||||
class="form-control__help-text"
|
||||
aria-hidden=${hasHelpText ? 'false' : 'true'}
|
||||
|
|
|
@ -34,7 +34,7 @@ describe('<sl-select>', () => {
|
|||
<sl-menu-item value="option-3">Option 3</sl-menu-item>
|
||||
</sl-select>
|
||||
`);
|
||||
const label = el.shadowRoot!.querySelector('[part="label"]')!;
|
||||
const label = el.shadowRoot!.querySelector('[part="form-control-label"]')!;
|
||||
const submitHandler = sinon.spy();
|
||||
|
||||
el.addEventListener('sl-focus', submitHandler);
|
||||
|
|
|
@ -11,7 +11,7 @@ import type SlMenu from '~/components/menu/menu';
|
|||
import type { MenuSelectEventDetail } from '~/components/menu/menu';
|
||||
import '~/components/tag/tag';
|
||||
import { emit } from '~/internal/event';
|
||||
import { FormSubmitController } from '~/internal/form-control';
|
||||
import { FormSubmitController } from '~/internal/form';
|
||||
import { getTextContent, HasSlotController } from '~/internal/slot';
|
||||
import { watch } from '~/internal/watch';
|
||||
import styles from './select.styles';
|
||||
|
@ -39,15 +39,16 @@ import type { TemplateResult } from 'lit';
|
|||
* @event sl-focus - Emitted when the control gains focus.
|
||||
* @event sl-blur - Emitted when the control loses focus.
|
||||
*
|
||||
* @csspart form-control - The form control that wraps the label, input, and help-text.
|
||||
* @csspart form-control-label - The label's wrapper.
|
||||
* @csspart form-control-input - The select's wrapper.
|
||||
* @csspart form-control-help-text - The help text's wrapper.
|
||||
* @csspart base - The component's internal wrapper.
|
||||
* @csspart clear-button - The clear button.
|
||||
* @csspart control - The container that holds the prefix, label, and suffix.
|
||||
* @csspart display-label - The label that displays the current selection. Not available when used with `multiple`.
|
||||
* @csspart form-control - The form control that wraps the label, input, and help text.
|
||||
* @csspart help-text - The select's help text.
|
||||
* @csspart icon - The select's icon.
|
||||
* @csspart prefix - The select's prefix.
|
||||
* @csspart label - The select's label.
|
||||
* @csspart suffix - The select's suffix.
|
||||
* @csspart menu - The select menu, an `<sl-menu>` element.
|
||||
* @csspart tag - The multi select option, an `<sl-tag>` element.
|
||||
|
@ -464,7 +465,7 @@ export default class SlSelect extends LitElement {
|
|||
})}
|
||||
>
|
||||
<label
|
||||
part="label"
|
||||
part="form-control-label"
|
||||
class="form-control__label"
|
||||
for="input"
|
||||
aria-hidden=${hasLabel ? 'false' : 'true'}
|
||||
|
@ -473,7 +474,7 @@ export default class SlSelect extends LitElement {
|
|||
<slot name="label">${this.label}</slot>
|
||||
</label>
|
||||
|
||||
<div class="form-control__input">
|
||||
<div part="form-control-input" class="form-control-input">
|
||||
<sl-dropdown
|
||||
part="base"
|
||||
.hoist=${this.hoist}
|
||||
|
@ -568,7 +569,7 @@ export default class SlSelect extends LitElement {
|
|||
</div>
|
||||
|
||||
<div
|
||||
part="help-text"
|
||||
part="form-control-help-text"
|
||||
id="help-text"
|
||||
class="form-control__help-text"
|
||||
aria-hidden=${hasHelpText ? 'false' : 'true'}
|
||||
|
|
|
@ -4,7 +4,7 @@ import { classMap } from 'lit/directives/class-map.js';
|
|||
import { ifDefined } from 'lit/directives/if-defined.js';
|
||||
import { live } from 'lit/directives/live.js';
|
||||
import { emit } from '~/internal/event';
|
||||
import { FormSubmitController } from '~/internal/form-control';
|
||||
import { FormSubmitController } from '~/internal/form';
|
||||
import { watch } from '~/internal/watch';
|
||||
import styles from './switch.styles';
|
||||
|
||||
|
|
|
@ -19,7 +19,7 @@ describe('<sl-textarea>', () => {
|
|||
|
||||
it('should focus the textarea when clicking on the label', async () => {
|
||||
const el = await fixture<SlTextarea>(html` <sl-textarea label="Name"></sl-textarea> `);
|
||||
const label = el.shadowRoot!.querySelector('[part="label"]')!;
|
||||
const label = el.shadowRoot!.querySelector('[part="form-control-label"]')!;
|
||||
const submitHandler = sinon.spy();
|
||||
|
||||
el.addEventListener('sl-focus', submitHandler);
|
||||
|
|
|
@ -4,7 +4,7 @@ import { classMap } from 'lit/directives/class-map.js';
|
|||
import { ifDefined } from 'lit/directives/if-defined.js';
|
||||
import { live } from 'lit/directives/live.js';
|
||||
import { emit } from '~/internal/event';
|
||||
import { FormSubmitController } from '~/internal/form-control';
|
||||
import { FormSubmitController } from '~/internal/form';
|
||||
import { HasSlotController } from '~/internal/slot';
|
||||
import { watch } from '~/internal/watch';
|
||||
import styles from './textarea.styles';
|
||||
|
@ -21,11 +21,12 @@ import styles from './textarea.styles';
|
|||
* @event sl-focus - Emitted when the control gains focus.
|
||||
* @event sl-blur - Emitted when the control loses focus.
|
||||
*
|
||||
* @csspart form-control - The form control that wraps the label, input, and help-text.
|
||||
* @csspart form-control-label - The label's wrapper.
|
||||
* @csspart form-control-input - The input's wrapper.
|
||||
* @csspart form-control-help-text - The help text's wrapper.
|
||||
* @csspart base - The component's internal wrapper.
|
||||
* @csspart form-control - The form control that wraps the label, textarea, and help text.
|
||||
* @csspart label - The textarea label.
|
||||
* @csspart textarea - The textarea control.
|
||||
* @csspart help-text - The textarea help text.
|
||||
*/
|
||||
@customElement('sl-textarea')
|
||||
export default class SlTextarea extends LitElement {
|
||||
|
@ -263,11 +264,16 @@ export default class SlTextarea extends LitElement {
|
|||
'form-control--has-help-text': hasHelpText
|
||||
})}
|
||||
>
|
||||
<label part="label" class="form-control__label" for="input" aria-hidden=${hasLabel ? 'false' : 'true'}>
|
||||
<label
|
||||
part="form-control-label"
|
||||
class="form-control__label"
|
||||
for="input"
|
||||
aria-hidden=${hasLabel ? 'false' : 'true'}
|
||||
>
|
||||
<slot name="label">${this.label}</slot>
|
||||
</label>
|
||||
|
||||
<div class="form-control__input">
|
||||
<div part="form-control-input" class="form-control-input">
|
||||
<div
|
||||
part="base"
|
||||
class=${classMap({
|
||||
|
@ -314,7 +320,7 @@ export default class SlTextarea extends LitElement {
|
|||
</div>
|
||||
|
||||
<div
|
||||
part="help-text"
|
||||
part="form-control-help-text"
|
||||
id="help-text"
|
||||
class="form-control__help-text"
|
||||
aria-hidden=${hasHelpText ? 'false' : 'true'}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { LitElement } from 'lit';
|
||||
import { property, query, state } from 'lit/decorators.js';
|
||||
import { emit } from '~/internal/event';
|
||||
import { FormSubmitController } from '~/internal/form-control';
|
||||
import { FormSubmitController } from '~/internal/form';
|
||||
import { watch } from '~/internal/watch';
|
||||
|
||||
/**
|
||||
|
|
Ładowanie…
Reference in New Issue