mirror of
https://github.com/shoelace-style/webawesome.git
synced 2026-01-12 04:09:12 +00:00
Merge branch 'next' into themer-rework
This commit is contained in:
@@ -5,17 +5,4 @@ layout: component
|
||||
category: Navigation
|
||||
---
|
||||
|
||||
```html {.example}
|
||||
<wa-breadcrumb>
|
||||
<wa-breadcrumb-item>
|
||||
<wa-icon slot="start" name="house" variant="solid"></wa-icon>
|
||||
Home
|
||||
</wa-breadcrumb-item>
|
||||
<wa-breadcrumb-item>Clothing</wa-breadcrumb-item>
|
||||
<wa-breadcrumb-item>Shirts</wa-breadcrumb-item>
|
||||
</wa-breadcrumb>
|
||||
```
|
||||
|
||||
:::info
|
||||
Additional demonstrations can be found in the [breadcrumb examples](/docs/components/breadcrumb).
|
||||
:::
|
||||
This component must be used as a child of `<wa-breadcrumb>`. Please see the [Breadcrumb docs](/docs/components/breadcrumb) to see examples of this component in action.
|
||||
|
||||
@@ -5,41 +5,4 @@ layout: component
|
||||
category: Imagery
|
||||
---
|
||||
|
||||
```html {.example}
|
||||
<wa-carousel pagination>
|
||||
<wa-carousel-item>
|
||||
<img
|
||||
alt="The sun shines on the mountains and trees - Photo by Adam Kool on Unsplash"
|
||||
src="/assets/examples/carousel/mountains.jpg"
|
||||
/>
|
||||
</wa-carousel-item>
|
||||
<wa-carousel-item>
|
||||
<img
|
||||
alt="A waterfall in the middle of a forest - Photo by Thomas Kelly on Unsplash"
|
||||
src="/assets/examples/carousel/waterfall.jpg"
|
||||
/>
|
||||
</wa-carousel-item>
|
||||
<wa-carousel-item>
|
||||
<img
|
||||
alt="The sun is setting over a lavender field - Photo by Leonard Cotte on Unsplash"
|
||||
src="/assets/examples/carousel/sunset.jpg"
|
||||
/>
|
||||
</wa-carousel-item>
|
||||
<wa-carousel-item>
|
||||
<img
|
||||
alt="A field of grass with the sun setting in the background - Photo by Sapan Patel on Unsplash"
|
||||
src="/assets/examples/carousel/field.jpg"
|
||||
/>
|
||||
</wa-carousel-item>
|
||||
<wa-carousel-item>
|
||||
<img
|
||||
alt="A scenic view of a mountain with clouds rolling in - Photo by V2osk on Unsplash"
|
||||
src="/assets/examples/carousel/valley.jpg"
|
||||
/>
|
||||
</wa-carousel-item>
|
||||
</wa-carousel>
|
||||
```
|
||||
|
||||
:::info
|
||||
Additional demonstrations can be found in the [carousel examples](/docs/components/carousel).
|
||||
:::
|
||||
This component must be used as a child of `<wa-carousel>`. Please see the [Carousel docs](/docs/components/carousel) to see examples of this component in action.
|
||||
|
||||
@@ -5,50 +5,4 @@ layout: component
|
||||
category: Form Controls
|
||||
---
|
||||
|
||||
```html {.example}
|
||||
<wa-select label="Select one">
|
||||
<wa-option value="option-1">Option 1</wa-option>
|
||||
<wa-option value="option-2">Option 2</wa-option>
|
||||
<wa-option value="option-3">Option 3</wa-option>
|
||||
</wa-select>
|
||||
```
|
||||
|
||||
## Examples
|
||||
|
||||
### Disabled
|
||||
|
||||
Use the `disabled` attribute to disable an option and prevent it from being selected.
|
||||
|
||||
```html {.example}
|
||||
<wa-select label="Select one">
|
||||
<wa-option value="option-1">Option 1</wa-option>
|
||||
<wa-option value="option-2" disabled>Option 2</wa-option>
|
||||
<wa-option value="option-3">Option 3</wa-option>
|
||||
</wa-select>
|
||||
```
|
||||
|
||||
### Start & End Decorations
|
||||
|
||||
Use the `start` and `end` slots to add presentational elements like `<wa-icon>` next to the option label.
|
||||
|
||||
```html {.example}
|
||||
<wa-select label="Select one">
|
||||
<wa-option value="option-1">
|
||||
<wa-icon slot="start" name="envelope"></wa-icon>
|
||||
Email
|
||||
<wa-icon slot="end" name="circle-check"></wa-icon>
|
||||
</wa-option>
|
||||
|
||||
<wa-option value="option-2">
|
||||
<wa-icon slot="start" name="phone"></wa-icon>
|
||||
Phone
|
||||
<wa-icon slot="end" name="circle-check"></wa-icon>
|
||||
</wa-option>
|
||||
|
||||
<wa-option value="option-3">
|
||||
<wa-icon slot="start" name="comment"></wa-icon>
|
||||
Chat
|
||||
<wa-icon slot="end" name="circle-check"></wa-icon>
|
||||
</wa-option>
|
||||
</wa-select>
|
||||
```
|
||||
This component must be used as a child of `<wa-select>`. Please see the [Select docs](/docs/components/select) to see examples of this component in action.
|
||||
|
||||
@@ -5,70 +5,4 @@ layout: component
|
||||
category: Form Controls
|
||||
---
|
||||
|
||||
Radios are designed to be used with [radio groups](/docs/components/radio-group).
|
||||
|
||||
```html {.example}
|
||||
<wa-radio-group label="Select an option" name="a" value="1">
|
||||
<wa-radio value="1">Option 1</wa-radio>
|
||||
<wa-radio value="2">Option 2</wa-radio>
|
||||
<wa-radio value="3">Option 3</wa-radio>
|
||||
</wa-radio-group>
|
||||
```
|
||||
|
||||
:::info
|
||||
This component works with standard `<form>` elements. Please refer to the section on [form controls](/docs/form-controls) to learn more about form submission and client-side validation.
|
||||
:::
|
||||
|
||||
## Examples
|
||||
|
||||
### Initial Value
|
||||
|
||||
To set the initial value and checked state, use the `value` attribute on the containing radio group.
|
||||
|
||||
```html {.example}
|
||||
<wa-radio-group label="Select an option" name="a" value="3">
|
||||
<wa-radio value="1">Option 1</wa-radio>
|
||||
<wa-radio value="2">Option 2</wa-radio>
|
||||
<wa-radio value="3">Option 3</wa-radio>
|
||||
</wa-radio-group>
|
||||
```
|
||||
|
||||
### Disabled
|
||||
|
||||
Use the `disabled` attribute to disable a radio.
|
||||
|
||||
```html {.example}
|
||||
<wa-radio-group label="Select an option" name="a" value="1">
|
||||
<wa-radio value="1">Option 1</wa-radio>
|
||||
<wa-radio value="2" disabled>Option 2</wa-radio>
|
||||
<wa-radio value="3">Option 3</wa-radio>
|
||||
</wa-radio-group>
|
||||
```
|
||||
|
||||
### Sizes
|
||||
|
||||
Add the `size` attribute to the [Radio Group](/docs/components/radio-group) to change the radios' size.
|
||||
|
||||
```html {.example}
|
||||
<wa-radio-group size="small" value="1">
|
||||
<wa-radio value="1">Small 1</wa-radio>
|
||||
<wa-radio value="2">Small 2</wa-radio>
|
||||
<wa-radio value="3">Small 3</wa-radio>
|
||||
</wa-radio-group>
|
||||
|
||||
<br />
|
||||
|
||||
<wa-radio-group size="medium" value="1">
|
||||
<wa-radio value="1">Medium 1</wa-radio>
|
||||
<wa-radio value="2">Medium 2</wa-radio>
|
||||
<wa-radio value="3">Medium 3</wa-radio>
|
||||
</wa-radio-group>
|
||||
|
||||
<br />
|
||||
|
||||
<wa-radio-group size="large" value="1">
|
||||
<wa-radio value="1">Large 1</wa-radio>
|
||||
<wa-radio value="2">Large 2</wa-radio>
|
||||
<wa-radio value="3">Large 3</wa-radio>
|
||||
</wa-radio-group>
|
||||
```
|
||||
This component must be used as a child of `<wa-radio-group>`. Please see the [Radio Group docs](/docs/components/radio-group) to see examples of this component in action.
|
||||
|
||||
@@ -108,13 +108,13 @@ Use the `disabled` attribute to disable a select.
|
||||
|
||||
### Multiple
|
||||
|
||||
To allow multiple options to be selected, use the `multiple` attribute. It's a good practice to use `with-clear` when this option is enabled. To set multiple values at once, set `value` to a space-delimited list of values.
|
||||
To allow multiple options to be selected, use the `multiple` attribute. It's a good practice to use `with-clear` when this option is enabled. You can select multiple options by adding the `selected` attribute to individual options.
|
||||
|
||||
```html {.example}
|
||||
<wa-select label="Select a Few" value="option-1 option-2 option-3" multiple with-clear>
|
||||
<wa-option value="option-1">Option 1</wa-option>
|
||||
<wa-option value="option-2">Option 2</wa-option>
|
||||
<wa-option value="option-3">Option 3</wa-option>
|
||||
<wa-select label="Select a Few" multiple with-clear>
|
||||
<wa-option value="option-1" selected>Option 1</wa-option>
|
||||
<wa-option value="option-2" selected>Option 2</wa-option>
|
||||
<wa-option value="option-3" selected>Option 3</wa-option>
|
||||
<wa-option value="option-4">Option 4</wa-option>
|
||||
<wa-option value="option-5">Option 5</wa-option>
|
||||
<wa-option value="option-6">Option 6</wa-option>
|
||||
@@ -122,33 +122,37 @@ To allow multiple options to be selected, use the `multiple` attribute. It's a g
|
||||
```
|
||||
|
||||
:::info
|
||||
Note that multi-select options may wrap, causing the control to expand vertically. You can use the `max-options-visible` attribute to control the maximum number of selected options to show at once.
|
||||
Selecting multiple options may result in wrapping, causing the control to expand vertically. You can use the `max-options-visible` attribute to control the maximum number of selected options to show at once.
|
||||
:::
|
||||
|
||||
### Setting Initial Values
|
||||
|
||||
Use the `value` attribute to set the initial selection.
|
||||
Use the `selected` attribute on individual options to set the initial selection, similar to native HTML.
|
||||
|
||||
```html {.example}
|
||||
<wa-select value="option-1">
|
||||
<wa-option value="option-1">Option 1</wa-option>
|
||||
<wa-select>
|
||||
<wa-option value="option-1" selected>Option 1</wa-option>
|
||||
<wa-option value="option-2">Option 2</wa-option>
|
||||
<wa-option value="option-3">Option 3</wa-option>
|
||||
<wa-option value="option-4">Option 4</wa-option>
|
||||
</wa-select>
|
||||
```
|
||||
|
||||
When using `multiple`, the `value` _attribute_ uses space-delimited values to select more than one option. Because of this, `<wa-option>` values cannot contain spaces. If you're accessing the `value` _property_ through Javascript, it will be an array.
|
||||
For multiple selections, apply it to all selected options.
|
||||
|
||||
```html {.example}
|
||||
<wa-select value="option-1 option-2" multiple with-clear>
|
||||
<wa-option value="option-1">Option 1</wa-option>
|
||||
<wa-option value="option-2">Option 2</wa-option>
|
||||
<wa-select multiple with-clear>
|
||||
<wa-option value="option-1" selected>Option 1</wa-option>
|
||||
<wa-option value="option-2" selected>Option 2</wa-option>
|
||||
<wa-option value="option-3">Option 3</wa-option>
|
||||
<wa-option value="option-4">Option 4</wa-option>
|
||||
</wa-select>
|
||||
```
|
||||
|
||||
:::info
|
||||
Framework users can bind directly to the `value` property for reactive data binding and form state management.
|
||||
:::
|
||||
|
||||
### Grouping Options
|
||||
|
||||
Use `<wa-divider>` to group listbox items visually. You can also use `<small>` to provide labels, but they won't be announced by most assistive devices.
|
||||
@@ -239,17 +243,17 @@ Use the `start` and `end` slots to add presentational elements like `<wa-icon>`
|
||||
|
||||
### Custom Tags
|
||||
|
||||
When multiple options can be selected, you can provide custom tags by passing a function to the `getTag` property. Your function can return a string of HTML, a <a href="https://lit.dev/docs/templates/overview/">Lit Template</a>, or an [`HTMLElement`](https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement). The `getTag()` function will be called for each option. The first argument is an `<wa-option>` element and the second argument is the tag's index (its position in the tag list).
|
||||
When multiple options can be selected, you can provide custom tags by passing a function to the `getTag` property. Your function can return a string of HTML, a [Lit Template](https://lit.dev/docs/templates/overview/), or an [`HTMLElement`](https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement). The `getTag()` function will be called for each option. The first argument is an `<wa-option>` element and the second argument is the tag's index (its position in the tag list).
|
||||
|
||||
Remember that custom tags are rendered in a shadow root. To style them, you can use the `style` attribute in your template or you can add your own [parts](/docs/customizing/#css-parts) and target them with the [`::part()`](https://developer.mozilla.org/en-US/docs/Web/CSS/::part) selector.
|
||||
|
||||
```html {.example}
|
||||
<wa-select placeholder="Select one" value="email phone" multiple with-clear class="custom-tag">
|
||||
<wa-option value="email">
|
||||
<wa-select placeholder="Select one" multiple with-clear class="custom-tag">
|
||||
<wa-option value="email" selected>
|
||||
<wa-icon slot="start" name="envelope" variant="solid"></wa-icon>
|
||||
Email
|
||||
</wa-option>
|
||||
<wa-option value="phone">
|
||||
<wa-option value="phone" selected>
|
||||
<wa-icon slot="start" name="phone" variant="solid"></wa-icon>
|
||||
Phone
|
||||
</wa-option>
|
||||
@@ -285,17 +289,15 @@ Be sure you trust the content you are outputting! Passing unsanitized user input
|
||||
|
||||
### Lazy loading options
|
||||
|
||||
Lazy loading options is very hard to get right. `<wa-select>` largely follows how a native `<select>` works.
|
||||
Lazy loading options works similarly to native `<select>` elements. The select component handles various scenarios intelligently:
|
||||
|
||||
Here are the following conditions:
|
||||
#### Basic lazy loading scenarios:
|
||||
|
||||
- If a `<wa-select>` is created without any options, but is given a `value` attribute, its `value` will be `""`, and then when options are added, if any of the options have a value equal to the `<wa-select>` value, the value of the `<wa-select>` will equal that of the option.
|
||||
- **Empty select with value**: If a `<wa-select>` is created without any options but given a `value` attribute, its value will be `""` initially. When options are added later, if any option has a value matching the select's value attribute, the select's value will update to match.
|
||||
|
||||
EX: `<wa-select value="foo">` will have a value of `""` until `<wa-option value="foo">Foo</wa-option>` connects, at which point its value will become `"foo"` when submitting.
|
||||
- **Multiple select with partial options**: If a `<wa-select multiple>` has an initial value with multiple options, but only some options are present in the DOM, it will respect only the available options. When additional selected options are loaded later (and the user hasn't changed the selection), those options will be automatically added to the selection.
|
||||
|
||||
- If a `<wa-select multiple>` with an initial value has multiple values, but only some of the options are present, it will only respect the options that are present, and if a selected option is loaded in later, _AND_ the value of the select has not changed via user interaction or direct property assignment, it will add the selected option to the form value and to the `.value` of the select.
|
||||
|
||||
This can be hard to conceptualize, so heres a fairly large example showing how lazy loaded options work with `<wa-select>` and `<wa-select multiple>` when given initial value attributes. Feel free to play around with it in a codepen.
|
||||
Here's a comprehensive example showing different lazy loading scenarios:
|
||||
|
||||
```html {.example}
|
||||
<form id="lazy-options-example">
|
||||
@@ -319,12 +321,12 @@ This can be hard to conceptualize, so heres a fairly large example showing how l
|
||||
<br />
|
||||
|
||||
<div>
|
||||
<wa-select name="select-3" value="foo bar baz" multiple label="Multiple Select (with existing options)">
|
||||
<wa-option value="bar">Bar</wa-option>
|
||||
<wa-option value="baz">Baz</wa-option>
|
||||
<wa-select name="select-3" multiple label="Multiple Select (with existing selected options)">
|
||||
<wa-option value="bar" selected>Bar</wa-option>
|
||||
<wa-option value="baz" selected>Baz</wa-option>
|
||||
</wa-select>
|
||||
<br />
|
||||
<wa-button type="button">Add "foo" option</wa-button>
|
||||
<wa-button type="button">Add "foo" option (selected)</wa-button>
|
||||
</div>
|
||||
|
||||
<br />
|
||||
@@ -365,6 +367,12 @@ This can be hard to conceptualize, so heres a fairly large example showing how l
|
||||
const option = document.createElement('wa-option');
|
||||
option.setAttribute('value', 'foo');
|
||||
option.innerText = 'Foo';
|
||||
|
||||
// For the multiple select with existing selected options, make the new option selected
|
||||
if (select.getAttribute('name') === 'select-3') {
|
||||
option.selected = true;
|
||||
}
|
||||
|
||||
select.append(option);
|
||||
}
|
||||
|
||||
@@ -391,3 +399,7 @@ This can be hard to conceptualize, so heres a fairly large example showing how l
|
||||
container.addEventListener('submit', handleLazySubmit);
|
||||
</script>
|
||||
```
|
||||
|
||||
:::info
|
||||
The key principle is that the select component prioritizes user interactions and explicit selections over programmatic changes, ensuring a predictable user experience even with dynamically loaded content.
|
||||
:::
|
||||
|
||||
@@ -5,20 +5,4 @@ layout: component
|
||||
category: Navigation
|
||||
---
|
||||
|
||||
```html {.example}
|
||||
<wa-tab-group>
|
||||
<wa-tab panel="general">General</wa-tab>
|
||||
<wa-tab panel="custom">Custom</wa-tab>
|
||||
<wa-tab panel="advanced">Advanced</wa-tab>
|
||||
<wa-tab panel="disabled" disabled>Disabled</wa-tab>
|
||||
|
||||
<wa-tab-panel name="general">This is the general tab panel.</wa-tab-panel>
|
||||
<wa-tab-panel name="custom">This is the custom tab panel.</wa-tab-panel>
|
||||
<wa-tab-panel name="advanced">This is the advanced tab panel.</wa-tab-panel>
|
||||
<wa-tab-panel name="disabled">This is a disabled tab panel.</wa-tab-panel>
|
||||
</wa-tab-group>
|
||||
```
|
||||
|
||||
:::info
|
||||
Additional demonstrations can be found in the [tab group examples](/docs/components/tab-group).
|
||||
:::
|
||||
This component must be used as a child of `<wa-tab-group>`. Please see the [Tab Group docs](/docs/components/tab-group) to see examples of this component in action.
|
||||
|
||||
@@ -5,6 +5,4 @@ layout: component
|
||||
category: Navigation
|
||||
---
|
||||
|
||||
:::info
|
||||
Additional demonstrations can be found in the [tab group examples](/docs/components/tab-group).
|
||||
:::
|
||||
This component must be used as a child of `<wa-tab-group>`. Please see the [Tab Group docs](/docs/components/tab-group) to see examples of this component in action.
|
||||
|
||||
@@ -5,78 +5,4 @@ layout: component
|
||||
category: Navigation
|
||||
---
|
||||
|
||||
```html {.example}
|
||||
<wa-tree>
|
||||
<wa-tree-item>
|
||||
Item 1
|
||||
<wa-tree-item>Item A</wa-tree-item>
|
||||
<wa-tree-item>Item B</wa-tree-item>
|
||||
<wa-tree-item>Item C</wa-tree-item>
|
||||
</wa-tree-item>
|
||||
<wa-tree-item>Item 2</wa-tree-item>
|
||||
<wa-tree-item>Item 3</wa-tree-item>
|
||||
</wa-tree>
|
||||
```
|
||||
|
||||
## Examples
|
||||
|
||||
### Nested tree items
|
||||
|
||||
A tree item can contain other tree items. This allows the node to be expanded or collapsed by the user.
|
||||
|
||||
```html {.example}
|
||||
<wa-tree>
|
||||
<wa-tree-item>
|
||||
Item 1
|
||||
<wa-tree-item>
|
||||
Item A
|
||||
<wa-tree-item>Item Z</wa-tree-item>
|
||||
<wa-tree-item>Item Y</wa-tree-item>
|
||||
<wa-tree-item>Item X</wa-tree-item>
|
||||
</wa-tree-item>
|
||||
<wa-tree-item>Item B</wa-tree-item>
|
||||
<wa-tree-item>Item C</wa-tree-item>
|
||||
</wa-tree-item>
|
||||
<wa-tree-item>Item 2</wa-tree-item>
|
||||
<wa-tree-item>Item 3</wa-tree-item>
|
||||
</wa-tree>
|
||||
```
|
||||
|
||||
### Selected
|
||||
|
||||
Use the `selected` attribute to select a tree item initially.
|
||||
|
||||
```html {.example}
|
||||
<wa-tree>
|
||||
<wa-tree-item selected>
|
||||
Item 1
|
||||
<wa-tree-item>Item A</wa-tree-item>
|
||||
<wa-tree-item>Item B</wa-tree-item>
|
||||
<wa-tree-item>Item C</wa-tree-item>
|
||||
</wa-tree-item>
|
||||
<wa-tree-item>Item 2</wa-tree-item>
|
||||
<wa-tree-item>Item 3</wa-tree-item>
|
||||
</wa-tree>
|
||||
```
|
||||
|
||||
### Expanded
|
||||
|
||||
Use the `expanded` attribute to expand a tree item initially.
|
||||
|
||||
```html {.example}
|
||||
<wa-tree>
|
||||
<wa-tree-item expanded>
|
||||
Item 1
|
||||
<wa-tree-item expanded>
|
||||
Item A
|
||||
<wa-tree-item>Item Z</wa-tree-item>
|
||||
<wa-tree-item>Item Y</wa-tree-item>
|
||||
<wa-tree-item>Item X</wa-tree-item>
|
||||
</wa-tree-item>
|
||||
<wa-tree-item>Item B</wa-tree-item>
|
||||
<wa-tree-item>Item C</wa-tree-item>
|
||||
</wa-tree-item>
|
||||
<wa-tree-item>Item 2</wa-tree-item>
|
||||
<wa-tree-item>Item 3</wa-tree-item>
|
||||
</wa-tree>
|
||||
```
|
||||
This component must be used as a child of `<wa-tree>`. Please see the [Tree docs](/docs/components/tree) to see examples of this component in action.
|
||||
|
||||
@@ -60,6 +60,7 @@ During the alpha period, things might break! We take breaking changes very serio
|
||||
- `<wa-input>`
|
||||
- `<wa-select>`
|
||||
- `<wa-option>`
|
||||
- 🚨 BREAKING: reworked `<wa-select>` to use `<wa-option selected>` to set initially selected options, removing the "no spaces allowed" restrictions for option values
|
||||
- Added a new free component: `<wa-popover>` (#2 of 14 per stretch goals)
|
||||
- Added a new free component: `<wa-zoomable-frame>` (#3 of 14 per stretch goals)
|
||||
- Added a `min-block-size` to `<wa-divider orientation="vertical">` to ensure the divider is visible regardless of container height [issue:675]
|
||||
|
||||
@@ -6,7 +6,7 @@ import WebAwesomeElement from '../../internal/webawesome-element.js';
|
||||
import styles from './breadcrumb-item.css';
|
||||
|
||||
/**
|
||||
* @summary Breadcrumb Items are used inside [breadcrumbs](/docs/components/breadcrumb) to represent different links.
|
||||
* @summary Breadcrumb Items are used inside breadcrumbs to represent different links.
|
||||
* @documentation https://backers.webawesome.com/docs/components/breadcrumb-item
|
||||
* @status stable
|
||||
* @since 2.0
|
||||
|
||||
@@ -4,7 +4,7 @@ import WebAwesomeElement from '../../internal/webawesome-element.js';
|
||||
import styles from './carousel-item.css';
|
||||
|
||||
/**
|
||||
* @summary A carousel item represent a slide within a [carousel](/docs/components/carousel).
|
||||
* @summary A carousel item represent a slide within a carousel.
|
||||
*
|
||||
* @since 2.0
|
||||
* @status experimental
|
||||
|
||||
@@ -8,7 +8,7 @@ import '../icon/icon.js';
|
||||
import styles from './option.css';
|
||||
|
||||
/**
|
||||
* @summary Options define the selectable items within various form controls such as [select](/docs/components/select).
|
||||
* @summary Options define the selectable items within a select component.
|
||||
* @documentation https://backers.webawesome.com/docs/components/option
|
||||
* @status stable
|
||||
* @since 2.0
|
||||
@@ -46,8 +46,6 @@ export default class WaOption extends WebAwesomeElement {
|
||||
// Set via the parent select
|
||||
@state() current = false;
|
||||
|
||||
@state() selected = false;
|
||||
|
||||
/**
|
||||
* The option's value. When selected, the containing form control will receive this value. The value must be unique
|
||||
* from other options in the same group. Values may not contain spaces, as spaces are used as delimiters when listing
|
||||
@@ -56,7 +54,13 @@ export default class WaOption extends WebAwesomeElement {
|
||||
@property({ reflect: true }) value = '';
|
||||
|
||||
/** Draws the option in a disabled state, preventing selection. */
|
||||
@property({ type: Boolean, reflect: true }) disabled = false;
|
||||
@property({ type: Boolean }) disabled = false;
|
||||
|
||||
/** @internal */
|
||||
@property({ type: Boolean, attribute: false }) selected = false;
|
||||
|
||||
/** Selects an option initially. */
|
||||
@property({ type: Boolean, attribute: 'selected' }) defaultSelected = false;
|
||||
|
||||
_label: string = '';
|
||||
/**
|
||||
@@ -107,10 +111,6 @@ export default class WaOption extends WebAwesomeElement {
|
||||
|
||||
private handleDefaultSlotChange() {
|
||||
// Tell the controller to update the label
|
||||
if (customElements.get('wa-select')) {
|
||||
this.closest('wa-select')?.selectionChanged();
|
||||
}
|
||||
|
||||
this.updateDefaultLabel();
|
||||
|
||||
if (this.isInitialized) {
|
||||
@@ -119,6 +119,7 @@ export default class WaOption extends WebAwesomeElement {
|
||||
const controller = this.closest('wa-select');
|
||||
if (controller) {
|
||||
controller.handleDefaultSlotChange();
|
||||
controller.selectionChanged?.();
|
||||
}
|
||||
});
|
||||
} else {
|
||||
@@ -136,6 +137,17 @@ export default class WaOption extends WebAwesomeElement {
|
||||
}
|
||||
};
|
||||
|
||||
protected willUpdate(changedProperties: PropertyValues<this>): void {
|
||||
if (changedProperties.has('defaultSelected')) {
|
||||
if (!this.closest('wa-select')?.hasInteracted) {
|
||||
const oldVal = this.selected;
|
||||
this.selected = this.defaultSelected;
|
||||
this.requestUpdate('selected', oldVal);
|
||||
}
|
||||
}
|
||||
super.willUpdate(changedProperties);
|
||||
}
|
||||
|
||||
updated(changedProperties: PropertyValues<this>) {
|
||||
super.updated(changedProperties);
|
||||
|
||||
@@ -146,6 +158,7 @@ export default class WaOption extends WebAwesomeElement {
|
||||
if (changedProperties.has('selected')) {
|
||||
this.setAttribute('aria-selected', this.selected ? 'true' : 'false');
|
||||
this.customStates.set('selected', this.selected);
|
||||
this.handleDefaultSlotChange();
|
||||
}
|
||||
|
||||
if (changedProperties.has('value')) {
|
||||
@@ -155,12 +168,6 @@ export default class WaOption extends WebAwesomeElement {
|
||||
this.value = String(this.value);
|
||||
}
|
||||
|
||||
if (this.value.includes(' ')) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.error(`Option values cannot include a space. All spaces have been replaced with underscores.`, this);
|
||||
this.value = this.value.replace(/ /g, '_');
|
||||
}
|
||||
|
||||
this.handleDefaultSlotChange();
|
||||
}
|
||||
|
||||
|
||||
@@ -223,7 +223,7 @@ describe('<wa-select>', () => {
|
||||
it('should not throw on incomplete events', async () => {
|
||||
const el = await fixture<WaSelect>(html`
|
||||
<wa-select required>
|
||||
<sl-option value="option-1">Option 1</sl-option>
|
||||
<wa-option value="option-1">Option 1</wa-option>
|
||||
</wa-select>
|
||||
`);
|
||||
|
||||
@@ -416,10 +416,10 @@ describe('<wa-select>', () => {
|
||||
it('should serialize its name and value in FormData when multiple options are selected', async () => {
|
||||
const form = await fixture<HTMLFormElement>(html`
|
||||
<form>
|
||||
<wa-select name="a" value="option-2 option-3" multiple>
|
||||
<wa-select name="a" multiple>
|
||||
<wa-option value="option-1">Option 1</wa-option>
|
||||
<wa-option value="option-2">Option 2</wa-option>
|
||||
<wa-option value="option-3">Option 3</wa-option>
|
||||
<wa-option value="option-2" selected>Option 2</wa-option>
|
||||
<wa-option value="option-3" selected>Option 3</wa-option>
|
||||
</wa-select>
|
||||
</form>
|
||||
`);
|
||||
@@ -445,10 +445,10 @@ describe('<wa-select>', () => {
|
||||
it('should serialize its name and value in JSON when multiple options are selected', async () => {
|
||||
const form = await fixture<HTMLFormElement>(html`
|
||||
<form>
|
||||
<wa-select name="a" value="option-2 option-3" multiple>
|
||||
<wa-select name="a" multiple>
|
||||
<wa-option value="option-1">Option 1</wa-option>
|
||||
<wa-option value="option-2">Option 2</wa-option>
|
||||
<wa-option value="option-3">Option 3</wa-option>
|
||||
<wa-option value="option-2" selected>Option 2</wa-option>
|
||||
<wa-option value="option-3" selected>Option 3</wa-option>
|
||||
</wa-select>
|
||||
</form>
|
||||
`);
|
||||
@@ -576,10 +576,10 @@ describe('<wa-select>', () => {
|
||||
|
||||
it('should emit change and input when a tag is removed', async () => {
|
||||
const el = await fixture<WaSelect>(html`
|
||||
<wa-select value="option-1 option-2 option-3" multiple>
|
||||
<wa-option value="option-1">Option 1</wa-option>
|
||||
<wa-option value="option-2">Option 2</wa-option>
|
||||
<wa-option value="option-3">Option 3</wa-option>
|
||||
<wa-select multiple>
|
||||
<wa-option value="option-1" selected>Option 1</wa-option>
|
||||
<wa-option value="option-2" selected>Option 2</wa-option>
|
||||
<wa-option value="option-3" selected>Option 3</wa-option>
|
||||
</wa-select>
|
||||
`);
|
||||
const changeHandler = sinon.spy();
|
||||
@@ -628,9 +628,9 @@ describe('<wa-select>', () => {
|
||||
|
||||
it('should have rounded tags when using the pill attribute', async () => {
|
||||
const el = await fixture<WaSelect>(html`
|
||||
<wa-select value="option-1 option-2" multiple pill>
|
||||
<wa-option value="option-1">Option 1</wa-option>
|
||||
<wa-option value="option-2">Option 2</wa-option>
|
||||
<wa-select multiple pill>
|
||||
<wa-option value="option-1" selected>Option 1</wa-option>
|
||||
<wa-option value="option-2" selected>Option 2</wa-option>
|
||||
<wa-option value="option-3">Option 3</wa-option>
|
||||
</wa-select>
|
||||
`);
|
||||
@@ -714,24 +714,17 @@ describe('<wa-select>', () => {
|
||||
it('Should not select the option if options already exists for multiple select', async () => {
|
||||
const form = await fixture<HTMLFormElement>(
|
||||
html` <form>
|
||||
<wa-select name="select" value="foo" multiple>
|
||||
<wa-select name="select" multiple>
|
||||
<wa-option value="bar">Bar</wa-option>
|
||||
<wa-option value="baz">Baz</wa-option>
|
||||
<wa-option value="foo" selected>Foo</wa-option>
|
||||
</wa-select>
|
||||
</form>`,
|
||||
);
|
||||
|
||||
const el = form.querySelector<WaSelect>('wa-select')!;
|
||||
expect(el.value).to.be.an('array');
|
||||
expect(el.value!.length).to.equal(0);
|
||||
|
||||
const option = document.createElement('wa-option');
|
||||
option.value = 'foo';
|
||||
option.innerText = 'Foo';
|
||||
el.append(option);
|
||||
|
||||
await aTimeout(10);
|
||||
await el.updateComplete;
|
||||
expect(el.value!.length).to.equal(1);
|
||||
expect(el.value).to.have.members(['foo']);
|
||||
expect(new FormData(form).getAll('select')).to.have.members(['foo']);
|
||||
});
|
||||
@@ -739,9 +732,9 @@ describe('<wa-select>', () => {
|
||||
it('Should only select the existing options if options already exists for multiple select', async () => {
|
||||
const form = await fixture<HTMLFormElement>(
|
||||
html` <form>
|
||||
<wa-select name="select" value="foo bar baz" multiple>
|
||||
<wa-option value="bar">Bar</wa-option>
|
||||
<wa-option value="baz">Baz</wa-option>
|
||||
<wa-select name="select" multiple>
|
||||
<wa-option value="bar" selected>Bar</wa-option>
|
||||
<wa-option value="baz" selected>Baz</wa-option>
|
||||
</wa-select>
|
||||
</form>`,
|
||||
);
|
||||
@@ -756,12 +749,13 @@ describe('<wa-select>', () => {
|
||||
const option = document.createElement('wa-option');
|
||||
option.value = 'foo';
|
||||
option.innerText = 'Foo';
|
||||
option.selected = true;
|
||||
el.append(option);
|
||||
|
||||
await aTimeout(10);
|
||||
await el.updateComplete;
|
||||
expect(el.value).to.have.members(['foo', 'bar', 'baz']);
|
||||
expect(new FormData(form).getAll('select')).to.have.members(['foo', 'bar', 'baz']);
|
||||
expect(el.value).to.have.members(['bar', 'baz', 'foo']);
|
||||
expect(new FormData(form).getAll('select')).to.have.members(['bar', 'baz', 'foo']);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -796,6 +790,74 @@ describe('<wa-select>', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('with selected attribute', () => {
|
||||
it('should select options using the selected attribute for single select', async () => {
|
||||
const el = await fixture<WaSelect>(html`
|
||||
<wa-select>
|
||||
<wa-option value="option-1">Option 1</wa-option>
|
||||
<wa-option value="option-2" selected>Option 2</wa-option>
|
||||
<wa-option value="option-3">Option 3</wa-option>
|
||||
</wa-select>
|
||||
`);
|
||||
|
||||
expect(el.value).to.equal('option-2');
|
||||
expect(el.displayInput.value).to.equal('Option 2');
|
||||
});
|
||||
|
||||
it('should select multiple options using the selected attribute', async () => {
|
||||
const el = await fixture<WaSelect>(html`
|
||||
<wa-select multiple>
|
||||
<wa-option value="option-1" selected>Option 1</wa-option>
|
||||
<wa-option value="option-2">Option 2</wa-option>
|
||||
<wa-option value="option-3" selected>Option 3</wa-option>
|
||||
</wa-select>
|
||||
`);
|
||||
|
||||
expect(el.value).to.have.members(['option-1', 'option-3']);
|
||||
expect(el.value).to.have.length(2);
|
||||
});
|
||||
|
||||
it('should handle options with spaces in values', async () => {
|
||||
const el = await fixture<WaSelect>(html`
|
||||
<wa-select>
|
||||
<wa-option value="option with spaces">Option with spaces</wa-option>
|
||||
<wa-option value="another option" selected>Another option</wa-option>
|
||||
</wa-select>
|
||||
`);
|
||||
|
||||
expect(el.value).to.equal('another option');
|
||||
expect(el.displayInput.value).to.equal('Another option');
|
||||
});
|
||||
|
||||
it('should handle multiple options with spaces in values', async () => {
|
||||
const el = await fixture<WaSelect>(html`
|
||||
<wa-select multiple>
|
||||
<wa-option value="option with spaces" selected>Option with spaces</wa-option>
|
||||
<wa-option value="another option">Another option</wa-option>
|
||||
<wa-option value="third option" selected>Third option</wa-option>
|
||||
</wa-select>
|
||||
`);
|
||||
|
||||
expect(el.value).to.have.members(['option with spaces', 'third option']);
|
||||
expect(el.value).to.have.length(2);
|
||||
});
|
||||
|
||||
it('should serialize options with spaces correctly in FormData', async () => {
|
||||
const form = await fixture<HTMLFormElement>(html`
|
||||
<form>
|
||||
<wa-select name="test" multiple>
|
||||
<wa-option value="option with spaces" selected>Option with spaces</wa-option>
|
||||
<wa-option value="another option" selected>Another option</wa-option>
|
||||
</wa-select>
|
||||
</form>
|
||||
`);
|
||||
|
||||
const formData = new FormData(form);
|
||||
const values = formData.getAll('test');
|
||||
expect(values).to.have.members(['option with spaces', 'another option']);
|
||||
});
|
||||
});
|
||||
|
||||
// https://github.com/shoelace-style/webawesome-alpha/issues/263
|
||||
it('should allow interaction after being disabled and re-enabled', async () => {
|
||||
const el = await fixture<WaSelect>(html`
|
||||
|
||||
@@ -127,21 +127,13 @@ export default class WaSelect extends WebAwesomeFormAssociatedElement {
|
||||
private _defaultValue: string | string[] = '';
|
||||
|
||||
@property({
|
||||
attribute: 'value',
|
||||
reflect: true,
|
||||
converter: {
|
||||
fromAttribute: (value: string) => value.split(' '),
|
||||
toAttribute: (value: string | string[]) => (Array.isArray(value) ? value.join(' ') : value),
|
||||
},
|
||||
attribute: false,
|
||||
})
|
||||
set defaultValue(val: string | string[]) {
|
||||
this._defaultValue = this.convertDefaultValue(val);
|
||||
}
|
||||
|
||||
get defaultValue() {
|
||||
if (!this.hasUpdated) {
|
||||
this._defaultValue = this.convertDefaultValue(this._defaultValue);
|
||||
}
|
||||
return this._defaultValue;
|
||||
}
|
||||
|
||||
@@ -154,28 +146,32 @@ export default class WaSelect extends WebAwesomeFormAssociatedElement {
|
||||
const isMultiple = this.multiple || this.hasAttribute('multiple');
|
||||
|
||||
if (!isMultiple && Array.isArray(val)) {
|
||||
val = val.join(' ');
|
||||
val = val[0];
|
||||
}
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
private _value: string[] | undefined;
|
||||
@property({ attribute: false })
|
||||
|
||||
/** The select's value. This will be a string for single select or an array for multi-select. */
|
||||
@property({ attribute: 'value', reflect: false })
|
||||
set value(val: string | string[]) {
|
||||
let oldValue = this.value;
|
||||
|
||||
if (!Array.isArray(val)) {
|
||||
val = val.split(' ');
|
||||
if ((val as any) instanceof FormData) {
|
||||
val = (val as unknown as FormData).getAll(this.name) as string[];
|
||||
}
|
||||
|
||||
if (!this._value || this._value.join(' ') !== val.join(' ')) {
|
||||
this._value = val;
|
||||
let newValue = this.value;
|
||||
if (!Array.isArray(val)) {
|
||||
val = [val];
|
||||
}
|
||||
|
||||
if (newValue !== oldValue) {
|
||||
this.requestUpdate('value', oldValue);
|
||||
}
|
||||
this._value = val;
|
||||
let newValue = this.value;
|
||||
|
||||
if (newValue !== oldValue) {
|
||||
this.requestUpdate('value', oldValue);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -300,6 +296,17 @@ export default class WaSelect extends WebAwesomeFormAssociatedElement {
|
||||
|
||||
// Because this is a form control, it shouldn't be opened initially
|
||||
this.open = false;
|
||||
|
||||
if (!this._defaultValue) {
|
||||
const allOptions = this.getAllOptions();
|
||||
const selectedOptions = allOptions.filter(el => el.selected || el.defaultSelected);
|
||||
if (selectedOptions.length > 0) {
|
||||
const selectedValues = selectedOptions.map(el => el.value);
|
||||
this._defaultValue = this.multiple ? selectedValues : selectedValues[0];
|
||||
} else if (this.hasAttribute('value')) {
|
||||
this._defaultValue = this.getAttribute('value') || '';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private addOpenListeners() {
|
||||
@@ -563,10 +570,19 @@ export default class WaSelect extends WebAwesomeFormAssociatedElement {
|
||||
const allOptions = this.getAllOptions();
|
||||
this.optionValues = undefined; // dirty the value so it gets recalculated
|
||||
|
||||
// Update defaultValue if it hasn't been explicitly set and we have selected options
|
||||
if (!this._defaultValue && !this.hasUpdated) {
|
||||
const selectedOptions = allOptions.filter(el => el.selected || el.defaultSelected);
|
||||
if (selectedOptions.length > 0) {
|
||||
const selectedValues = selectedOptions.map(el => el.value);
|
||||
this._defaultValue = this.multiple ? selectedValues : selectedValues[0];
|
||||
}
|
||||
}
|
||||
|
||||
const value = this.value;
|
||||
|
||||
// Select only the options that match the new value
|
||||
this.setSelectedOptions(allOptions.filter(el => value.includes(el.value)));
|
||||
this.setSelectedOptions(allOptions.filter(el => value.includes(el.value) || el.selected));
|
||||
}
|
||||
|
||||
private handleTagRemove(event: WaRemoveEvent, directOption?: WaOption) {
|
||||
@@ -645,7 +661,12 @@ export default class WaSelect extends WebAwesomeFormAssociatedElement {
|
||||
const newSelectedOptions = Array.isArray(option) ? option : [option];
|
||||
|
||||
// Clear existing selection
|
||||
allOptions.forEach(el => (el.selected = false));
|
||||
allOptions.forEach(el => {
|
||||
if (newSelectedOptions.includes(el)) {
|
||||
return;
|
||||
}
|
||||
el.selected = false;
|
||||
});
|
||||
|
||||
// Set the new selection
|
||||
if (newSelectedOptions.length) {
|
||||
@@ -673,7 +694,9 @@ export default class WaSelect extends WebAwesomeFormAssociatedElement {
|
||||
const options = this.getAllOptions();
|
||||
|
||||
// Update selected options cache
|
||||
this.selectedOptions = options.filter(el => el.selected);
|
||||
this.selectedOptions = options.filter(el => {
|
||||
return el.selected;
|
||||
});
|
||||
let selectedValues = new Set(this.selectedOptions.map(el => el.value));
|
||||
|
||||
// Toggle values present in the DOM from this.value, while preserving options NOT present in the DOM (for lazy loading)
|
||||
@@ -847,6 +870,11 @@ export default class WaSelect extends WebAwesomeFormAssociatedElement {
|
||||
this.value = this.defaultValue;
|
||||
super.formResetCallback();
|
||||
this.handleValueChange();
|
||||
|
||||
this.updateComplete.then(() => {
|
||||
this.dispatchEvent(new InputEvent('input', { bubbles: true, composed: true }));
|
||||
this.dispatchEvent(new Event('change', { bubbles: true, composed: true }));
|
||||
});
|
||||
}
|
||||
|
||||
render() {
|
||||
|
||||
@@ -25,8 +25,6 @@ import styles from './zoomable-frame.css';
|
||||
* @csspart controls - The container that surrounds zoom control buttons.
|
||||
* @csspart zoom-in-button - The zoom in button.
|
||||
* @csspart zoom-out-button - The zoom out button.
|
||||
*
|
||||
* @cssproperty [--aspect-ratio=16/9] - The aspect ratio of the frame.
|
||||
*/
|
||||
@customElement('wa-zoomable-frame')
|
||||
export default class WaZoomableFrame extends WebAwesomeElement {
|
||||
|
||||
Reference in New Issue
Block a user