From dd5c32680a4224ea19718f99e8e969d180533a77 Mon Sep 17 00:00:00 2001 From: Cory LaViska Date: Mon, 23 Jun 2025 10:38:02 -0400 Subject: [PATCH 1/2] remove redundant examples; closes #1041 (#1064) --- .../docs/docs/components/breadcrumb-item.md | 15 +--- .../docs/docs/components/carousel-item.md | 39 +--------- .../webawesome/docs/docs/components/option.md | 48 +----------- .../webawesome/docs/docs/components/radio.md | 69 +---------------- .../docs/docs/components/tab-panel.md | 18 +---- .../webawesome/docs/docs/components/tab.md | 4 +- .../docs/docs/components/tree-item.md | 76 +------------------ .../breadcrumb-item/breadcrumb-item.ts | 2 +- .../components/carousel-item/carousel-item.ts | 2 +- .../src/components/option/option.ts | 2 +- 10 files changed, 10 insertions(+), 265 deletions(-) diff --git a/packages/webawesome/docs/docs/components/breadcrumb-item.md b/packages/webawesome/docs/docs/components/breadcrumb-item.md index aa23f85a2..f010b18ec 100644 --- a/packages/webawesome/docs/docs/components/breadcrumb-item.md +++ b/packages/webawesome/docs/docs/components/breadcrumb-item.md @@ -5,17 +5,4 @@ tags: component parent: breadcrumb --- -```html {.example} - - - - Home - - Clothing - Shirts - -``` - -:::info -Additional demonstrations can be found in the [breadcrumb examples](/docs/components/breadcrumb). -::: +This component must be used as a child of ``. Please see the [Breadcrumb docs](/docs/components/breadcrumb) to see examples of this component in action. diff --git a/packages/webawesome/docs/docs/components/carousel-item.md b/packages/webawesome/docs/docs/components/carousel-item.md index 6fb06cce8..fa1d858a1 100644 --- a/packages/webawesome/docs/docs/components/carousel-item.md +++ b/packages/webawesome/docs/docs/components/carousel-item.md @@ -6,41 +6,4 @@ parent: carousel icon: carousel-item --- -```html {.example} - - - The sun shines on the mountains and trees - Photo by Adam Kool on Unsplash - - - A waterfall in the middle of a forest - Photo by Thomas Kelly on Unsplash - - - The sun is setting over a lavender field - Photo by Leonard Cotte on Unsplash - - - A field of grass with the sun setting in the background - Photo by Sapan Patel on Unsplash - - - A scenic view of a mountain with clouds rolling in - Photo by V2osk on Unsplash - - -``` - -:::info -Additional demonstrations can be found in the [carousel examples](/docs/components/carousel). -::: +This component must be used as a child of ``. Please see the [Carousel docs](/docs/components/carousel) to see examples of this component in action. diff --git a/packages/webawesome/docs/docs/components/option.md b/packages/webawesome/docs/docs/components/option.md index 84868b736..6d2343397 100644 --- a/packages/webawesome/docs/docs/components/option.md +++ b/packages/webawesome/docs/docs/components/option.md @@ -6,50 +6,4 @@ parent: select icon: option --- -```html {.example} - - Option 1 - Option 2 - Option 3 - -``` - -## Examples - -### Disabled - -Use the `disabled` attribute to disable an option and prevent it from being selected. - -```html {.example} - - Option 1 - Option 2 - Option 3 - -``` - -### Start & End Decorations - -Use the `start` and `end` slots to add presentational elements like `` next to the option label. - -```html {.example} - - - - Email - - - - - - Phone - - - - - - Chat - - - -``` +This component must be used as a child of ``. Please see the [Select docs](/docs/components/select) to see examples of this component in action. diff --git a/packages/webawesome/docs/docs/components/radio.md b/packages/webawesome/docs/docs/components/radio.md index 10adc4a44..3cf357f50 100644 --- a/packages/webawesome/docs/docs/components/radio.md +++ b/packages/webawesome/docs/docs/components/radio.md @@ -7,71 +7,4 @@ native: radio icon: radio-group --- -Radios are designed to be used with [radio groups](/docs/components/radio-group). - -```html {.example} - - Option 1 - Option 2 - Option 3 - -``` - -:::info -This component works with standard `
` 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} - - Option 1 - Option 2 - Option 3 - -``` - -### Disabled - -Use the `disabled` attribute to disable a radio. - -```html {.example} - - Option 1 - Option 2 - Option 3 - -``` - -### Sizes - -Add the `size` attribute to the [Radio Group](/docs/components/radio-group) to change the radios' size. - -```html {.example} - - Small 1 - Small 2 - Small 3 - - -
- - - Medium 1 - Medium 2 - Medium 3 - - -
- - - Large 1 - Large 2 - Large 3 - -``` - +This component must be used as a child of ``. Please see the [Radio Group docs](/docs/components/radio-group) to see examples of this component in action. diff --git a/packages/webawesome/docs/docs/components/tab-panel.md b/packages/webawesome/docs/docs/components/tab-panel.md index fcafe7c54..6dda59793 100644 --- a/packages/webawesome/docs/docs/components/tab-panel.md +++ b/packages/webawesome/docs/docs/components/tab-panel.md @@ -6,20 +6,4 @@ parent: tab-group icon: tab-panel --- -```html {.example} - - General - Custom - Advanced - Disabled - - This is the general tab panel. - This is the custom tab panel. - This is the advanced tab panel. - This is a disabled tab panel. - -``` - -:::info -Additional demonstrations can be found in the [tab group examples](/docs/components/tab-group). -::: +This component must be used as a child of ``. Please see the [Tab Group docs](/docs/components/tab-group) to see examples of this component in action. diff --git a/packages/webawesome/docs/docs/components/tab.md b/packages/webawesome/docs/docs/components/tab.md index 2c22508d1..a5356ebe9 100644 --- a/packages/webawesome/docs/docs/components/tab.md +++ b/packages/webawesome/docs/docs/components/tab.md @@ -6,6 +6,4 @@ parent: tab-group icon: tab --- -:::info -Additional demonstrations can be found in the [tab group examples](/docs/components/tab-group). -::: +This component must be used as a child of ``. Please see the [Tab Group docs](/docs/components/tab-group) to see examples of this component in action. diff --git a/packages/webawesome/docs/docs/components/tree-item.md b/packages/webawesome/docs/docs/components/tree-item.md index f86385e55..2fca9bfd9 100644 --- a/packages/webawesome/docs/docs/components/tree-item.md +++ b/packages/webawesome/docs/docs/components/tree-item.md @@ -5,78 +5,4 @@ tags: [navigation, disclosure, apps] icon: tree --- -```html {.example} - - - Item 1 - Item A - Item B - Item C - - Item 2 - Item 3 - -``` - -## 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} - - - Item 1 - - Item A - Item Z - Item Y - Item X - - Item B - Item C - - Item 2 - Item 3 - -``` - -### Selected - -Use the `selected` attribute to select a tree item initially. - -```html {.example} - - - Item 1 - Item A - Item B - Item C - - Item 2 - Item 3 - -``` - -### Expanded - -Use the `expanded` attribute to expand a tree item initially. - -```html {.example} - - - Item 1 - - Item A - Item Z - Item Y - Item X - - Item B - Item C - - Item 2 - Item 3 - -``` +This component must be used as a child of ``. Please see the [Tree docs](/docs/components/tree) to see examples of this component in action. diff --git a/packages/webawesome/src/components/breadcrumb-item/breadcrumb-item.ts b/packages/webawesome/src/components/breadcrumb-item/breadcrumb-item.ts index 610422755..274cf6f6e 100644 --- a/packages/webawesome/src/components/breadcrumb-item/breadcrumb-item.ts +++ b/packages/webawesome/src/components/breadcrumb-item/breadcrumb-item.ts @@ -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 diff --git a/packages/webawesome/src/components/carousel-item/carousel-item.ts b/packages/webawesome/src/components/carousel-item/carousel-item.ts index 779d5df08..a655b317c 100644 --- a/packages/webawesome/src/components/carousel-item/carousel-item.ts +++ b/packages/webawesome/src/components/carousel-item/carousel-item.ts @@ -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 diff --git a/packages/webawesome/src/components/option/option.ts b/packages/webawesome/src/components/option/option.ts index 5972cec9a..25ae09f30 100644 --- a/packages/webawesome/src/components/option/option.ts +++ b/packages/webawesome/src/components/option/option.ts @@ -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 From c11d6129a376bc8a167cc2cd1c3972e19343f24f Mon Sep 17 00:00:00 2001 From: Konnor Rogers Date: Mon, 23 Jun 2025 13:46:05 -0400 Subject: [PATCH 2/2] Rework setting initial values in `` (#1063) * fix select to use selected options * fix selected stuff * remove unused prop * update tests * fix default value and form reset * remove demo * update changelog * document value prop * recommend selected in docs * document props --------- Co-authored-by: Cory LaViska --- .../webawesome/docs/docs/components/select.md | 145 +++++++++--------- .../docs/docs/resources/changelog.md | 3 +- .../src/components/option/option.ts | 33 ++-- .../src/components/select/select.test.ts | 120 +++++++++++---- .../src/components/select/select.ts | 72 ++++++--- .../zoomable-frame/zoomable-frame.ts | 2 - 6 files changed, 237 insertions(+), 138 deletions(-) diff --git a/packages/webawesome/docs/docs/components/select.md b/packages/webawesome/docs/docs/components/select.md index 0b37eae6f..101367a10 100644 --- a/packages/webawesome/docs/docs/components/select.md +++ b/packages/webawesome/docs/docs/components/select.md @@ -109,13 +109,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} - - Option 1 - Option 2 - Option 3 + + Option 1 + Option 2 + Option 3 Option 4 Option 5 Option 6 @@ -123,33 +123,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} - - Option 1 + + Option 1 Option 2 Option 3 Option 4 ``` -When using `multiple`, the `value` _attribute_ uses space-delimited values to select more than one option. Because of this, `` 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} - - Option 1 - Option 2 + + Option 1 + Option 2 Option 3 Option 4 ``` +:::info +Framework users can bind directly to the `value` property for reactive data binding and form state management. +::: + ### Grouping Options Use `` to group listbox items visually. You can also use `` to provide labels, but they won't be announced by most assistive devices. @@ -240,23 +244,17 @@ Use the `start` and `end` slots to add presentational elements like `` ### 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 Lit Template, 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 `` 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 `` 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} - - + + Email - + Phone @@ -267,9 +265,9 @@ Remember that custom tags are rendered in a shadow root. To style them, you can ``` +:::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. +::: diff --git a/packages/webawesome/docs/docs/resources/changelog.md b/packages/webawesome/docs/docs/resources/changelog.md index d8398fcb1..03995163a 100644 --- a/packages/webawesome/docs/docs/resources/changelog.md +++ b/packages/webawesome/docs/docs/resources/changelog.md @@ -59,6 +59,7 @@ During the alpha period, things might break! We take breaking changes very serio - `` - `` - `` +- 🚨 BREAKING: reworked `` to use `` to set initially selected options, removing the "no spaces allowed" restrictions for option values - Added a new free component: `` (#2 of 14 per stretch goals) - Added a new free component: `` (#3 of 14 per stretch goals) - Added a `min-block-size` to `` to ensure the divider is visible regardless of container height [issue:675] @@ -378,4 +379,4 @@ Here's a list of some of the things that have changed since Shoelace v2. For que Did we miss something? [Let us know!](https://github.com/shoelace-style/webawesome-alpha/discussions) -Are you coming from Shoelace? [The 2.x changelog can be found here.](https://shoelace.style/resources/changelog/) \ No newline at end of file +Are you coming from Shoelace? [The 2.x changelog can be found here.](https://shoelace.style/resources/changelog/) diff --git a/packages/webawesome/src/components/option/option.ts b/packages/webawesome/src/components/option/option.ts index 25ae09f30..b8b826fcb 100644 --- a/packages/webawesome/src/components/option/option.ts +++ b/packages/webawesome/src/components/option/option.ts @@ -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): 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) { 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(); } diff --git a/packages/webawesome/src/components/select/select.test.ts b/packages/webawesome/src/components/select/select.test.ts index 972e0afc1..2da954a19 100644 --- a/packages/webawesome/src/components/select/select.test.ts +++ b/packages/webawesome/src/components/select/select.test.ts @@ -223,7 +223,7 @@ describe('', () => { it('should not throw on incomplete events', async () => { const el = await fixture(html` - Option 1 + Option 1 `); @@ -416,10 +416,10 @@ describe('', () => { it('should serialize its name and value in FormData when multiple options are selected', async () => { const form = await fixture(html` - + Option 1 - Option 2 - Option 3 + Option 2 + Option 3 `); @@ -445,10 +445,10 @@ describe('', () => { it('should serialize its name and value in JSON when multiple options are selected', async () => { const form = await fixture(html`
- + Option 1 - Option 2 - Option 3 + Option 2 + Option 3 `); @@ -576,10 +576,10 @@ describe('', () => { it('should emit change and input when a tag is removed', async () => { const el = await fixture(html` - - Option 1 - Option 2 - Option 3 + + Option 1 + Option 2 + Option 3 `); const changeHandler = sinon.spy(); @@ -628,9 +628,9 @@ describe('', () => { it('should have rounded tags when using the pill attribute', async () => { const el = await fixture(html` - - Option 1 - Option 2 + + Option 1 + Option 2 Option 3 `); @@ -714,24 +714,17 @@ describe('', () => { it('Should not select the option if options already exists for multiple select', async () => { const form = await fixture( html`
- + Bar Baz + Foo `, ); const el = form.querySelector('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('', () => { it('Should only select the existing options if options already exists for multiple select', async () => { const form = await fixture( html`
- - Bar - Baz + + Bar + Baz `, ); @@ -756,12 +749,13 @@ describe('', () => { 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('', () => { }); }); + describe('with selected attribute', () => { + it('should select options using the selected attribute for single select', async () => { + const el = await fixture(html` + + Option 1 + Option 2 + Option 3 + + `); + + 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(html` + + Option 1 + Option 2 + Option 3 + + `); + + 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(html` + + Option with spaces + Another option + + `); + + 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(html` + + Option with spaces + Another option + Third option + + `); + + 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(html` +
+ + Option with spaces + Another option + +
+ `); + + 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(html` diff --git a/packages/webawesome/src/components/select/select.ts b/packages/webawesome/src/components/select/select.ts index 18998413e..ba6d37209 100644 --- a/packages/webawesome/src/components/select/select.ts +++ b/packages/webawesome/src/components/select/select.ts @@ -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() { diff --git a/packages/webawesome/src/components/zoomable-frame/zoomable-frame.ts b/packages/webawesome/src/components/zoomable-frame/zoomable-frame.ts index 68a6aae48..6f952a6e3 100644 --- a/packages/webawesome/src/components/zoomable-frame/zoomable-frame.ts +++ b/packages/webawesome/src/components/zoomable-frame/zoomable-frame.ts @@ -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 {